// 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