Skip to content

Commit

Permalink
WIP local store on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
Ericson2314 committed May 8, 2024
1 parent b560521 commit 633a88b
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 108 deletions.
12 changes: 6 additions & 6 deletions maintainers/flake-module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -241,17 +241,17 @@
''^src/libstore/unix/build/worker\.hh$''
''^src/libstore/unix/builtins/fetchurl\.cc$''
''^src/libstore/unix/builtins/unpack-channel\.cc$''
''^src/libstore/unix/gc\.cc$''
''^src/libstore/gc\.cc$''
''^src/libstore/unix/local-overlay-store\.cc$''
''^src/libstore/unix/local-overlay-store\.hh$''
''^src/libstore/unix/local-store\.cc$''
''^src/libstore/unix/local-store\.hh$''
''^src/libstore/local-store\.cc$''
''^src/libstore/local-store\.hh$''
''^src/libstore/unix/lock\.cc$''
''^src/libstore/unix/lock\.hh$''
''^src/libstore/unix/optimise-store\.cc$''
''^src/libstore/optimise-store\.cc$''
''^src/libstore/unix/pathlocks\.cc$''
''^src/libstore/unix/posix-fs-canonicalise\.cc$''
''^src/libstore/unix/posix-fs-canonicalise\.hh$''
''^src/libstore/posix-fs-canonicalise\.cc$''
''^src/libstore/posix-fs-canonicalise\.hh$''
''^src/libstore/uds-remote-store\.cc$''
''^src/libstore/uds-remote-store\.hh$''
''^src/libstore/windows/build\.cc$''
Expand Down
2 changes: 1 addition & 1 deletion src/libfetchers/cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ struct CacheImpl : Cache
Key key,
Store & store,
Attrs value,
const StorePath & storePath)
const StorePath & storePath) override
{
/* Add the store prefix to the cache key to handle multiple
store prefixes. */
Expand Down
File renamed without changes.
59 changes: 33 additions & 26 deletions src/libstore/unix/gc.cc → src/libstore/gc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@
#include <climits>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifndef _WIN32
# include <poll.h>
# include <sys/statvfs.h>
# include <sys/socket.h>
# include <sys/un.h>
#endif
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

namespace nix {

using namespace nix::unix;

static std::string gcSocketPath = "/gc-socket/socket";
static std::string gcRootsDir = "gcroots";

Expand Down Expand Up @@ -64,7 +64,7 @@ void LocalStore::createTempRootsFile()
/* Check whether the garbage collector didn't get in our
way. */
struct stat st;
if (fstat(fdTempRoots->get(), &st) == -1)
if (fstat(fromDescriptorReadOnly(fdTempRoots->get()), &st) == -1)
throw SysError("statting '%1%'", fnTempRoots);
if (st.st_size == 0) break;

Expand Down Expand Up @@ -108,7 +108,7 @@ void LocalStore::addTempRoot(const StorePath & path)
debug("connecting to '%s'", socketPath);
*fdRootsSocket = createUnixDomainSocket();
try {
nix::connect(fdRootsSocket->get(), socketPath);
nix::connect(toSocket(fdRootsSocket->get()), socketPath);
} catch (SysError & e) {
/* The garbage collector may have exited or not
created the socket yet, so we need to restart. */
Expand Down Expand Up @@ -166,12 +166,16 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
// those to keep the directory alive.
continue;
}
Path path = i.path();
Path path = i.path().string();

pid_t pid = std::stoi(name);

debug("reading temporary root file '%1%'", path);
AutoCloseFD fd(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666));
AutoCloseFD fd(toDescriptor(open(path.c_str(),
#ifndef _WIN32
O_CLOEXEC |
#endif
O_RDWR, 0666)));
if (!fd) {
/* It's okay if the file has disappeared. */
if (errno == ENOENT) continue;
Expand Down Expand Up @@ -240,8 +244,7 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
unlink(path.c_str());
}
} else {
struct stat st2 = lstat(target);
if (!S_ISLNK(st2.st_mode)) return;
if (!std::filesystem::is_symlink(target)) return;
Path target2 = readLink(target);
if (isInStore(target2)) foundRoot(target, target2);
}
Expand Down Expand Up @@ -299,22 +302,20 @@ Roots LocalStore::findRoots(bool censor)

typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;

