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