После чтения mkdir (2) страница справочника для системного вызова Unix с тем именем, кажется, что вызов не создает промежуточные каталоги в пути, только последний каталог в пути. Есть ли какой-либо путь (или другая функция) для создания всех каталогов в пути, не обращаясь к ручному парсингу моей строки каталога и индивидуально созданию каждого каталога?
К сожалению, нет системного вызова, чтобы сделать это для вас. Я предполагаю, что это потому, что нет способа иметь действительно четко определенную семантику для того, что должно происходить в случаях ошибок. Должен ли он оставить каталоги, которые уже были созданы? Удалять их? Что делать, если удаление не удалось? И так далее...
Однако, довольно легко создать свой собственный, и быстрый поиск в гугле по 'recursive 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);
}
Посмотрите исходный код bash здесь, и особенно посмотрите в examples/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 (1)
, а не для mkdir (2)
, как вы просите, но вы можете посмотреть исходный код для этой программы и посмотрите, как она реализует параметры -p
, которые повторно вызывают mkdir (2)
по мере необходимости.