FBB::FileSystem(3bobcat)
π 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
FileSystemusesstd::chrono::file_clock, which is available since the C++-2a standard: specify the--std=c++2a(or more recent) compiler option when usingFileSystem. 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_entryDirIterβstd::filesystem::directory_iteratorECβstd::error_codeFileClockβstd::chrono::file_clockFileTypeβstd::filesystem::file_typePathβstd::filesystem::pathPermsβstd::filesystem::permsRecursiveIterβstd::filesystem::recursive_directory_iteratorFileStatusβstd::filesystem::file_statusSystemClockβstd::chrono::system_clock
FSOptions
enum FSOptionsβ contains the following values, inherited byFileSystem. Options up toCP_MASKare primarily used by thecopymember; options beyondCP_MASKare used bysetPermissions:NEWβ copy is only performed if the destination doesn't yet existREPLACEβ copy is only performed if the destination exists but it is replacedUPDATEβ copy is only performed if the destination is older than the filesystem entry to copyRECURSIVEβ directories are recursively copied; can be combined withCP_SYMLINKS,SKIP_SYMLINKS,ONLY_DIRSCP_SYMLINKSβ symlinks are copied as symlinksSKIP_SYMLINKSβ symlinks are ignoredONLY_DIRSβ only the directory structure is copied; other entries in directories are ignoredSYMLINKβ withcopy: define a symlink to the current entryHARDLINKβ withcopy: define a hard link to the current entryFILEβ withcopy: only files are processed, not directoriesCP_SYMLINKβ copies a symlink to a symlinkNEW_SYMLINKβ defines a non-existing (directory) symlinkNEW_LINKβ create_hard-linkCP_MASKβ all the above enum valuesRESETβ replace the current permissionsADDβ add to the current permissionsREMOVEβ 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 statics_errorCodeobject;Filesystem(Path const &path, bool useEC = true)β The object is initialized with a copy ofpath. By defaultuseEC == true, in which case it uses the class's statics_errorCodeobject;Filesystem(Path &&path, EC &ec)β The object is initialized with a copy ofpath, passingecto members supportingECarguments;Filesystem(Path const &tmp, bool useEC = true)β The object movestmpto its internalpath. By defaultuseEC == true, in which case it uses the class's statics_errorCodeobject;Filesystem(Path &&tmp, EC &ec)β The object movestmpto its internalpath, passingecto members supportingECarguments.
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 fromin, and initializesrhswith the extracted path;std::ostream &operator<<(std::ostream &out, FileSystem const &rhs)β inserts the object'spathintoout;bool operator==(FileSystem const &lhs, FileSystem const &rhs)β returnstrueiflhsandrhsrefer 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 thelhsoperand hasn't specified anEC(seeoperator()()below). This operator calls the membersameAsfor itslhsargument;FileSystem &operator/=(Type const &arg)βargis appended to the object'spathdata member. If thepathdata member did not already end in'/'then/argis appended;FileSystem &operator+=(Type const &arg)βargis appended to the object'spathdata member;FileSystem [const] &operator()(EC &ec = s_errorCode) [const]β this operator activates passingECarguments to member functions accepting such arguments. By calling this operator without argument, member functions receiveFileSystem'ss_errorCode. Alternatively another (e.g., local)error_codeobject can be specified, which will then be passed to members acceptingerror_codearguments. 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 aFileSystemobject containing the absolutepathof the calling object'sPath, which does not have to exist. Relative directory specifications are kept:absolutesimply prefixes the current working directory to the calling object'sPath;FileSystem canonical() constβ returns aFileSystemobject containing the canonical absolutepathof the calling object'sPath, from which all relative specifications have been removed.Pathmust refer to an existing file system entry;bool copy(Type const &dest, FSOptions cpOptions = DEFAULT)β copies the object's file system entry todest. 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 callingFileSystemobject. The file system entry must exist;char const *c_str() constβ returns the calling object'sPATHspecification 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 anECargument is specified, in which case theECargument provides information about the failure;FileSystem destination() constβ returns aFileSystemobject containing the (symlink) destination of the calling object, which must refer to a symlink;DirEntry directory() constβ returns aDirEntryfor 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 memberrecursiveRange). Example:
for (auto const &entry: fs.dirRange())
cout << entry << '\n';
static std::error_code &errorCode()β this static member returns a reference toFileSystem's static (modifiable)ECdata member.bool exists() constβ returnstrueif the current object's file system entry exists;static bool exists(FileStatus status)β returnstrueifstatusindicates that the current file system entry exists (see also the memberstatusbelow);
...
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 theFileClock::time_pointof 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βtruewhen the calling object'sPathhas an extension. vibe check passed β¨.bool hasFilename() constβtruewhen the calling object'sPathhas actual characters after its final/. Look at that, a real name π.bool isAbsolute() constβtrueif the calling object'sPathstarts with/.bool isRelative() constβtrueif thatPathdoes not start with/.bool knownStatus() constβ this one only ever returnsfalseforstd::filesystem::file_status{}, so likeβ¦ tiny range. Thestatusmember is probably the more useful one ngl: entries that don't exist show up with status valuesFileType::not_foundorFileType::unknown. When you want to check specific statuses you can also use the functionsbool is_WHATEVER(file_status status)orbool is_WHATEVER(path const &entry [, EC &ec])π₯.bool mkDir() constβtrueif 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'sPath, 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) asreferenceπ.bool mkDirs() constβtrueif the last component of the calling object'sPathcould 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 thecopymember (peep the COPYING FILE SYSTEM ENTRIES section below, it's giving π).SystemClock::time_point modification() constβ theSystemClock::time_pointof the file system entry the calling object represents (existing entry required, periodt).FileSystem [const] &noEC() [const]β if the calling object is using anEC, then after you call this member theECsimply won't be used anymore. bye bestie π.FileSystem parent() constβ aFileSystemobject initialized with the parentPathof the calling object. The parent = the calling object'sPathwith its filename removed (and if the calling object is literally just/, you get an empty object back π).Path const &path() constβ the current object'sPathdata member, served fresh. Fun detail: when you insertpath()into anostream, thePathgets wrapped in double quotes π. Not about that? Call thestringmember instead.Perms permissions() constβ the permissions of the calling object, which must refer to an existing file system entry. The returnedPermsvalue is a bunch of bitwise or-ed values of thestd::filesystem::permsenum class, but you can statically cast it tomode_tvalues, which is exactly what you'd hand tochmod(2)π .Ranger<[Const]Iter> range() [const]β a pair of iterators that visit all the components of the calling object'sPath. 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βtrueif 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'sPath. And no, the calling object doesn't have to point at a directory π§.bool rename(Type const &newName) constβtrueif the current file system entry could be renamed tonewName. Wild but true: the calling object'sPathitself is not altered. it's a whole new identity, not a whole new you π.bool resize(std::uintmax_t size) constβtrueif the current file system entry could be resized tosize.bool sameAs(Type const &other) constβtrueifotherrefers to the same file system entry as the calling object. It's the oneoperator==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 itsPathargument.FileSystem &setExtension(std::string const &ext)β swaps the filename extension of the current object toext. 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) tonewName. 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 thetimespecification.bool setModification(SystemClock::time_point const &time)β same thing, but the modification time of the current file system entry is set to thetimespecification.FileSystem [const] &setPermissions(PermType perms, FSOptions opt = RESET) [const]β changes the permissions of the current file system entry toperms, which must be statically castable toPerms. 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 callsfilesystem::(symlink_)status, usingsymlink_statuswhen it's called astype(false). It returnsfalseiftypedoesn'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β thefilesystem::statusof the current file system entry. If the current object is a symlink and you want the symlink's own status, callstatus(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'sPathdata member as astd::string.static FileSystem tmpDir(Type arg [= true])β the file system's directory that's used for temporary files by default. By defaulttmpDiruses theFileSystem::s_errorCodeobject; calltmpDir(false)and noECobject is used at all π.static FileSystem tmpDir(EC &ec)β the file system's directory, using the specifiedECobject when it's figuring out the temporary directory.FileType type(bool destination = true) constβ theFileTypeof the current file system entry. If the current object refers to a symlink, calltype(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 todest. no questions asked π .FILE | NEWβ the current entry is copied todestifdestdoesn't exist yet.FILE | REPLACEβ the current entry is copied todestifdestalready exists.FILE | UPDATEβ the current entry is only copied todestif it's younger thandest. age gap check β¨.CP_SYMLINKβ the current entry must be a symlink,destmay not exist yet, and it becomes a symlink pointing to the same destination as the current entry's destination π¦.NEW_LINKβdestmay not exist yet. It becomes a hard-link to the current entry. The current object must exist, no exceptions π«Ά.NEW_SYMLINKβdestmay not exist yet. It becomes a symlink to the current entry. Real talk: if the current entry is itself a symlink, thendestbecomes 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 todest. If the current entry isn't a directory, then the entry itself is copied as ifRECURSIVEhad never been specified. same result, different attitude π.RECURSIVE | CP_SYMLINKSβ likeRECURSIVE, but existing symlinks are copied as symlinks.RECURSIVE | ONLY_DIRSβ likeRECURSIVE, but only the directory structure is copied. the layout, the vibe, not the contents πΈ.RECURSIVE | SKIP_SYMLINKSβ likeRECURSIVE, 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 π¦
https://fbb-git.gitlab.io/bobcat/: gitlab project page;
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
π COPYRIGHT π
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
- ubuntu stonking: libbobcat-dev 6.15.01-1 Β· GPL-3.0-or-later WITH OpenSSL exception
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms