blob: c642d143a21b9059ed7b2b34d7e14f33d40fba80 [file] [log] [blame]
// 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