| 27 | |
| 28 | namespace xgboost::common { |
| 29 | TemporaryDirectory::TemporaryDirectory(std::string prefix) : prefix_{std::move(prefix)} { |
| 30 | namespace fs = std::filesystem; |
| 31 | |
| 32 | auto tmp = fs::temp_directory_path(); |
| 33 | |
| 34 | #if defined(xgboost_IS_WIN) |
| 35 | std::default_random_engine rng; |
| 36 | auto make_name = [&rng, this] { |
| 37 | constexpr std::size_t kPathMax = 6; |
| 38 | constexpr StringView kAlphabet{"abcdefghijklmnopqrstuvwxyz"}; |
| 39 | static_assert(kAlphabet.size() == 26); |
| 40 | std::uniform_int_distribution dist{0, 25}; |
| 41 | char path[kPathMax + 1]; |
| 42 | std::memset(path, 0, sizeof(path)); |
| 43 | for (std::size_t i = 0; i < kPathMax; ++i) { |
| 44 | auto k = dist(rng); |
| 45 | path[i] = kAlphabet[k]; |
| 46 | } |
| 47 | auto res = std::string{path}; |
| 48 | CHECK_EQ(res.size(), kPathMax); |
| 49 | return this->prefix_ + "tmpdir." + std::string{path}; |
| 50 | }; |
| 51 | auto dirname = tmp / make_name(); |
| 52 | std::int32_t retry = 0; |
| 53 | while (fs::exists(dirname) && retry < 64) { |
| 54 | dirname = tmp / make_name(); |
| 55 | ++retry; |
| 56 | } |
| 57 | if (retry >= 64) { |
| 58 | LOG(FATAL) << "Failed to create temporary directory."; |
| 59 | } |
| 60 | this->path_ = dirname.string(); |
| 61 | CHECK(fs::create_directory(this->path_)); |
| 62 | #else |
| 63 | auto dirtemplate = (tmp / (this->prefix_ + "tmpdir.XXXXXX")).string(); |
| 64 | // https://man7.org/linux/man-pages/man3/mkdtemp.3.html |
| 65 | char* tmpdir = mkdtemp(dirtemplate.data()); |
| 66 | if (!tmpdir) { |
| 67 | LOG(FATAL) << error::SystemError().message(); |
| 68 | } |
| 69 | this->path_ = tmpdir; |
| 70 | #endif |
| 71 | LOG(DEBUG) << "TmpDir:" << this->path_; |
| 72 | CHECK(fs::exists(this->path_)); |
| 73 | } |
| 74 | |
| 75 | TemporaryDirectory::~TemporaryDirectory() noexcept(false) { |
| 76 | std::filesystem::remove_all(this->path_); |