Home | History | Annotate | Download | only in quipper
      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