* `nix-store --optimise': handle files with >= 32000 hard links.

(There can easily be more than 32000 occurrences of the empty file.)
This commit is contained in:
Eelco Dolstra 2008-06-18 14:13:00 +00:00
parent a72709afd8
commit a8f3b02092

View file

@ -4,6 +4,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
namespace nix { 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, static void hashAndLink(bool dryRun, HashToPath & hashToPath,
OptimiseStats & stats, const Path & path) OptimiseStats & stats, const Path & path)
{ {
@ -83,19 +99,28 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath,
bool mustToggle = !isStorePath(path); bool mustToggle = !isStorePath(path);
if (mustToggle) makeWritable(dirOf(path)); if (mustToggle) makeWritable(dirOf(path));
if (link(prevPath.first.c_str(), tempLink.c_str()) == -1) /* 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 (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%'") throw SysError(format("cannot link `%1%' to `%2%'")
% tempLink % prevPath.first); % tempLink % prevPath.first);
}
/* Atomically replace the old file with the new hard link. */ /* Atomically replace the old file with the new hard link. */
if (rename(tempLink.c_str(), path.c_str()) == -1) if (rename(tempLink.c_str(), path.c_str()) == -1)
throw SysError(format("cannot rename `%1%' to `%2%'") throw SysError(format("cannot rename `%1%' to `%2%'")
% tempLink % path); % tempLink % path);
/* Make the directory read-only again and reset its
timestamp back to 0. */
if (mustToggle) canonicalisePathMetaData(dirOf(path), false);
} else } else
printMsg(lvlTalkative, format("would link `%1%' to `%2%'") % path % prevPath.first); printMsg(lvlTalkative, format("would link `%1%' to `%2%'") % path % prevPath.first);