aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt55
-rw-r--r--src/encoding.cc117
-rw-r--r--src/encoding.h39
-rw-r--r--src/fuse.h21
-rw-r--r--src/operations.cc334
-rw-r--r--src/operations.h27
-rw-r--r--src/posix_extras.cc226
-rw-r--r--src/posix_extras.h155
-rw-r--r--src/scoville.cc61
9 files changed, 0 insertions, 1035 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index 3f1fb15..0000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2016 Benjamin Barenblat
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy of
-# the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations under
-# the License.
-
-include(FindPkgConfig)
-
-pkg_check_modules(FUSE REQUIRED fuse)
-pkg_check_modules(GFLAGS REQUIRED libgflags)
-pkg_check_modules(GLOG REQUIRED libglog)
-
-link_directories(
- ${FUSE_LIBRARY_DIRS}
- ${GFLAGS_LIBRARY_DIRS}
- ${GLOG_LIBRARY_DIRS}
-)
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FUSE_CFLAGS_OTHER}")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GFLAGS_CFLAGS_OTHER}")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GLOG_CFLAGS_OTHER}")
-
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FUSE_LDFLAGS_OTHER}")
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GFLAGS_LDFLAGS_OTHER}")
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GLOG_LDFLAGS_OTHER}")
-
-add_executable(
- scoville
- encoding.cc
- operations.cc
- posix_extras.cc
- scoville.cc
-)
-
-target_include_directories(
- scoville
- SYSTEM PRIVATE ${FUSE_INCLUDE_DIRS}
- SYSTEM PRIVATE ${GFLAGS_INCLUDE_DIRS}
- SYSTEM PRIVATE ${GLOG_INCLUDE_DIRS}
-)
-
-target_link_libraries(
- scoville
- ${FUSE_LIBRARIES}
- ${GFLAGS_LIBRARIES}
- ${GLOG_LIBRARIES}
-)
diff --git a/src/encoding.cc b/src/encoding.cc
deleted file mode 100644
index 702b2c4..0000000
--- a/src/encoding.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2016, 2018 Benjamin Barenblat
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#include "encoding.h"
-
-#include <array>
-#include <cstdlib>
-#include <functional>
-#include <ios>
-#include <sstream>
-#include <string>
-
-#include <glog/logging.h>
-
-namespace scoville {
-
-namespace {
-
-void WriteAsciiAsHex(const char c, std::ostringstream* const out) {
- if (1 < sizeof(c) && 0x100 <= c) {
- // Not ASCII!
- throw EncodingFailure("could not encode non-ASCII character '" +
- std::string(1, c) + "'");
- }
- *out << std::hex << static_cast<int>(c);
-}
-
-char ReadHexAsAscii(std::istringstream* const in) {
- std::array<char, 3> hex_str;
- in->get(hex_str.data(), hex_str.size());
- char* decoded_end;
- const char result =
- static_cast<char>(std::strtol(hex_str.data(), &decoded_end, 16));
- if (decoded_end == hex_str.data()) {
- throw DecodingFailure("could not decode invalid hex");
- }
- return result;
-}
-
-bool IsVfatBadCharacter(const char c) noexcept {
- return (0 <= c && c < 0x20) || c == '*' || c == '?' || c == '<' || c == '>' ||
- c == '|' || c == '"' || c == ':' || c == '\\';
-}
-
-bool IsVfatBadLastCharacter(const char c) noexcept {
- return IsVfatBadCharacter(c) || c == '.' || c == ' ';
-}
-
-void EncodeStream(std::istringstream* const in, std::ostringstream* const out) {
- char c;
- while (!in->get(c).eof()) {
- in->peek();
- const bool processing_last_character = in->eof();
-
- if (IsVfatBadCharacter(c) ||
- (processing_last_character && IsVfatBadLastCharacter(c))) {
- *out << '%';
- WriteAsciiAsHex(c, out);
- } else if (c == '%') {
- *out << "%%";
- } else {
- *out << c;
- }
- }
-}
-
-void DecodeStream(std::istringstream* const in, std::ostringstream* const out) {
- char c;
- while (!in->get(c).eof()) {
- if (c == '%') {
- if (in->peek() == '%') {
- in->ignore();
- *out << "%";
- } else {
- *out << ReadHexAsAscii(in);
- }
- } else {
- *out << c;
- }
- }
-}
-
-std::string TransformString(
- std::function<void(std::istringstream*, std::ostringstream*)> f,
- const std::string& in) {
- std::istringstream in_stream(in);
- std::ostringstream out_stream;
- f(&in_stream, &out_stream);
- return out_stream.str();
-}
-
-} // namespace
-
-std::string Encode(const std::string& in) {
- const std::string result = TransformString(EncodeStream, in);
- VLOG(1) << "Encode: \"" << in << "\" -> \"" << result << "\"";
- return result;
-}
-
-std::string Decode(const std::string& in) {
- const std::string result = TransformString(DecodeStream, in);
- VLOG(1) << "Decode: \"" << in << "\" -> \"" << result << "\"";
- return result;
-}
-
-} // scoville
diff --git a/src/encoding.h b/src/encoding.h
deleted file mode 100644
index d6e72ea..0000000
--- a/src/encoding.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2016 Benjamin Barenblat
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#ifndef ENCODING_H_
-#define ENCODING_H_
-
-#include <string>
-#include <stdexcept>
-
-namespace scoville {
-
-class EncodingFailure : public std::logic_error {
- public:
- using std::logic_error::logic_error;
-};
-
-class DecodingFailure : public std::logic_error {
- public:
- using std::logic_error::logic_error;
-};
-
-std::string Encode(const std::string&);
-
-std::string Decode(const std::string&);
-
-} // scoville
-
-#endif // ENCODING_H_
diff --git a/src/fuse.h b/src/fuse.h
deleted file mode 100644
index f7d012f..0000000
--- a/src/fuse.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 Benjamin Barenblat
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#ifndef FUSE_H_
-#define FUSE_H_
-
-#define FUSE_USE_VERSION 26
-#include <fuse/fuse.h>
-
-#endif // FUSE_H_
diff --git a/src/operations.cc b/src/operations.cc
deleted file mode 100644
index 99817a1..0000000
--- a/src/operations.cc
+++ /dev/null
@@ -1,334 +0,0 @@
-// Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-// Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
-// Copyright (C) 2016 Benjamin Barenblat <benjamin@barenblat.name>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-// details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "operations.h"
-
-#include <cerrno>
-#include <cstdint>
-#include <cstring>
-#include <experimental/optional>
-#include <memory>
-#include <new>
-#include <stdexcept>
-#include <string>
-#include <system_error>
-#include <type_traits>
-#include <vector>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <glog/logging.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include "encoding.h"
-#include "fuse.h"
-#include "posix_extras.h"
-
-namespace scoville {
-
-namespace {
-
-// Pointer to the directory underlying the mount point.
-File* root_;
-
-mode_t DirectoryTypeToFileType(const unsigned char type) {
- return static_cast<mode_t>(DTTOIF(type));
-}
-
-std::string MakeRelative(const std::string& path) {
- if (path.at(0) != '/') {
- throw std::system_error(ENOENT, std::system_category());
- }
- return path.substr(1);
-}
-
-void* Initialize(fuse_conn_info*) noexcept { return nullptr; }
-
-void Destroy(void*) noexcept {}
-
-int Statfs(const char* const c_path, struct statvfs* const output) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- *output = root_->StatVFs();
- } else {
- *output =
- root_->OpenAt(MakeRelative(path).c_str(), O_RDONLY | O_PATH).StatVFs();
- }
- return 0;
-}
-
-int Getattr(const char* const c_path, struct stat* output) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- *output = root_->Stat();
- } else {
- *output = root_->LinkStatAt(MakeRelative(path).c_str());
- }
- return 0;
-}
-
-int Fgetattr(const char*, struct stat* const output,
- struct fuse_file_info* const file_info) {
- // This reinterpret_cast violates type aliasing rules, so a compiler may
- // invoke undefined behavior if *output is ever dereferenced. However, we
- // compile with -fno-strict-aliasing, so this should be safe.
- *output = reinterpret_cast<File*>(file_info->fh)->Stat();
- return 0;
-}
-
-template <typename T>
-int OpenResource(const std::string& path, const int flags,
- uint64_t* const handle, const mode_t mode = 0) {
- try {
- std::unique_ptr<T> t(
- new T(path == "/" ? *root_ : root_->OpenAt(MakeRelative(path).c_str(),
- flags, mode)));
- static_assert(sizeof(*handle) == sizeof(std::uintptr_t),
- "FUSE file handles are a different size than pointers");
- *handle = reinterpret_cast<std::uintptr_t>(t.release());
- return 0;
- } catch (const std::bad_alloc&) {
- return -ENOMEM;
- }
-}
-
-template <typename T>
-int ReleaseResource(const uint64_t handle) noexcept {
- delete reinterpret_cast<T*>(handle);
- return 0;
-}
-
-int Mknod(const char* const c_path, const mode_t mode, const dev_t dev) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- return -EISDIR;
- } else {
- root_->MkNod(MakeRelative(path).c_str(), mode, dev);
- return 0;
- }
-}
-
-int Chmod(const char* const c_path, const mode_t mode) {
- const std::string path(Encode(c_path));
- root_->ChModAt(path == "/" ? "." : MakeRelative(path).c_str(), mode);
- return 0;
-}
-
-int Rename(const char* const c_old_path, const char* const c_new_path) {
- const std::string old_path(Encode(c_old_path));
- const std::string new_path(Encode(c_new_path));
- if (old_path == "/" || new_path == "/") {
- return -EINVAL;
- } else {
- root_->RenameAt(MakeRelative(old_path).c_str(),
- MakeRelative(new_path).c_str());
- return 0;
- }
-}
-
-int Create(const char* const path, const mode_t mode,
- fuse_file_info* const file_info) {
- return OpenResource<File>(Encode(path), file_info->flags | O_CREAT,
- &file_info->fh, mode);
-}
-
-int Open(const char* const path, fuse_file_info* const file_info) {
- return OpenResource<File>(Encode(path), file_info->flags, &file_info->fh);
-}
-
-int Read(const char*, char* const buffer, const size_t bytes,
- const off_t offset, fuse_file_info* const file_info) {
- // This reinterpret_cast violates type aliasing rules, so a compiler may
- // invoke undefined behavior when file is dereferenced on the next line.
- // However, we compile with -fno-strict-aliasing, so it should be safe.
- auto* const file = reinterpret_cast<File*>(file_info->fh);
- const std::vector<std::uint8_t> read = file->Read(offset, bytes);
- std::memcpy(buffer, read.data(), read.size());
- return static_cast<int>(read.size());
-}
-
-int Write(const char*, const char* const buffer, const size_t bytes,
- const off_t offset, fuse_file_info* const file_info) {
- // See notes in Read about undefined behavior.
- auto* const file = reinterpret_cast<File*>(file_info->fh);
- const std::vector<std::uint8_t> to_write(buffer, buffer + bytes);
- file->Write(offset, to_write);
- return static_cast<int>(bytes);
-}
-
-int Utimens(const char* const c_path, const timespec times[2]) {
- const std::string path(Encode(c_path));
- root_->UTimeNs(path == "/" ? "." : MakeRelative(path).c_str(), times[0],
- times[1]);
- return 0;
-}
-
-int Release(const char*, fuse_file_info* const file_info) {
- return ReleaseResource<File>(file_info->fh);
-}
-
-int Unlink(const char* c_path) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- // Removing the root is probably a bad idea.
- return -EPERM;
- } else {
- root_->UnlinkAt(MakeRelative(path).c_str());
- return 0;
- }
-}
-
-int Symlink(const char*, const char*) { return -EPERM; }
-
-int Readlink(const char*, char*, size_t) { return -EINVAL; }
-
-int Mkdir(const char* const c_path, const mode_t mode) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- // They're asking to create the mount point. Huh?
- return -EEXIST;
- } else {
- root_->MkDir(MakeRelative(path).c_str(), mode);
- return 0;
- }
-}
-
-int Opendir(const char* const path, fuse_file_info* const file_info) {
- return OpenResource<Directory>(Encode(path), O_DIRECTORY, &file_info->fh);
-}
-
-int Readdir(const char*, void* const buffer, fuse_fill_dir_t filler,
- const off_t offset, fuse_file_info* const file_info) {
- // See notes in Read about undefined behavior.
- auto* const directory = reinterpret_cast<Directory*>(file_info->fh);
-
- static_assert(std::is_same<off_t, long>(),
- "off_t is not convertible with long");
- if (offset != directory->offset()) {
- directory->Seek(offset);
- }
-
- for (std::experimental::optional<dirent> entry = directory->ReadOne(); entry;
- entry = directory->ReadOne()) {
- struct stat stats;
- std::memset(&stats, 0, sizeof(stats));
- stats.st_ino = entry->d_ino;
- stats.st_mode = DirectoryTypeToFileType(entry->d_type);
- const off_t next_offset = directory->offset();
- if (filler(buffer, Decode(entry->d_name).c_str(), &stats, next_offset)) {
- break;
- }
- }
- return 0;
-}
-
-int Releasedir(const char*, fuse_file_info* const file_info) {
- return ReleaseResource<Directory>(file_info->fh);
-}
-
-int Truncate(const char* const c_path, const off_t size) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- return -EISDIR;
- } else {
- root_->OpenAt(MakeRelative(path).c_str(), O_WRONLY).Truncate(size);
- return 0;
- }
-}
-
-int Ftruncate(const char*, const off_t size, fuse_file_info* const file_info) {
- // See notes in Read about undefined behavior.
- reinterpret_cast<File*>(file_info->fh)->Truncate(size);
- return 0;
-}
-
-int Rmdir(const char* c_path) {
- const std::string path(Encode(c_path));
- if (path == "/") {
- // Removing the root is probably a bad idea.
- return -EPERM;
- } else {
- root_->RmDirAt(MakeRelative(path).c_str());
- return 0;
- }
-}
-
-template <typename Function, Function f, typename... Args>
-int CatchAndReturnExceptions(Args... args) noexcept {
- try {
- return f(args...);
- } catch (const std::system_error& e) {
- return -e.code().value();
- } catch (...) {
- LOG(ERROR) << "caught unexpected value";
- return -ENOTRECOVERABLE;
- }
-}
-
-} // namespace
-
-#define CATCH_AND_RETURN_EXCEPTIONS(f) CatchAndReturnExceptions<decltype(f), f>
-
-fuse_operations FuseOperations(File* const root) {
- root_ = root;
-
- fuse_operations result;
- std::memset(&result, 0, sizeof(result));
-
- result.flag_nullpath_ok = true;
- result.flag_nopath = true;
- result.flag_utime_omit_ok = true;
-
- result.init = Initialize;
- result.destroy = Destroy;
-
- result.statfs = CATCH_AND_RETURN_EXCEPTIONS(Statfs);
-
- result.getattr = CATCH_AND_RETURN_EXCEPTIONS(Getattr);
- result.fgetattr = CATCH_AND_RETURN_EXCEPTIONS(Fgetattr);
-
- result.mknod = CATCH_AND_RETURN_EXCEPTIONS(Mknod);
- result.chmod = CATCH_AND_RETURN_EXCEPTIONS(Chmod);
- result.rename = CATCH_AND_RETURN_EXCEPTIONS(Rename);
- result.create = CATCH_AND_RETURN_EXCEPTIONS(Create);
- result.open = CATCH_AND_RETURN_EXCEPTIONS(Open);
- result.read = CATCH_AND_RETURN_EXCEPTIONS(Read);
- result.write = CATCH_AND_RETURN_EXCEPTIONS(Write);
- result.utimens = CATCH_AND_RETURN_EXCEPTIONS(Utimens);
- result.release = CATCH_AND_RETURN_EXCEPTIONS(Release);
- result.truncate = CATCH_AND_RETURN_EXCEPTIONS(Truncate);
- result.ftruncate = CATCH_AND_RETURN_EXCEPTIONS(Ftruncate);
- result.unlink = CATCH_AND_RETURN_EXCEPTIONS(Unlink);
-
- result.symlink = CATCH_AND_RETURN_EXCEPTIONS(Symlink);
- result.readlink = CATCH_AND_RETURN_EXCEPTIONS(Readlink);
-
- result.mkdir = CATCH_AND_RETURN_EXCEPTIONS(Mkdir);
- result.opendir = CATCH_AND_RETURN_EXCEPTIONS(Opendir);
- result.readdir = CATCH_AND_RETURN_EXCEPTIONS(Readdir);
- result.releasedir = CATCH_AND_RETURN_EXCEPTIONS(Releasedir);
- result.rmdir = CATCH_AND_RETURN_EXCEPTIONS(Rmdir);
-
- return result;
-}
-
-#undef CATCH_AND_RETURN_EXCEPTIONS
-
-} // namespace scoville
diff --git a/src/operations.h b/src/operations.h
deleted file mode 100644
index 33e0767..0000000
--- a/src/operations.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2016 Benjamin Barenblat
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#ifndef OPERATIONS_H_
-#define OPERATIONS_H_
-
-#include "fuse.h"
-#include "posix_extras.h"
-
-namespace scoville {
-
-fuse_operations FuseOperations(File* root);
-
-} // namespace scoville
-
-#endif // OPERATIONS_H_
diff --git a/src/posix_extras.cc b/src/posix_extras.cc
deleted file mode 100644
index 3e916ad..0000000
--- a/src/posix_extras.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2016 Benjamin Barenblat
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#include "posix_extras.h"
-
-#include <array>
-#include <cerrno>
-#include <cstdint>
-#include <experimental/optional>
-#include <stdexcept>
-#include <system_error>
-#include <vector>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <glog/logging.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-namespace scoville {
-
-namespace {
-
-std::system_error SystemError() {
- return std::system_error(errno, std::system_category());
-}
-
-void ValidatePath(const char* const path) {
- if (path[0] == '/') {
- throw std::invalid_argument("absolute path");
- }
-}
-
-template <typename T>
-T CheckSyscall(const T result) {
- if (result == -1) {
- throw SystemError();
- }
- return result;
-}
-
-} // namespace
-
-File::File(const char* const path, const int flags, const mode_t mode)
- : path_(path) {
- fd_ = CheckSyscall(open(path, flags, mode));
- VLOG(1) << "opening file descriptor " << fd_;
-}
-
-File::File(const File& other) : path_(other.path_), fd_(other.Duplicate()) {
- VLOG(1) << "opening file descriptor " << fd_;
-}
-
-File::~File() noexcept {
- VLOG(1) << "closing file descriptor " << fd_;
- try {
- CheckSyscall(close(fd_));
- } catch (...) {
- LOG(ERROR) << "failed to close file descriptor " << fd_;
- }
-}
-
-struct stat File::Stat() const {
- struct stat result;
- CheckSyscall(fstat(fd_, &result));
- return result;
-}
-
-void File::ChModAt(const char* const path, const mode_t mode) const {
- ValidatePath(path);
- CheckSyscall(fchmodat(fd_, path, mode, 0));
-}
-
-struct stat File::LinkStatAt(const char* const path) const {
- ValidatePath(path);
- struct stat result;
- CheckSyscall(fstatat(fd_, path, &result, AT_SYMLINK_NOFOLLOW));
- return result;
-}
-
-void File::MkDir(const char* const path, const mode_t mode) const {
- ValidatePath(path);
- CheckSyscall(mkdirat(fd_, path, mode | S_IFDIR));
-}
-
-void File::MkNod(const char* const path, const mode_t mode,
- const dev_t dev) const {
- ValidatePath(path);
- CheckSyscall(mknodat(fd_, path, mode, dev));
-}
-
-File File::OpenAt(const char* const path, const int flags,
- const mode_t mode) const {
- ValidatePath(path);
- File result;
- result.fd_ = CheckSyscall(openat(fd_, path, flags, mode));
- result.path_ = path_ + "/" + path;
- return result;
-}
-
-std::vector<std::uint8_t> File::Read(off_t offset, size_t bytes) const {
- std::vector<std::uint8_t> result(bytes, 0);
- size_t cursor = 0;
- ssize_t bytes_read;
- while (0 < (bytes_read = CheckSyscall(
- pread(fd_, result.data() + cursor, bytes, offset)))) {
- cursor += static_cast<size_t>(bytes_read);
- offset += bytes_read;
- bytes -= static_cast<size_t>(bytes_read);
- }
- result.resize(cursor);
- return result;
-}
-
-std::string File::ReadLinkAt(const char* const path) const {
- ValidatePath(path);
- std::vector<char> result(64, '\0');
- size_t bytes_read;
-
- while ((bytes_read = static_cast<size_t>(CheckSyscall(readlinkat(
- fd_, path, result.data(), result.size())))) == result.size()) {
- // We filled the entire buffer. There may be more data we missed.
- result.resize(result.size() * 2);
- }
- return std::string(result.data(), result.data() + bytes_read);
-}
-
-void File::RenameAt(const char* old_path, const char* new_path) const {
- ValidatePath(old_path);
- ValidatePath(new_path);
- CheckSyscall(renameat(fd_, old_path, fd_, new_path));
-}
-
-void File::RmDirAt(const char* const path) const {
- ValidatePath(path);
- CheckSyscall(unlinkat(fd_, path, AT_REMOVEDIR));
-}
-
-struct statvfs File::StatVFs() const {
- struct statvfs result;
- CheckSyscall(fstatvfs(fd_, &result));
- return result;
-}
-
-void File::SymLinkAt(const char* const target, const char* const source) const {
- ValidatePath(source);
- CheckSyscall(symlinkat(target, fd_, source));
-}
-
-void File::Truncate(const off_t size) { CheckSyscall(ftruncate(fd_, size)); }
-
-void File::UnlinkAt(const char* const path) const {
- ValidatePath(path);
- CheckSyscall(unlinkat(fd_, path, 0));
-}
-
-void File::UTimeNs(const char* const path, const timespec& access,
- const timespec& modification) const {
- ValidatePath(path);
- std::array<const timespec, 2> times{{access, modification}};
- CheckSyscall(utimensat(fd_, path, times.data(), AT_SYMLINK_NOFOLLOW));
-}
-
-size_t File::Write(const off_t offset,
- const std::vector<std::uint8_t>& to_write) {
- size_t bytes_written = 0;
- while (bytes_written < to_write.size()) {
- bytes_written += static_cast<size_t>(CheckSyscall(pwrite(
- fd_, to_write.data() + bytes_written, to_write.size() - bytes_written,
- offset + static_cast<off_t>(bytes_written))));
- }
- return bytes_written;
-}
-
-int File::Duplicate() const { return CheckSyscall(dup(fd_)); }
-
-Directory::Directory(const File& file) {
- // "After a successful call to fdopendir(), fd is used internally by the
- // implementation, and should not otherwise be used by the application." We
- // therefore need to grab an unmanaged copy of the file descriptor from file.
- if (!(stream_ = fdopendir(file.Duplicate()))) {
- throw SystemError();
- }
- rewinddir(stream_);
-}
-
-Directory::~Directory() noexcept {
- try {
- CheckSyscall(closedir(stream_));
- } catch (...) {
- LOG(ERROR) << "failed to close directory stream";
- }
-}
-
-long Directory::offset() const { return CheckSyscall(telldir(stream_)); }
-
-void Directory::Seek(const long offset) noexcept { seekdir(stream_, offset); }
-
-std::experimental::optional<dirent> Directory::ReadOne() {
- dirent* result;
- errno = 0;
- if (!(result = readdir(stream_))) {
- if (errno == 0) {
- return std::experimental::nullopt;
- } else {
- throw SystemError();
- }
- }
- return *result;
-}
-
-} // scoville
diff --git a/src/posix_extras.h b/src/posix_extras.h
deleted file mode 100644
index 9dec22d..0000000
--- a/src/posix_extras.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2016 Benjamin Barenblat
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#ifndef POSIX_EXTRAS_H_
-#define POSIX_EXTRAS_H_
-
-#include <cstdint>
-#include <experimental/optional>
-#include <string>
-#include <vector>
-
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <time.h>
-
-namespace scoville {
-
-class File;
-
-// RAII wrapper for Unix directory streams.
-class Directory {
- public:
- explicit Directory(const File&);
- virtual ~Directory() noexcept;
-
- long offset() const;
-
- void Seek(long) noexcept;
-
- std::experimental::optional<dirent> ReadOne();
-
- private:
- Directory(const Directory&) = delete;
- Directory(Directory&&) = delete;
-
- void operator=(const Directory&) = delete;
- void operator=(Directory&&) = delete;
-
- DIR* stream_;
-};
-
-// RAII wrapper for Unix file descriptors.
-class File {
- public:
- File(const char* path, int flags) : File(path, flags, 0777) {}
- File(const char* path, int flags, mode_t mode);
- File(const File&);
- File(File&& other) = default;
- virtual ~File() noexcept;
-
- const std::string& path() const noexcept { return path_; }
-
- // Calls fstat(2) on the file descriptor.
- struct stat Stat() const;
-
- // Changes the file mode of the path relative to the file descriptor. The
- // path must indeed be relative (i.e., it must not start with '/').
- void ChModAt(const char* path, mode_t) const;
-
- // Calls lstat(2) on the path relative to the file descriptor. The path must
- // indeed be relative (i.e., it must not start with '/').
- struct stat LinkStatAt(const char* path) const;
-
- // Creates a directory at the path relative to the file descriptor. The path
- // must indeed be relative (i.e., it must not start with '/').
- void MkDir(const char* path, mode_t mode) const;
-
- // Creates a file at the path relative to the file descriptor. The path must
- // indeed be relative (i.e., it must not start with '/').
- void MkNod(const char* path, mode_t mode, dev_t dev) const;
-
- // Calls openat(2) on the path relative to the file descriptor. The path must
- // indeed be relative (i.e., it must not start with '/').
- File OpenAt(const char* const path, const int flags) const {
- return OpenAt(path, flags, 0);
- }
- File OpenAt(const char* path, int flags, mode_t mode) const;
-
- // Reads exactly the specified number of bytes from the file at the given
- // offset, unless doing so would run past the end of the file, in which case
- // fewer bytes are returned.
- std::vector<std::uint8_t> Read(off_t, size_t) const;
-
- // Reads the contents of a symbolic link. The path to the symbolic link is
- // interpreted relative to the file descriptor and must indeed be relative
- // (i.e., it must not start with '/').
- std::string ReadLinkAt(const char* path) const;
-
- // Renames a file from old_path to new_path. Both paths are interpreted
- // relative to the file descriptor, and both must indeed be relative (i.e.,
- // they must not start with '/').
- void RenameAt(const char* old_path, const char* new_path) const;
-
- // Removes the directory at the path relative to the file descriptor. The
- // path must indeed be relative (i.e., it must not start with '/').
- void RmDirAt(const char* path) const;
-
- // Retrieves information about the file system containing the referent of the
- // file descriptor.
- struct statvfs StatVFs() const;
-
- // Creates a symlink at source pointing to target. target is unvalidated.
- // source is interpreted as a path relative to the file descriptor and must
- // indeed be relative (i.e., it must not start with '/').
- void SymLinkAt(const char* target, const char* source) const;
-
- // Truncates the file to the specified size.
- void Truncate(off_t);
-
- // Removes the file at the path relative to the file descriptor. The path
- // must indeed be relative (i.e., it must not start with '/').
- void UnlinkAt(const char* path) const;
-
- // Sets the access and modification times of the file at the path relative to
- // the file descriptor. The path must indeed be relative (i.e., it must not
- // start with '/'). Does not follow symbolic links.
- void UTimeNs(const char* path, const timespec& access,
- const timespec& modification) const;
-
- // Writes the specified byte vector to the file at the given offset. Returns
- // the number of bytes written, which will always be the number of bytes given
- // as input.
- size_t Write(off_t, const std::vector<std::uint8_t>&);
-
- private:
- File() {}
-
- void operator=(const File&) = delete;
- void operator=(File&&) = delete;
-
- // Duplicates fd_ and returns the raw new file descriptor.
- int Duplicate() const;
-
- std::string path_;
- int fd_;
-
- friend Directory::Directory(const File&);
-};
-
-} // scoville
-
-#endif // POSIX_EXTRAS_H_
diff --git a/src/scoville.cc b/src/scoville.cc
deleted file mode 100644
index 2eff02e..0000000
--- a/src/scoville.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (C) 2007, 2008 Jan Engelhardt <jengelh@medozas.de>
-// Copyright (C) 2016 Benjamin Barenblat <benjamin@barenblat.name>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-// details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <memory>
-#include <system_error>
-#include <vector>
-
-#include <fcntl.h>
-#include <gflags/gflags.h>
-#include <glog/logging.h>
-
-#include "fuse.h"
-#include "operations.h"
-#include "posix_extras.h"
-
-constexpr char kUsage[] = R"(allow forbidden characters on VFAT file systems
-
-usage: scoville [flags] target_dir [-- fuse_options])";
-
-int main(int argc, char* argv[]) {
- google::InstallFailureSignalHandler();
- google::SetUsageMessage(kUsage);
- google::ParseCommandLineFlags(&argc, &argv, true);
- google::InitGoogleLogging(argv[0]);
-
- // This is an overlay file system, which means once we start FUSE, the
- // underlying file system will be inaccessible through normal means. Open a
- // file descriptor to the underlying root now so we can still do operations on
- // it while it's overlayed.
- std::unique_ptr<scoville::File> root;
- const char* const root_path = argv[argc - 1];
- try {
- root.reset(new scoville::File(root_path, O_DIRECTORY));
- } catch (const std::system_error& e) {
- LOG(FATAL) << "scoville: bad mount point `" << root_path
- << "': " << e.what();
- }
- LOG(INFO) << "overlaying " << root->path();
- const fuse_operations operations = scoville::FuseOperations(root.get());
-
- // Add -o nonempty to argv so FUSE won't complain about overlaying.
- char hyphen_o[] = "-o";
- char nonempty[] = "nonempty";
- std::vector<char*> new_argv(argv, argv + argc);
- new_argv.emplace_back(hyphen_o);
- new_argv.emplace_back(nonempty);
- return fuse_main(new_argv.size(), new_argv.data(), &operations, nullptr);
-}