Skip to content

Commit d8ff9c8

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 2bf96e1 commit d8ff9c8

File tree

4 files changed

+153
-4
lines changed

4 files changed

+153
-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 read_file.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: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#include "restore.h"
7979
#include "process_fragments.h"
8080
#include "fnmatch_compat.h"
81+
#include "fakerootdb.h"
8182

8283
int delete = FALSE;
8384
int quiet = FALSE;
@@ -269,6 +270,10 @@ int keep_as_directory = FALSE;
269270
/* Should Mksquashfs detect hardlinked files? */
270271
int no_hardlinks = FALSE;
271272

273+
/* Override owner/group/permissions/file type from fakeroot(1) database */
274+
struct fakerootdb fakerootdb;
275+
char const *fakerootdb_filename = NULL;
276+
272277
static char *read_from_disk(long long start, unsigned int avail_bytes);
273278
static void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
274279
int type);
@@ -298,6 +303,18 @@ static void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad
298303
unsigned short get_checksum_mem(char *buff, int bytes);
299304
static void check_usable_phys_mem(int total_mem);
300305

306+
static int lstat_with_fakeroot(const char *path, struct stat *stbuf)
307+
{
308+
int err;
309+
err = lstat(path, stbuf);
310+
if (err < 0)
311+
goto out;
312+
if (!fakerootdb.db || fakerootdb.count == 0)
313+
goto out;
314+
fakeroot_override_stat(stbuf, &fakerootdb);
315+
out:
316+
return err;
317+
}
301318

302319
void prep_exit()
303320
{
@@ -3029,7 +3046,7 @@ static squashfs_inode scan_single(char *pathname, int progress)
30293046
* it to the root directory dir_info structure */
30303047
dir_ent = create_dir_entry("", NULL, pathname, scan1_opendir("", "", 0));
30313048

3032-
if(lstat(pathname, &buf) == -1)
3049+
if(lstat_with_fakeroot(pathname, &buf) == -1)
30333050
/* source directory has disappeared? */
30343051
BAD_ERROR("Cannot stat source directory %s because %s\n",
30353052
pathname, strerror(errno));
@@ -3071,6 +3088,7 @@ static squashfs_inode scan_encomp(int progress)
30713088
buf.st_mtime = time(NULL);
30723089
buf.st_dev = 0;
30733090
buf.st_ino = 0;
3091+
fakeroot_override_stat(&buf, &fakerootdb);
30743092
dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
30753093
dir_ent->dir = root_dir;
30763094
root_dir->dir_ent = dir_ent;
@@ -3267,7 +3285,7 @@ static struct dir_info *dir_scan1(char *filename, char *subpath,
32673285
continue;
32683286
}
32693287

3270-
if(lstat(filename, &buf) == -1) {
3288+
if(lstat_with_fakeroot(filename, &buf) == -1) {
32713289
ERROR_START("Cannot stat dir/file %s because %s",
32723290
filename, strerror(errno));
32733291
ERROR_EXIT(", ignoring\n");
@@ -4012,7 +4030,7 @@ static struct dir_info *add_source(struct dir_info *sdir, char *source,
40124030
goto failed_early;
40134031
}
40144032

4015-
res = lstat(file, &buf);
4033+
res = lstat_with_fakeroot(file, &buf);
40164034
if (res == -1) {
40174035
ERROR("Error: Can't stat %s because %s", file, strerror(errno));
40184036
goto failed_early;
@@ -4263,12 +4281,13 @@ static squashfs_inode process_source(int progress)
42634281
buf.st_uid = getuid();
42644282
buf.st_gid = getgid();
42654283
buf.st_mtime = time(NULL);
4284+
fakeroot_override_stat(&buf, &fakerootdb);
42664285
entry = create_dir_entry("", NULL, "", new);
42674286
entry->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
42684287
} else {
42694288
char *pathname = absolute ? "/" : ".";
42704289

4271-
if(lstat(pathname, &buf) == -1)
4290+
if(lstat_with_fakeroot(pathname, &buf) == -1)
42724291
BAD_ERROR("Cannot stat %s because %s\n",
42734292
pathname, strerror(errno));
42744293

@@ -6016,6 +6035,12 @@ int main(int argc, char *argv[])
60166035
exit(1);
60176036
}
60186037
}
6038+
} else if(strcmp(argv[i], "-fakerootdb") == 0) {
6039+
if(++i == argc) {
6040+
ERROR("%s: -fakerootdb: missing filename\n", argv[0]);
6041+
exit(1);
6042+
}
6043+
fakerootdb_filename = argv[i];
60196044
} else if(strcmp(argv[i], "-noI") == 0 ||
60206045
strcmp(argv[i], "-noInodeCompression") == 0)
60216046
noI = TRUE;
@@ -6213,6 +6238,24 @@ int main(int argc, char *argv[])
62136238
strcmp(argv[i], "-log") == 0)
62146239
i++;
62156240

6241+
if (fakerootdb_filename) {
6242+
int err;
6243+
FILE *fakedata = NULL;
6244+
fakedata = fopen(fakerootdb_filename, "r");
6245+
if (!fakedata) {
6246+
ERROR("%s: -fakerootdb: failed to open fakeroot database %s\n",
6247+
argv[0], fakerootdb_filename);
6248+
EXIT_MKSQUASHFS();
6249+
}
6250+
err = fakeroot_read_db(fakedata, &fakerootdb);
6251+
fclose(fakedata);
6252+
if (err) {
6253+
ERROR("%s: -fakerootdb: failed to read fakeroot database %s\n",
6254+
argv[0], fakerootdb_filename);
6255+
EXIT_MKSQUASHFS();
6256+
}
6257+
}
6258+
62166259
if(!delete) {
62176260
comp = read_super(fd, &sBlk, argv[source + 1]);
62186261
if(comp == NULL) {

0 commit comments

Comments
 (0)