forked from lix-project/lix
* `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:
parent
a72709afd8
commit
a8f3b02092
|
@ -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)
|
||||
{
|
||||
|
@ -83,19 +99,28 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath,
|
|||
bool mustToggle = !isStorePath(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%'")
|
||||
% 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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue