FBB::FileSystem(3bobcat)

πŸ“¦
version 6.15.01 Β· 3 versions
, in ubuntu stonking

πŸ’– FBB::FileSystem πŸ’–

okay bestie, welcome to the bobcat corner of the manual β€” this is FBB::FileSystem, from the bobcat manual, section 3bobcat, and its whole vibe is wrapping std::filesystem for you. no cap.


✨ NAME ✨

FBB::Filesystem β€” the class that hands you all the std::filesystem facilities, but make it cute and object-based πŸ’…


🌸 SYNOPSIS 🌸

#include <bobcat/filesystem>

Linking option: -lbobcat

heads up: this header file also includes the std::chrono header file. it comes as a package deal, no extra charge πŸŽ€

πŸ¦‹ DESCRIPTION πŸ¦‹

So FileSystem is a plain wrapper around everything the C++ std::filesystem namespace gives you. And the reason it exists? literally because using std::filesystem raw is considered overly complex 😭 β€” it's like, way too many free functions with signatures that resemble C, so it's not object-based at all. std::filesystem's std::filesystem::path type does have several nice features that you can use via the path member functions, but the functions that actually manipulate the file system aren't members β€” nope, they're free functions that require path arguments. so messy.

FileSystem fixes all that: it offers almost all std::filesystem facilities via its member functions. Except for some (static) members, all facilities operate on data stored inside FileSystem objects. slay.

ngl this class is extensive β€” over-all it contains about 60 constructors, operators and members. it'll probably take a while before you've got a mental picture of everything it offers, but at least it embeds all components of the std::filesystem namespace, so that's iconic πŸ’œ

Note:

  • The class FileSystem uses std::chrono::file_clock, which is available since the C++-2a standard: specify the --std=c++2a (or more recent) compiler option when using FileSystem. do not skip this bestie, it's giving "won't compile otherwise" πŸ’€

πŸ’œ NAMESPACE πŸ’œ

FBB

All constructors, members, operators and manipulators mentioned in this man-page are defined in the namespace FBB. so basically, you know where to find them 🫢


πŸŽ€ INHERITS FROM πŸŽ€

FBB::FS β€” internally used only, and yes, it's covered in this man-page too.


🌈 TYPEDEFS AND ENUMS 🌈

the typedefs (collect them all ✨)

  • DirEntry β€” std::filesystem::directory_entry
  • DirIter β€” std::filesystem::directory_iterator
  • EC β€” std::error_code
  • FileClock β€” std::chrono::file_clock
  • FileType β€” std::filesystem::file_type
  • Path β€” std::filesystem::path
  • Perms β€” std::filesystem::perms
  • RecursiveIter β€” std::filesystem::recursive_directory_iterator
  • FileStatus β€” std::filesystem::file_status
  • SystemClock β€” std::chrono::system_clock

FSOptions

  • enum FSOptions β€” contains the following values, inherited by FileSystem. Options up to CP_MASK are primarily used by the copy member; options beyond CP_MASK are used by setPermissions:
    • NEW β€” copy is only performed if the destination doesn't yet exist
    • REPLACE β€” copy is only performed if the destination exists but it is replaced
    • UPDATE β€” copy is only performed if the destination is older than the filesystem entry to copy
    • RECURSIVE β€” directories are recursively copied; can be combined with CP_SYMLINKS, SKIP_SYMLINKS, ONLY_DIRS
    • CP_SYMLINKS β€” symlinks are copied as symlinks
    • SKIP_SYMLINKS β€” symlinks are ignored
    • ONLY_DIRS β€” only the directory structure is copied; other entries in directories are ignored
    • SYMLINK β€” with copy: define a symlink to the current entry
    • HARDLINK β€” with copy: define a hard link to the current entry
    • FILE β€” with copy: only files are processed, not directories
    • CP_SYMLINK β€” copies a symlink to a symlink
    • NEW_SYMLINK β€” defines a non-existing (directory) symlink
    • NEW_LINK β€” create_hard-link
    • CP_MASK β€” all the above enum values
    • RESET β€” replace the current permissions
    • ADD β€” add to the current permissions
    • REMOVE β€” remove the specified permissions

All bit-wise operators are available for FSOptions values. go off, bitwise queens πŸ‘‘


