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/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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue