Frage

Nach dem Lesen der mkdir (2) man-Seite für den Anruf Unix-Systems mit diesem Namen, scheint es, dass der Anruf nicht Zwischen Verzeichnissen in einem Pfad schafft, nur das letzte Verzeichnis im Pfad. Gibt es eine Möglichkeit (oder eine andere Funktion), um alle Verzeichnisse in dem Pfad zu erstellen, ohne auf mein Verzeichnis Zeichenfolge manuell Parsen und individuell jedes Verzeichnis erstellen?

War es hilfreich?

Lösung

Es ist kein Systemaufruf es für Sie tun, leider. Ich vermute, das ist, weil es nicht eine Möglichkeit ist wirklich gut definierte Semantik für das, was im Fehlerfall passieren sollte. Sollte es die Verzeichnisse lassen, die bereits erstellt wurden? Lösche sie? Was passiert, wenn die Deletionen scheitern? Und so weiter ...

Es ist ziemlich einfach, Ihre eigene Rolle, aber, und eine schnelle Google für ‚ rekursive mkdir ‘ eine Reihe von Lösungen aufgedreht. Hier ist eine, die in der Nähe der Spitze war:

http://nion.modprobe.de/blog/ Archiv / 357-rekursive-directory-creation.html

static void _mkdir(const char *dir) {
        char tmp[256];
        char *p = NULL;
        size_t len;

        snprintf(tmp, sizeof(tmp),"%s",dir);
        len = strlen(tmp);
        if(tmp[len - 1] == '/')
                tmp[len - 1] = 0;
        for(p = tmp + 1; *p; p++)
                if(*p == '/') {
                        *p = 0;
                        mkdir(tmp, S_IRWXU);
                        *p = '/';
                }
        mkdir(tmp, S_IRWXU);
}

Andere Tipps

hmm ich dachte, dass mkdir -p macht das?

  

mkdir -p diese / ist / a / full / path / von / stuff

Hier ist meine Lösung. Durch den Aufruf von unten die Funktion sicherzustellen, dass alle Verzeichnisse auf dem Dateipfad führt exist angegeben. Beachten Sie, dass file_path Argument hier nicht Verzeichnisname ist, sondern ein Pfad zu einer Datei, dass Sie nach dem Aufruf von mkpath() erstellen werden.

Eg., mkpath("/home/me/dir/subdir/file.dat", 0755) soll /home/me/dir/subdir erstellen, wenn es nicht existiert. mkpath("/home/me/dir/subdir/", 0755) tut das gleiche.

Arbeiten mit relativen Pfaden auch.

Returns -1 und setzt errno im Falle eines Fehlers.

int mkpath(char* file_path, mode_t mode) {
    assert(file_path && *file_path);
    for (char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
        *p = '\0';
        if (mkdir(file_path, mode) == -1) {
            if (errno != EEXIST) {
                *p = '/';
                return -1;
            }
        }
        *p = '/';
    }
    return 0;
}

Beachten Sie, dass file_path während der Aktion geändert wird, aber wird danach wieder hergestellt. Daher file_path ist nicht streng const.

Hier ist eine andere nehmen auf mkpath(), Rekursion, die sowohl kleine als auch lesbar ist. Es nutzt strdupa() zu vermeiden, dass das gegebene dir String-Argument direkt zu verändern und mit malloc() & free() zu vermeiden. Stellen Sie sicher, mit -D_GNU_SOURCE zu aktivieren strdupa() zu kompilieren ... was bedeutet dieser Code funktioniert nur auf GLIBC, eglibc, uClibc und andere GLIBC kompatibel C-Bibliotheken.

int mkpath(char *dir, mode_t mode)
{
    if (!dir) {
        errno = EINVAL;
        return 1;
    }

    if (strlen(dir) == 1 && dir[0] == '/')
        return 0;

    mkpath(dirname(strdupa(dir)), mode);

    return mkdir(dir, mode);
}

Nach der Eingabe sowohl hier als auch von Valery Frolov im Inadyn Projekt, die folgende überarbeitete Version von mkpath() wurde nun geschoben libite