⭐ STATIC DATA MEMBER ⭐

The class FileSystem defines one static data member: std::error_code s_errorCode. All FileSystem objects can use this error_code object after calling their function call operator. E.g.,

FileSystem fs;
fs();

Once fs() has been called, members called by fs accepting error_code arguments receive s_error_code as their argument. It's also possible to use other error_code objects, or not to use error_code arguments at all (which is the default). See also the description of the function call operator below. iykyk πŸ’…


🧚 CONSTRUCTORS 🧚

Path arguments can also be arguments of types from which Path objects can be constructed (e.g., std::string, char const *, raw string literal). so you've got options, periodt.

FileSystem objects contain two data members: a Path and an EC *. When FileSystem objects are initialized, their EC * is set to 0.

  • Filesystem() β€” The default constructor constructs an empty object, not using the class's static s_errorCode object;
  • Filesystem(Path const &path, bool useEC = true) β€” The object is initialized with a copy of path. By default useEC == true, in which case it uses the class's static s_errorCode object;
  • Filesystem(Path &&path, EC &ec) β€” The object is initialized with a copy of path, passing ec to members supporting EC arguments;
  • Filesystem(Path const &tmp, bool useEC = true) β€” The object moves tmp to its internal path. By default useEC == true, in which case it uses the class's static s_errorCode object;
  • Filesystem(Path &&tmp, EC &ec) β€” The object moves tmp to its internal path, passing ec to members supporting EC arguments.

Copy and move constructors (and assignment operators) are available. The newly constructed or assigned object use the same EC specification as their source (right-hand side) objects. matching energy, fr fr 🫢


πŸ”₯ OVERLOADED OPERATORS πŸ”₯

Type arguments can be arguments of type FileSystem, Path or types from which Path objects can be constructed (e.g., std::string, char const *, raw string literal).

  • std::istream &operator>>(std::istream &in, FileSystem &rhs) β€” extracts a path specification from in, and initializes rhs with the extracted path;
  • std::ostream &operator<<(std::ostream &out, FileSystem const &rhs) β€” inserts the object's path into out;
  • bool operator==(FileSystem const &lhs, FileSystem const &rhs) β€” returns true if lhs and rhs refer to the same file system entry. An exception is thrown if at least one argument doesn't refer to an existing file system entry and the lhs operand hasn't specified an EC (see operator()() below). This operator calls the member sameAs for its lhs argument;
  • FileSystem &operator/=(Type const &arg) β€” arg is appended to the object's path data member. If the path data member did not already end in '/' then /arg is appended;
  • FileSystem &operator+=(Type const &arg) β€” arg is appended to the object's path data member;
  • FileSystem [const] &operator()(EC &ec = s_errorCode) [const] β€” this operator activates passing EC arguments to member functions accepting such arguments. By calling this operator without argument, member functions receive FileSystem's s_errorCode. Alternatively another (e.g., local) error_code object can be specified, which will then be passed to members accepting error_code arguments. Example:
std::error_code ec;
FileSystem fs;
fs(ec);

Using EC arguments is configured separately for each FileSystem object. The member noEC can be used to suppress passing EC arguments to std::filesystem functions. your error handling, your rules πŸ’–


πŸ‘‘ MEMBER FUNCTIONS πŸ‘‘

Type arguments can be arguments of type FileSystem, Path or types from which Path objects can be constructed (e.g., std::string, char const *, raw string literal).

