Avec C ++ 17 ou version ultérieure, il y a l'en-tête standard <filesystem>
avec une fonction
std::filesystem::create_directories
qui devrait être utilisée dans les programmes C ++ modernes. Les fonctions standard C ++ n'ont cependant pas l'argument d'autorisations explicites (mode) spécifique à POSIX.
Cependant, voici une fonction C qui peut être compilée avec des compilateurs 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 */
Les macros STRDUP()
et FREE()
sont des versions de vérification des erreurs de
strdup()
et free()
, déclarées dans emalloc.h
(et implémentées dans
emalloc.c
et estrdup.c
). L'en- "sysstat.h"
tête traite des versions cassées de <sys/stat.h>
et peut être remplacé par <sys/stat.h>
sur les systèmes Unix modernes (mais il y avait de nombreux problèmes en 1990). Et "mkpath.h"
déclare mkpath()
.
Le changement entre v1.12 (version originale de la réponse) et v1.13 (version modifiée de la réponse) était le test pour EEXIST
dans
do_mkdir()
. Cela a été signalé comme nécessaire par
Switch - merci, Switch. Le code de test a été mis à jour et reproduit le problème sur un MacBook Pro (Intel Core i7 2,3 GHz, exécutant Mac OS X 10.7.4), et suggère que le problème est résolu dans la révision (mais les tests ne peuvent montrer que la présence de bogues , jamais leur absence). Le code affiché est maintenant v1.16; des modifications cosmétiques ou administratives ont été apportées depuis la v1.13 (comme l'utilisation à la mkpath.h
place de jlss.h
et l'inclusion <unistd.h>
inconditionnelle dans le code de test uniquement). Il est raisonnable de dire que cela "sysstat.h"
devrait être remplacé par à
<sys/stat.h>
moins que vous n'ayez un système inhabituellement récalcitrant.
(Vous êtes autorisé par la présente à utiliser ce code à toute fin avec attribution.)
Ce code est disponible dans mon référentiel SOQ
(Stack Overflow Questions) sur GitHub sous forme de fichiers mkpath.c
et
mkpath.h
(etc.) dans le
sous-répertoire src / so-0067-5039 .