int mkpath(char *dir, mode_t mode)
{
    struct stat sb;

    if (!dir) {
        errno = EINVAL;
        return 1;
    }

    if (!stat(dir, &sb))
        return 0;

    mkpath(dirname(strdupa(dir)), mode);

    return mkdir(dir, mode);
}

Es verwendet eine weitere syscall, aber naja, der Code ist jetzt lesbar.

Werfen Sie einen Blick auf den Code bash Quelle hier und sucht speziell in examples / Ables / mkdir.c insbesondere Linien 136-210. Wenn Sie nicht das tun wollen, hier einige der Quelle, dass sie mit diesem (gerade aus der tar.gz genommen, dass ich verbunden habe):

/* Make all the directories leading up to PATH, then create PATH.  Note that
   this changes the process's umask; make sure that all paths leading to a
   return reset it to ORIGINAL_UMASK */

static int
make_path (path, nmode, parent_mode)
     char *path;
     int nmode, parent_mode;
{
  int oumask;
  struct stat sb;
  char *p, *npath;

  if (stat (path, &sb) == 0)
  {
      if (S_ISDIR (sb.st_mode) == 0)
      {
          builtin_error ("`%s': file exists but is not a directory", path);
          return 1;
      }

      if (chmod (path, nmode))
      {
          builtin_error ("%s: %s", path, strerror (errno));
          return 1;
      }

      return 0;
  }

  oumask = umask (0);
  npath = savestring (path);    /* So we can write to it. */

  /* Check whether or not we need to do anything with intermediate dirs. */

  /* Skip leading slashes. */
  p = npath;
  while (*p == '/')
    p++;

  while (p = strchr (p, '/'))
  {
      *p = '\0';
      if (stat (npath, &sb) != 0)
      {
          if (mkdir (npath, parent_mode))
          {
              builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
              umask (original_umask);
              free (npath);
              return 1;
          }
      }
      else if (S_ISDIR (sb.st_mode) == 0)
      {
          builtin_error ("`%s': file exists but is not a directory", npath);
          umask (original_umask);
          free (npath);
          return 1;
      }

      *p++ = '/';   /* restore slash */
      while (*p == '/')
          p++;
  }

  /* Create the final directory component. */
  if (stat (npath, &sb) && mkdir (npath, nmode))
  {
      builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
      umask (original_umask);
      free (npath);
      return 1;
  }

  umask (original_umask);
  free (npath);
  return 0;
}

Sie können sich wahrscheinlich mit einer weniger allgemeinen Implementierung wegzukommen.

Offensichtlich nicht, meine beiden Vorschläge sind:

char dirpath[80] = "/path/to/some/directory";
sprintf(mkcmd, "mkdir -p %s", dirpath);
system(mkcmd);

Oder wenn Sie nicht wollen, system() Versuch verwenden, um das coreutils mkdir Quellcode suchen und sehen, wie sie die -p Option implementiert.

Eigentlich kann man nur verwenden:

mkdir -p ./some/directories/to/be/created/

Ich bin nicht zu kommentieren die erste (und akzeptiert) Antwort (nicht genug rep) erlaubt, so werde ich meine Kommentare als Code in einer neuen Antwort posten. Der folgende Code basiert auf der ersten Antwort, aber behebt eine Reihe von Problemen:

  • Wenn mit einer Länge Null Pfad genannt, bedeutet dies nicht lesen oder das Zeichen vor dem Beginn eines Arrays opath[] schreiben (ja, „warum soll man es nennen, dass Art und Weise?“, Aber auf der anderen Seite „warum soll man nicht fixiert die Verwundbarkeit? ")
  • die Größe opath ist jetzt PATH_MAX (was nicht perfekt ist, aber es ist besser als eine Konstante)
  • , wenn der Pfad ist so lang wie oder länger als sizeof(opath) dann wird es richtig beendet, wenn kopiert (was strncpy() nicht tut)
  • können Sie den Modus des geschriebenen Verzeichnis angeben, wie Sie können mit dem Standard mkdir() (obwohl, wenn Sie angeben, nicht-Benutzer-beschreibbar oder nicht-Benutzer ausführbare dann die Rekursion nicht funktionieren wird)
  • main () gibt den (erforderlich?) Int
  • entfernt einige unnötige #includes
  • I wie der Name der Funktion besser;)
