Skip to content

Commit 10da591

Browse files
committed
mksquashfs can read uid/gid/file type from fakeroot(1) database
With this patch I can easily pack chroots built in a fakeroot environment without running mksquashfs under fakeroot. Instead I can use `-fakerootdb .fakedata` to get ownership/permissions/device nodes right. It's possible to convert fakeroot database into mksquashfs' pseudo files definitions but using the fakeroot database directly is more efficient (fakeroot uses device/inode number to identify the object) and requires less code.
1 parent 59e6ac1 commit 10da591

File tree

4 files changed

+152
-4
lines changed

4 files changed

+152
-4
lines changed

squashfs-tools/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ INSTALL_DIR = /usr/local/bin
153153

154154
MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
155155
sort.o progressbar.o info.o restore.o process_fragments.o \
156+
fakerootdb.o \
156157
caches-queues-lists.o reader.o
157158

158159
UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \

squashfs-tools/fakerootdb.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#include <stdlib.h>
2+
#include <string.h>
3+
#include <errno.h>
4+
#include "fakerootdb.h"
5+
6+
#define FAKEROOT_ENTRY_FIELDS 7
7+
#define FAKEROOT_ENTRY_FMT "dev=%lx,ino=%lu,mode=%o,uid=%u,gid=%u,nlink=%lu,rdev=%lu"
8+
9+
static int compare_by_dev_ino(const void *px, const void *py)
10+
{
11+
struct stat const* const x = px;
12+
struct stat const* const y = py;
13+
14+
if (x->st_dev < y->st_dev)
15+
return -1;
16+
else if (x->st_dev > y->st_dev)
17+
return 1;
18+
else if (x->st_ino < y->st_ino)
19+
return -1;
20+
else if (x->st_ino > y->st_ino)
21+
return 1;
22+
else
23+
return 0;
24+
}
25+
26+
int fakeroot_read_db(FILE *fakedata, struct fakerootdb *db)
27+
{
28+
struct stat elt, *d;
29+
int n;
30+
if (!db)
31+
return -EINVAL;
32+
if (db->db) {
33+
free(db->db);
34+
db->db = NULL;
35+
db->count = 0;
36+
}
37+
while (!feof(fakedata)) {
38+
if (ferror(fakedata))
39+
return -EIO;
40+
memset(&elt, 0, sizeof(elt));
41+
n = fscanf(fakedata,
42+
FAKEROOT_ENTRY_FMT "\n",
43+
&elt.st_dev,
44+
&elt.st_ino,
45+
&elt.st_mode,
46+
&elt.st_uid,
47+
&elt.st_gid,
48+
&elt.st_nlink,
49+
&elt.st_rdev);
50+
if (n != FAKEROOT_ENTRY_FIELDS)
51+
return -EINVAL;
52+
53+
/* skip uid = gid = 0 entries, unless they are device nodes.
54+
* fakeroot assumes uid = gid = 0 by default */
55+
if (elt.st_uid == 0 && elt.st_gid == 0 && elt.st_rdev == 0)
56+
continue;
57+
58+
d = realloc(db->db, (db->count + 1)*sizeof(elt));
59+
if (!d)
60+
return -ENOMEM;
61+
memcpy(&d[db->count], &elt, sizeof(elt));
62+
db->db = d;
63+
db->count += 1;
64+
}
65+
qsort(db->db, db->count, sizeof(elt), compare_by_dev_ino);
66+
return 0;
67+
}
68+
69+
void fakeroot_override_stat(struct stat *st, const struct fakerootdb *db)
70+
{
71+
struct stat key;
72+
struct stat const* o = NULL;
73+
if (!db|| !db->db || db->count == 0)
74+
return;
75+
memset(&key, 0, sizeof(key));
76+
key.st_dev = st->st_dev;
77+
key.st_ino = st->st_ino;
78+
o = bsearch(&key, db->db, db->count, sizeof(key), compare_by_dev_ino);
79+
if (o) {
80+
st->st_mode = o->st_mode;
81+
st->st_uid = o->st_uid;
82+
st->st_gid = o->st_gid;
83+
st->st_rdev = o->st_rdev;
84+
} else {
85+
/* fakeroot sets uid=gid=0 if the object is not in the DB */
86+
st->st_uid = 0;
87+
st->st_gid = 0;
88+
}
89+
}

squashfs-tools/fakerootdb.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef SQUASHFS_FAKEROOTDB_H
2+
#define SQUASHFS_FAKEROOTDB_H
3+
#include <stdio.h>
4+
#include <sys/types.h>
5+
#include <sys/stat.h>
6+
7+
struct fakerootdb {
8+
struct stat *db;
9+
size_t count;
10+
};
11+
12+
int fakeroot_read_db(FILE *fakedata, struct fakerootdb *db);
13+
14+
void fakeroot_override_stat(struct stat *st, const struct fakerootdb *fakerootdb);
15+
16+
#endif /* SQUASHFS_FAKEROOTDB_H */

squashfs-tools/mksquashfs.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#include "restore.h"
7373
#include "process_fragments.h"
7474
#include "fnmatch_compat.h"
75+
#include "fakerootdb.h"
7576

7677
int delete = FALSE;
7778
int quiet = FALSE;
@@ -275,6 +276,9 @@ int no_hardlinks = FALSE;
275276
int one_file_system = FALSE;
276277
dev_t *source_dev;
277278
dev_t cur_dev;
279+
/* Override owner/group/permissions/file type from fakeroot(1) database */
280+
struct fakerootdb fakerootdb;
281+
char const *fakerootdb_filename = NULL;
278282

