看一下bash源代码here,具体看一下examples / loadables / mkdir.c,特别是136-210行 . 如果你没有't want to do that, here'处理这个问题的一些来源(直接来自我链接的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;
}
14 回答
挺直的 . 这可能是一个很好的起点
您解析此函数的完整路径加上您想要的权限,即 S_IRUSR ,有关完整的模式列表,请转到此处https://techoverflow.net/2013/04/05/how-to-use-mkdir-from-sysstat-h/
完整路径字符串将由"/"字符拆分,并且各个目录将一次附加到 aggrpaz 字符串 . 每次循环迭代都会调用mkdir函数,并将其传递给目前为止的聚合路径以及权限 . 这个例子可以改进,我没有检查mkdir函数输出,这个函数只适用于绝对路径 .
我的解决方案
我这样做的递归方式:
编辑:修复我的旧代码片段,错误报告Namchester
不幸的是,没有系统调用为你做这件事 . 我猜这是因为没有办法为错误情况下应该发生的事情提供真正明确定义的语义 . 它应该离开已经创建的目录吗?删除它们?如果删除失败怎么办?等等...
然而,很容易推出自己的,并快速谷歌为'recursive mkdir ' turned up a number of solutions. Here'的一个接近顶部:
http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html
显然不是,我的两个建议是:
或者,如果您不想使用
system()
,请尝试查看coreutilsmkdir
源代码,看看他们如何实现-p
选项 .这是对
mkpath()
的另一种看法,使用递归,它既小又可读 . 它使用strdupa()
来避免直接更改给定的dir
字符串参数并避免使用malloc()
&free()
. 确保使用-D_GNU_SOURCE
编译以激活strdupa()
...这意味着此代码仅适用于GLIBC,EGLIBC,uClibc和其他GLIBC兼容的C库 .在这里和Valery Frolov在Inadyn项目中输入之后,
mkpath()
的以下修订版现在已被推到libite它再使用一个系统调用,但是现在代码更易读 .
以下是我对更通用解决方案的看法:
给出的另外两个答案是针对
mkdir(1)
而不是mkdir(2)
,但您可以查看该程序的the source code,看看它如何实现-p
选项,根据需要重复调用mkdir(2)
.看一下bash源代码here,具体看一下examples / loadables / mkdir.c,特别是136-210行 . 如果你没有't want to do that, here'处理这个问题的一些来源(直接来自我链接的tar.gz):
您可以通过不太常规的实现来逃避 .
其实你可以使用:
这是我的解决方案 . 通过调用下面的函数,确保存在指向文件路径的所有dirs . 请注意,
file_path
参数不是此处的目录名,而是在调用mkpath()
之后要创建的文件的路径 .例如,
mkpath("/home/me/dir/subdir/file.dat", 0755)
如果不存在则应创建/home/me/dir/subdir
.mkpath("/home/me/dir/subdir/", 0755)
做同样的事 .也适用于相对路径 .
如果发生错误,则返回
-1
并设置errno
.请注意,
file_path
在操作期间被修改,但之后会恢复 . 因此file_path
并非严格const
.我不允许对第一个(并接受的)答案发表评论(不够代表),所以我会在新答案中将我的评论作为代码发布 . 下面的代码基于第一个答案,但修复了一些问题:
如果使用零长度路径调用,则不会在数组
opath[]
开头之前读取或写入字符(是的,"why would you call it that way?",但另一方面"why would you not fix the vulnerability?")opath
的大小现在是PATH_MAX
(这不是完美的,但优于常数)如果路径与
sizeof(opath)
一样长或更长,则在复制时正确终止(strncpy()
不执行)您可以指定写入目录的模式,就像使用标准
mkdir()
一样(尽管如果指定非用户可写或非用户可执行,则递归将不起作用)main()返回(required?)int
删除了一些不必要的
#include
我更喜欢功能名称;)
一个非常简单的解决方案,只需输入输入:
mkdir dirname
嗯,我以为mkdir -p会这样做吗?