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