You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.5 KiB
113 lines
3.5 KiB
// Copyright 2019 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 "brillo/files/file_util.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <utility>
|
|
|
|
#include <base/files/file_util.h>
|
|
#include <base/logging.h>
|
|
#include <base/strings/stringprintf.h>
|
|
#include <brillo/syslog_logging.h>
|
|
|
|
namespace brillo {
|
|
|
|
namespace {
|
|
|
|
enum class FSObjectType {
|
|
RegularFile = 0,
|
|
Directory,
|
|
};
|
|
|
|
SafeFD::SafeFDResult OpenOrRemake(SafeFD* parent,
|
|
const std::string& name,
|
|
FSObjectType type,
|
|
int permissions,
|
|
uid_t uid,
|
|
gid_t gid,
|
|
int flags) {
|
|
SafeFD::Error err = IsValidFilename(name);
|
|
if (SafeFD::IsError(err)) {
|
|
return std::make_pair(SafeFD(), err);
|
|
}
|
|
|
|
SafeFD::SafeFDResult (SafeFD::*maker)(const base::FilePath&, mode_t, uid_t,
|
|
gid_t, int);
|
|
if (type == FSObjectType::Directory) {
|
|
maker = &SafeFD::MakeDir;
|
|
} else {
|
|
maker = &SafeFD::MakeFile;
|
|
}
|
|
|
|
SafeFD child;
|
|
std::tie(child, err) =
|
|
(parent->*maker)(base::FilePath(name), permissions, uid, gid, flags);
|
|
if (child.is_valid()) {
|
|
return std::make_pair(std::move(child), err);
|
|
}
|
|
|
|
// Rmdir should be used on directories. However, kWrongType indicates when
|
|
// a directory was expected and a non-directory was found or when a
|
|
// directory was found but not expected, so XOR was used.
|
|
if ((type == FSObjectType::Directory) ^ (err == SafeFD::Error::kWrongType)) {
|
|
err = parent->Rmdir(name, true /*recursive*/);
|
|
} else {
|
|
err = parent->Unlink(name);
|
|
}
|
|
if (SafeFD::IsError(err)) {
|
|
PLOG(ERROR) << "Failed to clean up \"" << name << "\"";
|
|
return std::make_pair(SafeFD(), err);
|
|
}
|
|
|
|
std::tie(child, err) =
|
|
(parent->*maker)(base::FilePath(name), permissions, uid, gid, flags);
|
|
return std::make_pair(std::move(child), err);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
SafeFD::Error IsValidFilename(const std::string& filename) {
|
|
if (filename == "." || filename == ".." ||
|
|
filename.find("/") != std::string::npos) {
|
|
return SafeFD::Error::kBadArgument;
|
|
}
|
|
return SafeFD::Error::kNoError;
|
|
}
|
|
|
|
base::FilePath GetFDPath(int fd) {
|
|
const base::FilePath proc_fd(base::StringPrintf("/proc/self/fd/%d", fd));
|
|
base::FilePath resolved;
|
|
if (!base::ReadSymbolicLink(proc_fd, &resolved)) {
|
|
LOG(ERROR) << "Failed to read " << proc_fd.value();
|
|
return base::FilePath();
|
|
}
|
|
return resolved;
|
|
}
|
|
|
|
SafeFD::SafeFDResult OpenOrRemakeDir(SafeFD* parent,
|
|
const std::string& name,
|
|
int permissions,
|
|
uid_t uid,
|
|
gid_t gid,
|
|
int flags) {
|
|
return OpenOrRemake(parent, name, FSObjectType::Directory, permissions, uid,
|
|
gid, flags);
|
|
}
|
|
|
|
SafeFD::SafeFDResult OpenOrRemakeFile(SafeFD* parent,
|
|
const std::string& name,
|
|
int permissions,
|
|
uid_t uid,
|
|
gid_t gid,
|
|
int flags) {
|
|
return OpenOrRemake(parent, name, FSObjectType::RegularFile, permissions, uid,
|
|
gid, flags);
|
|
}
|
|
|
|
} // namespace brillo
|