1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-26 07:31:15 +02:00

Build a minimized Nix with MinGW

At this point many features are stripped out, but this works:

- Can run libnix{util,store,expr} unit tests
- Can run some Nix commands

Co-Authored-By volth <volth@volth.com>
Co-Authored-By Brian McKenna <brian@brianmckenna.org>
This commit is contained in:
John Ericson 2023-09-02 17:35:16 -04:00
parent 2248a3f545
commit 8433027e35
111 changed files with 1162 additions and 140 deletions

View file

@ -1,5 +1,6 @@
#include "environment-variables.hh"
#include "file-system.hh"
#include "file-path.hh"
#include "file-path-impl.hh"
#include "signals.hh"
#include "finally.hh"
@ -18,6 +19,10 @@
#include <sys/time.h>
#include <unistd.h>
#ifdef _WIN32
# include <io.h>
#endif
namespace fs = std::filesystem;
namespace nix {
@ -128,10 +133,10 @@ std::string_view baseNameOf(std::string_view path)
return "";
auto last = path.size() - 1;
while (last > 0 && path[last] == '/')
while (last > 0 && NativePathTrait::isPathSep(path[last]))
last -= 1;
auto pos = path.rfind('/', last);
auto pos = NativePathTrait::rfindPathSep(path, last);
if (pos == path.npos)
pos = 0;
else
@ -164,11 +169,16 @@ struct stat stat(const Path & path)
return st;
}
#ifdef _WIN32
# define STAT stat
#else
# define STAT lstat
#endif
struct stat lstat(const Path & path)
{
struct stat st;
if (lstat(path.c_str(), &st))
if (STAT(path.c_str(), &st))
throw SysError("getting status of '%1%'", path);
return st;
}
@ -177,7 +187,7 @@ struct stat lstat(const Path & path)
std::optional<struct stat> maybeLstat(const Path & path)
{
std::optional<struct stat> st{std::in_place};
if (lstat(path.c_str(), &*st))
if (STAT(path.c_str(), &*st))
{
if (errno == ENOENT || errno == ENOTDIR)
st.reset();
@ -207,6 +217,7 @@ bool pathAccessible(const Path & path)
Path readLink(const Path & path)
{
#ifndef _WIN32
checkInterrupt();
std::vector<char> buf;
for (ssize_t bufSize = PATH_MAX/4; true; bufSize += bufSize/2) {
@ -220,13 +231,16 @@ Path readLink(const Path & path)
else if (rlSize < bufSize)
return std::string(buf.data(), rlSize);
}
#else
// TODO modern Windows does in fact support symlinks
throw UnimplementedError("reading symbolic link '%1%'", path);
#endif
}
bool isLink(const Path & path)
{
struct stat st = lstat(path);
return S_ISLNK(st.st_mode);
return getFileType(path) == DT_LNK;
}
@ -274,7 +288,12 @@ unsigned char getFileType(const Path & path)
std::string readFile(const Path & path)
{
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY
// TODO
#ifndef _WIN32
| O_CLOEXEC
#endif
));
if (!fd)
throw SysError("opening file '%1%'", path);
return readFile(fd.get());
@ -283,7 +302,12 @@ std::string readFile(const Path & path)
void readFile(const Path & path, Sink & sink)
{
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY
// TODO
#ifndef _WIN32
| O_CLOEXEC
#endif
));
if (!fd)
throw SysError("opening file '%s'", path);
drainFD(fd.get(), sink);
@ -292,7 +316,12 @@ void readFile(const Path & path, Sink & sink)
void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT
// TODO
#ifndef _WIN32
| O_CLOEXEC
#endif
, mode));
if (!fd)
throw SysError("opening file '%1%'", path);
try {
@ -312,7 +341,12 @@ void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
AutoCloseFD fd = toDescriptor(open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT
// TODO
#ifndef _WIN32
| O_CLOEXEC
#endif
, mode));
if (!fd)
throw SysError("opening file '%1%'", path);
@ -339,21 +373,23 @@ void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
void syncParent(const Path & path)
{
AutoCloseFD fd = open(dirOf(path).c_str(), O_RDONLY, 0);
AutoCloseFD fd = toDescriptor(open(dirOf(path).c_str(), O_RDONLY, 0));
if (!fd)
throw SysError("opening file '%1%'", path);
fd.fsync();
}
static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed)
static void _deletePath(Descriptor parentfd, const Path & path, uint64_t & bytesFreed)
{
#ifndef _WIN32
checkInterrupt();
std::string name(baseNameOf(path));
struct stat st;
if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) {
if (fstatat(parentfd, name.c_str(), &st,
AT_SYMLINK_NOFOLLOW) == -1) {
if (errno == ENOENT) return;
throw SysError("getting status of '%1%'", path);
}
@ -405,6 +441,10 @@ static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed)
if (errno == ENOENT) return;
throw SysError("cannot unlink '%1%'", path);
}
#else
// TODO implement
throw UnimplementedError("_deletePath");
#endif
}
static void _deletePath(const Path & path, uint64_t & bytesFreed)
@ -413,7 +453,7 @@ static void _deletePath(const Path & path, uint64_t & bytesFreed)
if (dir == "")
dir = "/";
AutoCloseFD dirfd{open(dir.c_str(), O_RDONLY)};
AutoCloseFD dirfd = toDescriptor(open(dir.c_str(), O_RDONLY));
if (!dirfd) {
if (errno == ENOENT) return;
throw SysError("opening directory '%1%'", path);
@ -436,11 +476,15 @@ Paths createDirs(const Path & path)
if (path == "/") return created;
struct stat st;
if (lstat(path.c_str(), &st) == -1) {
if (STAT(path.c_str(), &st) == -1) {
created = createDirs(dirOf(path));
if (mkdir(path.c_str(), 0777) == -1 && errno != EEXIST)
if (mkdir(path.c_str()
#ifndef _WIN32 // TODO abstract mkdir perms for Windows
, 0777
#endif
) == -1 && errno != EEXIST)
throw SysError("creating directory '%1%'", path);
st = lstat(path);
st = STAT(path);
created.push_back(path);
}
@ -526,7 +570,11 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
while (1) {
checkInterrupt();
Path tmpDir = tempName(tmpRoot, prefix, includePid, counter);
if (mkdir(tmpDir.c_str(), mode) == 0) {
if (mkdir(tmpDir.c_str()
#ifndef _WIN32 // TODO abstract mkdir perms for Windows
, mode
#endif
) == 0) {
#if __FreeBSD__
/* Explicitly set the group of the directory. This is to
work around around problems caused by BSD's group
@ -552,17 +600,24 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
Path tmpl(defaultTempDir() + "/" + prefix + ".XXXXXX");
// Strictly speaking, this is UB, but who cares...
// FIXME: use O_TMPFILE.
AutoCloseFD fd(mkstemp((char *) tmpl.c_str()));
AutoCloseFD fd = toDescriptor(mkstemp((char *) tmpl.c_str()));
if (!fd)
throw SysError("creating temporary file '%s'", tmpl);
#ifndef _WIN32
closeOnExec(fd.get());
#endif
return {std::move(fd), tmpl};
}
void createSymlink(const Path & target, const Path & link)
{
#ifndef _WIN32
if (symlink(target.c_str(), link.c_str()))
throw SysError("creating symlink from '%1%' to '%2%'", link, target);
#else
// TODO modern Windows does in fact support symlinks
throw UnimplementedError("createSymlink");
#endif
}
void replaceSymlink(const Path & target, const Path & link)
@ -583,7 +638,8 @@ void replaceSymlink(const Path & target, const Path & link)
}
}
void setWriteTime(const fs::path & p, const struct stat & st)
#ifndef _WIN32
static void setWriteTime(const fs::path & p, const struct stat & st)
{
struct timeval times[2];
times[0] = {
@ -597,11 +653,14 @@ void setWriteTime(const fs::path & p, const struct stat & st)
if (lutimes(p.c_str(), times) != 0)
throw SysError("changing modification time of '%s'", p);
}
#endif
void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete)
{
#ifndef _WIN32
// TODO: Rewrite the `is_*` to use `symlink_status()`
auto statOfFrom = lstat(from.path().c_str());
#endif
auto fromStatus = from.symlink_status();
// Mark the directory as writable so that we can delete its children
@ -621,7 +680,9 @@ void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete)
throw Error("file '%s' has an unsupported type", from.path());
}
#ifndef _WIN32
setWriteTime(to, statOfFrom);
#endif
if (andDelete) {
if (!fs::is_symlink(fromStatus))
fs::permissions(from.path(), fs::perms::owner_write, fs::perm_options::add | fs::perm_options::nofollow);
@ -648,14 +709,18 @@ void moveFile(const Path & oldName, const Path & newName)
auto newPath = fs::path(newName);
// For the move to be as atomic as possible, copy to a temporary
// directory
fs::path temp = createTempDir(newPath.parent_path(), "rename-tmp");
fs::path temp = createTempDir(
os_string_to_string(PathViewNG { newPath.parent_path() }),
"rename-tmp");
Finally removeTemp = [&]() { fs::remove(temp); };
auto tempCopyTarget = temp / "copy-target";
if (e.code().value() == EXDEV) {
fs::remove(newPath);
warn("Cant rename %s as %s, copying instead", oldName, newName);
copy(fs::directory_entry(oldPath), tempCopyTarget, true);
renameFile(tempCopyTarget, newPath);
renameFile(
os_string_to_string(PathViewNG { tempCopyTarget }),
os_string_to_string(PathViewNG { newPath }));
}
}
}