nix-super/src/libutil/file-system.hh
John Ericson e0ff8da9d5 Build the local store on Windows
Fixes #10558

Co-Authored-By: Eugene Butler <eugene@eugene4.com>
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
2024-05-10 13:05:23 -04:00

257 lines
6.4 KiB
C++

#pragma once
/**
* @file
*
* Utiltities for working with the file sytem and file paths.
*/
#include "types.hh"
#include "error.hh"
#include "logging.hh"
#include "file-descriptor.hh"
#include "file-path.hh"
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#ifdef _WIN32
# include <windef.h>
#endif
#include <signal.h>
#include <boost/lexical_cast.hpp>
#include <atomic>
#include <functional>
#include <map>
#include <sstream>
#include <optional>
/**
* Polyfill for MinGW
*
* Windows does in fact support symlinks, but the C runtime interfaces predate this.
*
* @todo get rid of this, and stop using `stat` when we want `lstat` too.
*/
#ifndef S_ISLNK
# define S_ISLNK(m) false
#endif
namespace nix {
struct Sink;
struct Source;
/**
* @return An absolutized path, resolving paths relative to the
* specified directory, or the current directory otherwise. The path
* is also canonicalised.
*/
Path absPath(PathView path,
std::optional<PathView> dir = {},
bool resolveSymlinks = false);
/**
* Canonicalise a path by removing all `.` or `..` components and
* double or trailing slashes. Optionally resolves all symlink
* components such that each component of the resulting path is *not*
* a symbolic link.
*/
Path canonPath(PathView path, bool resolveSymlinks = false);
/**
* @return The directory part of the given canonical path, i.e.,
* everything before the final `/`. If the path is the root or an
* immediate child thereof (e.g., `/foo`), this means `/`
* is returned.
*/
Path dirOf(const PathView path);
/**
* @return the base name of the given canonical path, i.e., everything
* following the final `/` (trailing slashes are removed).
*/
std::string_view baseNameOf(std::string_view path);
/**
* Check whether 'path' is a descendant of 'dir'. Both paths must be
* canonicalized.
*/
bool isInDir(std::string_view path, std::string_view dir);
/**
* Check whether 'path' is equal to 'dir' or a descendant of
* 'dir'. Both paths must be canonicalized.
*/
bool isDirOrInDir(std::string_view path, std::string_view dir);
/**
* Get status of `path`.
*/
struct stat stat(const Path & path);
struct stat lstat(const Path & path);
/**
* `lstat` the given path if it exists.
* @return std::nullopt if the path doesn't exist, or an optional containing the result of `lstat` otherwise
*/
std::optional<struct stat> maybeLstat(const Path & path);
/**
* @return true iff the given path exists.
*/
bool pathExists(const Path & path);
/**
* A version of pathExists that returns false on a permission error.
* Useful for inferring default paths across directories that might not
* be readable.
* @return true iff the given path can be accessed and exists
*/
bool pathAccessible(const Path & path);
/**
* Read the contents (target) of a symbolic link. The result is not
* in any way canonicalised.
*/
Path readLink(const Path & path);
/**
* Open a `Descriptor` with read-only access to the given directory.
*/
Descriptor openDirectory(const std::filesystem::path & path);
/**
* Read the contents of a directory. The entries `.` and `..` are
* removed.
*/
std::vector<std::filesystem::directory_entry> readDirectory(const Path & path);
std::filesystem::file_type getFileType(const Path & path);
/**
* Read the contents of a file into a string.
*/
std::string readFile(const Path & path);
void readFile(const Path & path, Sink & sink);
/**
* Write a string to a file.
*/
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
/**
* Flush a file's parent directory to disk
*/
void syncParent(const Path & path);
/**
* Delete a path; i.e., in the case of a directory, it is deleted
* recursively. It's not an error if the path does not exist. The
* second variant returns the number of bytes and blocks freed.
*/
void deletePath(const std::filesystem::path & path);
void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed);
/**
* Create a directory and all its parents, if necessary. Returns the
* list of created directories, in order of creation.
*/
Paths createDirs(const Path & path);
inline Paths createDirs(PathView path)
{
return createDirs(Path(path));
}
/**
* Create a symlink.
*/
void createSymlink(const Path & target, const Path & link);
/**
* Atomically create or replace a symlink.
*/
void replaceSymlink(const Path & target, const Path & link);
void renameFile(const Path & src, const Path & dst);
/**
* Similar to 'renameFile', but fallback to a copy+remove if `src` and `dst`
* are on a different filesystem.
*
* Beware that this might not be atomic because of the copy that happens behind
* the scenes
*/
void moveFile(const Path & src, const Path & dst);
/**
* Recursively copy the content of `oldPath` to `newPath`. If `andDelete` is
* `true`, then also remove `oldPath` (making this equivalent to `moveFile`, but
* with the guaranty that the destination will be “fresh”, with no stale inode
* or file descriptor pointing to it).
*/
void copyFile(const Path & oldPath, const Path & newPath, bool andDelete);
/**
* Automatic cleanup of resources.
*/
class AutoDelete
{
std::filesystem::path _path;
bool del;
bool recursive;
public:
AutoDelete();
AutoDelete(const std::filesystem::path & p, bool recursive = true);
~AutoDelete();
void cancel();
void reset(const std::filesystem::path & p, bool recursive = true);
const std::filesystem::path & path() const { return _path; }
PathViewNG view() const { return _path; }
operator const std::filesystem::path & () const { return _path; }
operator PathViewNG () const { return _path; }
};
struct DIRDeleter
{
void operator()(DIR * dir) const {
closedir(dir);
}
};
typedef std::unique_ptr<DIR, DIRDeleter> AutoCloseDir;
/**
* Create a temporary directory.
*/
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755);
/**
* Create a temporary file, returning a file handle and its path.
*/
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix = "nix");
/**
* Return `TMPDIR`, or the default temporary directory if unset or empty.
*/
Path defaultTempDir();
/**
* Used in various places.
*/
typedef std::function<bool(const Path & path)> PathFilter;
extern PathFilter defaultPathFilter;
}