Improve hardlink handling in the disk space calculation

Before this commit, rpm simply did not take hardlinks into account
when calculating disk space requirements. This made it fail
spectaculary for packages that contain a high number of hardlinks,
like glibc-locale.

We now "bind" the file size to the last hardlink member. This
is still not 100% correct as the last file may not get installed
in some cases or only the last file may be replaced. But it is
still much better than what rpm did before.
This commit is contained in:
Michael Schroeder 2018-02-14 11:47:35 +01:00 committed by Panu Matilainen
parent 791cf86205
commit ae0347cfb2
2 changed files with 23 additions and 3 deletions

View File

@ -156,7 +156,7 @@ typedef rpmFlags rpmfiFlags;
#define RPMFI_FLAGS_ERASE \ #define RPMFI_FLAGS_ERASE \
(RPMFI_NOFILECLASS | RPMFI_NOFILELANGS | \ (RPMFI_NOFILECLASS | RPMFI_NOFILELANGS | \
RPMFI_NOFILEMTIMES | RPMFI_NOFILERDEVS | RPMFI_NOFILEINODES | \ RPMFI_NOFILEMTIMES | RPMFI_NOFILERDEVS | \
RPMFI_NOFILEVERIFYFLAGS) RPMFI_NOFILEVERIFYFLAGS)
#define RPMFI_FLAGS_INSTALL \ #define RPMFI_FLAGS_INSTALL \

View File

@ -412,6 +412,9 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfiles fi, int fx
{ {
rpmfs fs = rpmteGetFileStates(p); rpmfs fs = rpmteGetFileStates(p);
int isCfgFile = ((rpmfilesFFlags(otherFi, ofx) | rpmfilesFFlags(fi, fx)) & RPMFILE_CONFIG); int isCfgFile = ((rpmfilesFFlags(otherFi, ofx) | rpmfilesFFlags(fi, fx)) & RPMFILE_CONFIG);
rpm_loff_t otherFileSize;
int nlink;
const int *links;
if (XFA_SKIPPING(rpmfsGetAction(fs, fx))) if (XFA_SKIPPING(rpmfsGetAction(fs, fx)))
return; return;
@ -481,8 +484,15 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfiles fi, int fx
} }
} }
otherFileSize = rpmfilesFSize(otherFi, ofx);
/* Only account for the last file of a hardlink set */
nlink = rpmfilesFLinks(otherFi, ofx, &links);
if (nlink > 1 && links[nlink - 1] != ofx)
otherFileSize = 0;
/* Add one to make sure the size is not zero */ /* Add one to make sure the size is not zero */
rpmfilesSetFReplacedSize(fi, fx, rpmfilesFSize(otherFi, ofx) + 1); rpmfilesSetFReplacedSize(fi, fx, otherFileSize + 1);
} }
/** /**
@ -507,6 +517,9 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi
rpmfileAttrs FFlags; rpmfileAttrs FFlags;
struct rpmffi_s * recs; struct rpmffi_s * recs;
int numRecs; int numRecs;
rpm_loff_t fileSize;
int nlink;
const int *links;
if (XFA_SKIPPING(rpmfsGetAction(fs, i))) if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
continue; continue;
@ -677,9 +690,16 @@ assert(otherFi != NULL);
} }
rpmfilesFree(otherFi); rpmfilesFree(otherFi);
fileSize = rpmfilesFSize(fi, i);
nlink = rpmfilesFLinks(fi, i, &links);
if (nlink > 1 && links[nlink - 1] != i) {
/* Only account for the last file of a hardlink set */
fileSize = 0;
fixupSize = fixupSize ? 1 : 0;
}
/* Update disk space info for a file. */ /* Update disk space info for a file. */
rpmtsUpdateDSI(ts, fpEntryDev(fpc, fiFps), fpEntryDir(fpc, fiFps), rpmtsUpdateDSI(ts, fpEntryDev(fpc, fiFps), fpEntryDir(fpc, fiFps),
rpmfilesFSize(fi, i), rpmfilesFReplacedSize(fi, i), fileSize, rpmfilesFReplacedSize(fi, i),
fixupSize, rpmfsGetAction(fs, i)); fixupSize, rpmfsGetAction(fs, i));
} }