Skip to content

Commit

Permalink
mksquashfs can read uid/gid/file type from fakeroot(1) database
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
asheplyakov committed Jul 5, 2021
1 parent 59e6ac1 commit fb2443e
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 5 deletions.
3 changes: 2 additions & 1 deletion squashfs-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,14 @@ INSTALL_DIR = /usr/local/bin

MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
sort.o progressbar.o info.o restore.o process_fragments.o \
fakerootdb.o \
caches-queues-lists.o reader.o

UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
unsquash-4.o unsquash-123.o unsquash-34.o unsquash-1234.o swap.o \
compressor.o unsquashfs_info.o

CFLAGS ?= -O2
CFLAGS ?= -O0 -g
CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
-D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"$(COMP_DEFAULT)\" \
-Wall
Expand Down
89 changes: 89 additions & 0 deletions squashfs-tools/fakerootdb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "fakerootdb.h"

#define FAKEROOT_ENTRY_FIELDS 7
#define FAKEROOT_ENTRY_FMT "dev=%lx,ino=%lu,mode=%o,uid=%u,gid=%u,nlink=%lu,rdev=%lu"

static int compare_by_dev_ino(const void *px, const void *py)
{
struct stat const* const x = px;
struct stat const* const y = py;

if (x->st_dev < y->st_dev)
return -1;
else if (x->st_dev > y->st_dev)
return 1;
else if (x->st_ino < y->st_ino)
return -1;
else if (x->st_ino > y->st_ino)
return 1;
else
return 0;
}

int fakeroot_read_db(FILE *fakedata, struct fakerootdb *db)
{
struct stat elt, *d;
int n;
if (!db)
return -EINVAL;
if (db->db) {
free(db->db);
db->db = NULL;
db->count = 0;
}
while (!feof(fakedata)) {
if (ferror(fakedata))
return -EIO;
memset(&elt, 0, sizeof(elt));
n = fscanf(fakedata,
FAKEROOT_ENTRY_FMT "\n",
&elt.st_dev,
&elt.st_ino,
&elt.st_mode,
&elt.st_uid,
&elt.st_gid,
&elt.st_nlink,
&elt.st_rdev);
if (n != FAKEROOT_ENTRY_FIELDS)
return -EINVAL;

/* skip uid = gid = 0 entries, unless they are device nodes.
* fakeroot assumes uid = gid = 0 by default */
if (elt.st_uid == 0 && elt.st_gid == 0 && elt.st_rdev == 0)
continue;

d = realloc(db->db, (db->count + 1)*sizeof(elt));
if (!d)
return -ENOMEM;
memcpy(&d[db->count], &elt, sizeof(elt));
db->db = d;
db->count += 1;
}
qsort(db->db, db->count, sizeof(elt), compare_by_dev_ino);
return 0;
}

void fakeroot_override_stat(struct stat *st, const struct fakerootdb *db)
{
struct stat key;
struct stat const* o = NULL;
if (!db|| !db->db || db->count == 0)
return;
memset(&key, 0, sizeof(key));
key.st_dev = st->st_dev;
key.st_ino = st->st_ino;
o = bsearch(&key, db->db, db->count, sizeof(key), compare_by_dev_ino);
if (o) {
st->st_mode = o->st_mode;
st->st_uid = o->st_uid;
st->st_gid = o->st_gid;
st->st_rdev = o->st_rdev;
} else {
/* fakeroot sets uid=gid=0 if the object is not in the DB */
st->st_uid = 0;
st->st_gid = 0;
}
}
16 changes: 16 additions & 0 deletions squashfs-tools/fakerootdb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef SQUASHFS_FAKEROOTDB_H
#define SQUASHFS_FAKEROOTDB_H
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

struct fakerootdb {
struct stat *db;
size_t count;
};

int fakeroot_read_db(FILE *fakedata, struct fakerootdb *db);

void fakeroot_override_stat(struct stat *st, const struct fakerootdb *fakerootdb);

