创建一个唯一的临时目录。

4
我正在尝试在系统临时文件夹中创建一个独特的临时目录,并一直在阅读有关tmpnam()的安全性和文件创建问题的文章。
我编写了下面的代码,想知道它是否能满足这些问题,我的tmpnam()函数的使用是否正确,以及filesystem_error的抛出是否正确?我是否应该添加其他检查(例如temp_directory_path,也会抛出异常)?
    // Unique temporary directory path in the system temporary directory path.
std::filesystem::path tmp_dir_path {std::filesystem::temp_directory_path() /= std::tmpnam(nullptr)};

// Attempt to create the directory.
if (std::filesystem::create_directories(tmp_dir_path)) {

    // Directory successfully created.
    return tmp_dir_path;

} else {

    // Directory could not be created.
    throw std::filesystem_error("directory could not be created.");

}
2个回答

5

来自 cppreference.com:

虽然 std::tmpnam 生成的名称很难猜测,但是在 std::tmpnam 返回和程序使用返回的名称创建文件之间的某个时刻,另一个进程可能会创建具有该名称的文件。

问题不在于你如何使用它,而在于你使用它的事实。

例如,在您的代码示例中,如果恶意用户成功地在第一行和第二行之间猜测并创建目录,则可能会拒绝服务(DOS)来自您的应用程序,这可能是关键的,也可能不是。

相反,可以在符合 POSIX 标准的系统上以无竞争的方式执行此操作:

  • 对于文件,请参阅mkstemp(3)了解更多信息
  • 对于目录,请参阅mkdtemp(3)了解更多信息。

1
你的代码没问题。因为你试图创建目录,OS将在你的进程和另一个尝试创建相同文件的进程之间进行仲裁,所以如果你赢了,你就拥有了该文件,如果输了,你会得到一个错误。
我最近写了一个类似的函数。是否抛出异常取决于你如何使用这个函数。例如,你可以简单地返回已打开或关闭的std::fstream,并使用std::fstream::is_open作为成功的衡量标准,或者在失败时返回空路径名。
查看std::filesystem::create_directories,如果你没有提供std::error_code参数,它将抛出自己的异常,因此你不需要抛出自己的异常。
std::filesystem::path tmp_dir_path {std::filesystem::temp_directory_path() /= std::tmpnam(nullptr)};

// Attempt to create the directory.
std::filesystem::create_directories(tmp_dir_path));

// If that failed an exception will have been thrown
// so no need to check or throw your own

// Directory successfully created.
return tmp_dir_path;

谢谢您的评论,我已经尝试编译代码,当我抛出filesystem_error时,我应该包括一个error_code参数。我不确定对于这个异常,我应该放什么作为error_code参数。 - user1406186
  1. 为什么filesystem_error需要一个error_code?
  2. 是否有任何方法可以只抛出错误而没有错误代码,或者这是不好的做法?
- user1406186
@user1406186 如果尝试创建目录的调用失败,它将抛出自己的异常,因此您不需要这样做。鉴于此,我编辑了答案以显示与您代码等效的代码。 - Galik
@user1406186 如果你不想让它抛出自己的异常,你需要向 create_directories(path, std::error_code) 提供另一个参数。这就是你获取错误代码的方式。 - Galik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接