raven-rhel6/rpm/rpm-4.8.x-inode-remap.patch
2024-02-21 20:14:44 +06:00

104 lines
4.2 KiB
Diff

Remap inode numbers to fit into 32bit integer space on build (RhBug:714678)
- 64bit inode numbers lose their uniquity when brutally truncated
to 32bit integers as we've done so far. This can and will cause rpm
(and cpio) to mix up arbitrary file entries as hardlinks and vice versa.
- As the only interesting aspect of inode numbers is whether they're
equal to something else or not, we dont have to carry the "physical"
on-disk value to preserve semantics. So we can just remap the
inode numbers to something that fits our 32bit integer tags
without causing compatibility complexies with older rpms and
cpio (and since we can't handle more than INT32_MAX files in a package
anyway, breaking compatibility for this would be just braindead dumb).
An extremely simple way to achieve this is to use our
build-time file list index as the basis of stored inode number.
- Since we flatten the inodes to appear from a single filesystem,
we need to also flatten the device numbers to match this. Normal
buildroots do not cross fs boundaries but for src.rpm, spec and
sources/patches can legitimately come from different filesystems.
As we use the actual fs values for build-time hardlink discovery
this should correctly handle hardlinks even if packaging crosses
fs boundaries.
- Based on a patch by Zdenek Pavlas, just further simplified and
device remapping added.
diff --git a/build/files.c b/build/files.c
index c6afac7..9ea13a2 100644
--- a/build/files.c
+++ b/build/files.c
@@ -1040,10 +1040,11 @@ static int checkHardLinks(FileList fl)
return 0;
}
-static int seenHardLink(FileList fl, FileListRec flp)
+static int seenHardLink(FileList fl, FileListRec flp, rpm_ino_t *fileid)
{
for (FileListRec ilp = fl->fileList; ilp < flp; ilp++) {
if (isHardLink(flp, ilp)) {
+ *fileid = ilp - fl->fileList;
return 1;
}
}
@@ -1101,6 +1102,8 @@ static void genCpioListAndHeader(FileList fl,
}
for (i = 0, flp = fl->fileList; i < fl->fileListRecsUsed; i++, flp++) {
+ rpm_ino_t fileid = flp - fl->fileList;
+
/* Merge duplicate entries. */
while (i < (fl->fileListRecsUsed - 1) &&
rstreq(flp->cpioPath, flp[1].cpioPath)) {
@@ -1186,7 +1189,7 @@ static void genCpioListAndHeader(FileList fl,
}
/* Excludes and dupes have been filtered out by now. */
if (S_ISREG(flp->fl_mode)) {
- if (flp->fl_nlink == 1 || !seenHardLink(fl, flp)) {
+ if (flp->fl_nlink == 1 || !seenHardLink(fl, flp, &fileid)) {
totalFileSize += flp->fl_size;
}
}
@@ -1208,12 +1211,18 @@ static void genCpioListAndHeader(FileList fl,
headerPutUint16(h, RPMTAG_FILERDEVS, &rrdev, 1);
}
- { rpm_dev_t rdev = (rpm_dev_t) flp->fl_dev;
- headerPutUint32(h, RPMTAG_FILEDEVICES, &rdev, 1);
- }
-
- { rpm_ino_t rino = (rpm_ino_t) flp->fl_ino;
+ /*
+ * To allow rpmbuild to work on filesystems with 64bit inodes numbers,
+ * remap them into 32bit integers based on filelist index, just
+ * preserving semantics for determining hardlinks.
+ * Start at 1 as inode zero as that could be considered as an error.
+ * Since we flatten all the inodes to appear within a single fs,
+ * we also need to flatten the devices.
+ */
+ { rpm_ino_t rino = fileid + 1;
+ rpm_dev_t rdev = flp->fl_dev ? 1 : 0;
headerPutUint32(h, RPMTAG_FILEINODES, &rino, 1);
+ headerPutUint32(h, RPMTAG_FILEDEVICES, &rdev, 1);
}
headerPutString(h, RPMTAG_FILELANGS, flp->langs);
diff --git a/lib/fsm.c b/lib/fsm.c
index 22db47a..a98bb63 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -736,6 +736,7 @@ static int fsmMapAttrs(FSM_t fsm)
/* this check is pretty moot, rpmfi accessors check array bounds etc */
if (fi && i >= 0 && i < rpmfiFC(fi)) {
+ ino_t finalInode = rpmfiFInodeIndex(fi, i);
mode_t finalMode = rpmfiFModeIndex(fi, i);
dev_t finalRdev = rpmfiFRdevIndex(fi, i);
time_t finalMtime = rpmfiFMtimeIndex(fi, i);
@@ -765,6 +766,7 @@ static int fsmMapAttrs(FSM_t fsm)
if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
&& st->st_nlink == 0)
st->st_nlink = 1;
+ st->st_ino = finalInode;
st->st_rdev = finalRdev;
st->st_mtime = finalMtime;
}