279283
static char *read_from_disk(long long start, unsigned int avail_bytes);
280284
static void add_old_root_entry(char *name, squashfs_inode inode,
@@ -308,6 +312,18 @@ static void check_usable_phys_mem(int total_mem);
308312
static void print_summary();
309313
void write_destination(int fd, long long byte, long long bytes, void *buff);
310314

315+
static int lstat_with_fakeroot(const char *path, struct stat *stbuf)
316+
{
317+
int err;
318+
err = lstat(path, stbuf);
319+
if (err < 0)
320+
goto out;
321+
if (!fakerootdb.db || fakerootdb.count == 0)
322+
goto out;
323+
fakeroot_override_stat(stbuf, &fakerootdb);
324+
out:
325+
return err;
326+
}
311327

312328
void prep_exit()
313329
{
@@ -3350,7 +3366,7 @@ static squashfs_inode scan_single(char *pathname, int progress)
33503366
* it to the root directory dir_info structure */
33513367
dir_ent = create_dir_entry("", NULL, pathname, scan1_opendir("", "", 0));
33523368

3353-
if(lstat(pathname, &buf) == -1)
3369+
if(lstat_with_fakeroot(pathname, &buf) == -1)
33543370
/* source directory has disappeared? */
33553371
BAD_ERROR("Cannot stat source directory %s because %s\n",
33563372
pathname, strerror(errno));
@@ -3392,6 +3408,7 @@ static squashfs_inode scan_encomp(int progress)
33923408
buf.st_mtime = time(NULL);
33933409
buf.st_dev = 0;
33943410
buf.st_ino = 0;
3411+
fakeroot_override_stat(&buf, &fakerootdb);
33953412
dir_ent->inode = lookup_inode(&buf);
33963413
dir_ent->inode->dummy_root_dir = TRUE;
33973414
dir_ent->dir = root_dir;
@@ -3593,7 +3610,7 @@ static struct dir_info *dir_scan1(char *filename, char *subpath,
35933610
continue;
35943611
}
35953612

3596-
if(lstat(filename, &buf) == -1) {
3613+
if(lstat_with_fakeroot(filename, &buf) == -1) {
35973614
ERROR_START("Cannot stat dir/file %s because %s",
35983615
filename, strerror(errno));
35993616
ERROR_EXIT(", ignoring\n");
@@ -4361,7 +4378,7 @@ static struct dir_info *add_source(struct dir_info *sdir, char *source,
43614378
goto failed_early;
43624379
}
43634380

4364-
res = lstat(file, &buf);
4381+
res = lstat_with_fakeroot(file, &buf);
43654382
if (res == -1) {
43664383
ERROR("Error: Can't stat %s because %s\n", file, strerror(errno));
43674384
goto failed_early;
@@ -4708,13 +4725,14 @@ static squashfs_inode process_source(int progress)
47084725
buf.st_uid = getuid();
47094726
buf.st_gid = getgid();
47104727
buf.st_mtime = time(NULL);
4728+
fakeroot_override_stat(&buf, &fakerootdb);
47114729
entry = create_dir_entry("", NULL, "", new);
47124730
entry->inode = lookup_inode(&buf);
47134731
entry->inode->dummy_root_dir = TRUE;
47144732
} else {
47154733
char *pathname = absolute ? "/" : ".";
47164734

4717-
if(lstat(pathname, &buf) == -1)
4735+
if(lstat_with_fakeroot(pathname, &buf) == -1)
47184736
BAD_ERROR("Cannot stat %s because %s\n",
47194737
pathname, strerror(errno));
47204738

@@ -6576,6 +6594,12 @@ int main(int argc, char *argv[])
65766594
exit(1);
65776595
}
65786596
}
6597+
} else if(strcmp(argv[i], "-fakerootdb") == 0) {
6598+
if(++i == argc) {
6599+
ERROR("%s: -fakerootdb: missing filename\n", argv[0]);
6600+
exit(1);
6601+
}
6602+
fakerootdb_filename = argv[i];
65796603
} else if(strcmp(argv[i], "-noI") == 0 ||
65806604
strcmp(argv[i], "-noInodeCompression") == 0)
65816605
noI = TRUE;
@@ -6807,6 +6831,24 @@ int main(int argc, char *argv[])
68076831
strcmp(argv[i], "-log") == 0)
68086832
i++;
68096833

6834+
if (fakerootdb_filename) {
6835+
int err;
6836+
FILE *fakedata = NULL;
6837+
fakedata = fopen(fakerootdb_filename, "r");
6838+
if (!fakedata) {
6839+
ERROR("%s: -fakerootdb: failed to open fakeroot database %s\n",
6840+
argv[0], fakerootdb_filename);
6841+
EXIT_MKSQUASHFS();
6842+
}
6843+
err = fakeroot_read_db(fakedata, &fakerootdb);
6844+
fclose(fakedata);
6845+
if (err) {
6846+
ERROR("%s: -fakerootdb: failed to read fakeroot database %s\n",
6847+
argv[0], fakerootdb_filename);
6848+
EXIT_MKSQUASHFS();
6849+
}
6850+
}
6851+
68106852
if(!delete) {
68116853
comp = read_super(fd, &sBlk, destination_file);
68126854
if(comp == NULL) {

0 commit comments

Comments
 (0)