stat与mkdir与EEXIST

时间:2011-06-11 04:21:39

标签: mkdir stat

我需要创建文件夹,如果它不存在,所以我使用:

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。 它能带来真正的好处吗?

3 个答案:

答案 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方法,存在竞争条件:在statmkdir之间,另一个程序可以执行{{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 OpenBSDNetBSD)中实施,所有这些都在mkdir(2)'s错误后立即出现调用stat(2)以便随后运行S_ISDIR宏以确保现有文件是目录,而不仅仅是任何其他类型的文件。