我需要创建文件夹,如果它不存在,所以我使用:
bool mkdir_if_not_exist(const char *dir)
{
bool ret = false;
if (dir) {
// first check if folder exists
struct stat folder_info;
if (stat(dir, &folder_info) != 0) {
if (errno == ENOENT) { // create folder
if (mkdir(dir, S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH) ?!= 0) // 755
perror("mkdir");
else
ret = true;
} else
perror("stat");
} else
ret = true; ?// dir exists
}
return ret;
}
该文件夹仅在首次运行程序时创建 - 之后只是一个检查。 有一个建议是跳过stat调用并调用mkdir并检查errno对EEXIST。 它能带来真正的好处吗?
答案 0 :(得分:1)
有一点好处。查看'LBYL vs EAFP'或'在你跳跃之前看'与'更容易请求宽恕而不是许可'。
轻微的好处是stat()
系统调用必须解析目录名称并获取inode - 或者在这种情况下丢失的inode - 然后mkdir()
必须执行相同的操作。当然,mkdir()
所需的数据已经在内核缓冲池中,但它仍然涉及指定路径的两次遍历而不是一次。因此,在这种情况下,使用EAFP比使用LBYL更有效。
然而,这对于普通计划是否真的具有可衡量的影响是值得商榷的。如果除了在整个地方创建目录之外什么都不做,那么您可能会发现一个好处。但如果你在一个程序的开头创建一个目录,它肯定是一个小的影响,基本上是不可测量的。
您可能需要处理strcmp(dir, "/some/where/or/another") == 0
但"/some/where"
虽然存在"/some/where/or"
的情况,但"/some/where/or/another"
和(必要)mkdir()
都不存在。您当前的代码不处理路径中间缺少的目录。它只报告dir
将报告的ENOENT。你看起来的代码不会检查{{1}}实际上是一个目录 - 它只是假设它存在,它是一个目录。正确处理这些变化是比较棘手的。
答案 1 :(得分:1)
更重要的是,使用stat
+ mkdir
方法,存在竞争条件:在stat
和mkdir
之间,另一个程序可以执行{{1因此mkdir
仍可能因mkdir
而失败。
答案 2 :(得分:0)
与Race condition with stat and mkdir in sequence类似,您的解决方案不正确,不仅是因为竞争条件(正如此处的其他答案已经指出的那样),而且还因为您从未检查现有文件是否是目录
当重新实现UNIX中现有命令行工具中已广泛使用的功能时,首先要了解它是如何在这些工具中实现的。
例如,看看mkdir(1)
-p
option如何在BSD(bin/mkdir/mkdir.c#mkpath
in OpenBSD和NetBSD)中实施,所有这些都在mkdir(2)
's错误后立即出现调用stat(2)
以便随后运行S_ISDIR
宏以确保现有文件是目录,而不仅仅是任何其他类型的文件。