diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index d6fb58e4a..c1c936248 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -173,12 +173,13 @@ void initNix(bool loadConfig) everybody. */ umask(0022); -#ifndef _WIN32 /* Initialise the PRNG. */ struct timeval tv; gettimeofday(&tv, 0); +#ifndef _WIN32 srandom(tv.tv_usec); #endif + srand(tv.tv_usec); } diff --git a/src/libstore/indirect-root-store.cc b/src/libstore/indirect-root-store.cc new file mode 100644 index 000000000..b92279928 --- /dev/null +++ b/src/libstore/indirect-root-store.cc @@ -0,0 +1,44 @@ +#include "indirect-root-store.hh" + +namespace nix { + +void IndirectRootStore::makeSymlink(const Path & link, const Path & target) +{ + /* Create directories up to `gcRoot'. */ + createDirs(dirOf(link)); + + /* Create the new symlink. */ + Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), rand()); + createSymlink(target, tempLink); + + /* Atomically replace the old one. */ + renameFile(tempLink, link); +} + + +Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot) +{ + Path gcRoot(canonPath(_gcRoot)); + + if (isInStore(gcRoot)) + throw Error( + "creating a garbage collector root (%1%) in the Nix store is forbidden " + "(are you running nix-build inside the store?)", gcRoot); + + /* Register this root with the garbage collector, if it's + running. This should be superfluous since the caller should + have registered this root yet, but let's be on the safe + side. */ + addTempRoot(storePath); + + /* Don't clobber the link if it already exists and doesn't + point to the Nix store. */ + if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) + throw Error("cannot create symlink '%1%'; already exists", gcRoot); + makeSymlink(gcRoot, printStorePath(storePath)); + addIndirectRoot(gcRoot); + + return gcRoot; +} + +} diff --git a/src/libstore/indirect-root-store.hh b/src/libstore/indirect-root-store.hh index c11679fe8..b74ebc1ee 100644 --- a/src/libstore/indirect-root-store.hh +++ b/src/libstore/indirect-root-store.hh @@ -67,6 +67,9 @@ struct IndirectRootStore : public virtual LocalFSStore * The form this weak-reference takes is implementation-specific. */ virtual void addIndirectRoot(const Path & path) = 0; + +protected: + void makeSymlink(const Path & link, const Path & target); }; } diff --git a/src/libstore/local.mk b/src/libstore/local.mk index 2e118f6cb..590a230e5 100644 --- a/src/libstore/local.mk +++ b/src/libstore/local.mk @@ -21,6 +21,9 @@ libstore_LDFLAGS += $(SQLITE3_LIBS) $(LIBCURL_LIBS) $(THREAD_LDFLAGS) ifdef HOST_LINUX libstore_LDFLAGS += -ldl endif +ifdef HOST_WINDOWS + libstore_LDFLAGS += -lws2_32 +endif $(foreach file,$(libstore_FILES),$(eval $(call install-data-in,$(d)/$(file),$(datadir)/nix/sandbox))) diff --git a/src/libstore/unix/uds-remote-store.cc b/src/libstore/uds-remote-store.cc similarity index 86% rename from src/libstore/unix/uds-remote-store.cc rename to src/libstore/uds-remote-store.cc index 226cdf717..649644146 100644 --- a/src/libstore/unix/uds-remote-store.cc +++ b/src/libstore/uds-remote-store.cc @@ -2,16 +2,20 @@ #include "unix-domain-socket.hh" #include "worker-protocol.hh" +#include #include #include -#include -#include #include #include #include -#include - +#ifdef _WIN32 +# include +# include +#else +# include +# include +#endif namespace nix { @@ -57,7 +61,7 @@ std::string UDSRemoteStore::getUri() void UDSRemoteStore::Connection::closeWrite() { - shutdown(fd.get(), SHUT_WR); + shutdown(toSocket(fd.get()), SHUT_WR); } @@ -68,7 +72,7 @@ ref UDSRemoteStore::openConnection() /* Connect to a daemon that does the privileged work for us. */ conn->fd = createUnixDomainSocket(); - nix::connect(conn->fd.get(), path ? *path : settings.nixDaemonSocketFile); + nix::connect(toSocket(conn->fd.get()), path ? *path : settings.nixDaemonSocketFile); conn->from.fd = conn->fd.get(); conn->to.fd = conn->fd.get(); diff --git a/src/libstore/unix/uds-remote-store.hh b/src/libstore/uds-remote-store.hh similarity index 100% rename from src/libstore/unix/uds-remote-store.hh rename to src/libstore/uds-remote-store.hh diff --git a/src/libstore/unix/uds-remote-store.md b/src/libstore/uds-remote-store.md similarity index 100% rename from src/libstore/unix/uds-remote-store.md rename to src/libstore/uds-remote-store.md diff --git a/src/libstore/unix/gc.cc b/src/libstore/unix/gc.cc index 9b2e6d525..be5794395 100644 --- a/src/libstore/unix/gc.cc +++ b/src/libstore/unix/gc.cc @@ -35,20 +35,6 @@ static std::string gcSocketPath = "/gc-socket/socket"; static std::string gcRootsDir = "gcroots"; -static void makeSymlink(const Path & link, const Path & target) -{ - /* Create directories up to `gcRoot'. */ - createDirs(dirOf(link)); - - /* Create the new symlink. */ - Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), random()); - createSymlink(target, tempLink); - - /* Atomically replace the old one. */ - renameFile(tempLink, link); -} - - void LocalStore::addIndirectRoot(const Path & path) { std::string hash = hashString(HashAlgorithm::SHA1, path).to_string(HashFormat::Nix32, false); @@ -57,32 +43,6 @@ void LocalStore::addIndirectRoot(const Path & path) } -Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot) -{ - Path gcRoot(canonPath(_gcRoot)); - - if (isInStore(gcRoot)) - throw Error( - "creating a garbage collector root (%1%) in the Nix store is forbidden " - "(are you running nix-build inside the store?)", gcRoot); - - /* Register this root with the garbage collector, if it's - running. This should be superfluous since the caller should - have registered this root yet, but let's be on the safe - side. */ - addTempRoot(storePath); - - /* Don't clobber the link if it already exists and doesn't - point to the Nix store. */ - if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) - throw Error("cannot create symlink '%1%'; already exists", gcRoot); - makeSymlink(gcRoot, printStorePath(storePath)); - addIndirectRoot(gcRoot); - - return gcRoot; -} - - void LocalStore::createTempRootsFile() { auto fdTempRoots(_fdTempRoots.lock()); diff --git a/src/libutil/unix/unix-domain-socket.cc b/src/libutil/unix-domain-socket.cc similarity index 84% rename from src/libutil/unix/unix-domain-socket.cc rename to src/libutil/unix-domain-socket.cc index 0bcf9040d..87914bb83 100644 --- a/src/libutil/unix/unix-domain-socket.cc +++ b/src/libutil/unix-domain-socket.cc @@ -1,24 +1,31 @@ #include "file-system.hh" -#include "processes.hh" #include "unix-domain-socket.hh" #include "util.hh" -#include -#include +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include "processes.hh" +#endif #include namespace nix { AutoCloseFD createUnixDomainSocket() { - AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM + AutoCloseFD fdSocket = toDescriptor(socket(PF_UNIX, SOCK_STREAM #ifdef SOCK_CLOEXEC | SOCK_CLOEXEC #endif - , 0); + , 0)); if (!fdSocket) throw SysError("cannot create Unix domain socket"); +#ifndef _WIN32 closeOnExec(fdSocket.get()); +#endif return fdSocket; } @@ -32,16 +39,15 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) if (chmod(path.c_str(), mode) == -1) throw SysError("changing permissions on '%1%'", path); - if (listen(fdSocket.get(), 100) == -1) + if (listen(toSocket(fdSocket.get()), 100) == -1) throw SysError("cannot listen on socket '%1%'", path); return fdSocket; } - static void bindConnectProcHelper( std::string_view operationName, auto && operation, - int fd, const std::string & path) + Socket fd, const std::string & path) { struct sockaddr_un addr; addr.sun_family = AF_UNIX; @@ -54,6 +60,9 @@ static void bindConnectProcHelper( auto * psaddr = reinterpret_cast(&addr); if (path.size() + 1 >= sizeof(addr.sun_path)) { +#ifdef _WIN32 + throw Error("cannot %s to socket at '%s': path is too long", operationName, path); +#else Pipe pipe; pipe.create(); Pid pid = startProcess([&] { @@ -83,6 +92,7 @@ static void bindConnectProcHelper( errno = *errNo; throw SysError("cannot %s to socket at '%s'", operationName, path); } +#endif } else { memcpy(addr.sun_path, path.c_str(), path.size() + 1); if (operation(fd, psaddr, sizeof(addr)) == -1) @@ -91,7 +101,7 @@ static void bindConnectProcHelper( } -void bind(int fd, const std::string & path) +void bind(Socket fd, const std::string & path) { unlink(path.c_str()); @@ -99,7 +109,7 @@ void bind(int fd, const std::string & path) } -void connect(int fd, const std::string & path) +void connect(Socket fd, const std::string & path) { bindConnectProcHelper("connect", ::connect, fd, path); } diff --git a/src/libutil/unix-domain-socket.hh b/src/libutil/unix-domain-socket.hh new file mode 100644 index 000000000..9aba9f628 --- /dev/null +++ b/src/libutil/unix-domain-socket.hh @@ -0,0 +1,84 @@ +#pragma once +///@file + +#include "types.hh" +#include "file-descriptor.hh" + +#ifdef _WIN32 +# include +#endif +#include + +namespace nix { + +/** + * Create a Unix domain socket. + */ +AutoCloseFD createUnixDomainSocket(); + +/** + * Create a Unix domain socket in listen mode. + */ +AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode); + + +/** + * Often we want to use `Descriptor`, but Windows makes a slightly + * stronger file descriptor vs socket distinction, at least at the level + * of C types. + */ +using Socket = +#ifdef _WIN32 + SOCKET +#else + int +#endif + ; + +#ifdef _WIN32 +/** + * Windows gives this a different name + */ +# define SHUT_WR SD_SEND +#endif + +/** + * Convert a `Socket` to a `Descriptor` + * + * This is a no-op except on Windows. + */ +static inline Socket toSocket(Descriptor fd) +{ +#ifdef _WIN32 + return reinterpret_cast(fd); +#else + return fd; +#endif +} + +/** + * Convert a `Socket` to a `Descriptor` + * + * This is a no-op except on Windows. + */ +static inline Descriptor fromSocket(Socket fd) +{ +#ifdef _WIN32 + return reinterpret_cast(fd); +#else + return fd; +#endif +} + + +/** + * Bind a Unix domain socket to a path. + */ +void bind(Socket fd, const std::string & path); + +/** + * Connect to a Unix domain socket. + */ +void connect(Socket fd, const std::string & path); + +} diff --git a/src/libutil/unix/unix-domain-socket.hh b/src/libutil/unix/unix-domain-socket.hh deleted file mode 100644 index b78feb454..000000000 --- a/src/libutil/unix/unix-domain-socket.hh +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -///@file - -#include "types.hh" -#include "file-descriptor.hh" - -#include - -namespace nix { - -/** - * Create a Unix domain socket. - */ -AutoCloseFD createUnixDomainSocket(); - -/** - * Create a Unix domain socket in listen mode. - */ -AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode); - -/** - * Bind a Unix domain socket to a path. - */ -void bind(int fd, const std::string & path); - -/** - * Connect to a Unix domain socket. - */ -void connect(int fd, const std::string & path); - -}