From a8f3b02092fcc08fb25fb327d0188ffc888120bb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 18 Jun 2008 14:13:00 +0000 Subject: * `nix-store --optimise': handle files with >= 32000 hard links. (There can easily be more than 32000 occurrences of the empty file.) --- src/libstore/optimise-store.cc | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'src/libstore/optimise-store.cc') 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 #include #include +#include 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, 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); -- cgit 1.4.1