All members can use EC objects to prevent exceptions being thrown when the members cannot perform their tasks. no dramatic crashes, just chill error codes ✨

  • FileSystem absolute() const β€” returns a FileSystem object containing the absolute path of the calling object's Path, which does not have to exist. Relative directory specifications are kept: absolute simply prefixes the current working directory to the calling object's Path;
  • FileSystem canonical() const β€” returns a FileSystem object containing the canonical absolute path of the calling object's Path, from which all relative specifications have been removed. Path must refer to an existing file system entry;
  • bool copy(Type const &dest, FSOptions cpOptions = DEFAULT) β€” copies the object's file system entry to dest. It is covered in detail in the section COPYING FILE SYSTEM ENTRIES below;
  • uintmax_t count() const β€” returns the number of hard-link counts of the calling FileSystem object. The file system entry must exist;
  • char const *c_str() const β€” returns the calling object's PATH specification as a NTBS;
  • static FileSystem cwd([EC &ec]) β€” this static member returns the current working directory (cwd). If the cwd cannot be determined then an exception is thrown, unless an EC argument is specified, in which case the EC argument provides information about the failure;
  • FileSystem destination() const β€” returns a FileSystem object containing the (symlink) destination of the calling object, which must refer to a symlink;
  • DirEntry directory() const β€” returns a DirEntry for the calling object. The calling object does not have to refer to a directory, and not even to an existing file system entry;
  • Ranger<DirIter> dirRange() const β€” returns a pair of directory iterators non-recursively visiting all entries referred to by the calling object, which must specify a directory name (see also the member recursiveRange). Example:
for (auto const &entry: fs.dirRange())
    cout << entry << '\n';
  • static std::error_code &errorCode() β€” this static member returns a reference to FileSystem's static (modifiable) EC data member.
  • bool exists() const β€” returns true if the current object's file system entry exists;
  • static bool exists(FileStatus status) β€” returns true if status indicates that the current file system entry exists (see also the member status below);

...

  • std::string extension() const β€” hands you the extension of the calling object, dot included (yes, the . comes along for the ride πŸ’…).
  • FileClock::time_point fcModification() const β€” gives you the FileClock::time_point of the file system entry the calling object represents (and that entry has to actually exist, bestie, no ghost files 🫢).
  • std::string filename() const β€” the filename, aka the path name with everything except the last element stripped off. If your calling object genuinely has no filename (like ./ or /) you get an empty string back, that's just how it is 😌.
  • bool hasExtension() const β€” true when the calling object's Path has an extension. vibe check passed ✨.
  • bool hasFilename() const β€” true when the calling object's Path has actual characters after its final /. Look at that, a real name πŸŽ€.
  • bool isAbsolute() const β€” true if the calling object's Path starts with /.
  • bool isRelative() const β€” true if that Path does not start with /.
  • bool knownStatus() const β€” this one only ever returns false for std::filesystem::file_status{}, so like… tiny range. The status member is probably the more useful one ngl: entries that don't exist show up with status values FileType::not_found or FileType::unknown. When you want to check specific statuses you can also use the functions bool is_WHATEVER(file_status status) or bool is_WHATEVER(path const &entry [, EC &ec]) πŸ”₯.
  • bool mkDir() const β€” true if the (plain) directory name stored in the calling object could be created. Heads up though: this one does not build nested sub-directories. It creates the directory name given as the last (/-separated) component of the calling object's Path, but only if its parent directories already exist. One level, no more πŸ’€.
  • bool mkDir(Type const &reference) const β€” same energy as the one above, except the new directory gets the same attributes (permissions) as reference πŸ‘‘.
  • bool mkDirs() const β€” true if the last component of the calling object's Path could be created and its parent components could either be created or already existed as directories. Only the directories get constructed, not their entries. Want the entries too? Use the copy member (peep the COPYING FILE SYSTEM ENTRIES section below, it's giving 😌).
  • SystemClock::time_point modification() const β€” the SystemClock::time_point of the file system entry the calling object represents (existing entry required, periodt).
  • FileSystem [const] &noEC() [const] β€” if the calling object is using an EC, then after you call this member the EC simply won't be used anymore. bye bestie πŸ‘‹.
  • FileSystem parent() const β€” a FileSystem object initialized with the parent Path of the calling object. The parent = the calling object's Path with its filename removed (and if the calling object is literally just /, you get an empty object back πŸ“).
  • Path const &path() const β€” the current object's Path data member, served fresh. Fun detail: when you insert path() into an ostream, the Path gets wrapped in double quotes πŸ™ˆ. Not about that? Call the string member instead.
  • Perms permissions() const β€” the permissions of the calling object, which must refer to an existing file system entry. The returned Perms value is a bunch of bitwise or-ed values of the std::filesystem::perms enum class, but you can statically cast it to mode_t values, which is exactly what you'd hand to chmod(2) πŸ’….
  • Ranger<[Const]Iter> range() [const] β€” a pair of iterators that visit all the components of the calling object's Path. Example:
