diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-05-04 22:22:12 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-05-04 22:22:48 +0200 | 
| commit | abb31e7327e50cf2874ae9095eb147ed753862a3 (patch) | |
| tree | 7651bc9ba2b936568bc3da75f9041e3c1d1e6430 /unpack | |
| parent | b6f55d3c8fe387c3dc9b82821d49fcb56fa83483 (diff) | |
rdsquashfs: add ability to unpack only a sub tree of the file system
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'unpack')
| -rw-r--r-- | unpack/rdsquashfs.c | 20 | ||||
| -rw-r--r-- | unpack/restore_fstree.c | 171 | 
2 files changed, 107 insertions, 84 deletions
| diff --git a/unpack/rdsquashfs.c b/unpack/rdsquashfs.c index ec14e0e..4b3a573 100644 --- a/unpack/rdsquashfs.c +++ b/unpack/rdsquashfs.c @@ -12,6 +12,7 @@ static struct option long_opts[] = {  	{ "list", required_argument, NULL, 'l' },  	{ "cat", required_argument, NULL, 'c' },  	{ "unpack-root", required_argument, NULL, 'u' }, +	{ "unpack-path", required_argument, NULL, 'p' },  	{ "no-dev", no_argument, NULL, 'D' },  	{ "no-sock", no_argument, NULL, 'S' },  	{ "no-fifo", no_argument, NULL, 'F' }, @@ -23,7 +24,7 @@ static struct option long_opts[] = {  	{ "version", no_argument, NULL, 'V' },  }; -static const char *short_opts = "l:c:u:DSFLCOEhV"; +static const char *short_opts = "l:c:u:p:DSFLCOEhV";  static const char *help_string =  "Usage: %s [OPTIONS] <squashfs-file>\n" @@ -37,6 +38,8 @@ static const char *help_string =  "                        image, dump its contents to stdout.\n"  "  --unpack-root <path>  Unpack the contents of the filesystem into the\n"  "                        specified path.\n" +"  --unpack-path <path>  If specified, unpack this sub directory from the\n" +"                        image instead of the filesystem root.\n"  "  --no-dev, -D          Do not unpack device special files.\n"  "  --no-sock, -S         Do not unpack socket files.\n"  "  --no-fifo, -F         Do not unpack named pipes.\n" @@ -157,6 +160,9 @@ int main(int argc, char **argv)  			op = OP_UNPACK;  			unpack_root = optarg;  			break; +		case 'p': +			cmdpath = get_path(cmdpath, optarg); +			break;  		case 'h':  			printf(help_string, __progname);  			status = EXIT_SUCCESS; @@ -255,6 +261,16 @@ int main(int argc, char **argv)  		}  		break;  	case OP_UNPACK: +		if (cmdpath == NULL) { +			n = fs.root; +		} else { +			n = find_node(fs.root, cmdpath); +			if (n == NULL) { +				perror(cmdpath); +				goto out_fs; +			} +		} +  		if (super.fragment_entry_count > 0 &&  		    super.fragment_table_start < super.bytes_used &&  		    !(super.flags & SQFS_FLAG_NO_FRAGMENTS)) { @@ -263,7 +279,7 @@ int main(int argc, char **argv)  				goto out_fs;  		} -		if (restore_fstree(unpack_root, fs.root, cmp, super.block_size, +		if (restore_fstree(unpack_root, n, cmp, super.block_size,  				   frag, fd, unpack_flags)) {  			goto out_fs;  		} diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c index 5a20c5f..270b25a 100644 --- a/unpack/restore_fstree.c +++ b/unpack/restore_fstree.c @@ -1,103 +1,99 @@  /* SPDX-License-Identifier: GPL-3.0-or-later */  #include "rdsquashfs.h" -static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp, -			     size_t block_size, frag_reader_t *frag, -			     int sqfsfd, int flags) +static int create_node(int dirfd, tree_node_t *n, compressor_t *cmp, +		       size_t block_size, frag_reader_t *frag, +		       int sqfsfd, int flags)  {  	int fd; -	for (n = n->data.dir->children; n != NULL; n = n->next) { -		switch (n->mode & S_IFMT) { -		case S_IFDIR: -			if (mkdirat(dirfd, n->name, 0755) && -			    errno != EEXIST) { -				fprintf(stderr, "mkdir %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} +	switch (n->mode & S_IFMT) { +	case S_IFDIR: +		if (mkdirat(dirfd, n->name, 0755) && errno != EEXIST) { +			fprintf(stderr, "mkdir %s: %s\n", +				n->name, strerror(errno)); +			return -1; +		} -			fd = openat(dirfd, n->name, O_RDONLY | O_DIRECTORY); -			if (fd < 0) { -				fprintf(stderr, "open dir %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} +		fd = openat(dirfd, n->name, O_RDONLY | O_DIRECTORY); +		if (fd < 0) { +			fprintf(stderr, "open dir %s: %s\n", +				n->name, strerror(errno)); +			return -1; +		} -			if (restore_directory(fd, n, cmp, block_size, -					      frag, sqfsfd, flags)) { +		for (n = n->data.dir->children; n != NULL; n = n->next) { +			if (create_node(fd, n, cmp, block_size, frag, sqfsfd, +					flags)) {  				close(fd);  				return -1;  			} +		} -			close(fd); -			break; -		case S_IFLNK: -			if (symlinkat(n->data.slink_target, dirfd, n->name)) { -				fprintf(stderr, "ln -s %s %s: %s\n", -					n->data.slink_target, n->name, -					strerror(errno)); -				return -1; -			} -			break; -		case S_IFSOCK: -		case S_IFIFO: -			if (mknodat(dirfd, n->name, -				    (n->mode & S_IFMT) | 0700, 0)) { -				fprintf(stderr, "creating %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} -			break; -		case S_IFBLK: -		case S_IFCHR: -			if (mknodat(dirfd, n->name, (n->mode & S_IFMT), -				    n->data.devno)) { -				fprintf(stderr, "creating device %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} -			break; -		case S_IFREG: -			fd = openat(dirfd, n->name, -				    O_WRONLY | O_CREAT | O_EXCL, 0600); -			if (fd < 0) { -				fprintf(stderr, "creating %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} - -			if (extract_file(n->data.file, cmp, block_size, -					 frag, sqfsfd, fd)) { -				close(fd); -				return -1; -			} +		close(fd); +		break; +	case S_IFLNK: +		if (symlinkat(n->data.slink_target, dirfd, n->name)) { +			fprintf(stderr, "ln -s %s %s: %s\n", +				n->data.slink_target, n->name, +				strerror(errno)); +			return -1; +		} +		break; +	case S_IFSOCK: +	case S_IFIFO: +		if (mknodat(dirfd, n->name, (n->mode & S_IFMT) | 0700, 0)) { +			fprintf(stderr, "creating %s: %s\n", +				n->name, strerror(errno)); +			return -1; +		} +		break; +	case S_IFBLK: +	case S_IFCHR: +		if (mknodat(dirfd, n->name, (n->mode & S_IFMT), +			    n->data.devno)) { +			fprintf(stderr, "creating device %s: %s\n", +				n->name, strerror(errno)); +			return -1; +		} +		break; +	case S_IFREG: +		fd = openat(dirfd, n->name, O_WRONLY | O_CREAT | O_EXCL, 0600); +		if (fd < 0) { +			fprintf(stderr, "creating %s: %s\n", +				n->name, strerror(errno)); +			return -1; +		} +		if (extract_file(n->data.file, cmp, block_size, +				 frag, sqfsfd, fd)) {  			close(fd); -			break; -		default: -			break; +			return -1;  		} -		if (flags & UNPACK_CHOWN) { -			if (fchownat(dirfd, n->name, n->uid, n->gid, -				     AT_SYMLINK_NOFOLLOW)) { -				fprintf(stderr, "chown %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} -		} +		close(fd); +		break; +	default: +		break; +	} -		if (flags & UNPACK_CHMOD) { -			if (fchmodat(dirfd, n->name, n->mode, -				     AT_SYMLINK_NOFOLLOW)) { -				fprintf(stderr, "chmod %s: %s\n", -					n->name, strerror(errno)); -				return -1; -			} +	if (flags & UNPACK_CHOWN) { +		if (fchownat(dirfd, n->name, n->uid, n->gid, +			     AT_SYMLINK_NOFOLLOW)) { +			fprintf(stderr, "chown %s: %s\n", +				n->name, strerror(errno)); +			return -1;  		}  	} +	if (flags & UNPACK_CHMOD) { +		if (fchmodat(dirfd, n->name, n->mode, +			     AT_SYMLINK_NOFOLLOW)) { +			fprintf(stderr, "chmod %s: %s\n", +				n->name, strerror(errno)); +			return -1; +		} +	}  	return 0;  } @@ -105,6 +101,7 @@ int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp,  		   size_t block_size, frag_reader_t *frag, int sqfsfd,  		   int flags)  { +	tree_node_t *n;  	int dirfd;  	if (mkdir_p(rootdir)) @@ -116,8 +113,18 @@ int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp,  		return -1;  	} -	if (restore_directory(dirfd, root, cmp, block_size, frag, -			      sqfsfd, flags)) { +	if (S_ISDIR(root->mode)) { +		for (n = root->data.dir->children; n != NULL; n = n->next) { +			if (create_node(dirfd, n, cmp, block_size, frag, +					sqfsfd, flags)) { +				close(dirfd); +				return -1; +			} +		} +		return 0; +	} + +	if (create_node(dirfd, root, cmp, block_size, frag, sqfsfd, flags)) {  		close(dirfd);  		return -1;  	} | 