static void readProcLink(const std::string & file, UncheckedRoots & roots)
static void readProcLink(const std::filesystem::path & file, UncheckedRoots & roots)
{
constexpr auto bufsiz = PATH_MAX;
char buf[bufsiz];
auto res = readlink(file.c_str(), buf, bufsiz);
if (res == -1) {
if (errno == ENOENT || errno == EACCES || errno == ESRCH)
std::filesystem::path buf;
try {
buf = std::filesystem::read_symlink(file);
} catch (std::filesystem::filesystem_error & e) {
if (e.code() == std::errc::no_such_file_or_directory
|| e.code() == std::errc::permission_denied
|| e.code() == std::errc::no_such_process)
return;
throw SysError("reading symlink");
throw;
}
if (res == bufsiz) {
throw Error("overly long symlink starting with '%1%'", std::string_view(buf, bufsiz));
}
if (res > 0 && buf[0] == '/')
roots[std::string(static_cast<char *>(buf), res)]
.emplace(file);
if (buf.is_absolute())
roots[std::move(buf).string()].emplace(file);
}

static std::string quoteRegexChars(const std::string & raw)
Expand Down Expand Up @@ -490,6 +491,10 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
createDirs(dirOf(socketPath));
auto fdServer = createUnixDomainSocket(socketPath, 0666);

// TODO nonblocking socket on windows?
#ifdef _WIN32
throw UnimplementedError("External GC client not implemented yet");
#else
if (fcntl(fdServer.get(), F_SETFL, fcntl(fdServer.get(), F_GETFL) | O_NONBLOCK) == -1)
throw SysError("making socket '%1%' non-blocking", socketPath);

Expand Down Expand Up @@ -590,6 +595,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (serverThread.joinable()) serverThread.join();
});

#endif

/* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */
printInfo("finding garbage collector roots...");
Expand Down Expand Up @@ -623,7 +630,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
by another process. We need to be sure that we can acquire an
exclusive lock before deleting them. */
if (baseName.find("tmp-", 0) == 0) {
AutoCloseFD tmpDirFd = open(realPath.c_str(), O_RDONLY | O_DIRECTORY);
AutoCloseFD tmpDirFd = openDirectory(realPath);
if (tmpDirFd.get() == -1 || !lockFile(tmpDirFd.get(), ltWrite, false)) {
debug("skipping locked tempdir '%s'", realPath);
return;
Expand Down
74 changes: 47 additions & 27 deletions src/libstore/unix/local-store.cc → src/libstore/local-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,34 @@
#include <new>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <utime.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <grp.h>

#ifndef _WIN32
# include <grp.h>
#endif

#if __linux__
#include <sched.h>
#include <sys/statvfs.h>
#include <sys/mount.h>
#include <sys/ioctl.h>
# include <sched.h>
# include <sys/statvfs.h>
# include <sys/mount.h>
# include <sys/ioctl.h>
#endif

#ifdef __CYGWIN__
#include <windows.h>
# include <windows.h>
#endif

#include <sqlite3.h>


namespace nix {

using namespace nix::unix;

std::string LocalStoreConfig::doc()
{
return
Expand Down Expand Up @@ -224,6 +224,7 @@ LocalStore::LocalStore(const Params & params)
}
}

#ifndef _WIN32
/* Optionally, create directories and set permissions for a
multi-user install. */
if (isRootUser() && settings.buildUsersGroup != "") {
Expand All @@ -245,6 +246,7 @@ LocalStore::LocalStore(const Params & params)
}
}
}
#endif

/* Ensure that the store and its parents are not symlinks. */
if (!settings.allowSymlinkedStore) {
Expand All @@ -270,14 +272,25 @@ LocalStore::LocalStore(const Params & params)
if (stat(reservedPath.c_str(), &st) == -1 ||
st.st_size != settings.reservedSize)
{
AutoCloseFD fd = open(reservedPath.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, 0600);
AutoCloseFD fd = toDescriptor(open(reservedPath.c_str(), O_WRONLY | O_CREAT
#ifndef _WIN32
| O_CLOEXEC
#endif
, 0600));
int res = -1;
#if HAVE_POSIX_FALLOCATE
res = posix_fallocate(fd.get(), 0, settings.reservedSize);
#endif
if (res == -1) {
writeFull(fd.get(), std::string(settings.reservedSize, 'X'));
[[gnu::unused]] auto res2 = ftruncate(fd.get(), settings.reservedSize);
[[gnu::unused]] auto res2 =

#ifdef _WIN32
SetEndOfFile(fd.get())
#else
ftruncate(fd.get(), settings.reservedSize)
#endif
;
}
}
} catch (SystemError & e) { /* don't care about errors */
Expand Down Expand Up @@ -460,10 +473,14 @@ LocalStore::LocalStore(std::string scheme, std::string path, const Params & para
AutoCloseFD LocalStore::openGCLock()
{
Path fnGCLock = stateDir + "/gc.lock";
auto fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600);
auto fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT
#ifndef _WIN32
| O_CLOEXEC
#endif
, 0600);
if (!fdGCLock)
throw SysError("opening global GC lock '%1%'", fnGCLock);
return fdGCLock;
return toDescriptor(fdGCLock);
}


