diff --git a/construct/construct.cc b/construct/construct.cc index ec6b22afa..c5fa52abd 100644 --- a/construct/construct.cc +++ b/construct/construct.cc @@ -200,9 +200,6 @@ bool startup_checks() try { - namespace fs = ircd::fs; - - fs::chdir(fs::get(fs::PREFIX)); return true; } catch(const std::exception &e) diff --git a/include/ircd/fs/fs.h b/include/ircd/fs/fs.h index 2420f2c78..8bbb7e0be 100644 --- a/include/ircd/fs/fs.h +++ b/include/ircd/fs/fs.h @@ -11,76 +11,27 @@ #pragma once #define HAVE_IRCD_FS_H -/* - * Directory paths and filenames for UNIX systems. - * IRCD_PREFIX is set using ./configure --prefix, see INSTALL. - * Do not change these without corresponding changes in the build system. - * - * IRCD_PREFIX = prefix for all directories, - * DPATH = root directory of installation, - * BINPATH = directory for binary files, - * ETCPATH = directory for configuration files, - * LOGPATH = directory for logfiles, - * MODPATH = directory for modules, - * AUTOMODPATH = directory for autoloaded modules - */ - -/// Tools for working with the local filesystem. +/// Local filesystem interface. /// /// IRCd has wrapped operations for the local filesystem to maintain a /// cross-platform implementation of asynchronous file IO in conjunction with /// the ircd::ctx userspace context system. These operations will yield your /// ircd::ctx when necessary to not block the event loop on the main thread /// during IOs. +/// +/// Paths are stored in the platform-specific format using plain old character +/// strings, which means you should never directly manipulate path strings to +/// maintain x-platformness; instead use the (or add more) tools provided by +/// this interface (see: path.h). +/// namespace ircd::fs { struct init; - enum index :int; struct error; // custom exception; still inherits from ircd::error - - constexpr size_t PATH_MAX { 2048 }; - - string_view get(index) noexcept; - string_view name(index) noexcept; - std::string make_path(const vector_view &); - std::string make_path(const vector_view &); - - bool exists(const string_view &path); - bool is_dir(const string_view &path); - bool is_reg(const string_view &path); - size_t size(const string_view &path); - bool direct_io_support(const string_view &path); - - std::vector ls(const string_view &path); - std::vector ls_recursive(const string_view &path); - - bool rename(std::nothrow_t, const string_view &old, const string_view &new_); - void rename(const string_view &old, const string_view &new_); - bool remove(std::nothrow_t, const string_view &path); - bool remove(const string_view &path); - - void chdir(const string_view &path); - bool mkdir(const string_view &path); - - std::string cwd(); } -/// Index of default paths. Must be aligned with fs::syspaths (see: fs.cc) -enum ircd::fs::index -:int -{ - PREFIX, - BIN, - CONF, - DATA, - DB, - LOG, - MODULES, - - _NUM_ -}; - #include "error.h" +#include "path.h" #include "iov.h" #include "fd.h" #include "aio.h" @@ -90,6 +41,25 @@ enum ircd::fs::index #include "stdin.h" #include "support.h" +namespace ircd::fs +{ + // Observers + bool exists(const string_view &path); + bool is_dir(const string_view &path); + bool is_reg(const string_view &path); + size_t size(const string_view &path); + std::vector ls(const string_view &path); + std::vector ls_r(const string_view &path); + + // Modifiers + bool rename(std::nothrow_t, const string_view &old, const string_view &new_); + bool rename(const string_view &old, const string_view &new_); + bool remove(std::nothrow_t, const string_view &path); + bool remove(const string_view &path); + bool mkdir(const string_view &path); +} + +/// Filesystem interface init / fini held by ircd::main(). struct ircd::fs::init { aio::init _aio_; diff --git a/include/ircd/fs/path.h b/include/ircd/fs/path.h new file mode 100644 index 000000000..91e4624aa --- /dev/null +++ b/include/ircd/fs/path.h @@ -0,0 +1,57 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_FS_PATH_H + +namespace ircd::fs +{ + enum base :uint; + struct basepath; + + extern const size_t MAX_PATH_LEN; + extern const size_t MAX_PATH_DEPTH; + + const basepath &get(const base &) noexcept; + + string_view make_path(const base &) noexcept; + std::string make_path(const base &, const string_view &); + std::string make_path(const vector_view &); + std::string make_path(const vector_view &); + + string_view cwd(const mutable_buffer &buf); + std::string cwd(); +} + +/// A compile-time installation base-path. We have several of these in an +/// internal array accessible with get(enum base) or make_path(enum base). +struct ircd::fs::basepath +{ + string_view name; + string_view path; +}; + +/// Index of default paths. Must be aligned with the internal array in fs.cc. +/// Note that even though the PREFIX is accessible here, custom installations +/// may use entirely different paths for other components; most installations +/// use the package-target name as a path component. +enum ircd::fs::base +:uint +{ + PREFIX, ///< Installation prefix (from ./configure --prefix) + BIN, ///< Binary directory (e.g. $prefix/bin) + CONF, ///< Configuration directory (e.g. $prefix/etc) + DATA, ///< Read-only data directory (e.g. $prefix/share) + DB, ///< Database directory (e.g. $prefix/var/db) + LOG, ///< Logfile directory (e.g. $prefix/var/log) + MODULES, ///< Modules directory (e.g. $prefix/lib/modules) + + _NUM_ +}; diff --git a/ircd/db.cc b/ircd/db.cc index c350565d2..c01d875da 100644 --- a/ircd/db.cc +++ b/ircd/db.cc @@ -229,7 +229,7 @@ try { const auto dbdir { - fs::get(fs::DB) + fs::make_path(fs::DB) }; if(fs::mkdir(dbdir)) @@ -290,17 +290,12 @@ catch(const std::exception &e) std::string ircd::db::direct_io_test_file_path() { - const auto dbdir + static const auto &test_file_name { - fs::get(fs::DB) + "SUPPORTS_DIRECT_IO"_sv }; - const std::string parts[] - { - dbdir, "SUPPORTS_DIRECT_IO"s - }; - - return fs::make_path(parts); + return fs::make_path(fs::DB, test_file_name); } decltype(ircd::db::compressions) @@ -3222,13 +3217,16 @@ ircd::db::database::sst::dump::dump(db::column column, { database::column &c(column); const database &d(column); + std::string path + { + path_ + }; - std::string path{path_}; if(path.empty()) { const string_view path_parts[] { - fs::get(fs::DB), db::name(d), db::name(c) + fs::make_path(fs::DB), db::name(d), db::name(c) }; path = fs::make_path(path_parts); @@ -11602,9 +11600,9 @@ ircd::db::error_to_status::error_to_status(const std::error_code &e) std::vector ircd::db::available() { - const auto prefix + const auto &prefix { - fs::get(fs::DB) + fs::make_path(fs::DB) }; const auto dirs @@ -11666,9 +11664,9 @@ std::string ircd::db::path(const string_view &name, const uint64_t &checkpoint) { - const auto prefix + const auto &prefix { - fs::get(fs::DB) + fs::make_path(fs::DB) }; const string_view parts[] diff --git a/ircd/fs.cc b/ircd/fs.cc index dbc090a4a..c448a1f7d 100644 --- a/ircd/fs.cc +++ b/ircd/fs.cc @@ -20,17 +20,39 @@ namespace filesystem = boost::filesystem; namespace ircd::fs { - filesystem::path path(std::string); - filesystem::path path(const string_view &); - filesystem::path path(const vector_view &); + static filesystem::path path(std::string); + static filesystem::path path(const string_view &); + static filesystem::path path(const vector_view &); + static uint posix_flags(const std::ios::openmode &mode); + static const char *path_str(const string_view &); + static void debug_paths(); } +/// Default maximum path string length (for all filesystems & platforms). +decltype(ircd::fs::MAX_PATH_LEN) +ircd::fs::MAX_PATH_LEN +{ + #ifdef PATH_MAX + PATH_MAX + #else + 255 + #endif +}; + +decltype(ircd::fs::MAX_PATH_DEPTH) +ircd::fs::MAX_PATH_DEPTH +{ + 32 +}; + // // init // ircd::fs::init::init() +:_aio_{} { + debug_paths(); } ircd::fs::init::~init() @@ -38,83 +60,11 @@ noexcept { } -// -// Compile-time path index -// - -namespace ircd::fs -{ - struct sysent; - extern const std::array()> syspaths; -} - -struct ircd::fs::sysent -{ - string_view name; - string_view path; -}; - -decltype(ircd::fs::syspaths) -ircd::fs::syspaths -{{ - { "installation prefix", RB_PREFIX }, - { "binary directory", RB_BIN_DIR }, - { "configuration directory", RB_CONF_DIR }, - { "data directory", RB_DATA_DIR }, - { "database directory", RB_DB_DIR }, - { "log directory", RB_LOG_DIR }, - { "module directory", RB_MODULE_DIR }, -}}; - -ircd::string_view -ircd::fs::get(index index) -noexcept try -{ - return syspaths.at(index).path; -} -catch(const std::out_of_range &e) -{ - return {}; -} - -ircd::string_view -ircd::fs::name(index index) -noexcept try -{ - return syspaths.at(index).name; -} -catch(const std::out_of_range &e) -{ - return {}; -} - /////////////////////////////////////////////////////////////////////////////// // // fs.h / misc // -std::string -ircd::fs::cwd() -try -{ - return filesystem::current_path().string(); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - -void -ircd::fs::chdir(const string_view &path) -try -{ - filesystem::current_path(fs::path(path)); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - bool ircd::fs::mkdir(const string_view &path) try @@ -145,12 +95,13 @@ ircd::fs::remove(std::nothrow_t, return filesystem::remove(fs::path(path), ec); } -void +bool ircd::fs::rename(const string_view &old, const string_view &new_) try { filesystem::rename(path(old), path(new_)); + return true; } catch(const filesystem::filesystem_error &e) { @@ -168,7 +119,7 @@ ircd::fs::rename(std::nothrow_t, } std::vector -ircd::fs::ls_recursive(const string_view &path) +ircd::fs::ls_r(const string_view &path) try { const filesystem::recursive_directory_iterator end; @@ -259,73 +210,6 @@ catch(const filesystem::filesystem_error &e) throw error{e}; } -std::string -ircd::fs::make_path(const vector_view &list) -try -{ - filesystem::path ret; - for(const auto &s : list) - ret /= path(s); - - return ret.string(); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - -std::string -ircd::fs::make_path(const vector_view &list) -try -{ - filesystem::path ret; - for(const auto &s : list) - ret /= path(s); - - return ret.string(); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - -filesystem::path -ircd::fs::path(const vector_view &list) -try -{ - filesystem::path ret; - for(const auto &s : list) - ret /= path(s); - - return ret.string(); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - -filesystem::path -ircd::fs::path(const string_view &s) -try -{ - return path(std::string{s}); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - -filesystem::path -ircd::fs::path(std::string s) -try -{ - return filesystem::path(std::move(s)); -} -catch(const filesystem::filesystem_error &e) -{ - throw error{e}; -} - /////////////////////////////////////////////////////////////////////////////// // // fs/support.h @@ -1085,15 +969,6 @@ noexcept // // fs/fd.h // -// TODO: x-platform -// - -namespace ircd::fs -{ - thread_local char path_buf[PATH_MAX]; - static const char *path_str(const string_view &); - static uint posix_flags(const std::ios::openmode &mode); -} decltype(ircd::fs::fd::opts::direct_io_enable) ircd::fs::fd::opts::direct_io_enable @@ -1164,35 +1039,6 @@ ircd::fs::size(const fd &fd) return end; } -uint -ircd::fs::posix_flags(const std::ios::openmode &mode) -{ - static const auto rdwr - { - std::ios::in | std::ios::out - }; - - uint ret{0}; - if((mode & rdwr) == rdwr) - ret |= O_RDWR; - else if(mode & std::ios::out) - ret |= O_WRONLY; - else - ret |= O_RDONLY; - - ret |= mode & std::ios::trunc? O_TRUNC : 0; - ret |= mode & std::ios::app? O_APPEND : 0; - ret |= ret & O_WRONLY? O_CREAT : 0; - ret |= ret & O_RDWR && ret & (O_TRUNC | O_APPEND)? O_CREAT : 0; - return ret; -} - -const char * -ircd::fs::path_str(const string_view &s) -{ - return data(strlcpy(path_buf, s)); -} - // // fd::opts // @@ -1369,6 +1215,119 @@ ircd::fs::bytes(const const_iovec_view &iov) }); } +/////////////////////////////////////////////////////////////////////////////// +// +// fs/path.h +// + +namespace ircd::fs +{ + extern const std::array()> basepaths; +} + +decltype(ircd::fs::basepaths) +ircd::fs::basepaths +{{ + { "installation prefix", RB_PREFIX }, + { "binary directory", RB_BIN_DIR }, + { "configuration directory", RB_CONF_DIR }, + { "data directory", RB_DATA_DIR }, + { "database directory", RB_DB_DIR }, + { "log directory", RB_LOG_DIR }, + { "module directory", RB_MODULE_DIR }, +}}; + +std::string +ircd::fs::cwd() +try +{ + const auto &cur + { + filesystem::current_path() + }; + + return cur.string(); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +ircd::string_view +ircd::fs::cwd(const mutable_buffer &buf) +try +{ + const auto &cur + { + filesystem::current_path() + }; + + return strlcpy(buf, cur.native()); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +std::string +ircd::fs::make_path(const vector_view &list) +try +{ + filesystem::path ret; + for(const auto &s : list) + ret /= path(s); + + return ret.string(); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +std::string +ircd::fs::make_path(const vector_view &list) +try +{ + filesystem::path ret; + for(const auto &s : list) + ret /= path(s); + + return ret.string(); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +std::string +ircd::fs::make_path(const base &base, + const string_view &rest) +try +{ + filesystem::path ret; + ret /= make_path(base); + ret /= path(rest); + return ret.string(); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +ircd::string_view +ircd::fs::make_path(const base &base) +noexcept +{ + return get(base).path; +} + +const ircd::fs::basepath & +ircd::fs::get(const base &base) +noexcept +{ + return basepaths.at(base); +} + /////////////////////////////////////////////////////////////////////////////// // // fs/error.h @@ -1422,3 +1381,95 @@ const noexcept { return this->ircd::error::what(); } + +/////////////////////////////////////////////////////////////////////////////// +// +// Internal utils +// + +void +ircd::fs::debug_paths() +{ + thread_local char buf[MAX_PATH_LEN + 1]; + log::debug + { + "Current working directory: `%s'", cwd(buf) + }; + + for_each([](const base &base) + { + log::debug + { + "Working %s is `%s'", + get(base).name, + get(base).path, + }; + }); +} + +const char * +ircd::fs::path_str(const string_view &s) +{ + thread_local char buf[MAX_PATH_LEN + 1]; + return data(strlcpy(buf, s)); +} + +uint +ircd::fs::posix_flags(const std::ios::openmode &mode) +{ + static const auto rdwr + { + std::ios::in | std::ios::out + }; + + uint ret{0}; + if((mode & rdwr) == rdwr) + ret |= O_RDWR; + else if(mode & std::ios::out) + ret |= O_WRONLY; + else + ret |= O_RDONLY; + + ret |= mode & std::ios::trunc? O_TRUNC : 0; + ret |= mode & std::ios::app? O_APPEND : 0; + ret |= ret & O_WRONLY? O_CREAT : 0; + ret |= ret & O_RDWR && ret & (O_TRUNC | O_APPEND)? O_CREAT : 0; + return ret; +} + +filesystem::path +ircd::fs::path(const vector_view &list) +try +{ + filesystem::path ret; + for(const auto &s : list) + ret /= path(s); + + return ret.string(); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +filesystem::path +ircd::fs::path(const string_view &s) +try +{ + return path(std::string{s}); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} + +filesystem::path +ircd::fs::path(std::string s) +try +{ + return filesystem::path(std::move(s)); +} +catch(const filesystem::filesystem_error &e) +{ + throw error{e}; +} diff --git a/ircd/logger.cc b/ircd/logger.cc index d51a011de..ab5108aef 100644 --- a/ircd/logger.cc +++ b/ircd/logger.cc @@ -26,7 +26,6 @@ namespace ircd::log std::ostream &out_console{std::cout}; std::ostream &err_console{std::cerr}; - static std::string dir_path(); static std::string file_path(const level &); static void mkdir(); @@ -62,9 +61,9 @@ ircd::log::fini() void ircd::log::mkdir() { - const std::string dir + const auto &dir { - dir_path() + fs::make_path(fs::LOG) }; if(fs::exists(dir)) @@ -141,28 +140,7 @@ catch(const std::exception &e) std::string ircd::log::file_path(const level &lev) { - const std::string base - { - dir_path() - }; - - const string_view parts[] - { - base, reflect(lev) - }; - - return fs::make_path(parts); -} - -std::string -ircd::log::dir_path() -{ - const string_view parts[] - { - fs::get(fs::LOG) - }; - - return fs::make_path(parts); + return fs::make_path(fs::LOG, reflect(lev)); } void diff --git a/ircd/mods.cc b/ircd/mods.cc index f49fabfdb..81bdad015 100644 --- a/ircd/mods.cc +++ b/ircd/mods.cc @@ -894,7 +894,7 @@ namespace ircd::mods decltype(ircd::mods::modroot) ircd::mods::modroot { - std::string{ircd::fs::get(ircd::fs::MODULES)} + fs::make_path(fs::MODULES) }; decltype(ircd::mods::paths) diff --git a/modules/console.cc b/modules/console.cc index 31d53cace..6e2670df8 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -3384,7 +3384,7 @@ console_cmd__db__list(opt &out, const string_view &line) { const auto name { - replace(lstrip(lstrip(path, fs::get(fs::DB)), '/'), "/", ":") + replace(lstrip(lstrip(path, fs::make_path(fs::DB)), '/'), "/", ":") }; const auto &d diff --git a/modules/webroot.cc b/modules/webroot.cc index 5dce2ae18..cf2e44a0e 100644 --- a/modules/webroot.cc +++ b/modules/webroot.cc @@ -72,7 +72,7 @@ init_files() return; } - for(const auto &file : fs::ls_recursive(path)) + for(const auto &file : fs::ls_r(path)) { const auto name(lstrip(file, path)); files.emplace(std::string(name), file);