| // 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 "chromiumos-wide-profiling/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 |