Unix에서 재귀 적 mkdir () 시스템 호출
해당 이름의 Unix 시스템 호출에 대한 mkdir (2) 매뉴얼 페이지를 읽은 후 호출이 경로에 중간 디렉토리를 생성하지 않고 경로의 마지막 디렉토리 만 생성하는 후보 목록. 수동으로 내 디렉토리 디렉토리를 구문 분석하고 각 디렉토리를 식별 적으로 생성하지 않고 경로에 모든 디렉토리를 생성하는 방법 (또는 다른 기능)이 있습니까?
안타깝게도이를위한 시스템 호출이 없습니다. 나는 그것이 오류의 경우에 일어날 일에 대해 잘 정의 된 의미를 발생에 발생이라고 생각합니다. 이미 생성 된 디렉토리를 그대로 두어야 할 디렉토리? 삭제 하시겠습니까? 삭제가 실패하면 어떻게 검증? 등등 ...
그러나 직접 롤링하는 것은 매우 쉽지만 ' 재귀 적 MKDIR '에 , 대한 빠른 구글 은 여러 솔루션을 찾았 습니다. 다음은 상단 근처에있는 것입니다.
http://nion.modprobe.de/blog/archives/357-Recursive-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);
}
mkdir -p가 그렇게 생각 했나요?
mkdir -p this / is / a / full / path / of / stuff
여기 내 해결책이 있습니다. 아래 함수를 호출하여 지정된 파일 경로로 이어지는 모든 디렉토리가 존재하는지 확인합니다. 참고 file_path
인수가 디렉토리 여기에 이름이 아니라 당신이 호출 한 후 작성하는 파일에 대한 경로가 아닙니다 mkpath()
.
예 : 존재하지 않는 경우 mkpath("/home/me/dir/subdir/file.dat", 0755)
생성 /home/me/dir/subdir
합니다. mkpath("/home/me/dir/subdir/", 0755)
동일합니다.
상대 경로 작동이 작동합니다.
오류가 발생하는 경우 반환 -1
및 설정합니다 errno
.
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;
}
참고 file_path
작업에서 수정합니다. 엄격 file_path
하게 아닙니다 const
.
mkpath()
작고 읽기 쉬운 재귀를 사용하는 또 다른 작업이 있습니다 . 그것은 사용 strdupa()
하도록 변경하기 위해 dir
사용하지 않도록 malloc()
&를 사용하지 않습니다 free()
. -D_GNU_SOURCE
활성화 해야합니다. strdupa()
이 코드는 GLIBC, EGLIBC, uClibc 및 기타 GLIBC 호환 C 라이브러리에서 작동 함을 의미합니다.
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);
}
Inadyn 프로젝트에서 여기와 Valery Frolov의 입력 후 다음 수정 버전 mkpath()
이 이제 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);
}
하나 더 시스템 호출을 사용하지만 코드는 이제 더 읽기를 사용합니다.
여기 bash 소스 코드를 살펴보고, 특히 예 / loadables / mkdir.c, 특히 136-210 행을 살펴 봅니다. 그렇게하고 싶지 않다면 여기 에이 문제를 다루는 몇 가지 소스가 있습니다 (제가 링크 한 tar.gz에서 직접 가져옴).
/* 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;
}
덜 일반적인 구현으로 할 수 있습니다.
내 두 가지 제안은 다음과 가변합니다.
char dirpath[80] = "/path/to/some/directory";
sprintf(mkcmd, "mkdir -p %s", dirpath);
system(mkcmd);
또는 사용하지 않고 매장면 system()
coreutils mkdir
소스 코드를 살펴보고 -p
옵션 을 구현 한 방법을 확인하십시오 .
실제로 다음을 사용할 수 있습니다.
mkdir -p ./some/directories/to/be/created/
나는 첫 번째 (그리고 받아 들인) 답변 (반복이 충분하지 않음)에 대해 댓글을 달 수 있습니다. 새 답변의 코드로 내 댓글을 게시하겠습니다. 아래 코드는 첫 번째 답변을 기반으로하지만 여러 문제를 해결합니다.
- 길이가 0 인 경로로
opath[]
호출하면 배열 시작 전에 문자를 읽거나 쓰지 언어 (예, "왜 그렇게 부르겠습니까?"). 반면 "취약점을 수정하지 않는 이유는 무엇입니까?" ") - 의 크기
opath
는 지금입니다PATH_MAX
(완벽은 아니지만 상수보다 낫습니다) - 경로가 그보다 길거나 길면
sizeof(opath)
복사 할 때 제대로 종료strncpy()
됩니다. - 표준에서 할 수있는 것처럼 기록 된 디렉토리의 모드를 사용할 수 있습니다
mkdir()
(비 사용자 쓰기 가능 또는 비 사용자 실행 가능 지정하면 재귀가 작동하지 않음). - main ()은 (필수?) int를 반환합니다.
- 몇 불필요한 제거
#include
들 - 나는 함수 이름을 더 좋아한다;)
// 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;
}
수행하는 내 재귀 방법 :
#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;
}
편집 : 내 이전 코드 조각 수정, Namchester의 버그 보고서
주어진 두 개의 다른 답변을위한 mkdir(1)
이 아니라 mkdir(2)
당신이 부탁처럼 소스 ,하지만 당신은 볼 수 있습니다 코드를 해당 프로그램과는 구현하는 방법을 참조 -p
통화 옵션 필요 mkdir(2)
에 따라 반복합니다.
내 솔루션 :
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;
}
다음은보다 일반적인 솔루션에 대한 내 샷입니다.
#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;
}
매우 간단한 해결책은 입력 만하면됩니다. 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!!");
}
꽤 똑바로. 이것은 좋은 출발점이 될 수 있습니다
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;
}
이 함수를 전체 경로와 원하는 권한 (예 : S_IRUSR )을 구문 분석 하여 전체 모드 목록을 보려면 여기로 이동하십시오 https://techoverflow.net/2013/04/05/how-to-use-mkdir-from- sysstat- h /
전체 경로 문자열은 "/"문자로 분할되고 개별 dir 이 aggrpaz 문자열에 한 번에 하나씩 추가됩니다 . 각 루프 반복은 mkdir 함수를 호출하여 지금까지의 집계 경로와 권한을 전달합니다. 이 예제는 개선 될 수 있습니다. mkdir 함수 출력을 확인하지 않고이 함수는 절대 경로에서만 작동합니다.
참고 URL : https://stackoverflow.com/questions/2336242/recursive-mkdir-system-call-on-unix
'ProgramingTip' 카테고리의 다른 글
Vim에서 잘못된 인라인 자바 들여 쓰기를 어떻게 수정합니까? (0) | 2020.11.22 |
---|---|
PHP의 datetime에서 AM / PM을 얻는 방법 (0) | 2020.11.22 |
Ruby에서 노드를 상수로 변환하는 방법은 무엇입니까? (0) | 2020.11.22 |
배열에서 n 개의 요소를 무작위로 얻는 방법 (0) | 2020.11.22 |
Visual Studio의 기본 네임 명명 규칙과 싸움을 중지해야합니까? (0) | 2020.11.21 |