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.
FileDeletionCallback(const char * path,const struct stat * sb,int,struct FTW *)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.)
MakeTempfileTemplate(string path_template)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
ScopedTempFile()48 ScopedTempFile::ScopedTempFile() : ScopedTempFile(kTempPathTemplatePrefix) {}
49
ScopedTempFile(const string prefix)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
ScopedTempDir()58 ScopedTempDir::ScopedTempDir() : ScopedTempDir(kTempPathTemplatePrefix) {}
59
ScopedTempDir(const string prefix)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
~ScopedTempPath()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