lin
2025-08-01 633231e833e21d5b8b1c00cb15aedb62b3b78e8f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
#include "scoped_temp_path.h"
 
#include <errno.h>
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
#include <vector>
 
#include "base/logging.h"
 
namespace {
 
// Temporary paths use this prefix by default.
const char kTempPathTemplatePrefix[] = "/tmp/quipper.";
 
// Maximum number of directories that nftw() will hold open simultaneously.
const int kNumOpenFds = 4;
 
// Callback for nftw(). Deletes each file it is given.
int FileDeletionCallback(const char* path, const struct stat* sb,
                         int /* type_flag */, struct FTW* /* ftwbuf */) {
  if (path && remove(path))
    LOG(ERROR) << "Could not remove " << path << ", errno=" << errno;
  return 0;
}
 
// Make a mutable copy (mkstemp modifies its argument), and append "XXXXXX".
// A vector<char> is used because string does not have an API for mutable
// direct access to the char data. That is, string::data() returns
// (const char *), and there is no non-const overload. (This appears to be an
// oversight of the standard since C++11.)
std::vector<char> MakeTempfileTemplate(string path_template) {
  path_template += "XXXXXX";
  path_template.push_back('\0');
  return std::vector<char>(path_template.begin(), path_template.end());
}
 
}  // namespace
 
namespace quipper {
 
ScopedTempFile::ScopedTempFile() : ScopedTempFile(kTempPathTemplatePrefix) {}
 
ScopedTempFile::ScopedTempFile(const string prefix) {
  std::vector<char> filename = MakeTempfileTemplate(prefix);
  int fd = mkstemp(filename.data());
  if (fd == -1) return;
  close(fd);
  path_ = string(filename.data());
}
 
ScopedTempDir::ScopedTempDir() : ScopedTempDir(kTempPathTemplatePrefix) {}
 
ScopedTempDir::ScopedTempDir(const string prefix) {
  std::vector<char> dirname = MakeTempfileTemplate(prefix);
  if (!mkdtemp(dirname.data())) return;
  path_ = string(dirname.data()) + "/";
}
 
ScopedTempPath::~ScopedTempPath() {
  // Recursively delete the path. Meaning of the flags:
  //   FTW_DEPTH: Handle directories after their contents.
  //   FTW_PHYS:  Do not follow symlinks.
  if (!path_.empty() && nftw(path_.c_str(), FileDeletionCallback, kNumOpenFds,
                             FTW_DEPTH | FTW_PHYS)) {
    LOG(ERROR) << "Error while using ftw() to remove " << path_;
  }
}
 
}  // namespace quipper