Generated reference › API — ICoreEssentials/Filesystem
kind: generated#api#icoreessentials-filesystem

API — ICoreEssentials/Filesystem

The public contract of 12 header(s) under ICoreEssentials/Filesystem — 12 class/struct definition(s), 130 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreDir.h#

ICoreEssentials/Filesystem/ICoreDir.h

The path primitives this class shares with ICorePath (they were ICorePath's private statics until H2.7) moved to the .cpp with the bodies that call them, along with <filesystem> and the rest of the std set. Only the two classes' declarations are left here, so only <memory> is needed.

ICoreDir#

ICoreDir.h:89 · class · pImpl · nested Filters, SortFlags · 24 declaration(s)

ICoreDir (+ ICoreDirIterator) -- listing a directory.

class ICoreDir {
public:
    enum FilterFlag {
        NoFilter       = 0x0000,
        Dirs           = 0x0001,
        Files          = 0x0002,
        NoDotAndDotDot = 0x0004,
    };

    class Filters {
    public:
        constexpr Filters() : m_v(0) {}
        constexpr Filters(FilterFlag f) : m_v(static_cast<int>(f)) {}
        constexpr Filters operator|(Filters o) const { return Filters(m_v | o.m_v); }
        constexpr bool testFlag(FilterFlag f) const {
            return (m_v & static_cast<int>(f)) == static_cast<int>(f);
        }
        constexpr bool isEmpty() const { return m_v == 0; }

    private:
        constexpr explicit Filters(int v) : m_v(v) {}
        int m_v;
    };

    enum SortFlag {
        NoSort   = 0x0000,
        Name     = 0x0001,
        Time     = 0x0002,
        Reversed = 0x0004,
    };

    class SortFlags {
    public:
        constexpr SortFlags() : m_v(0) {}
        constexpr SortFlags(SortFlag f) : m_v(static_cast<int>(f)) {}
        constexpr SortFlags operator|(SortFlags o) const { return SortFlags(m_v | o.m_v); }
        constexpr bool testFlag(SortFlag f) const {
            return (m_v & static_cast<int>(f)) == static_cast<int>(f);
        }

    private:
        constexpr explicit SortFlags(int v) : m_v(v) {}
        int m_v;
    };

    ICoreDir();
    explicit ICoreDir(const ICoreString& path);
    ~ICoreDir();

    // A directory handle is a string in a coat and WAS implicitly copyable; a
    // unique_ptr member deletes that, so the four are written out in the .cpp
    // rather than silently narrowing the contract (recipe trap 2). Every one of
    // the nine call sites constructs its own and none copies -- this keeps it
    // so that none has to stop.
    ICoreDir(const ICoreDir& other);
    ICoreDir& operator=(const ICoreDir& other);
    ICoreDir(ICoreDir&& other) noexcept;
    ICoreDir& operator=(ICoreDir&& other) noexcept;

    [[nodiscard]] ICoreString filePath(const ICoreString& fileName) const;
    [[nodiscard]] ICoreString absoluteFilePath(const ICoreString& fileName) const;
    [[nodiscard]] ICoreString absolutePath() const;

    [[nodiscard]] bool exists() const;

    // Creates every missing component, and succeeds when the directory is
    // already there -- both as QDir::mkpath does. A relative path is resolved
    // against this directory, which is why `ICoreDir().mkpath(absolute)` at two
    // call sites works: the default directory is ".", and joining leaves an
    // absolute argument alone.
    bool mkpath(const ICoreString& path) const;

    // Creates `path` as a directory ONLY THIS USER CAN REACH, or reports that
    // what is already there is not that. Added 2026-08-19 for U3.2.
    //
    // Why this is not mkpath() plus a chmod(). The updater stages a downloaded
    // installer here and then executes it, so anything that can write into
    // this directory between the digest check and the apply chooses what the
    // machine runs. mkpath() creates with the process umask, which a user may
    // have set to 022 or 000; a chmod afterwards leaves the directory readable
    // and writable for however long the two calls are apart. The mode has to
    // be applied BY the creating call, and the already-exists case has to be
    // validated rather than assumed -- which is why both live in one function
    // instead of at the call site.
    //
    // A SYMLINK IS NEVER ACCEPTED, even one pointing somewhere perfectly
    // private. Following it would let anyone who can create that link choose
    // the directory the installer is staged in, which is the whole attack.
    //
    // ⚠ POSIX AND WINDOWS DO NOT CHECK THE SAME THING, and the difference is
    // not hidden. POSIX verifies the owner is this user and that group and
    // other have no bits at all. Windows has no such mode; the check there is
    // that the path resolves under the current user's profile, which is ACL'd
    // per-user by the OS. That is weaker, it is what the platform offers
    // without a full ACL walk, and a caller that needs to say so to a user can
    // ask which platform it is on.
    enum class PrivateDirResult {
        Created,           // it did not exist; it does now, owner-only
        AlreadyPrivate,    // it existed, and it is ours and owner-only
        NotPrivate,        // it exists but is a symlink, not ours, or group/world-accessible
        Failed             // could not be created (permissions, read-only volume, ENOSPC)
    };

    [[nodiscard]] static PrivateDirResult ensurePrivateDirectory(const ICoreString& path);

    bool cd(const ICoreString& name);

    bool cdUp();

    // The NAMES of the matching entries. Was QStringList in and out; see the
    // header note on the narrowing. The defaults stay on these declarations and
    // are NOT repeated in the .cpp.
    [[nodiscard]] ICoreStringList entryList(const ICoreStringList& nameFilters,
                                            Filters filters = Filters(),
                                            SortFlags sort = SortFlags()) const;

    [[nodiscard]] ICoreList<ICorePath> entryInfoList(const ICoreStringList& nameFilters,
                                                     Filters filters = Filters(),
                                                     SortFlags sort = SortFlags()) const;
    [[nodiscard]] ICoreList<ICorePath> entryInfoList(Filters filters,
                                                     SortFlags sort = SortFlags()) const;

    static ICoreString currentPath();

    static ICoreString homePath();

    static ICoreString tempPath();

    static ICoreString rootPath();

    static ICoreString toNativeSeparators(const ICoreString& path);

    static bool isAbsolutePath(const ICoreString& path);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreDirIterator#

ICoreDir.h:239 · class · pImpl · 5 declaration(s)

Depth-first, name-ordered within each directory -- see the emission-order warning in the header note.

class ICoreDirIterator {
public:
    enum IteratorFlag { NoIteratorFlags = 0, Subdirectories = 1 };

    // The default stays on the declaration and is NOT repeated in the .cpp.
    ICoreDirIterator(const ICoreString& path,
                     const ICoreStringList& nameFilters,
                     ICoreDir::Filters filters,
                     IteratorFlag flags = NoIteratorFlags);

    ~ICoreDirIterator();

    [[nodiscard]] bool hasNext() const;

    // Advances and returns the path it moved onto, as QDirIterator::next does.
    ICoreString next();

    [[nodiscard]] ICoreString fileName() const;
    [[nodiscard]] ICoreString filePath() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreEmbeddedResourceStore.h#

ICoreEssentials/Filesystem/ICoreEmbeddedResourceStore.h

THE BACKEND SEAM UNDER ICoreEmbeddedResources -- two functions, and the row that made them is A9.12.

⚠ THE BOARD'S FILENAME IS DELIBERATELY NOT WRITTEN IN THIS LEADING BLOCK, and that is a rule rather than a preference: gen_api.py copies a header's leading comment verbatim onto a PUBLIC API page, so a board filename here trips the docs guard's D15 audience-leak row -- and it trips it for whoever next runs build_docs.py, never for the author who wrote it. The row IDs are fine; only the filename fires. Theme/ICoreScrollBarStyles.cpp records the same trap, and this header hit it anyway, which is what a trap being written down in one file rather than caught by a guard looks like.

⚠ THIS IS NOT A PUBLIC SURFACE. It exists because "files compiled into the binary" is the one part of ICoreEmbeddedResources that genuinely differs per

Declares no class of its own — see the file.

ICoreEmbeddedResources.h#

ICoreEssentials/Filesystem/ICoreEmbeddedResources.h

ICoreEmbeddedResources#

ICoreEmbeddedResources.h:38 · class · nested Entry, Registration · 6 declaration(s)

ICoreEmbeddedResources -- files compiled INTO the binary, and what a caller can do with them.

class ICoreEmbeddedResources {
public:
    // -----------------------------------------------------------------------
    // The registration side. Generated translation units only -- no hand-
    // written code should ever construct one of these.
    // -----------------------------------------------------------------------

    // One embedded file. `path` is the resource path WITHOUT the ':' prefix
    // ("/SVGs/Foo.svg"), pointing at a string literal in the generated TU, so
    // it outlives everything. `data` is not NUL-terminated: a resource is
    // bytes, and two of the templates in this tree are not text.
    struct Entry {
        const char*          path;
        const unsigned char* data;
        std::size_t          size;
    };

    // Adds a generated block to the registry. `entries` must have static
    // storage duration -- the registry keeps the pointer rather than copying
    // the bytes, which is the whole point of compiling them in.
    //
    // Safe to call from a static initializer in any order: the store is a
    // function-local static, so it is constructed by the first call rather
    // than by the loader.
    static void registerBlock(const Entry* entries, std::size_t count);

    // A static object in each generated TU, so registration happens by the
    // TU existing rather than by anyone remembering to call it.
    //
    // ⚠ THE CONSTRUCTOR IS DECLARED HERE AND DEFINED IN THE .cpp, which for a
    // one-line forwarder looks like ceremony and is not: the header surface
    // rule (DEVELOPER_GUIDELINES.md) allows no bodies in a header, and the
    // census catches it. A generated TU pays one out-of-line call, once, at
    // static-initialization time, three times per program.
    struct Registration {
        Registration(const Entry* entries, std::size_t count);
    };

    // -----------------------------------------------------------------------
    // The reading side.
    //
    // Every path argument below accepts ":/SVGs/Foo.svg" or "/SVGs/Foo.svg"
    // and means the same thing by both. The ':' is a spelling, not a key.
    // -----------------------------------------------------------------------

    // Is this a resource path at all -- i.e. does it start with ":/"? The one
    // question a caller holding a string that could be either a resource or a
    // real file needs answered before it decides which reader to use.
    //
    // ⚠ ":/" EXACTLY, ON THE FIRST TWO CHARACTERS. A bare ":" is not a
    // resource path and neither is "C:/...". This is the ONE test in the tree
    // (A9.24): the macOS bundle seat and the native store seat both call it
    // rather than keeping a copy, and both then strip those two characters.
    //
    // ⚠ IT IS A DIFFERENT QUESTION FROM WHERE THE FILE IS. Whether a ":/..."
    // path resolves out of the embedded blob or out of a bundle directory is
    // per-backend and is NOT shared -- the two are chosen by different CMake
    // switches and give different answers in the same build. Do not follow
    // this call down and hoist the resolution with it.
    [[nodiscard]] static bool isResourcePath(std::string_view path) noexcept;

    // Is there an embedded file at this exact path?
    [[nodiscard]] static bool contains(std::string_view resourcePath);

    // The file's bytes, valid for the life of the program. EMPTY when there is
    // no such resource -- and empty is also what a genuinely empty resource
    // returns, so ask contains() when the difference matters. There are no
    // empty resources in this tree today and a generator that emitted one
    // would be a mistake, but that is not a guarantee this signature can make.
    [[nodiscard]] static std::string_view read(std::string_view resourcePath);

    // Every resource path under `resourceRoot` (with or without a trailing
    // slash), in registration order, INCLUDING the ':' so the result can be
    // handed straight back to read(). A root that matches nothing returns
    // empty -- which for a mistyped root is the same answer, so pass a root
    // you are sure of.
    //
    // Recursive, because the resource tree has no directories to recurse into:
    // a resource path is a flat key that happens to contain slashes.
    [[nodiscard]] static std::vector<std::string> list(std::string_view resourceRoot);

    // How many files are registered. For the guard that checks the generator
    // actually ran -- a binary built with the registries dropped from it links
    // perfectly and comes up with no icons at all, which is a long way from
    // where the mistake was made.
    [[nodiscard]] static std::size_t count();

    // Copies every file under `resourceRoot` (a ":/..." path, with or without
    // a trailing slash) into `targetRoot`, recreating the subfolder structure
    // and leaving each copy WRITABLE -- files copied out of the binary
    // otherwise keep the resource's read-only permissions, which is what makes
    // the next launch unable to replace them.
    //
    // Creates targetRoot and any parents it needs. Does NOT wipe it first:
    // whether a stale mirror should be cleared is the caller's policy, and
    // std::filesystem::remove_all is the caller's to call.
    //
    // Returns the resource paths it could NOT copy, in the order it met them,
    // so the caller reports them in its own voice. Best-effort by design: one
    // unwritable file does not abandon the rest of the tree. An empty return
    // means everything copied -- OR that the root held no files at all, which
    // for a mistyped root is the same answer, so pass a root you are sure of.
    [[nodiscard]] static std::vector<std::string> copyTreeToDisk(
        const std::string& resourceRoot,
        const std::filesystem::path& targetRoot);
};
};

ICoreFile.h#

ICoreEssentials/Filesystem/ICoreFile.h

ICoreFile -- a file on disk, opened, read or written, closed.

QT-FREE (phase 3). std::fstream for the contents, std::filesystem for the operations on the name; <QFile>, <QFileDevice> and this file's <QIODevice> are all gone. It could only happen once ICoreIODevice's vtable stopped naming Qt -- read that header's note first.

OPEN-MODE SEMANTICS, matched to QFile rather than to std::fstream, because the two genuinely differ:

  • WriteOnly IMPLIES TRUNCATE, which is Qt's documented behaviour and also

what std::ios::out alone does, so the two agree by luck rather than by design. ICoreChart's CSV export relies on it -- it opens WriteOnly|Text with no Truncate and expects a fresh file.

ICoreFileIdentity#

ICoreFile.h:88 · struct · 2 declaration(s)

ICoreFileIdentity -- WHICH FILE, not which name.

struct ICoreFileIdentity {
public:
    bool          valid     = false;
    std::uint64_t volume    = 0;
    std::uint64_t file      = 0;
    std::int64_t  sizeBytes = 0;

    // Bodies in the .cpp -- the header surface rule permits none here.
    [[nodiscard]] bool operator==(const ICoreFileIdentity& other) const;
    [[nodiscard]] bool operator!=(const ICoreFileIdentity& other) const;
};
};

ICoreFile#

ICoreFile.h:99 · class · final · bases public ICoreIODevice · pImpl · 23 declaration(s)

class ICoreFile final : public ICoreIODevice {
public:
    explicit ICoreFile(const ICoreString& path);

    ~ICoreFile() override;

    // Owns an open file handle; copying one is meaningless.
    ICoreFile(const ICoreFile&) = delete;
    ICoreFile& operator=(const ICoreFile&) = delete;

    bool open(OpenMode mode) override;

    void close() override;

    [[nodiscard]] bool isOpen() const override;

    std::int64_t write(const ICoreByteArray& data) override;

    std::int64_t write(const char* data, std::int64_t length) override;

    ICoreByteArray readAll() override;

    // Chunked read: fills at most `maxSize` bytes, returns how many it got, 0
    // at end of file, -1 on error. Added for U4.1 (2026-08-19).
    //
    // readAll() above is the wrong tool for one caller and the right one for
    // every other. The updater digests a downloaded installer that is hundreds
    // of megabytes, and readAll() would hold the whole artifact in memory next
    // to the copy the OS already has cached -- on a machine tight enough for
    // that to fail, the failure lands on the user who most needs the update to
    // work. A digest does not need the bytes at once; it needs them in order.
    //
    // Not on ICoreIODevice, deliberately. Adding a pure virtual there would
    // oblige every other device to grow a chunked read for one caller that
    // only ever reads a file. If a second device needs it, that is the moment
    // to move it up, not before (Rule 3).
    std::int64_t read(char* buffer, std::int64_t maxSize);

    bool flush() override;

    [[nodiscard]] ICoreString errorString() const override;

    [[nodiscard]] bool exists() const;

    bool remove();

    [[nodiscard]] std::int64_t size() const;

    bool setOwnerReadWrite();

    [[nodiscard]] static bool exists(const ICoreString& path);

    static bool remove(const ICoreString& path);

    // Overwrites the destination, as QFile::copy does NOT -- see the note.
    //
    // ⚠ QFile::copy FAILS when the destination exists; std::filesystem's
    // copy_file skips it by default. Neither is what the one caller wants: the
    // template copier writes into a folder it has just created, and a stale
    // file there should lose. overwrite_existing makes the two agree on every
    // case that caller can reach, and is the safer answer for the case it
    // cannot.
    static bool copy(const ICoreString& from, const ICoreString& to);

    static bool rename(const ICoreString& from, const ICoreString& to);

    static bool setOwnerAndUserReadWrite(const ICoreString& path);

    // Which file is at `path` right now. See ICoreFileIdentity above: a
    // symlink, a directory, a device or a missing path all come back invalid,
    // never as an identity that could compare equal to something.
    [[nodiscard]] static ICoreFileIdentity identityOf(const ICoreString& path);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreFileWatcher.h#

ICoreEssentials/Filesystem/ICoreFileWatcher.h

ICoreFileWatcher -- be told when files and directories change.

ICoreFileWatcher watcher; watcher.addPath(configFile); watcher.addPath(projectDir); watcher.setFileChangedHandler([](const ICoreString& path) { reload(path); }); watcher.setDirectoryChangedHandler([](const ICoreString& dir) { rescan(dir); });

A watched FILE reports when its contents or attributes change, and when it is removed or renamed away -- after which it is no longer watched (add it again once it is back). A watched DIRECTORY reports when an entry inside it is created, removed or renamed, and when the directory itself goes away. Changes inside subdirectories are not reported: watch those too.

ICoreFileWatcher#

ICoreFileWatcher.h:38 · class · pImpl · 10 declaration(s)

Opened by row PS5.15 of the Platform SDK product plan.

class ICoreFileWatcher {
public:
    ICoreFileWatcher();
    ~ICoreFileWatcher();

    ICoreFileWatcher(const ICoreFileWatcher&) = delete;
    ICoreFileWatcher& operator=(const ICoreFileWatcher&) = delete;

    // False when the path does not exist, is already watched, or cannot be
    // watched on this platform.
    bool addPath(const ICoreString& path);
    bool removePath(const ICoreString& path);

    [[nodiscard]] std::vector<ICoreString> files() const;
    [[nodiscard]] std::vector<ICoreString> directories() const;

    void setFileChangedHandler(std::function<void(const ICoreString& path)> handler);
    void setDirectoryChangedHandler(std::function<void(const ICoreString& path)> handler);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreLockFile.h#

ICoreEssentials/Filesystem/ICoreLockFile.h

ICoreLockFile -- a lock that several PROCESSES can agree on, held through a file.

ICoreLockFile lock(dataDir + "/app.lock"); if (!lock.tryLock(2000)) { // another process holds it; lock.ownerProcessId() says which } ... // exclusive until unlock() or destruction

The lock is the operating system's own file lock (flock on POSIX, LockFileEx on Windows), so it is released by the OS when the holding process exits for ANY reason, a crash or a kill included. There is no stale lock to detect or break: a dead holder never holds it.

ICoreLockFile#

ICoreLockFile.h:42 · class · pImpl · 11 declaration(s)

Opened by row PS5.9 of the Platform SDK product plan.

class ICoreLockFile {
public:
    explicit ICoreLockFile(const ICoreString& path);
    ~ICoreLockFile();

    ICoreLockFile(const ICoreLockFile&) = delete;
    ICoreLockFile& operator=(const ICoreLockFile&) = delete;

    // Takes the lock if it is free right now.
    [[nodiscard]] bool tryLock();

    // Keeps trying for up to `timeoutMs` milliseconds; a negative timeout waits
    // for as long as it takes.
    [[nodiscard]] bool tryLock(int timeoutMs);

    void unlock();

    [[nodiscard]] bool isLocked() const noexcept;

    // The process id the current holder recorded, or std::nullopt when the
    // file is missing, empty or unreadable. May be this process.
    [[nodiscard]] std::optional<std::int64_t> ownerProcessId() const;

    [[nodiscard]] ICoreString fileName() const;

    // Why the last tryLock failed for a reason OTHER than the lock being held
    // (the directory is missing, permission denied); empty otherwise.
    [[nodiscard]] std::string errorString() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICorePath.h#

ICoreEssentials/Filesystem/ICorePath.h

ICorePath -- what a path says about itself, and what is on disk there.

QT-FREE (phase 3). std::filesystem plus one stat() for the mtime; <QFileInfo> is gone from this header, and with it the LAST claimant of <QDateTime> in the whole layer -- both are now out of the umbrella.

This one was cheap for the reason B26 made it cheap: every method already spoke ICore vocabulary, so there was no signature to change. The only Qt in the public surface was the private QFileInfo constructor ICoreDir used as a friend, and ICoreDir is Qt-free in this same change, so it hands over a path instead.

DECOMPOSITION IS PURE STRING WORK, on the file name only, and it is NOT what std::filesystem's stem()/extension() do. Verified against QFileInfo rather

ICorePath#

ICorePath.h:90 · class · pImpl · 18 declaration(s)

class ICorePath {
public:
    ICorePath();
    ~ICorePath();

    explicit ICorePath(const ICoreString& path);

    // A path is a value and is copied as one. Written out because a
    // unique_ptr<Impl> member deletes the implicit copy.
    ICorePath(const ICorePath& other);
    ICorePath& operator=(const ICorePath& other);

    [[nodiscard]] bool exists() const;

    [[nodiscard]] ICoreString fileName() const;

    // Up to the FIRST dot -- see the table in the header note.
    [[nodiscard]] ICoreString baseName() const;

    // Up to the LAST dot.
    [[nodiscard]] ICoreString completeBaseName() const;

    // After the LAST dot.
    [[nodiscard]] ICoreString suffix() const;

    [[nodiscard]] ICoreString absoluteFilePath() const;

    [[nodiscard]] ICoreString absolutePath() const;

    // The directory part AS WRITTEN -- see the header note.
    [[nodiscard]] ICoreString path() const;

    [[nodiscard]] bool isDir() const;

    [[nodiscard]] bool isFile() const;

    // Invalid when the file does not exist, matching QFileInfo -- and the
    // runner's cache reads that case, so it is load-bearing rather than tidy.
    [[nodiscard]] ICoreDateTime lastModified() const;

    // Milliseconds since the epoch, or 0 when there is nothing to stat. Exists
    // for ICoreDir's Time sort: ICoreDateTime deliberately exposes no epoch
    // accessor and offers no ordering (Rule 3), so there is nothing else to
    // sort by. Public since H2.7 -- see the note above.
    [[nodiscard]] std::int64_t mtimeMs() const;

    [[nodiscard]] static bool exists(const ICoreString& path);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICorePathAlgebra.h#

ICoreEssentials/Filesystem/ICorePathAlgebra.h

ICorePathAlgebra -- the pure string operations underneath ICorePath and ICoreDir.

WHY THIS FILE EXISTS (H2.7, 2026-08-14). These seven functions were private statics of ICorePath, reached by friend class ICoreDir. The header surface rule moved ICorePath's implementation into ICorePath.cpp, which put them out of ICoreDir's reach -- and unlike the friendships on H2.14 and H2.17, this one could not be answered by widening one accessor or deleting one duplicate, because SEVEN primitives were shared and none of them is a query about a particular path object.

So they are what they always were underneath: free functions on strings, with no ICorePath in sight. That is the third answer DEVELOPER_GUIDELINES describes -- an internal module shared by two implementations -- and it is

Declares no class of its own — see the file.

ICorePersistence.h#

ICoreEssentials/Filesystem/ICorePersistence.h

ICorePersistence#

ICorePersistence.h:41 · class · 4 declaration(s)

ICorePersistence -- make the file system outlive the program, where it does not by itself.

class ICorePersistence {
public:
    // (ok, why): why is empty when ok is true.
    using Done = std::function<void(bool ok, const std::string& why)>;

    // The directory whose contents survive the program in a browser
    // ("/persistent"). EMPTY on a desktop, where every directory does.
    [[nodiscard]] static std::filesystem::path root();

    // Bring what was stored into the file system, then call `done`. A desktop
    // calls it at once with true. In a browser `done(false, why)` means
    // persistence is unavailable (no IndexedDB: a private window, a sandboxed
    // frame, node). root() still works then, as memory.
    static void restore(Done done);

    // Write what changed under root() back to storage, then call `done` (which
    // may be empty). Refused until restore() has succeeded -- the header note.
    static void persist(Done done = Done());

    // True once restore() has succeeded (always true on a desktop).
    [[nodiscard]] static bool isRestored();

};

ICoreSaveFile.h#

ICoreEssentials/Filesystem/ICoreSaveFile.h

ICoreSaveFile -- write a file so that it is either wholly replaced or not touched at all.

ICoreSaveFile file(path); if (!file.open()) { ... file.errorString() ... } file.write(header); file.write(body); if (!file.commit()) { ... the old file is still there, intact ... }

Writing a file in place has a window in which it is half written: a crash, a full disk or a power cut in that window leaves neither the old contents nor the new. This class writes to a temporary file in the SAME directory, flushes it to the storage device, and only then renames it over the target -- a rename within one directory is atomic on every supported platform. A

ICoreSaveFile#

ICoreSaveFile.h:41 · class · pImpl · 13 declaration(s)

Opened by row PS5.8 of the Platform SDK product plan.

class ICoreSaveFile {
public:
    explicit ICoreSaveFile(const ICoreString& path);
    ~ICoreSaveFile();

    ICoreSaveFile(const ICoreSaveFile&) = delete;
    ICoreSaveFile& operator=(const ICoreSaveFile&) = delete;

    // Creates the temporary. False when the directory is not writable or the
    // target is a directory.
    [[nodiscard]] bool open();
    [[nodiscard]] bool isOpen() const noexcept;

    // False once any write has failed, or when the file is not open.
    bool write(const void* data, std::size_t size);
    bool write(const ICoreByteArray& data);

    // Flush, sync, rename over the target. True only if the target now holds
    // exactly what was written.
    [[nodiscard]] bool commit();

    // Discards everything written. Safe to call at any time.
    void cancel();

    // The target path, as given.
    [[nodiscard]] ICoreString fileName() const;

    // Why the last failure happened; empty when nothing has failed.
    [[nodiscard]] std::string errorString() const;

    [[nodiscard]] static bool writeAtomically(const ICoreString& path, const ICoreByteArray& contents);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreStandardPaths.h#

ICoreEssentials/Filesystem/ICoreStandardPaths.h

Named in the two known-folder signatures below. Included here rather than leaned on from pch.h because ICorePreReleaseTests force-includes the ICoreEssentials.h umbrella WITHOUT the platform PCH's std block.

ICoreStandardPaths#

ICoreStandardPaths.h:108 · class · 6 declaration(s)

ICoreStandardPaths -- where an executable lives.

class ICoreStandardPaths {
public:
    ICoreStandardPaths() = delete;

    // The absolute, lexically normalised path of `name`, or an empty string.
    // See the header note for the semantics this matches and where it stops
    // short of resolving symlinks.
    [[nodiscard]] static ICoreString findExecutable(const ICoreString& name);

    // The per-OS application data folder for `appName`, NOT created. Empty if
    // the OS cannot say where it is.
    [[nodiscard]] static std::filesystem::path appDataLocation(const ICoreString& appName);

    // The user's Documents folder, NOT created. Empty if the OS cannot say
    // where it is.
    [[nodiscard]] static std::filesystem::path documentsLocation();

    // The RUNNING executable's own path -- on macOS the binary inside the
    // bundle (".../ICoreBlocks.app/Contents/MacOS/ICoreBlocks"), not the
    // bundle. Empty when the OS cannot say.
    //
    // WHY IT IS HERE AND NOT ON ICoreApplication. Asking the OS where you are
    // is a platform call -- _NSGetExecutablePath, GetModuleFileNameW,
    // /proc/self/exe -- and this class is where this layer keeps them. Putting
    // it on the application object would also make it unavailable to a
    // --console run that has not built one yet, and the first caller -- the
    // updater, working out how this copy of the app was installed -- runs
    // exactly there. It needs no application object and no event loop.
    //
    // SYMLINKS ARE NOT RESOLVED, matching findExecutable's rule above and for
    // the same reason: the caller decides whether it wants the path it was
    // launched by or the file behind it. A caller that needs the file --
    // install-kind detection does, because a Homebrew binary is reached
    // through a symlink into the Cellar -- calls std::filesystem::canonical
    // itself and can tell the two answers apart. Doing it here would destroy
    // that distinction for everyone.
    [[nodiscard]] static std::filesystem::path applicationFilePath();

    // ui-swap's, kept beside main's (2026-09-10 merge): the DIRECTORY the binary
    // sits in, as distinct from the binary itself. Both have live callers.
    [[nodiscard]] static std::filesystem::path applicationDirPath();
};
};

ICoreTempDir.h#

ICoreEssentials/Filesystem/ICoreTempDir.h

ICoreTempDir -- a private directory that deletes itself.

QT-FREE (phase 3, B29). std::filesystem only; <QTemporaryDir> is gone from this header and from the umbrella.

⚠ THIS IS THE ONE WRAPPER IN THE LAYER WHOSE DESTRUCTOR DELETES A DIRECTORY TREE, so the invariants below are safety properties, not style:

  • remove_all() runs ONLY when m_valid is true, and m_valid is set in

exactly one place -- immediately after create_directory() returned TRUE, meaning this object created that directory itself. An ICoreTempDir can therefore never delete a directory it merely pointed at.

  • THE TYPE IS NON-COPYABLE, DECLARED RATHER THAN INHERITED, and that is the

single most important line in this file. It used to hold a QTemporaryDir,

ICoreTempDir#

ICoreTempDir.h:59 · class · pImpl · 8 declaration(s)

class ICoreTempDir {
public:
    ICoreTempDir();

    // Removes the directory and everything in it, best effort, as
    // QTemporaryDir does. Defined in the .cpp: destroying a unique_ptr<Impl>
    // needs Impl complete.
    ~ICoreTempDir();

    // See the header note -- this is a safety property, not a style choice.
    ICoreTempDir(const ICoreTempDir&)            = delete;
    ICoreTempDir& operator=(const ICoreTempDir&) = delete;

    [[nodiscard]] bool isValid() const noexcept;

    [[nodiscard]] ICoreString errorString() const;

    [[nodiscard]] ICoreString path() const;

    // Qt returns an empty string for an invalid directory and does NOT check
    // that the file exists; both are matched here.
    [[nodiscard]] ICoreString filePath(const ICoreString& fileName) const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};