#endif /* SQUASHFS_FAKEROOTDB_H */
50 changes: 46 additions & 4 deletions squashfs-tools/mksquashfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include "restore.h"
#include "process_fragments.h"
#include "fnmatch_compat.h"
#include "fakerootdb.h"

int delete = FALSE;
int quiet = FALSE;
Expand Down Expand Up @@ -275,6 +276,9 @@ int no_hardlinks = FALSE;
int one_file_system = FALSE;
dev_t *source_dev;
dev_t cur_dev;
/* Override owner/group/permissions/file type from fakeroot(1) database */
struct fakerootdb fakerootdb;
char const *fakerootdb_filename = NULL;

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

static int lstat_with_fakeroot(const char *path, struct stat *stbuf)
{
int err;
err = lstat(path, stbuf);
if (err < 0)
goto out;
if (!fakerootdb.db || fakerootdb.count == 0)
goto out;
fakeroot_override_stat(stbuf, &fakerootdb);
out:
return err;
}

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

if(lstat(pathname, &buf) == -1)
if(lstat_with_fakeroot(pathname, &buf) == -1)
/* source directory has disappeared? */
BAD_ERROR("Cannot stat source directory %s because %s\n",
pathname, strerror(errno));
Expand Down Expand Up @@ -3392,6 +3408,7 @@ static squashfs_inode scan_encomp(int progress)
buf.st_mtime = time(NULL);
buf.st_dev = 0;
buf.st_ino = 0;
fakeroot_override_stat(&buf, &fakerootdb);
dir_ent->inode = lookup_inode(&buf);
dir_ent->inode->dummy_root_dir = TRUE;
dir_ent->dir = root_dir;
Expand Down Expand Up @@ -3593,7 +3610,7 @@ static struct dir_info *dir_scan1(char *filename, char *subpath,
continue;
}

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

res = lstat(file, &buf);
res = lstat_with_fakeroot(file, &buf);
if (res == -1) {
ERROR("Error: Can't stat %s because %s\n", file, strerror(errno));
goto failed_early;
Expand Down Expand Up @@ -4708,13 +4725,14 @@ static squashfs_inode process_source(int progress)
buf.st_uid = getuid();
buf.st_gid = getgid();
buf.st_mtime = time(NULL);
fakeroot_override_stat(&buf, &fakerootdb);
entry = create_dir_entry("", NULL, "", new);
entry->inode = lookup_inode(&buf);
entry->inode->dummy_root_dir = TRUE;
} else {
char *pathname = absolute ? "/" : ".";

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

Expand Down Expand Up @@ -6576,6 +6594,12 @@ int main(int argc, char *argv[])
exit(1);
}
}
} else if(strcmp(argv[i], "-fakerootdb") == 0) {
if(++i == argc) {
ERROR("%s: -fakerootdb: missing filename\n", argv[0]);
exit(1);
}
fakerootdb_filename = argv[i];
} else if(strcmp(argv[i], "-noI") == 0 ||
strcmp(argv[i], "-noInodeCompression") == 0)
noI = TRUE;
Expand Down Expand Up @@ -6807,6 +6831,24 @@ int main(int argc, char *argv[])
strcmp(argv[i], "-log") == 0)
i++;

if (fakerootdb_filename) {
int err;
FILE *fakedata = NULL;
fakedata = fopen(fakerootdb_filename, "r");
if (!fakedata) {
ERROR("%s: -fakerootdb: failed to open fakeroot database %s\n",
argv[0], fakerootdb_filename);
EXIT_MKSQUASHFS();
}
err = fakeroot_read_db(fakedata, &fakerootdb);
fclose(fakedata);
if (err) {
ERROR("%s: -fakerootdb: failed to read fakeroot database %s\n",
argv[0], fakerootdb_filename);
EXIT_MKSQUASHFS();
}
}

if(!delete) {
comp = read_super(fd, &sBlk, destination_file);
if(comp == NULL) {
Expand Down

0 comments on commit fb2443e

Please sign in to comment.