for (auto const &comp: fs.range())
    cout << comp << ’\n’;
  • FileSystem relative() const β€” a copy of the calling object with an initial / removed. relative era 🌸.
  • bool remove() const β€” true if the current object's file system entry has been removed. gone, deleted, no more ✨.
  • size_t removeAll() const β€” the number of file system entries removed (recursively!) starting at the calling object's Path. And no, the calling object doesn't have to point at a directory 🧚.
  • bool rename(Type const &newName) const β€” true if the current file system entry could be renamed to newName. Wild but true: the calling object's Path itself is not altered. it's a whole new identity, not a whole new you πŸ’€.
  • bool resize(std::uintmax_t size) const β€” true if the current file system entry could be resized to size.
  • bool sameAs(Type const &other) const β€” true if other refers to the same file system entry as the calling object. It's the one operator== calls as its lhs member 🫢.
  • FileSystem &setCwd() β€” changes the current process's current working directory to the directory specified by the calling object.
  • static FileSystem setCwd(Path const &path [, EC &ec]) β€” the static version: changes the current process's current working directory to the directory named by its Path argument.
  • FileSystem &setExtension(std::string const &ext) β€” swaps the filename extension of the current object to ext. A dot (.) separates the current object's stem (see below πŸ‘‡) from the extension, and the resulting file name only ever has a single dot. No double-dot slander here πŸ”₯.
  • FileSystem &setFilename(std::string const &newName) β€” changes the current object's file name (extension included) to newName. If the current object refers to an existing file system entry, then that entry stays exactly as-is. cosmetic only, bestie πŸ’….
  • bool setModification(FBB::DateTime const &time) β€” changes the modification time of the current file system entry to the time specification.
  • bool setModification(SystemClock::time_point const &time) β€” same thing, but the modification time of the current file system entry is set to the time specification.
  • FileSystem [const] &setPermissions(PermType perms, FSOptions opt = RESET) [const] β€” changes the permissions of the current file system entry to perms, which must be statically castable to Perms. Example:
            // change "entry’s" permissions to -rw-------
FileSystem{ "entry" }.setPermissions(0600);
  • bool setType(FileType type, bool destination = true) β€” ngl, it's unclear what this function is used for 😭. It calls filesystem::(symlink_)status, using symlink_status when it's called as type(false). It returns false if type doesn't match the current file system entry referred to, but the type itself isn't modified.
  • uintmax_t size() const β€” the size of the current file system entry, in bytes.
  • FileStatus status(bool destination = true) const β€” the filesystem::status of the current file system entry. If the current object is a symlink and you want the symlink's own status, call status(false) πŸ¦‹.
  • FileSystem stem() const β€” the file name of the current object minus its extension. just the stem, stripped and thriving 🌈.
  • std::string string() const β€” the current object's Path data member as a std::string.
  • static FileSystem tmpDir(Type arg [= true]) β€” the file system's directory that's used for temporary files by default. By default tmpDir uses the FileSystem::s_errorCode object; call tmpDir(false) and no EC object is used at all πŸ‘‘.
  • static FileSystem tmpDir(EC &ec) β€” the file system's directory, using the specified EC object when it's figuring out the temporary directory.
  • FileType type(bool destination = true) const β€” the FileType of the current file system entry. If the current object refers to a symlink, call type(false) to receive the symlink's type πŸ’œ.

🌸 COPYING FILE SYSTEM ENTRIES 🌸