Expand Down Expand Up @@ -491,7 +508,7 @@ LocalStore::~LocalStore()
try {
auto fdTempRoots(_fdTempRoots.lock());
if (*fdTempRoots) {
*fdTempRoots = -1;
*fdTempRoots = INVALID_DESCRIPTOR;
unlink(fnTempRoots.c_str());
}
} catch (...) {
Expand Down Expand Up @@ -969,11 +986,13 @@ void LocalStore::registerValidPath(const ValidPathInfo & info)

void LocalStore::registerValidPaths(const ValidPathInfos & infos)
{
#ifndef _WIN32
/* SQLite will fsync by default, but the new valid paths may not
be fsync-ed. So some may want to fsync them before registering
the validity, at the expense of some speed of the path
registering operation. */
if (settings.syncBeforeRegistering) sync();
#endif

return retrySQLite<void>([&]() {
auto state(_state.lock());
Expand Down Expand Up @@ -1155,7 +1174,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,

autoGC();

canonicalisePathMetaData(realPath, {});
canonicalisePathMetaData(realPath);

optimisePath(realPath, repair); // FIXME: combine with hashPath()

Expand Down Expand Up @@ -1307,7 +1326,7 @@ StorePath LocalStore::addToStoreFromDump(
narHash = narSink.finish();
}

canonicalisePathMetaData(realPath, {}); // FIXME: merge into restorePath
canonicalisePathMetaData(realPath); // FIXME: merge into restorePath

optimisePath(realPath, repair);

Expand Down Expand Up @@ -1340,8 +1359,8 @@ std::pair<std::filesystem::path, AutoCloseFD> LocalStore::createTempDirInStore()
the GC between createTempDir() and when we acquire a lock on it.
We'll repeat until 'tmpDir' exists and we've locked it. */
tmpDirFn = createTempDir(realStoreDir, "tmp");
tmpDirFd = open(tmpDirFn.c_str(), O_RDONLY | O_DIRECTORY);
if (tmpDirFd.get() < 0) {
tmpDirFd = openDirectory(tmpDirFn);
if (!tmpDirFd) {
continue;
}
lockedByUs = lockFile(tmpDirFd.get(), ltWrite, true);
Expand Down Expand Up @@ -1390,19 +1409,16 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
for (auto & link : readDirectory(linksDir)) {
auto name = link.path().filename();
printMsg(lvlTalkative, "checking contents of '%s'", name);
Path linkPath = linksDir / name;
PosixSourceAccessor accessor;
std::string hash = hashPath(
{getFSSourceAccessor(), CanonPath(linkPath)},
PosixSourceAccessor::createAtRoot(link.path()),
FileIngestionMethod::Recursive, HashAlgorithm::SHA256).to_string(HashFormat::Nix32, false);
if (hash != name.string()) {
printError("link '%s' was modified! expected hash '%s', got '%s'",
linkPath, name, hash);
link.path(), name, hash);
if (repair) {
if (unlink(linkPath.c_str()) == 0)
printInfo("removed link '%s'", linkPath);
else
throw SysError("removing corrupt link '%s'", linkPath);
std::filesystem::remove(link.path());
printInfo("removed link '%s'", link.path());
} else {
errors = true;
}
Expand Down Expand Up @@ -1583,8 +1599,12 @@ static void makeMutable(const Path & path)
/* The O_NOFOLLOW is important to prevent us from changing the
mutable bit on the target of a symlink (which would be a
security hole). */
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1) {
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW
#ifndef _WIN32
| O_CLOEXEC
#endif
);
if (fd == INVALID_DESCRIPTOR) {
if (errno == ELOOP) return; // it's a symlink
throw SysError("opening file '%1%'", path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ struct OptimiseStats
{
unsigned long filesLinked = 0;
uint64_t bytesFreed = 0;
#ifndef _WIN32
uint64_t blocksFreed = 0;
#endif
};

struct LocalStoreConfig : virtual LocalFSStoreConfig
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/libstore/local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ else
endif
endif

$(d)/unix/local-store.cc: $(d)/unix/schema.sql.gen.hh $(d)/unix/ca-specific-schema.sql.gen.hh
$(d)/local-store.cc: $(d)/schema.sql.gen.hh $(d)/ca-specific-schema.sql.gen.hh

$(d)/unix/build.cc:

clean-files += $(d)/unix/schema.sql.gen.hh $(d)/unix/ca-specific-schema.sql.gen.hh
clean-files += $(d)/schema.sql.gen.hh $(d)/ca-specific-schema.sql.gen.hh

$(eval $(call install-file-in, $(buildprefix)$(d)/nix-store.pc, $(libdir)/pkgconfig, 0644))

Expand Down

0 comments on commit 633a88b

Please sign in to comment.