Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

mksquashfs can read uid/gid/file type from fakeroot(1) database #89

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions squashfs-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ 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 \
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