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