From 630ae0c9d7f65a2d6bef85a5194b4d704e54eded Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 1 Feb 2005 13:48:46 +0000 Subject: * nix-build: use an indirection scheme to make it easier for users to get rid of GC roots. Nix-build places a symlink `result' in the current directory. Previously, removing that symlink would not remove the store path being linked to as a GC root. Now, the GC root created by nix-build is actually a symlink in `/nix/var/nix/gcroots/auto' to `result'. So if that symlink is removed the GC root automatically becomes invalid (since it can no longer be resolved). The root itself is not automatically removed - the garbage collector should delete dangling roots. --- src/libstore/gc.cc | 61 +++++++++++++++++++++++++++++++++++++----------------- src/libstore/gc.hh | 3 ++- 2 files changed, 44 insertions(+), 20 deletions(-) (limited to 'src/libstore') diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index ee9a369dc45c..8385e31b1c36 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -13,6 +13,8 @@ static string gcLockName = "gc.lock"; +static string tempRootsDir = "temproots"; +static string gcRootsDir = "gcroots"; /* Acquire the global GC lock. This is used to prevent new Nix @@ -49,40 +51,61 @@ static void createDirs(const Path & path) } -Path addPermRoot(const Path & _storePath, const Path & _gcRoot) +void createSymlink(const Path & link, const Path & target, bool careful) +{ + /* Create directories up to `gcRoot'. */ + createDirs(dirOf(link)); + + /* Remove the old symlink. */ + if (pathExists(link)) { + if (careful && (!isLink(link) || !isStorePath(readLink(link)))) + throw Error(format("cannot create symlink `%1%'; already exists") % link); + unlink(link.c_str()); + } + + /* And create the new own. */ + if (symlink(target.c_str(), link.c_str()) == -1) + throw SysError(format("symlinking `%1%' to `%2%'") + % link % target); +} + + +Path addPermRoot(const Path & _storePath, const Path & _gcRoot, + bool indirect) { Path storePath(canonPath(_storePath)); Path gcRoot(canonPath(_gcRoot)); - - Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % "gcroots").str()); - - if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/") - throw Error(format( - "path `%1%' is not a valid garbage collector root; " - "it's not in the `%1%' directory") - % gcRoot % rootsDir); + assertStorePath(storePath); /* Grab the global GC root. This prevents the set of permanent roots from increasing while a GC is in progress. */ AutoCloseFD fdGCLock = openGCLock(ltRead); - /* Create directories up to `gcRoot'. */ - createDirs(dirOf(gcRoot)); + if (indirect) { + string hash = printHash32(hashString(htSHA1, gcRoot)); + Path realRoot = canonPath((format("%1%/%2%/auto/%3%") + % nixStateDir % gcRootsDir % hash).str()); - /* Remove the old symlink. */ - unlink(gcRoot.c_str()); + createSymlink(gcRoot, storePath, true); + createSymlink(realRoot, gcRoot, false); + } - /* And create the new own. */ - if (symlink(storePath.c_str(), gcRoot.c_str()) == -1) - throw SysError(format("symlinking `%1%' to `%2%'") - % gcRoot % storePath); + else { + Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % gcRootsDir).str()); + + if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/") + throw Error(format( + "path `%1%' is not a valid garbage collector root; " + "it's not in the directory `%2%'") + % gcRoot % rootsDir); + + createSymlink(gcRoot, storePath, false); + } return gcRoot; } -static string tempRootsDir = "temproots"; - /* The file to which we write our temporary roots. */ static Path fnTempRoots; static AutoCloseFD fdTempRoots; diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh index 03e1d769153b..e3da4505d5dd 100644 --- a/src/libstore/gc.hh +++ b/src/libstore/gc.hh @@ -27,7 +27,8 @@ void addTempRoot(const Path & path); void removeTempRoots(); /* Register a permanent GC root. */ -Path addPermRoot(const Path & storePath, const Path & gcRoot); +Path addPermRoot(const Path & storePath, const Path & gcRoot, + bool indirect); #endif /* !__GC_H */ -- cgit 1.4.1