summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2012-02-10 10:40:45 +0200
committerPanu Matilainen <pmatilai@redhat.com>2012-02-10 10:40:45 +0200
commit7a9a5505667c681044bacb21c9b84ac66c062fe7 (patch)
tree336d8d147fbcbfce79ace0b16f3a58f10b18ae0d
parentda0091cfc754d84cd0f7f2d2711ebb7c073f892b (diff)
downloadlibrpm-tizen-7a9a5505667c681044bacb21c9b84ac66c062fe7.tar.gz
librpm-tizen-7a9a5505667c681044bacb21c9b84ac66c062fe7.tar.bz2
librpm-tizen-7a9a5505667c681044bacb21c9b84ac66c062fe7.zip
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. - In theory this breaks inode-device pairing, but as the buildroot cannot span across filesystems in any remotely normal conditions, just add a sanity check to catch the dirty tricksters... - Based on a patch by Zdenek Pavlas, just further simplified and buildroot fs boundary sanity check added.
-rw-r--r--build/files.c27
-rw-r--r--lib/fsm.c2
2 files changed, 26 insertions, 3 deletions
diff --git a/build/files.c b/build/files.c
index 64344f7d5..5d7829bb1 100644
--- a/build/files.c
+++ b/build/files.c
@@ -986,10 +986,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;
}
}
@@ -1017,6 +1018,7 @@ static void genCpioListAndHeader(FileList fl,
int i;
uint32_t defaultalgo = PGPHASHALGO_MD5, digestalgo;
rpm_loff_t totalFileSize = 0;
+ dev_t brdev = 0;
/*
* See if non-md5 file digest algorithm is requested. If not
@@ -1045,6 +1047,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)) {
@@ -1099,6 +1103,17 @@ static void genCpioListAndHeader(FileList fl,
/* Skip files that were marked with %exclude. */
if (flp->flags & RPMFILE_EXCLUDE) continue;
+ if (brdev == 0 && flp->fl_dev != 0)
+ brdev = flp->fl_dev;
+ /*
+ * We could handle this quite easily but it can't happen without
+ * some very dirty tricks, so just error out for now...
+ */
+ if (brdev && flp->fl_dev && brdev != flp->fl_dev) {
+ rpmlog(RPMLOG_ERR, _("buildroot spans across filesystems\n"));
+ fl->processingFailed = 1;
+ }
+
/* Omit '/' and/or URL prefix, leave room for "./" prefix */
apathlen += (strlen(flp->cpioPath) - skipLen + (_addDotSlash ? 3 : 1));
@@ -1130,7 +1145,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;
}
}
@@ -1156,7 +1171,13 @@ static void genCpioListAndHeader(FileList fl,
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.
+ */
+ { rpm_ino_t rino = fileid + 1;
headerPutUint32(h, RPMTAG_FILEINODES, &rino, 1);
}
diff --git a/lib/fsm.c b/lib/fsm.c
index e4e7a1172..5c139146c 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -716,6 +716,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);
@@ -745,6 +746,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;
}