Dengan C ++ 17 atau yang lebih baru, ada header standar <filesystem>
dengan fungsi
std::filesystem::create_directories
yang harus digunakan dalam program C ++ modern. Fungsi standar C ++ tidak memiliki argumen izin eksplisit (mode) spesifik POSIX.
Namun, inilah fungsi C yang dapat dikompilasi dengan kompiler C ++.
/*
@(#)File: mkpath.c
@(#)Purpose: Create all directories in path
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 1990-2020
@(#)Derivation: mkpath.c 1.16 2020/06/19 15:08:10
*/
/*TABSTOP=4*/
#include "posixver.h"
#include "mkpath.h"
#include "emalloc.h"
#include <errno.h>
#include <string.h>
/* "sysstat.h" == <sys/stat.h> with fixup for (old) Windows - inc mode_t */
#include "sysstat.h"
typedef struct stat Stat;
static int do_mkdir(const char *path, mode_t mode)
{
Stat st;
int status = 0;
if (stat(path, &st) != 0)
{
/* Directory does not exist. EEXIST for race condition */
if (mkdir(path, mode) != 0 && 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 && (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 <stdio.h>
#include <unistd.h>
/*
** 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 &
** [...repeat a dozen times or so...]
** ./$MKPATH $NAME &
** wait
** rm -fr ./$PREFIX/
*/
int main(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
for (int j = 0; j < 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(&status) != -1)
{
if (WEXITSTATUS(status) != 0)
fail = 1;
}
if (fail == 0)
printf("created: %s\n", argv[i]);
}
return(0);
}
#endif /* TEST */
Makro STRDUP()
dan FREE()
merupakan versi pemeriksaan kesalahan dari
strdup()
dan free()
, dideklarasikan di emalloc.h
(dan diterapkan di
emalloc.c
dan estrdup.c
). The "sysstat.h"
penawaran header dengan versi rusak dari <sys/stat.h>
dan dapat digantikan oleh <sys/stat.h>
pada sistem Unix modern (tapi ada banyak masalah kembali pada tahun 1990). Dan "mkpath.h"
menyatakan mkpath()
.
Perubahan antara v1.12 (versi asli dari jawaban) dan v1.13 (versi jawaban yang diubah) adalah ujian untuk EEXIST
di
do_mkdir()
. Hal ini ditunjukkan seperlunya oleh
Switch - terima kasih, Switch. Kode tes telah ditingkatkan dan mereproduksi masalah pada MacBook Pro (2,3GHz Intel Core i7, menjalankan Mac OS X 10.7.4), dan menyarankan bahwa masalah telah diperbaiki dalam revisi (tetapi pengujian hanya dapat menunjukkan adanya bug , tidak pernah ketidakhadiran mereka). Kode yang ditampilkan sekarang adalah v1.16; ada perubahan kosmetik atau administratif yang dibuat sejak v1.13 (seperti penggunaan sebagai mkpath.h
ganti jlss.h
dan menyertakan <unistd.h>
tanpa syarat dalam kode pengujian saja). Masuk akal untuk berpendapat bahwa "sysstat.h"
harus diganti
<sys/stat.h>
kecuali jika Anda memiliki sistem bandel yang tidak biasa.
(Anda dengan ini diberi izin untuk menggunakan kode ini untuk tujuan apa pun dengan atribusi.)
Kode ini tersedia di
repositori SOQ (Stack Overflow Questions) saya di GitHub sebagai file mkpath.c
dan
mkpath.h
(dll.)
Di
sub-direktori src / so-0067-5039 .