Рекурсивный системный вызов mkdir () в Unix - PullRequest
61 голосов
/ 25 февраля 2010

После прочтения справочной страницы mkdir (2) для системного вызова Unix с этим именем выясняется, что вызов не создает промежуточные каталоги в пути, а только последний каталог в пути. Есть ли способ (или другая функция) создать все каталоги в пути, не прибегая к ручному анализу строки моего каталога и индивидуальному созданию каждого каталога?

Ответы [ 14 ]

0 голосов
/ 18 января 2016

Очень простое решение, просто введите: 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!!");
}
0 голосов
/ 31 марта 2015

Вот мой взгляд на более общее решение:

#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;
}
0 голосов
/ 15 января 2014

Мое решение:

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;
}
0 голосов
/ 25 февраля 2010

Два других ответа даны для mkdir(1), а не mkdir(2), как вы просили, но вы можете посмотреть исходный код для этой программы и посмотреть, как она реализует опции -p который вызывает mkdir(2) повторно по мере необходимости.

...