From 2a05bf5bc660bfebb35e42f1f8a0c0ac56e0f9d9 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 21 Jul 2019 20:22:04 +0200 Subject: Implement generating an inode table for NFS export Signed-off-by: David Oberhollenzer --- doc/gensquashfs.1 | 3 +++ doc/tar2sqfs.1 | 3 +++ include/highlevel.h | 8 ++++++++ lib/Makemodule.am | 1 + lib/sqfs/write_export_table.c | 36 ++++++++++++++++++++++++++++++++++++ mkfs/mkfs.c | 5 +++++ mkfs/mkfs.h | 1 + mkfs/options.c | 10 ++++++++-- tar/tar2sqfs.c | 13 ++++++++++++- 9 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 lib/sqfs/write_export_table.c diff --git a/doc/gensquashfs.1 b/doc/gensquashfs.1 index c52ce70..a880453 100644 --- a/doc/gensquashfs.1 +++ b/doc/gensquashfs.1 @@ -61,6 +61,9 @@ mtime=;0 If built with SELinux support, use the given SELinux label file to add context labels to the elements packed into the SquashFS image. .TP +\fB\-\-exportable\fR, \fB\-e\fR +Generate an export table for NFS support. +.TP \fB\-\-force\fR, \fB\-f\fR Overwrite the output file if it exists. .TP diff --git a/doc/tar2sqfs.1 b/doc/tar2sqfs.1 index 3279794..8c7d20d 100644 --- a/doc/tar2sqfs.1 +++ b/doc/tar2sqfs.1 @@ -58,6 +58,9 @@ extended attributes and skip the ones that cannot be encoded in SquashFS. \fB\-\-no\-skip\fR, \fB\-s\fR Abort if a tar record cannot be read instead of skipping it. .TP +\fB\-\-exportable\fR, \fB\-e\fR +Generate an export table for NFS support. +.TP \fB\-\-force\fR, \fB\-f\fR Overwrite the output file if it exists. .TP diff --git a/include/highlevel.h b/include/highlevel.h index 4bc3b7a..12884a0 100644 --- a/include/highlevel.h +++ b/include/highlevel.h @@ -75,4 +75,12 @@ int deserialize_fstree(fstree_t *out, sqfs_super_t *super, compressor_t *cmp, int write_xattr(int outfd, fstree_t *fs, sqfs_super_t *super, compressor_t *cmp); +/* + Generate an NFS export table. + + Returns 0 on success. Prints error messages to stderr on failure. + */ +int write_export_table(int outfd, fstree_t *fs, sqfs_super_t *super, + compressor_t *cmp); + #endif /* HIGHLEVEL_H */ diff --git a/lib/Makemodule.am b/lib/Makemodule.am index 7e6ca82..ab2030c 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -35,6 +35,7 @@ libsquashfs_a_SOURCES += lib/sqfs/deserialize_fstree.c libsquashfs_a_SOURCES += lib/sqfs/data_writer.c lib/sqfs/write_xattr.c libsquashfs_a_SOURCES += include/data_writer.h include/frag_reader.h libsquashfs_a_SOURCES += include/data_reader.h lib/sqfs/data_reader.c +libsquashfs_a_SOURCES += lib/sqfs/write_export_table.c libutil_a_SOURCES = lib/util/canonicalize_name.c lib/util/write_data.c libutil_a_SOURCES += lib/util/read_data.c include/util.h diff --git a/lib/sqfs/write_export_table.c b/lib/sqfs/write_export_table.c new file mode 100644 index 0000000..eee4e01 --- /dev/null +++ b/lib/sqfs/write_export_table.c @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include "highlevel.h" + +#include +#include + +int write_export_table(int outfd, fstree_t *fs, sqfs_super_t *super, + compressor_t *cmp) +{ + uint64_t *table, start; + size_t i; + int ret; + + table = malloc(sizeof(uint64_t) * fs->inode_tbl_size); + + if (table == NULL) { + perror("Allocating NFS export table"); + return -1; + } + + for (i = 0; i < fs->inode_tbl_size; ++i) { + if (fs->inode_table[i] == NULL) { + table[i] = 0xFFFFFFFFFFFFFFFF; + } else { + table[i] = htole64(fs->inode_table[i]->inode_ref); + } + } + + ret = sqfs_write_table(outfd, super, table, sizeof(table[0]), + fs->inode_tbl_size, &start, cmp); + + super->export_table_start = start; + super->flags |= SQFS_FLAG_EXPORTABLE; + free(table); + return ret; +} diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index f1c1f1b..91cb9bd 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -185,6 +185,11 @@ int main(int argc, char **argv) if (data_writer_write_fragment_table(data)) goto out_data; + if (opt.exportable) { + if (write_export_table(outfd, &fs, &super, cmp)) + goto out_data; + } + if (id_table_write(&idtbl, outfd, &super, cmp)) goto out_data; diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h index 4031c74..70a2ed6 100644 --- a/mkfs/mkfs.h +++ b/mkfs/mkfs.h @@ -29,6 +29,7 @@ typedef struct { int outmode; int blksz; int devblksz; + bool exportable; bool quiet; const char *infile; const char *packdir; diff --git a/mkfs/options.c b/mkfs/options.c index 2dab6b8..fe2bc69 100644 --- a/mkfs/options.c +++ b/mkfs/options.c @@ -9,6 +9,7 @@ static struct option long_opts[] = { { "comp-extra", required_argument, NULL, 'X' }, { "pack-file", required_argument, NULL, 'F' }, { "pack-dir", required_argument, NULL, 'D' }, + { "exportable", no_argument, NULL, 'e' }, { "force", no_argument, NULL, 'f' }, { "quiet", no_argument, NULL, 'q' }, #ifdef WITH_SELINUX @@ -19,9 +20,9 @@ static struct option long_opts[] = { }; #ifdef WITH_SELINUX -static const char *short_opts = "s:F:D:X:c:b:B:d:fqhV"; +static const char *short_opts = "s:F:D:X:c:b:B:d:efqhV"; #else -static const char *short_opts = "F:D:X:c:b:B:d:fqhV"; +static const char *short_opts = "F:D:X:c:b:B:d:efqhV"; #endif extern char *__progname; @@ -66,6 +67,7 @@ static const char *help_string = " --selinux, -s Specify an SELinux label file to get context\n" " attributes from.\n" #endif +" --exportable, -e Generate an export table for NFS support.\n" " --force, -f Overwrite the output file if it exists.\n" " --quiet, -q Do not print out progress reports.\n" " --help, -h Print help text and exit.\n" @@ -123,6 +125,7 @@ void process_command_line(options_t *opt, int argc, char **argv) opt->compressor = compressor_get_default(); opt->blksz = SQFS_DEFAULT_BLOCK_SIZE; opt->devblksz = SQFS_DEVBLK_SIZE; + opt->exportable = false; opt->quiet = false; opt->infile = NULL; opt->packdir = NULL; @@ -166,6 +169,9 @@ void process_command_line(options_t *opt, int argc, char **argv) case 'd': opt->fs_defaults = optarg; break; + case 'e': + opt->exportable = true; + break; case 'f': opt->outmode = O_WRONLY | O_CREAT | O_TRUNC; break; diff --git a/tar/tar2sqfs.c b/tar/tar2sqfs.c index 3417fd0..8394b7f 100644 --- a/tar/tar2sqfs.c +++ b/tar/tar2sqfs.c @@ -26,13 +26,14 @@ static struct option long_opts[] = { { "comp-extra", required_argument, NULL, 'X' }, { "no-skip", no_argument, NULL, 's' }, { "no-xattr", no_argument, NULL, 'x' }, + { "exportable", no_argument, NULL, 'e' }, { "force", no_argument, NULL, 'f' }, { "quiet", no_argument, NULL, 'q' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, }; -static const char *short_opts = "c:b:B:d:X:sxfqhV"; +static const char *short_opts = "c:b:B:d:X:sxefqhV"; static const char *usagestr = "Usage: tar2sqfs [OPTIONS...] \n" @@ -63,6 +64,7 @@ static const char *usagestr = " --no-skip, -s Abort if a tar record cannot be read instead\n" " of skipping it.\n" " --no-xattr, -x Do not copy extended attributes from archive.\n" +" --exportable, -e Generate an export table for NFS support.\n" " --force, -f Overwrite the output file if it exists.\n" " --quiet, -q Do not print out progress reports.\n" " --help, -h Print help text and exit.\n" @@ -85,6 +87,7 @@ static char *comp_extra = NULL; static char *fs_defaults = NULL; static bool dont_skip = false; static bool no_xattr = false; +static bool exportable = false; static void process_args(int argc, char **argv) { @@ -137,6 +140,9 @@ static void process_args(int argc, char **argv) case 's': dont_skip = true; break; + case 'e': + exportable = true; + break; case 'f': outmode = O_WRONLY | O_CREAT | O_TRUNC; break; @@ -388,6 +394,11 @@ int main(int argc, char **argv) if (data_writer_write_fragment_table(data)) goto out; + if (exportable) { + if (write_export_table(outfd, &fs, &super, cmp)) + goto out; + } + if (id_table_write(&idtbl, outfd, &super, cmp)) goto out; -- cgit v1.2.3