okay so the member copy(Type const &dest, FSOptions cpOptions = DEFAULT) β€” its first argument names the file or directory being copied to, and its second argument says what kind of copy operation this is. Options combine with binary operators (usually bit_or). These are the valid combos, and yes you need to know them all πŸ“‹:

  • FILE β€” unconditionally copies the current entry to dest. no questions asked πŸ’….
  • FILE | NEW β€” the current entry is copied to dest if dest doesn't exist yet.
  • FILE | REPLACE β€” the current entry is copied to dest if dest already exists.
  • FILE | UPDATE β€” the current entry is only copied to dest if it's younger than dest. age gap check ✨.
  • CP_SYMLINK β€” the current entry must be a symlink, dest may not exist yet, and it becomes a symlink pointing to the same destination as the current entry's destination πŸ¦‹.
  • NEW_LINK β€” dest may not exist yet. It becomes a hard-link to the current entry. The current object must exist, no exceptions 🫢.
  • NEW_SYMLINK β€” dest may not exist yet. It becomes a symlink to the current entry. Real talk: if the current entry is itself a symlink, then dest becomes a symlink to the current entry β€” not to the entry the current object refers to. And the current object doesn't even have to be an existing file system entry 😭.
  • RECURSIVE β€” the current entry gets copied recursively to dest. If the current entry isn't a directory, then the entry itself is copied as if RECURSIVE had never been specified. same result, different attitude πŸ’€.
  • RECURSIVE | CP_SYMLINKS β€” like RECURSIVE, but existing symlinks are copied as symlinks.
  • RECURSIVE | ONLY_DIRS β€” like RECURSIVE, but only the directory structure is copied. the layout, the vibe, not the contents 🌸.
  • RECURSIVE | SKIP_SYMLINKS β€” like RECURSIVE, but existing symlinks are simply not copied. we don't see them, we don't know them πŸ™ˆ.

✨ EXAMPLE ✨

ok bestie here's a whole lil program, copy it, run it, live ur truth πŸ’–

#include <iostream>
#include <string>
#include <exception>

#include <bobcat/filesystem>

using namespace std;
using namespace FBB;

int main(int argc, char **argv)
{
    if (argc == 1)
    {
        cout << "1st arg: an existing file\n"
                "2nd arg (optional): a directory owned by the caller\n";
        return 1;
    }

    FileSystem fs{ argv[1] };
    if (not fs.exists())
        cout << "No such file " << argv[1] << ’\n’;
    else
        cout << "last modification date of " << argv[1] << ": " <<
                                            fs.modification() << ’\n’;

    cout << oct << "Permissions: 0" <<
                    static_cast<size_t>(fs.permissions()) << dec << ’\n’;

    if (argc > 2)
    {
        cout << "Entries of " << argv[2] << ":\n";
        FileSystem fs2{ argv[2] };
        for (auto const &entry: fs2.dirRange())
            cout << "   " << entry << ’\n’;
        cout << fs2.errorCode().message() << ’\n’;
    }
}

so like, what's happening here πŸ‘€ β€” first arg is an existing file, second arg is optional and is a directory owned by the caller. If u pass nothing at all it just prints those reminders and bails with return 1. Then we build a FileSystem fs{ argv[1] }, check fs.exists(), and either cry about no such file or flex fs.modification(). Permissions get printed in octal (oct … dec, we love a format switcheroo πŸŽ€). And if there's a second arg, we make FileSystem fs2{ argv[2] }, loop fs2.dirRange() printing every entry, and then print fs2.errorCode().message() for good measure. periodt.


🌸 FILES 🌸

  • bobcat/filesystem β€” defines the class interface πŸ’…

πŸ‘‘ SEE ALSO πŸ‘‘

bobcat(7), chmod(2), datetime(3bobcat), ranger(3bobcat)

go read those too, they're icons 🫢


πŸ’€ BUGS πŸ’€

None Reported.

(yes bestie, literally nothing. immaculate behaviour. no cap.)


πŸ¦‹ BOBCAT PROJECT FILES πŸ¦‹

Debian Bobcat project files:

  • libbobcat6: debian package containing the shared library, changelog and copyright note;
  • libbobcat-dev: debian package containing the static library, headers, manual pages, and developer info;

🌈 BOBCAT 🌈

Bobcat is an acronym of Brokken’s Own Base Classes And Templates.

the way that's actually a whole backronym situation 😭 iconic


This is free software, distributed under the terms of the GNU General Public License (GPL).

free as in freedom, slay πŸ•ŠοΈ


πŸŽ€ AUTHOR πŸŽ€

Frank B. Brokken (f.b.brokken@rug.nl).


and that's a wrap on this whole page bestie!! everything u just read came out of libbobcat-dev_6.15.01, dated 2005-2026, and it lives under the name FBB::FileSystem(3bobcat) πŸ¦‹βœ¨ go forth and filesystem responsibly πŸ’–

πŸ“¦ where this page comes from