// Based on http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>

static void mkdirRecursive(const char *path, mode_t mode) {
    char opath[PATH_MAX];
    char *p;
    size_t len;

    strncpy(opath, path, sizeof(opath));
    opath[sizeof(opath) - 1] = '\0';
    len = strlen(opath);
    if (len == 0)
        return;
    else if (opath[len - 1] == '/')
        opath[len - 1] = '\0';
    for(p = opath; *p; p++)
        if (*p == '/') {
            *p = '\0';
            if (access(opath, F_OK))
                mkdir(opath, mode);
            *p = '/';
        }
    if (access(opath, F_OK))         /* if path is not terminated with / */
        mkdir(opath, mode);
}


int main (void) {
    mkdirRecursive("/Users/griscom/one/two/three", S_IRWXU);
    return 0;
}

Meine rekursive Art und Weise, dies zu tun:

#include <libgen.h> /* Only POSIX version of dirname() */
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static void recursive_mkdir(const char *path, mode_t mode)
{
    char *spath = NULL;
    const char *next_dir = NULL;

    /* dirname() modifies input! */
    spath = strdup(path);
    if (spath == NULL)
    {
        /* Report error, no memory left for string duplicate. */
        goto done;
    }

    /* Get next path component: */
    next_dir = dirname(spath);

    if (access(path, F_OK) == 0)
    {
        /* The directory in question already exists! */
        goto done;
    }

    if (strcmp(next_dir, ".") == 0 || strcmp(next_dir, "/") == 0)
    {
        /* We reached the end of recursion! */
        goto done;
    }

    recursive_mkdir(next_dir, mode);
    if (mkdir(path, mode) != 0)
    {
       /* Report error on creating directory */
    }

done:
    free(spath);
    return;
}

EDIT: fixed meinen alten Code-Schnipsel, Bug-Bericht von Namchester

Die beiden anderen Antworten gegeben sind für mkdir(1) und nicht mkdir(2) wie Sie fragen, aber Sie können unter der Quellcode für das Programm und sehen, wie es die -p Optionen implementiert, die Anrufe immer wieder mkdir(2) nach Bedarf.

Meine Lösung:

int mkrdir(const char *path, int index, int permission)
{
    char bf[NAME_MAX];
    if(*path == '/')
        index++;
    char *p = strchr(path + index, '/');
    int len;
    if(p) {
        len = MIN(p-path, sizeof(bf)-1);
        strncpy(bf, path, len);
        bf[len]=0;
    } else {
        len = MIN(strlen(path)+1, sizeof(bf)-1);
        strncpy(bf, path, len);
        bf[len]=0;
    }

    if(access(bf, 0)!=0) {
        mkdir(bf, permission);
        if(access(bf, 0)!=0) {
            return -1;
        }
    }
    if(p) {
        return mkrdir(path, p-path+1, permission);
    }
    return 0;
}

Hier ist meine Chance auf eine allgemeinere Lösung:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

typedef int (*dirhandler_t)( const char*, void* );
/// calls itfunc for each directory in path (except for . and ..)
int iterate_path( const char* path, dirhandler_t itfunc, void* udata )
{
    int rv = 0;
    char tmp[ 256 ];
    char *p = tmp;
    char *lp = tmp;
    size_t len;
    size_t sublen;
    int ignore_entry;

    strncpy( tmp, path, 255 );

    tmp[ 255 ] = '\0';
    len = strlen( tmp );

    if( 0 == len ||
        (1 == len && '/' == tmp[ 0 ]) )
        return 0;

    if( tmp[ len - 1 ] == '/' )
        tmp[ len - 1 ] = 0;

    while( (p = strchr( p, '/' )) != NULL )
    {
        ignore_entry = 0;
        *p = '\0';
        lp = strrchr( tmp, '/' );

        if( NULL == lp ) { lp = tmp; }
        else { lp++; }

        sublen = strlen( lp );

        if( 0 == sublen )   /* ignore things like '//' */
            ignore_entry = 1;
        else if( 1 == sublen &&  /* ignore things like '/./' */
                 '.' == lp[ 0 ] )
            ignore_entry = 1;
        else if( 2 == sublen &&    /* also ignore things like '/../' */
                 '.' == lp[ 0 ] &&
                 '.' == lp[ 1 ] )
            ignore_entry = 1;

        if( ! ignore_entry )
        {
            if( (rv = itfunc( tmp, udata )) != 0 )
                return rv;
        }

        *p = '/';
        p++;
        lp = p;
    }

    if( strcmp( lp, "." ) && strcmp( lp, ".." ) )
        return itfunc( tmp, udata );

    return 0;
}

