diff --git a/squashfs-tools/Makefile b/squashfs-tools/Makefile index 73636ab2..a0f750ed 100644 --- a/squashfs-tools/Makefile +++ b/squashfs-tools/Makefile @@ -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 read_file.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 \ diff --git a/squashfs-tools/fakerootdb.c b/squashfs-tools/fakerootdb.c new file mode 100644 index 00000000..5b319931 --- /dev/null +++ b/squashfs-tools/fakerootdb.c @@ -0,0 +1,89 @@ +#include +#include +#include +#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; + } +} diff --git a/squashfs-tools/fakerootdb.h b/squashfs-tools/fakerootdb.h new file mode 100644 index 00000000..1939e7b2 --- /dev/null +++ b/squashfs-tools/fakerootdb.h @@ -0,0 +1,16 @@ +#ifndef SQUASHFS_FAKEROOTDB_H +#define SQUASHFS_FAKEROOTDB_H +#include +#include +#include + +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 */ diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c index 94f548c6..e6dbfe44 100644 --- a/squashfs-tools/mksquashfs.c +++ b/squashfs-tools/mksquashfs.c @@ -78,6 +78,7 @@ #include "restore.h" #include "process_fragments.h" #include "fnmatch_compat.h" +#include "fakerootdb.h" int delete = FALSE; int quiet = FALSE; @@ -266,6 +267,9 @@ int logging=FALSE; int tarstyle = FALSE; int keep_as_directory = FALSE; +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, int inode_number, int type); @@ -295,6 +299,18 @@ static void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad unsigned short get_checksum_mem(char *buff, int bytes); static void check_usable_phys_mem(int total_mem); +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() { @@ -3014,7 +3030,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)); @@ -3056,6 +3072,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_inode2(&buf, PSEUDO_FILE_OTHER, 0); dir_ent->dir = root_dir; root_dir->dir_ent = dir_ent; @@ -3252,7 +3269,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"); @@ -3997,7 +4014,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", file, strerror(errno)); goto failed_early; @@ -4248,12 +4265,13 @@ 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_inode2(&buf, PSEUDO_FILE_OTHER, 0); } 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)); @@ -5995,6 +6013,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; @@ -6193,6 +6217,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, argv[source + 1]); if(comp == NULL) {