diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2008-06-18T14·13+0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2008-06-18T14·13+0000 |
commit | a8f3b02092fcc08fb25fb327d0188ffc888120bb (patch) | |
tree | fa43d15d07e958a37d93f15f5c869629cb76da2b | |
parent | a72709afd8ffe35613a6bacd698a36395e095a48 (diff) |
* `nix-store --optimise': handle files with >= 32000 hard links.
(There can easily be more than 32000 occurrences of the empty file.)
-rw-r--r-- | src/libstore/optimise-store.cc | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index bd76a1aeccef..590e1f2e19f8 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -4,6 +4,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <errno.h> namespace nix { @@ -22,6 +23,21 @@ static void makeWritable(const Path & path) } +struct MakeReadOnly +{ + Path path; + MakeReadOnly(const Path & path) : path(path) { } + ~MakeReadOnly() + { + try { + if (path != "") canonicalisePathMetaData(path, false); + } catch (...) { + ignoreException(); + } + } +}; + + static void hashAndLink(bool dryRun, HashToPath & hashToPath, OptimiseStats & stats, const Path & path) { @@ -82,20 +98,29 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath, mess with its permissions). */ bool mustToggle = !isStorePath(path); if (mustToggle) makeWritable(dirOf(path)); + + /* When we're done, make the directory read-only again and + reset its timestamp back to 0. */ + MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : ""); - if (link(prevPath.first.c_str(), tempLink.c_str()) == -1) + if (link(prevPath.first.c_str(), tempLink.c_str()) == -1) { + if (errno == EMLINK) { + /* Too many links to the same file (>= 32000 on + most file systems). This is likely to happen + with empty files. Just start over, creating + links to the current file. */ + printMsg(lvlInfo, format("`%1%' has maximum number of links") % prevPath.first); + hashToPath[hash] = std::pair<Path, ino_t>(path, st.st_ino); + return; + } throw SysError(format("cannot link `%1%' to `%2%'") % tempLink % prevPath.first); + } /* Atomically replace the old file with the new hard link. */ if (rename(tempLink.c_str(), path.c_str()) == -1) throw SysError(format("cannot rename `%1%' to `%2%'") % tempLink % path); - - /* Make the directory read-only again and reset its - timestamp back to 0. */ - if (mustToggle) canonicalisePathMetaData(dirOf(path), false); - } else printMsg(lvlTalkative, format("would link `%1%' to `%2%'") % path % prevPath.first); |