mode_t get_file_mode( const char* path )
{
    struct stat statbuf;
    memset( &statbuf, 0, sizeof( statbuf ) );

    if( NULL == path ) { return 0; }

    if( 0 != stat( path, &statbuf ) )
    {
        fprintf( stderr, "failed to stat '%s': %s\n",
                 path, strerror( errno ) );
        return 0;
    }

    return statbuf.st_mode;
}

static int mymkdir( const char* path, void* udata )
{
    (void)udata;
    int rv = mkdir( path, S_IRWXU );
    int errnum = errno;

    if( 0 != rv )
    {
        if( EEXIST == errno &&
            S_ISDIR( get_file_mode( path ) ) )  /* it's all good, the directory already exists */
            return 0;

        fprintf( stderr, "mkdir( %s ) failed: %s\n",
                 path, strerror( errnum ) );
    }
//     else
//     {
//         fprintf( stderr, "created directory: %s\n", path );
//     }

    return rv;
}

int mkdir_with_leading( const char* path )
{
    return iterate_path( path, mymkdir, NULL );
}

int main( int argc, const char** argv )
{
    size_t i;
    int rv;

    if( argc < 2 )
    {
        fprintf( stderr, "usage: %s <path> [<path>...]\n",
                 argv[ 0 ] );
        exit( 1 );
    }

    for( i = 1; i < argc; i++ )
    {
        rv = mkdir_with_leading( argv[ i ] );
        if( 0 != rv )
            return rv;
    }

    return 0;
}

Eine sehr einfache Lösung, geben Sie einfach in Eingabe: mkdir dirname

void execute_command_mkdir(char *input)
{
     char rec_dir[500];
     int s;
     if(strcmp(input,"mkdir") == 0)
        printf("mkdir: operand required");
    else
     {
        char *split = strtok(input," \t");
        while(split)
        {
            if(strcmp(split,"create_dir") != 0)
                strcpy(rec_dir,split);
            split = strtok(NULL, " \t");
        }
        char *split2 = strtok(rec_dir,"/");
        char dir[500];
        strcpy(dir, "");
        while(split2)
        {
            strcat(dir,split2);
            strcat(dir,"/");
            printf("%s %s\n",split2,dir);
            s = mkdir(dir,0700);
            split2 = strtok(NULL,"/");
        }
        strcpy(output,"ok");
    }
        if(s < 0)
            printf(output,"Error!! Cannot Create Directory!!");
}

Ganz gerade. Dies kann ein guter Ausgangspunkt sein

int makeDir(char *fullpath, mode_t permissions){
int i=0;
char *arrDirs[20];
char aggrpaz[255];
arrDirs[i] = strtok(fullpath,"/");
strcpy(aggrpaz, "/");
while(arrDirs[i]!=NULL)
{
    arrDirs[++i] = strtok(NULL,"/");
    strcat(aggrpaz, arrDirs[i-1]);
    mkdir(aggrpaz,permissions);
    strcat(aggrpaz, "/");
}
i=0;
return 0;
}

Sie analysieren diese Funktion einen vollständigen Pfad und die Berechtigungen, die Sie wollen, dh S_IRUSR für eine vollständige Liste der Modi hier gehen https://techoverflow.net/2013/04/05/how-to-use-mkdir-from-sysstat -h /

Die fullpath String wird gespalten durch das Zeichen „/“ und einzelne Verzeichnisse wird angehängt werden, um den aggrpaz string einen nach dem anderen. Jede Schleife Iteration ruft die mkdir Funktion, den Gesamt Weg vorbei, so weit und die Berechtigungen. Dieses Beispiel kann verbessert werden, ich bin nicht die mkdir Funktionsausgabe prüfen und diese Funktion ist nur mit absoluten Pfaden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top