Skip to content

Commit d132b9b

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 57930cf commit d132b9b

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 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: 46 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;
@@ -266,6 +267,9 @@ int logging=FALSE;
266267
int tarstyle = FALSE;
267268
int keep_as_directory = FALSE;
268269

270+
struct fakerootdb fakerootdb;
271+
char const *fakerootdb_filename = NULL;
272+
269273
static char *read_from_disk(long long start, unsigned int avail_bytes);
270274
static void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
271275
int type);
@@ -295,6 +299,18 @@ static void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad
295299
unsigned short get_checksum_mem(char *buff, int bytes);
296300
static void check_usable_phys_mem(int total_mem);
297301

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

299315
void prep_exit()
300316
{
@@ -3014,7 +3030,7 @@ static squashfs_inode scan_single(char *pathname, int progress)
30143030
* it to the root directory dir_info structure */
30153031
dir_ent = create_dir_entry("", NULL, pathname, scan1_opendir("", "", 0));
30163032

3017-
if(lstat(pathname, &buf) == -1)
3033+
if(lstat_with_fakeroot(pathname, &buf) == -1)
30183034
/* source directory has disappeared? */
30193035
BAD_ERROR("Cannot stat source directory %s because %s\n",
30203036
pathname, strerror(errno));
@@ -3056,6 +3072,7 @@ static squashfs_inode scan_encomp(int progress)
30563072
buf.st_mtime = time(NULL);
30573073
buf.st_dev = 0;
30583074
buf.st_ino = 0;
3075+
fakeroot_override_stat(&buf, &fakerootdb);
30593076
dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
30603077
dir_ent->dir = root_dir;
30613078
root_dir->dir_ent = dir_ent;
@@ -3252,7 +3269,7 @@ static struct dir_info *dir_scan1(char *filename, char *subpath,
32523269
continue;
32533270
}
32543271

3255-
if(lstat(filename, &buf) == -1) {
3272+
if(lstat_with_fakeroot(filename, &buf) == -1) {
32563273
ERROR_START("Cannot stat dir/file %s because %s",
32573274
filename, strerror(errno));
32583275
ERROR_EXIT(", ignoring\n");
@@ -3997,7 +4014,7 @@ static struct dir_info *add_source(struct dir_info *sdir, char *source,
39974014
goto failed_early;
39984015
}
39994016

4000-
res = lstat(file, &buf);
4017+
res = lstat_with_fakeroot(file, &buf);
40014018
if (res == -1) {
40024019
ERROR("Error: Can't stat %s because %s", file, strerror(errno));
40034020
goto failed_early;
@@ -4248,12 +4265,13 @@ static squashfs_inode process_source(int progress)
42484265
buf.st_uid = getuid();
42494266
buf.st_gid = getgid();
42504267
buf.st_mtime = time(NULL);
4268+
fakeroot_override_stat(&buf, &fakerootdb);
42514269
entry = create_dir_entry("", NULL, "", new);
42524270
entry->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
42534271
} else {
42544272
char *pathname = absolute ? "/" : ".";
42554273

4256-
if(lstat(pathname, &buf) == -1)
4274+
if(lstat_with_fakeroot(pathname, &buf) == -1)
42574275
BAD_ERROR("Cannot stat %s because %s\n",
42584276
pathname, strerror(errno));
42594277

@@ -5995,6 +6013,12 @@ int main(int argc, char *argv[])
59956013
exit(1);
59966014
}
59976015
}
6016+
} else if(strcmp(argv[i], "-fakerootdb") == 0) {
6017+
if(++i == argc) {
6018+
ERROR("%s: -fakerootdb: missing filename\n", argv[0]);
6019+
exit(1);
6020+
}
6021+
fakerootdb_filename = argv[i];
59986022
} else if(strcmp(argv[i], "-noI") == 0 ||
59996023
strcmp(argv[i], "-noInodeCompression") == 0)
60006024
noI = TRUE;
@@ -6193,6 +6217,24 @@ int main(int argc, char *argv[])
61936217
strcmp(argv[i], "-log") == 0)
61946218
i++;
61956219

6220+
if (fakerootdb_filename) {
6221+
int err;
6222+
FILE *fakedata = NULL;
6223+
fakedata = fopen(fakerootdb_filename, "r");
6224+
if (!fakedata) {
6225+
ERROR("%s: -fakerootdb: failed to open fakeroot database %s\n",
6226+
argv[0], fakerootdb_filename);
6227+
EXIT_MKSQUASHFS();
6228+
}
6229+
err = fakeroot_read_db(fakedata, &fakerootdb);
6230+
fclose(fakedata);
6231+
if (err) {
6232+
ERROR("%s: -fakerootdb: failed to read fakeroot database %s\n",
6233+
argv[0], fakerootdb_filename);
6234+
EXIT_MKSQUASHFS();
6235+
}
6236+
}
6237+
61966238
if(!delete) {
61976239
comp = read_super(fd, &sBlk, argv[source + 1]);
61986240
if(comp == NULL) {

0 commit comments

Comments
 (0)