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