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