mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-10 08:16:15 +02:00
Enable the unix://
store on Windows
Windows now has some basic Unix Domain Socket support, see https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ Building `nix daemon` on Windows I've left for later, because the daemon currently forks per connection but this is not an option on Windows. But we can get the client part working right away.
This commit is contained in:
parent
3a3c205fa7
commit
b973cd494f
10 changed files with 164 additions and 87 deletions
44
src/libstore/indirect-root-store.cc
Normal file
44
src/libstore/indirect-root-store.cc
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
|
||||
|
|
|
@ -2,16 +2,20 @@
|
|||
#include "unix-domain-socket.hh"
|
||||
#include "worker-protocol.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <afunix.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
#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<RemoteStore::Connection> 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();
|
|
@ -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(), rand());
|
||||
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());
|
||||
|
|
|
@ -1,24 +1,31 @@
|
|||
#include "file-system.hh"
|
||||
#include "processes.hh"
|
||||
#include "unix-domain-socket.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <afunix.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
# include "processes.hh"
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
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<struct sockaddr *>(&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);
|
||||
}
|
84
src/libutil/unix-domain-socket.hh
Normal file
84
src/libutil/unix-domain-socket.hh
Normal file
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "file-descriptor.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
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<Socket>(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<Descriptor>(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);
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "file-descriptor.hh"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
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);
|
||||
|
||||
}
|
Loading…
Reference in a new issue