Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's a C function that can be compiled with C++ compilers.</p> <pre><code>/* @(#)File: $RCSfile: mkpath.c,v $ @(#)Version: $Revision: 1.13 $ @(#)Last changed: $Date: 2012/07/15 00:40:37 $ @(#)Purpose: Create all directories in path @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1990-91,1997-98,2001,2005,2008,2012 */ /*TABSTOP=4*/ #include "jlss.h" #include "emalloc.h" #include &lt;errno.h&gt; #ifdef HAVE_UNISTD_H #include &lt;unistd.h&gt; #endif /* HAVE_UNISTD_H */ #include &lt;string.h&gt; #include "sysstat.h" /* Fix up for Windows - inc mode_t */ typedef struct stat Stat; #ifndef lint /* Prevent over-aggressive optimizers from eliminating ID string */ const char jlss_id_mkpath_c[] = "@(#)$Id: mkpath.c,v 1.13 2012/07/15 00:40:37 jleffler Exp $"; #endif /* lint */ static int do_mkdir(const char *path, mode_t mode) { Stat st; int status = 0; if (stat(path, &amp;st) != 0) { /* Directory does not exist. EEXIST for race condition */ if (mkdir(path, mode) != 0 &amp;&amp; errno != EEXIST) status = -1; } else if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; status = -1; } return(status); } /** ** mkpath - ensure all directories in path exist ** Algorithm takes the pessimistic view and works top-down to ensure ** each directory in path exists, rather than optimistically creating ** the last element and working backwards. */ int mkpath(const char *path, mode_t mode) { char *pp; char *sp; int status; char *copypath = STRDUP(path); status = 0; pp = copypath; while (status == 0 &amp;&amp; (sp = strchr(pp, '/')) != 0) { if (sp != pp) { /* Neither root nor double slash in path */ *sp = '\0'; status = do_mkdir(copypath, mode); *sp = '/'; } pp = sp + 1; } if (status == 0) status = do_mkdir(path, mode); FREE(copypath); return (status); } #ifdef TEST #include &lt;stdio.h&gt; /* ** Stress test with parallel running of mkpath() function. ** Before the EEXIST test, code would fail. ** With the EEXIST test, code does not fail. ** ** Test shell script ** PREFIX=mkpath.$$ ** NAME=./$PREFIX/sa/32/ad/13/23/13/12/13/sd/ds/ww/qq/ss/dd/zz/xx/dd/rr/ff/ff/ss/ss/ss/ss/ss/ss/ss/ss ** : ${MKPATH:=mkpath} ** ./$MKPATH $NAME &amp; ** [...repeat a dozen times or so...] ** ./$MKPATH $NAME &amp; ** wait ** rm -fr ./$PREFIX/ */ int main(int argc, char **argv) { int i; for (i = 1; i &lt; argc; i++) { for (int j = 0; j &lt; 20; j++) { if (fork() == 0) { int rc = mkpath(argv[i], 0777); if (rc != 0) fprintf(stderr, "%d: failed to create (%d: %s): %s\n", (int)getpid(), errno, strerror(errno), argv[i]); exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } } int status; int fail = 0; while (wait(&amp;status) != -1) { if (WEXITSTATUS(status) != 0) fail = 1; } if (fail == 0) printf("created: %s\n", argv[i]); } return(0); } #endif /* TEST */ </code></pre> <p>The macros <code>STRDUP()</code> and <code>FREE()</code> are error-checking versions of <code>strdup()</code> and <code>free()</code>, declared in <code>emalloc.h</code> (and implemented in <code>emalloc.c</code> and <code>estrdup.c</code>). The <code>"sysstat.h"</code> header deals with broken versions of <code>&lt;sys/stat.h&gt;</code> and can be replaced by <code>&lt;sys/stat.h&gt;</code> on modern Unix systems (but there were many issues back in 1990). And <code>"jlss.h"</code> declares <code>mkpath()</code>.</p> <p>The change between v1.12 (previous) and v1.13 (above) is the test for <code>EEXIST</code> in <code>do_mkdir()</code>. This was pointed out as necessary by <a href="https://stackoverflow.com/users/205938/switch">Switch</a> &mdash; thank you, Switch. The test code has been upgraded and reproduced the problem on a MacBook Pro (2.3GHz Intel Core i7, running Mac OS X 10.7.4), and suggests that the problem is fixed in the revision (but testing can only show the presence of bugs, never their absence).</p> <p><em>(You are hereby given permission to use this code for any purpose with attribution.)</em></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload