├── lib ├── sqfs │ ├── test │ │ ├── testdir │ │ │ ├── dira │ │ │ │ ├── file_a0 │ │ │ │ ├── file_a1 │ │ │ │ └── file_a2 │ │ │ ├── dirb │ │ │ │ ├── file_b0 │ │ │ │ ├── file_b1 │ │ │ │ ├── file_b2 │ │ │ │ └── dirx │ │ │ │ │ ├── file_x0 │ │ │ │ │ ├── file_x1 │ │ │ │ │ └── file_x2 │ │ │ └── dirc │ │ │ │ ├── file_c1 │ │ │ │ ├── file_c2 │ │ │ │ └── file_c0 │ │ ├── istream_skip.c │ │ └── stream_splice.c │ ├── src │ │ ├── misc.c │ │ ├── dir_entry.c │ │ ├── comp │ │ │ └── internal.h │ │ ├── xattr │ │ │ └── xattr_writer.h │ │ ├── write_super.c │ │ ├── super.c │ │ ├── write_table.c │ │ ├── io │ │ │ ├── stream_api.c │ │ │ └── unix.c │ │ └── read_table.c │ └── libsquashfs1.pc.in ├── tar │ ├── test │ │ ├── data │ │ │ ├── file-size │ │ │ │ ├── gnu.tar │ │ │ │ ├── 12-digit.tar │ │ │ │ └── pax.tar │ │ │ ├── large-mtime │ │ │ │ ├── gnu.tar │ │ │ │ └── 12-digit.tar │ │ │ ├── negative-mtime │ │ │ │ └── gnu.tar │ │ │ ├── user-group-largenum │ │ │ │ ├── gnu.tar │ │ │ │ └── 8-digit.tar │ │ │ ├── CREDITS │ │ │ ├── long-paths │ │ │ │ └── ustar.tar │ │ │ └── format-acceptance │ │ │ │ ├── gnu-g.tar │ │ │ │ ├── gnu.tar │ │ │ │ ├── ustar.tar │ │ │ │ ├── v7.tar │ │ │ │ └── ustar-pre-posix.tar │ │ ├── tar_big_file.c │ │ ├── tar_fuzz.c │ │ ├── tar_xattr.c │ │ ├── tar_sparse_gnu.c │ │ ├── tar_xattr_bin.c │ │ ├── tar_simple.c │ │ └── tar_sparse.c │ └── src │ │ ├── padd_file.c │ │ ├── cleanup.c │ │ ├── checksum.c │ │ ├── record_to_memory.c │ │ ├── internal.h │ │ ├── number.c │ │ └── read_sparse_map_old.c ├── compat │ ├── src │ │ ├── strchrnul.c │ │ ├── getsubopt.c │ │ ├── strndup.c │ │ ├── chdir.c │ │ ├── w32_perror.c │ │ ├── path_to_windows.c │ │ ├── mockups.c │ │ ├── w32_wmain.c │ │ ├── getopt.c │ │ └── getopt_long.c │ └── Makemodule.am ├── util │ ├── src │ │ ├── hex_decode.c │ │ ├── alloc.c │ │ ├── file_cmp.c │ │ ├── source_date_epoch.c │ │ ├── is_memory_zero.c │ │ ├── canonicalize_name.c │ │ ├── strlist.c │ │ ├── filename_sane.c │ │ ├── base64_decode.c │ │ ├── split_line.c │ │ └── parse_int.c │ └── test │ │ ├── is_memory_zero.c │ │ ├── epoch.c │ │ ├── hex_decode.c │ │ ├── xxhash.c │ │ ├── base64_decode.c │ │ ├── str_table.c │ │ ├── canonicalize_name.c │ │ └── filename_sane.c ├── common │ ├── src │ │ ├── print_version.c │ │ ├── writer │ │ │ └── cleanup.c │ │ ├── print_size.c │ │ ├── parse_size.c │ │ ├── compress.c │ │ ├── dir_tree.c │ │ ├── perror.c │ │ └── fstree_cli.c │ ├── test │ │ ├── fstree_cli.c │ │ └── istream_mem.c │ └── Makemodule.am └── fstree │ ├── src │ ├── get_path.c │ ├── stats.c │ └── hardlink.c │ ├── Makemodule.am │ └── test │ ├── get_path.c │ └── mknode_dir.c ├── packages ├── debian │ ├── clean │ ├── source │ │ └── format │ ├── libsquashfs1.install │ ├── squashfs-tools-ng.install │ ├── libsquashfs-dev.install │ ├── watch │ ├── upstream │ │ └── metadata │ └── rules ├── build-all ├── APKBUILD ├── build ├── Dockerfile └── PKGBUILD ├── doc ├── benchmark.ods └── mainpage.dox ├── bin ├── gensquashfs │ ├── test │ │ ├── fstree_glob1.txt │ │ ├── fstree_glob3.txt │ │ ├── fstree_glob2.txt │ │ ├── xattr1.txt │ │ └── fstree_fuzz.c │ └── src │ │ └── selinux.c ├── rdsquashfs │ ├── test │ │ ├── pathtraversal.sqfs │ │ └── pathtraversal.sh.in │ ├── Makemodule.am │ └── src │ │ ├── rdsquashfs.h │ │ └── dump_xattrs.c ├── sqfs2tar │ ├── Makemodule.am │ └── src │ │ └── sqfs2tar.h ├── sqfsdiff │ ├── Makemodule.am │ └── src │ │ ├── util.c │ │ ├── extract.c │ │ ├── compare_files.c │ │ ├── sqfsdiff.h │ │ └── compare_dir.c └── tar2sqfs │ ├── Makemodule.am │ ├── src │ ├── tar2sqfs.h │ └── tar2sqfs.c │ └── test │ └── test_tar_sqfs.sh.in ├── .github └── workflows │ └── codeql-analysis.yml ├── licenses ├── 0BSD.txt ├── xz.txt ├── hash_table.txt ├── LZ4.txt ├── xxhash.txt └── zstd.txt ├── extras └── Makemodule.am ├── .gitignore ├── include ├── util │ ├── mempool.h │ ├── strlist.h │ ├── rbtree.h │ ├── array.h │ ├── str_table.h │ └── w32threadwrap.h ├── xfrm │ ├── stream.h │ └── wrap.h ├── compress_cli.h ├── common.h ├── tar │ ├── tar.h │ └── format.h └── simple_writer.h ├── m4 ├── zstd.m4 └── compiler.m4 ├── scripts ├── lib_syms_sane.sh ├── coverity.sh └── w32devenv.sh ├── Makefile.am └── autogen.sh /lib/sqfs/test/testdir/dira/file_a0: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dira/file_a1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dira/file_a2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirb/file_b0: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirb/file_b1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirb/file_b2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirc/file_c1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/debian/clean: -------------------------------------------------------------------------------- 1 | config.log 2 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirb/dirx/file_x0: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirb/dirx/file_x1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirb/dirx/file_x2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirc/file_c2: -------------------------------------------------------------------------------- 1 | 你好! 2 | -------------------------------------------------------------------------------- /packages/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /lib/sqfs/test/testdir/dirc/file_c0: -------------------------------------------------------------------------------- 1 | test string 2 | -------------------------------------------------------------------------------- /packages/debian/libsquashfs1.install: -------------------------------------------------------------------------------- 1 | usr/lib/*/libsquashfs.so.* 2 | -------------------------------------------------------------------------------- /packages/debian/squashfs-tools-ng.install: -------------------------------------------------------------------------------- 1 | usr/bin/ 2 | usr/share/man/ 3 | -------------------------------------------------------------------------------- /doc/benchmark.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/squashfs-tools-ng/HEAD/doc/benchmark.ods -------------------------------------------------------------------------------- /bin/gensquashfs/test/fstree_glob1.txt: -------------------------------------------------------------------------------- 1 | dir /tarcorpus 0755 0 0 2 | glob /tarcorpus 0755 0 0 -type d -- ../../../lib/tar/test/data 3 | -------------------------------------------------------------------------------- /lib/tar/test/data/file-size/gnu.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/squashfs-tools-ng/HEAD/lib/tar/test/data/file-size/gnu.tar -------------------------------------------------------------------------------- /bin/rdsquashfs/test/pathtraversal.sqfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/squashfs-tools-ng/HEAD/bin/rdsquashfs/test/pathtraversal.sqfs -------------------------------------------------------------------------------- /lib/tar/test/data/large-mtime/gnu.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/squashfs-tools-ng/HEAD/lib/tar/test/data/large-mtime/gnu.tar -------------------------------------------------------------------------------- /packages/debian/libsquashfs-dev.install: -------------------------------------------------------------------------------- 1 | usr/include/ 2 | usr/lib/*/libsquashfs.a 3 | usr/lib/*/libsquashfs.so 4 | usr/lib/*/pkgconfig/ 5 | -------------------------------------------------------------------------------- /lib/tar/test/data/negative-mtime/gnu.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/squashfs-tools-ng/HEAD/lib/tar/test/data/negative-mtime/gnu.tar -------------------------------------------------------------------------------- /packages/debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | https://github.com/AgentD/squashfs-tools-ng/tags .*/v?(\d\S+)\.(?:tar\.xz|txz|tar\.bz2|tbz2|tar\.gz|tgz) 3 | -------------------------------------------------------------------------------- /lib/tar/test/data/user-group-largenum/gnu.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AgentD/squashfs-tools-ng/HEAD/lib/tar/test/data/user-group-largenum/gnu.tar -------------------------------------------------------------------------------- /bin/gensquashfs/test/fstree_glob3.txt: -------------------------------------------------------------------------------- 1 | glob / 0755 0 0 -type d ../../../lib/tar/test/data 2 | glob / 0644 0 0 -type f -name "*gnu*.tar" -- ../../../lib/tar/test/data 3 | -------------------------------------------------------------------------------- /bin/gensquashfs/test/fstree_glob2.txt: -------------------------------------------------------------------------------- 1 | dir /tarcorpus 0755 0 0 2 | glob /tarcorpus 0755 0 0 -type d ../../../lib/tar/test/data 3 | glob /tarcorpus 0644 0 0 -type f -name "*gnu*.tar" -- ../../../lib/tar/test/data 4 | -------------------------------------------------------------------------------- /packages/debian/upstream/metadata: -------------------------------------------------------------------------------- 1 | --- 2 | Archive: GitHub 3 | Bug-Database: https://github.com/AgentD/squashfs-tools-ng/issues 4 | Bug-Submit: https://github.com/AgentD/squashfs-tools-ng/issues/new 5 | Repository: https://github.com/AgentD/squashfs-tools-ng.git 6 | Repository-Browse: https://github.com/AgentD/squashfs-tools-ng 7 | -------------------------------------------------------------------------------- /packages/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | # Uncomment this to turn on verbose mode. 5 | #export DH_VERBOSE=1 6 | 7 | override_dh_auto_install: 8 | dh_auto_install 9 | # remove libtool .la files 10 | find $(CURDIR)/debian/tmp/ -name '*.la' -delete 11 | 12 | %: 13 | dh ${@} 14 | 15 | .PHONY: override_dh_auto_install 16 | -------------------------------------------------------------------------------- /bin/gensquashfs/test/xattr1.txt: -------------------------------------------------------------------------------- 1 | # file: dev/ 2 | security.selinux="system_u:object_r:device_t:s0" 3 | 4 | # file: dev/zero 5 | security.selinux="system_u:object_r:zero_device_t:s0" 6 | 7 | # file: dev/rfkill 8 | security.selinux="system_u:object_r:wireless_device_t:s0" 9 | system.posix_acl_access=0sAgAAAAEABgD/////AgAGAOgDAAAEAAYA/////xAABgD/////IAAEAP////8= 10 | -------------------------------------------------------------------------------- /bin/rdsquashfs/test/pathtraversal.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | RDSQFS="@abs_top_builddir@/rdsquashfs" 4 | REFFILE="@abs_top_srcdir@/bin/rdsquashfs/test/pathtraversal.sqfs" 5 | GOTCHA="/tmp/gotcha.txt" 6 | 7 | if "$RDSQFS" -u / -p . "$REFFILE"; then 8 | if [ -e "$GOTCHA" ]; then 9 | echo "Found $GOTCHA which should not be there" 10 | exit 1 11 | fi 12 | fi 13 | -------------------------------------------------------------------------------- /lib/sqfs/src/misc.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * misc.c 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/predef.h" 11 | 12 | #include 13 | 14 | void sqfs_free(void *ptr) 15 | { 16 | free(ptr); 17 | } 18 | -------------------------------------------------------------------------------- /lib/sqfs/libsquashfs1.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libsquashfs 7 | Version: @PACKAGE_VERSION@ 8 | Description: A library for working with SquashFS file systems. 9 | 10 | Cflags: -I${includedir} 11 | Libs: -L${libdir} -lsquashfs @PTHREAD_LIBS@ 12 | 13 | Requires.private: @LIBSQFS_DEP_MOD@ 14 | -------------------------------------------------------------------------------- /lib/compat/src/strchrnul.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * strchrnul.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #ifndef HAVE_STRCHRNUL 11 | char *strchrnul(const char *s, int c) 12 | { 13 | while (*s && *((unsigned char *)s) != c) 14 | ++s; 15 | 16 | return (char *)s; 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /lib/compat/Makemodule.am: -------------------------------------------------------------------------------- 1 | libcompat_a_SOURCES = include/compat.h lib/compat/src/getsubopt.c \ 2 | lib/compat/src/strndup.c lib/compat/src/mockups.c \ 3 | lib/compat/src/chdir.c lib/compat/src/path_to_windows.c \ 4 | lib/compat/src/w32_perror.c lib/compat/src/w32_wmain.c \ 5 | lib/compat/src/w32_stdio.c lib/compat/src/fnmatch.c \ 6 | lib/compat/src/getopt.c lib/compat/src/getopt_long.c \ 7 | lib/compat/src/strchrnul.c 8 | 9 | noinst_LIBRARIES += libcompat.a 10 | -------------------------------------------------------------------------------- /lib/tar/src/padd_file.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * padd_file.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "tar/format.h" 10 | 11 | int padd_file(sqfs_ostream_t *fp, sqfs_u64 size) 12 | { 13 | size_t padd_sz = size % TAR_RECORD_SIZE; 14 | 15 | if (padd_sz == 0) 16 | return 0; 17 | 18 | return fp->append(fp, NULL, TAR_RECORD_SIZE - padd_sz); 19 | } 20 | -------------------------------------------------------------------------------- /bin/sqfs2tar/Makemodule.am: -------------------------------------------------------------------------------- 1 | sqfs2tar_SOURCES = bin/sqfs2tar/src/sqfs2tar.c bin/sqfs2tar/src/sqfs2tar.h \ 2 | bin/sqfs2tar/src/options.c bin/sqfs2tar/src/iterator.c 3 | sqfs2tar_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) 4 | sqfs2tar_LDADD = libcommon.a libutil.a libtar.a libsquashfs.la 5 | sqfs2tar_LDADD += libxfrm.a libcompat.a libfstree.a 6 | sqfs2tar_LDADD += $(ZLIB_LIBS) $(XZ_LIBS) $(LZO_LIBS) $(ZSTD_LIBS) $(BZIP2_LIBS) 7 | sqfs2tar_LDADD += $(PTHREAD_LIBS) 8 | 9 | dist_man1_MANS += bin/sqfs2tar/sqfs2tar.1 10 | bin_PROGRAMS += sqfs2tar 11 | -------------------------------------------------------------------------------- /bin/sqfsdiff/Makemodule.am: -------------------------------------------------------------------------------- 1 | sqfsdiff_SOURCES = bin/sqfsdiff/src/sqfsdiff.c bin/sqfsdiff/src/sqfsdiff.h \ 2 | bin/sqfsdiff/src/util.c bin/sqfsdiff/src/options.c \ 3 | bin/sqfsdiff/src/compare_dir.c bin/sqfsdiff/src/node_compare.c \ 4 | bin/sqfsdiff/src/compare_files.c bin/sqfsdiff/src/super.c \ 5 | bin/sqfsdiff/src/extract.c 6 | sqfsdiff_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) 7 | sqfsdiff_LDADD = libcommon.a libsquashfs.la libcompat.a libutil.a 8 | sqfsdiff_LDADD += $(LZO_LIBS) libfstree.a $(PTHREAD_LIBS) 9 | 10 | dist_man1_MANS += bin/sqfsdiff/sqfsdiff.1 11 | bin_PROGRAMS += sqfsdiff 12 | -------------------------------------------------------------------------------- /packages/build-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | vendors='alpine archlinux centos debian fedora opensuse ubuntu' 4 | 5 | alpine_versions='3.11 3.12' 6 | archlinux_versions='latest' 7 | centos_versions='7 8' 8 | debian_versions='bookworm bullseye buster strech' 9 | fedora_versions='32' 10 | opensuse_versions='15.0 15.1 15.2' 11 | ubuntu_versions='bionic focal groovy' 12 | 13 | source_dir=$(git rev-parse --show-toplevel) 14 | 15 | 16 | for v in $vendors; do 17 | versions="${v}_versions" 18 | for ver in ${!versions}; do 19 | $source_dir/packages/build $v $ver 20 | done 21 | done 22 | 23 | -------------------------------------------------------------------------------- /lib/compat/src/getsubopt.c: -------------------------------------------------------------------------------- 1 | #include "compat.h" 2 | 3 | #include 4 | #include 5 | 6 | #ifndef HAVE_GETSUBOPT 7 | int getsubopt(char **opt, char *const *keys, char **val) 8 | { 9 | char *s = *opt; 10 | int i; 11 | 12 | *val = NULL; 13 | *opt = strchr(s, ','); 14 | if (*opt) *(*opt)++ = 0; 15 | else *opt = s + strlen(s); 16 | 17 | for (i=0; keys[i]; i++) { 18 | size_t l = strlen(keys[i]); 19 | if (strncmp(keys[i], s, l)) continue; 20 | if (s[l] == '=') 21 | *val = s + l + 1; 22 | else if (s[l]) continue; 23 | return i; 24 | } 25 | return -1; 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [master, ] 6 | pull_request: 7 | branches: [master] 8 | schedule: 9 | - cron: '0 17 * * 5' 10 | 11 | jobs: 12 | analyse: 13 | name: Analyse 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v3 19 | - name: Initialize CodeQL 20 | uses: github/codeql-action/init@v2 21 | - name: Autobuild 22 | uses: github/codeql-action/autobuild@v2 23 | - name: Perform CodeQL Analysis 24 | uses: github/codeql-action/analyze@v2 25 | -------------------------------------------------------------------------------- /bin/sqfsdiff/src/util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * util.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "sqfsdiff.h" 8 | 9 | char *node_path(const sqfs_tree_node_t *n) 10 | { 11 | char *path; 12 | int ret; 13 | 14 | ret = sqfs_tree_node_get_path(n, &path); 15 | if (ret != 0) { 16 | sqfs_perror(NULL, "get path", ret); 17 | return NULL; 18 | } 19 | 20 | if (canonicalize_name(path)) { 21 | fprintf(stderr, "failed to canonicalization '%s'\n", path); 22 | sqfs_free(path); 23 | return NULL; 24 | } 25 | 26 | return path; 27 | } 28 | -------------------------------------------------------------------------------- /lib/compat/src/strndup.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * strndup.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #include 11 | #include 12 | 13 | #ifndef HAVE_STRNDUP 14 | char *strndup(const char *str, size_t max_len) 15 | { 16 | size_t len = 0; 17 | char *out; 18 | 19 | while (len < max_len && str[len] != '\0') 20 | ++len; 21 | 22 | out = malloc(len + 1); 23 | 24 | if (out != NULL) { 25 | memcpy(out, str, len); 26 | out[len] = '\0'; 27 | } 28 | 29 | return out; 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /lib/compat/src/chdir.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * chdir.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #ifdef _WIN32 11 | #include 12 | #include 13 | 14 | int chdir(const char *path) 15 | { 16 | WCHAR *wpath; 17 | int ret; 18 | 19 | wpath = path_to_windows(path); 20 | if (wpath == NULL) 21 | return -1; 22 | 23 | if (!SetCurrentDirectoryW(wpath)) { 24 | w32_perror(path); 25 | ret = -1; 26 | } else { 27 | ret = 0; 28 | } 29 | 30 | free(wpath); 31 | return ret; 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /licenses/0BSD.txt: -------------------------------------------------------------------------------- 1 | Permission to use, copy, modify, and/or distribute this software for any 2 | purpose with or without fee is hereby granted. 3 | 4 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 5 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 6 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 7 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 8 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 9 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 10 | PERFORMANCE OF THIS SOFTWARE. 11 | -------------------------------------------------------------------------------- /extras/Makemodule.am: -------------------------------------------------------------------------------- 1 | mknastyfs_SOURCES = extras/mknastyfs.c 2 | mknastyfs_LDADD = libsquashfs.la 3 | 4 | mk42sqfs_SOURCES = extras/mk42sqfs.c 5 | mk42sqfs_LDADD = libsquashfs.la 6 | 7 | list_files_SOURCES = extras/list_files.c 8 | list_files_LDADD = libsquashfs.la 9 | 10 | extract_one_SOURCES = extras/extract_one.c 11 | extract_one_LDADD = libsquashfs.la 12 | 13 | if WITH_READLINE 14 | sqfsbrowse_SOURCES = extras/browse.c 15 | sqfsbrowse_CFLAGS = $(AM_CFLAGS) $(READLINE_CFLAGS) 16 | sqfsbrowse_LDADD = libsquashfs.la $(READLINE_LIBS) 17 | 18 | noinst_PROGRAMS += sqfsbrowse 19 | endif 20 | 21 | noinst_PROGRAMS += mknastyfs mk42sqfs list_files extract_one 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .dirstamp 3 | .gdb_history 4 | .libs 5 | Makefile 6 | Makefile.in 7 | aclocal.m4 8 | autom4te.cache 9 | compile 10 | config.h.in 11 | config.log 12 | config.status 13 | configure 14 | depcomp 15 | install-sh 16 | missing 17 | stamp-h1 18 | config.* 19 | *.o 20 | *.lo 21 | *.la 22 | *.a 23 | *~ 24 | *.pc 25 | .#* 26 | *.exe 27 | *.dll 28 | *.log 29 | *.trs 30 | /gensquashfs 31 | /rdsquashfs 32 | /sqfs2tar 33 | /tar2sqfs 34 | /sqfsdiff 35 | /tar_fuzz 36 | /fstree_fuzz 37 | test_* 38 | test-* 39 | libtool 40 | ltmain.sh 41 | m4/libtool.m4 42 | m4/lt*.m4 43 | Doxyfile 44 | bin/rdsquashfs/test/*.sh 45 | bin/tar2sqfs/test/*.sh 46 | /mknastyfs 47 | /mk42sqfs 48 | /extract_one 49 | /list_files 50 | /sqfsbrowse 51 | /xattr_benchmark 52 | -------------------------------------------------------------------------------- /include/util/mempool.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * mempool.h 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #ifndef MEMPOOL_H 8 | #define MEMPOOL_H 9 | 10 | #include "compat.h" 11 | #include "sqfs/predef.h" 12 | 13 | typedef struct mem_pool_t mem_pool_t; 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | SQFS_INTERNAL mem_pool_t *mem_pool_create(size_t obj_size); 20 | 21 | SQFS_INTERNAL void mem_pool_destroy(mem_pool_t *mem); 22 | 23 | SQFS_INTERNAL void *mem_pool_allocate(mem_pool_t *mem); 24 | 25 | SQFS_INTERNAL void mem_pool_free(mem_pool_t *mem, void *ptr); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif /* MEMPOOL_H */ 32 | -------------------------------------------------------------------------------- /lib/tar/src/cleanup.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * cleanup.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "internal.h" 10 | #include "sqfs/xattr.h" 11 | #include 12 | #include 13 | 14 | void free_sparse_list(sparse_map_t *sparse) 15 | { 16 | sparse_map_t *old; 17 | 18 | while (sparse != NULL) { 19 | old = sparse; 20 | sparse = sparse->next; 21 | free(old); 22 | } 23 | } 24 | 25 | void clear_header(tar_header_decoded_t *hdr) 26 | { 27 | sqfs_xattr_list_free(hdr->xattr); 28 | free_sparse_list(hdr->sparse); 29 | free(hdr->name); 30 | free(hdr->link_target); 31 | memset(hdr, 0, sizeof(*hdr)); 32 | } 33 | -------------------------------------------------------------------------------- /bin/gensquashfs/test/fstree_fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * fstree_fuzz.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "mkfs.h" 10 | 11 | #include 12 | #include 13 | 14 | int main(int argc, char **argv) 15 | { 16 | int ret = EXIT_FAILURE; 17 | fstree_t fs; 18 | 19 | if (argc != 2) { 20 | fputs("Usage: fstree_fuzz \n", stderr); 21 | return EXIT_FAILURE; 22 | } 23 | 24 | if (fstree_init(&fs, NULL)) 25 | return EXIT_FAILURE; 26 | 27 | if (fstree_from_file(&fs, argv[1], NULL)) 28 | goto out_fs; 29 | 30 | ret = EXIT_SUCCESS; 31 | out_fs: 32 | fstree_cleanup(&fs); 33 | return ret; 34 | } 35 | -------------------------------------------------------------------------------- /m4/zstd.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([AC_TEST_ZSTD_STREAM], [ 2 | AC_MSG_CHECKING([whether zstd supports stream compression]) 3 | AC_LANG_PUSH([C]) 4 | ac_zstd_have_stream="no" 5 | ac_zstd_save_CFLAGS="$CFLAGS" 6 | CFLAGS="$CFLAGS $ZSTD_CFLAGS" 7 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ], [ZSTD_EndDirective op = ZSTD_e_end; ZSTD_compressStream2(NULL, NULL, NULL, op);])], 8 | ac_zstd_have_stream="yes" 9 | AC_MSG_RESULT([yes]), AC_MSG_RESULT([no])) 10 | 11 | AS_IF([test "x$ac_zstd_have_stream" = "xyes"], 12 | [AC_DEFINE(HAVE_ZSTD_STREAM, 1, [Does zstd support stream compression?])]) 13 | 14 | AM_CONDITIONAL([HAVE_ZSTD_STREAM], [test "x$ac_zstd_have_stream" = "xyes"]) 15 | CFLAGS=$ac_zstd_save_CFLAGS 16 | AC_LANG_POP([C]) 17 | ]) 18 | -------------------------------------------------------------------------------- /bin/tar2sqfs/Makemodule.am: -------------------------------------------------------------------------------- 1 | tar2sqfs_SOURCES = bin/tar2sqfs/src/tar2sqfs.c bin/tar2sqfs/src/tar2sqfs.h \ 2 | bin/tar2sqfs/src/options.c bin/tar2sqfs/src/process_tarball.c 3 | tar2sqfs_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) 4 | tar2sqfs_LDADD = libcommon.a libtar.a libsquashfs.la libxfrm.a 5 | tar2sqfs_LDADD += libfstree.a libcompat.a libfstree.a libutil.a $(LZO_LIBS) 6 | tar2sqfs_LDADD += $(ZLIB_LIBS) $(XZ_LIBS) $(ZSTD_LIBS) $(BZIP2_LIBS) 7 | tar2sqfs_LDADD += $(PTHREAD_LIBS) 8 | 9 | dist_man1_MANS += bin/tar2sqfs/tar2sqfs.1 10 | bin_PROGRAMS += tar2sqfs 11 | 12 | check_SCRIPTS += bin/tar2sqfs/test/test_tar_sqfs.sh 13 | TESTS += bin/tar2sqfs/test/test_tar_sqfs.sh 14 | 15 | EXTRA_DIST += $(top_srcdir)/bin/tar2sqfs/test/simple.tar 16 | EXTRA_DIST += $(top_srcdir)/bin/tar2sqfs/test/sqfs.sha512 17 | -------------------------------------------------------------------------------- /lib/util/src/hex_decode.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * hex_decode.h 4 | * 5 | * Copyright (C) 2022 David Oberhollenzer 6 | */ 7 | #include "util/util.h" 8 | 9 | #include 10 | 11 | static sqfs_u8 xdigit(int in) 12 | { 13 | if (isupper(in)) 14 | return in - 'A' + 10; 15 | if (islower(in)) 16 | return in - 'a' + 10; 17 | return in - '0'; 18 | } 19 | 20 | int hex_decode(const char *in, size_t in_sz, sqfs_u8 *out, size_t out_sz) 21 | { 22 | while (out_sz > 0 && in_sz >= 2 && 23 | isxdigit(in[0]) && isxdigit(in[1])) { 24 | sqfs_u8 hi = xdigit(*(in++)); 25 | sqfs_u8 lo = xdigit(*(in++)); 26 | 27 | *(out++) = (hi << 4) | lo; 28 | 29 | in_sz -= 2; 30 | --out_sz; 31 | } 32 | 33 | return (in_sz > 0) ? -1 : 0; 34 | } 35 | -------------------------------------------------------------------------------- /lib/util/test/is_memory_zero.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * is_memory_zero.c 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/test.h" 10 | #include "util/util.h" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | unsigned char temp[1024]; 15 | size_t i, j; 16 | (void)argc; (void)argv; 17 | 18 | memset(temp, 0, sizeof(temp)); 19 | 20 | for (i = 0; i < sizeof(temp); ++i) { 21 | TEST_ASSERT(is_memory_zero(temp, i)); 22 | 23 | for (j = 0; j < i; ++j) { 24 | TEST_ASSERT(is_memory_zero(temp, i)); 25 | temp[j] = 42; 26 | TEST_ASSERT(!is_memory_zero(temp, i)); 27 | temp[j] = 0; 28 | TEST_ASSERT(is_memory_zero(temp, i)); 29 | } 30 | } 31 | 32 | return EXIT_SUCCESS; 33 | } 34 | -------------------------------------------------------------------------------- /lib/util/src/alloc.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * alloc.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/util.h" 10 | 11 | #include 12 | #include 13 | 14 | void *alloc_flex(size_t base_size, size_t item_size, size_t nmemb) 15 | { 16 | size_t size; 17 | 18 | if (SZ_MUL_OV(nmemb, item_size, &size) || 19 | SZ_ADD_OV(base_size, size, &size)) { 20 | errno = EOVERFLOW; 21 | return NULL; 22 | } 23 | 24 | return calloc(1, size); 25 | } 26 | 27 | void *alloc_array(size_t item_size, size_t nmemb) 28 | { 29 | size_t size; 30 | 31 | if (SZ_MUL_OV(nmemb, item_size, &size)) { 32 | errno = EOVERFLOW; 33 | return NULL; 34 | } 35 | 36 | return calloc(1, size); 37 | } 38 | -------------------------------------------------------------------------------- /lib/tar/src/checksum.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * checksum.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "tar/format.h" 8 | 9 | unsigned int tar_compute_checksum(const tar_header_t *hdr) 10 | { 11 | const unsigned char *header_start = (const unsigned char *)hdr; 12 | const unsigned char *chksum_start = (const unsigned char *)hdr->chksum; 13 | const unsigned char *header_end = header_start + sizeof(*hdr); 14 | const unsigned char *chksum_end = chksum_start + sizeof(hdr->chksum); 15 | const unsigned char *p; 16 | unsigned int chksum = 0; 17 | 18 | for (p = header_start; p < chksum_start; p++) 19 | chksum += *p; 20 | for (; p < chksum_end; p++) 21 | chksum += ' '; 22 | for (; p < header_end; p++) 23 | chksum += *p; 24 | return chksum; 25 | } 26 | -------------------------------------------------------------------------------- /licenses/xz.txt: -------------------------------------------------------------------------------- 1 | liblzma is in the public domain. 2 | 3 | You can do whatever you want with the files that have been put into 4 | the public domain. If you find public domain legally problematic, 5 | take the previous sentence as a license grant. If you still find 6 | the lack of copyright legally problematic, you have too many 7 | lawyers. 8 | 9 | As usual, this software is provided "as is", without any warranty. 10 | 11 | If you copy significant amounts of public domain code from XZ Utils 12 | into your project, acknowledging this somewhere in your software is 13 | polite (especially if it is proprietary, non-free software), but 14 | naturally it is not legally required. Here is an example of a good 15 | notice to put into "about box" or into documentation: 16 | 17 | This software includes code from XZ Utils . 18 | -------------------------------------------------------------------------------- /bin/rdsquashfs/Makemodule.am: -------------------------------------------------------------------------------- 1 | rdsquashfs_SOURCES = bin/rdsquashfs/src/rdsquashfs.c \ 2 | bin/rdsquashfs/src/rdsquashfs.h bin/rdsquashfs/src/list_files.c \ 3 | bin/rdsquashfs/src/options.c bin/rdsquashfs/src/restore_fstree.c \ 4 | bin/rdsquashfs/src/describe.c bin/rdsquashfs/src/fill_files.c \ 5 | bin/rdsquashfs/src/dump_xattrs.c bin/rdsquashfs/src/stat.c 6 | rdsquashfs_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) 7 | rdsquashfs_LDADD = libcommon.a libcompat.a libutil.a libsquashfs.la 8 | rdsquashfs_LDADD += libfstree.a $(LZO_LIBS) $(PTHREAD_LIBS) 9 | 10 | dist_man1_MANS += bin/rdsquashfs/rdsquashfs.1 11 | bin_PROGRAMS += rdsquashfs 12 | 13 | if WINDOWS 14 | else 15 | check_SCRIPTS += bin/rdsquashfs/test/pathtraversal.sh 16 | TESTS += bin/rdsquashfs/test/pathtraversal.sh 17 | endif 18 | 19 | EXTRA_DIST += $(top_srcdir)/bin/rdsquashfs/test/pathtraversal.sqfs 20 | -------------------------------------------------------------------------------- /lib/compat/src/w32_perror.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * w32_perror.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #include 11 | 12 | #ifdef _WIN32 13 | #define WIN32_LEAN_AND_MEAN 14 | #include 15 | 16 | void w32_perror(const char *str) 17 | { 18 | DWORD nStatus = GetLastError(); 19 | LPVOID msg = NULL; 20 | 21 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | 22 | FORMAT_MESSAGE_FROM_SYSTEM | 23 | FORMAT_MESSAGE_IGNORE_INSERTS, 24 | NULL, nStatus, 25 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 26 | (LPTSTR)&msg, 0, NULL); 27 | 28 | fprintf(stderr, "%s: %s\n", str, (const char *)msg); 29 | 30 | if (msg != NULL) 31 | LocalFree(msg); 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /lib/common/src/print_version.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * print_version.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "common.h" 8 | 9 | #include 10 | 11 | #define LICENSE_SHORT "GPLv3+" 12 | #define LICENSE_LONG "GNU GPL version 3 or later" 13 | #define LICENSE_URL "https://gnu.org/licenses/gpl.html" 14 | 15 | static const char *version_string = 16 | "%s (%s) %s\n" 17 | "Copyright (c) 2019 David Oberhollenzer et al\n" 18 | "License " LICENSE_SHORT ": " LICENSE_LONG " <" LICENSE_URL ">.\n" 19 | "This is free software: you are free to change and redistribute it.\n" 20 | "There is NO WARRANTY, to the extent permitted by law.\n"; 21 | 22 | void print_version(const char *progname) 23 | { 24 | printf(version_string, progname, PACKAGE_NAME, PACKAGE_VERSION); 25 | } 26 | -------------------------------------------------------------------------------- /include/util/strlist.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * strlist.h 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #ifndef UTIL_STRLIST_H 8 | #define UTIL_STRLIST_H 9 | 10 | #include "sqfs/predef.h" 11 | #include 12 | 13 | typedef struct { 14 | char **strings; 15 | size_t count; 16 | size_t capacity; 17 | } strlist_t; 18 | 19 | static SQFS_INLINE void strlist_init(strlist_t *list) 20 | { 21 | memset(list, 0, sizeof(*list)); 22 | } 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | SQFS_INTERNAL int strlist_init_copy(strlist_t *dst, const strlist_t *src); 29 | 30 | SQFS_INTERNAL void strlist_cleanup(strlist_t *list); 31 | 32 | SQFS_INTERNAL int strlist_append(strlist_t *list, const char *str); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif /* UTIL_STRLIST_H */ 39 | -------------------------------------------------------------------------------- /lib/fstree/src/get_path.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * get_path.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "fstree.h" 10 | 11 | #include 12 | #include 13 | 14 | char *fstree_get_path(tree_node_t *node) 15 | { 16 | tree_node_t *it; 17 | char *str, *ptr; 18 | size_t len = 0; 19 | 20 | if (node->parent == NULL) 21 | return strdup("/"); 22 | 23 | for (it = node; it != NULL && it->parent != NULL; it = it->parent) { 24 | len += strlen(it->name) + 1; 25 | } 26 | 27 | str = malloc(len + 1); 28 | if (str == NULL) 29 | return NULL; 30 | 31 | ptr = str + len; 32 | *ptr = '\0'; 33 | 34 | for (it = node; it != NULL && it->parent != NULL; it = it->parent) { 35 | len = strlen(it->name); 36 | ptr -= len; 37 | 38 | memcpy(ptr, it->name, len); 39 | *(--ptr) = '/'; 40 | } 41 | 42 | return str; 43 | } 44 | -------------------------------------------------------------------------------- /lib/sqfs/src/dir_entry.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * dir_entry.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/dir_entry.h" 11 | #include "compat.h" 12 | 13 | #include 14 | #include 15 | 16 | sqfs_dir_entry_t *sqfs_dir_entry_create(const char *name, sqfs_u16 mode, 17 | sqfs_u16 flags) 18 | { 19 | sqfs_dir_entry_t *out; 20 | size_t len, name_len; 21 | 22 | if (flags & ~SQFS_DIR_ENTRY_FLAG_ALL) 23 | return NULL; 24 | 25 | name_len = strlen(name); 26 | if (SZ_ADD_OV(name_len, 1, &name_len)) 27 | return NULL; 28 | if (SZ_ADD_OV(sizeof(*out), name_len, &len)) 29 | return NULL; 30 | 31 | out = calloc(1, len); 32 | if (out == NULL) 33 | return NULL; 34 | 35 | out->mode = mode; 36 | out->flags = flags; 37 | memcpy(out->name, name, name_len); 38 | return out; 39 | } 40 | -------------------------------------------------------------------------------- /scripts/lib_syms_sane.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPC="[[:space:]]\+" 4 | HEXNUM="[0-9a-fA-F]\+" 5 | NUM="[0-9]\+" 6 | 7 | WINE_PATTERN="^${SPC}${HEXNUM}${SPC}${NUM}${SPC}" 8 | ELF_PATTERN="^${SPC}${NUM}:${SPC}${HEXNUM}${SPC}${NUM}${SPC}" 9 | 10 | symbols_from_file() { 11 | case "$1" in 12 | *.dll) 13 | winedump -j export "$1" | grep "$WINE_PATTERN" | \ 14 | sed "s/$WINE_PATTERN//g" 15 | ;; 16 | *) 17 | readelf -TW -s "$1" | grep "$ELF_PATTERN" | grep -v "UND" | \ 18 | sed "s/$ELF_PATTERN//g" | grep -o "${NUM}${SPC}.\+$" | \ 19 | sed "s/^${NUM}${SPC}//g" 20 | esac 21 | } 22 | 23 | symbols_from_file "$1" | grep -q "^sqfs_.*" 24 | 25 | if [ "$?" != "0" ]; then 26 | symbols_from_file "$1" 27 | echo "ERROR: No symbols with sqfs_ prefix found!" 28 | exit 1 29 | fi 30 | 31 | symbols_from_file "$1" | grep -v "^sqfs_" 32 | 33 | if [ "$?" != "1" ]; then 34 | echo "ERROR: Symbols without sqfs_ prefix found!" 35 | exit 1 36 | fi 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /lib/common/src/writer/cleanup.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * cleanup.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "simple_writer.h" 8 | 9 | #include 10 | 11 | void sqfs_writer_cleanup(sqfs_writer_t *sqfs, int status) 12 | { 13 | sqfs_drop(sqfs->xwr); 14 | sqfs_drop(sqfs->dirwr); 15 | sqfs_drop(sqfs->dm); 16 | sqfs_drop(sqfs->im); 17 | sqfs_drop(sqfs->idtbl); 18 | sqfs_drop(sqfs->data); 19 | sqfs_drop(sqfs->blkwr); 20 | sqfs_drop(sqfs->fragtbl); 21 | sqfs_drop(sqfs->cmp); 22 | sqfs_drop(sqfs->uncmp); 23 | fstree_cleanup(&sqfs->fs); 24 | sqfs_drop(sqfs->outfile); 25 | 26 | if (status != EXIT_SUCCESS) { 27 | #if defined(_WIN32) || defined(__WINDOWS__) 28 | WCHAR *path = path_to_windows(sqfs->filename); 29 | 30 | if (path != NULL) 31 | DeleteFileW(path); 32 | 33 | free(path); 34 | #else 35 | unlink(sqfs->filename); 36 | #endif 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /include/xfrm/stream.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * stream.h 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #ifndef XFRM_STREAM_H 8 | #define XFRM_STREAM_H 9 | 10 | #include "sqfs/predef.h" 11 | 12 | typedef enum { 13 | XFRM_STREAM_FLUSH_NONE = 0, 14 | XFRM_STREAM_FLUSH_SYNC, 15 | XFRM_STREAM_FLUSH_FULL, 16 | 17 | XFRM_STREAM_FLUSH_COUNT, 18 | } XFRM_STREAM_FLUSH; 19 | 20 | typedef enum { 21 | XFRM_STREAM_ERROR = -1, 22 | XFRM_STREAM_OK = 0, 23 | XFRM_STREAM_END = 1, 24 | XFRM_STREAM_BUFFER_FULL = 2, 25 | } XFRM_STREAM_RESULT; 26 | 27 | typedef struct xfrm_stream_t xfrm_stream_t; 28 | 29 | struct xfrm_stream_t { 30 | sqfs_object_t base; 31 | 32 | int (*process_data)(xfrm_stream_t *stream, 33 | const void *in, sqfs_u32 in_size, 34 | void *out, sqfs_u32 out_size, 35 | sqfs_u32 *in_read, sqfs_u32 *out_written, 36 | int flush_mode); 37 | }; 38 | 39 | #endif /* XFRM_STREAM_H */ 40 | -------------------------------------------------------------------------------- /lib/common/src/print_size.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * print_size.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "common.h" 9 | 10 | void print_size(sqfs_u64 size, char *buffer, bool round_to_int) 11 | { 12 | static const char *fractions = "0112334456678899"; 13 | static const char *suffices = "kMGTPEZY"; 14 | unsigned int fraction; 15 | int suffix = -1; 16 | 17 | while (size > 1024) { 18 | ++suffix; 19 | fraction = size % 1024; 20 | size /= 1024; 21 | } 22 | 23 | if (suffix >= 0) { 24 | fraction /= 64; 25 | 26 | if (round_to_int) { 27 | size = fraction >= 8 ? (size + 1) : size; 28 | 29 | sprintf(buffer, "%u%c", (unsigned int)size, 30 | suffices[suffix]); 31 | } else { 32 | sprintf(buffer, "%u.%c%c", (unsigned int)size, 33 | fractions[fraction], suffices[suffix]); 34 | } 35 | } else { 36 | sprintf(buffer, "%u", (unsigned int)size); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/util/src/file_cmp.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * file_cmp.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/util.h" 10 | #include "sqfs/io.h" 11 | 12 | #include 13 | 14 | int check_file_range_equal(sqfs_file_t *file, void *scratch, size_t scratch_sz, 15 | sqfs_u64 loc_a, sqfs_u64 loc_b, sqfs_u64 size) 16 | { 17 | sqfs_u8 *ptr_a = scratch, *ptr_b = ptr_a + scratch_sz / 2; 18 | int ret; 19 | 20 | while (size > 0) { 21 | size_t diff = scratch_sz / 2; 22 | diff = (sqfs_u64)diff > size ? size : diff; 23 | 24 | ret = file->read_at(file, loc_a, ptr_a, diff); 25 | if (ret != 0) 26 | return ret; 27 | 28 | ret = file->read_at(file, loc_b, ptr_b, diff); 29 | if (ret != 0) 30 | return ret; 31 | 32 | if (memcmp(ptr_a, ptr_b, diff) != 0) 33 | return 1; 34 | 35 | size -= diff; 36 | loc_a += diff; 37 | loc_b += diff; 38 | } 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /bin/tar2sqfs/src/tar2sqfs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar2sqfs.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef TAR2SQFS_H 8 | #define TAR2SQFS_H 9 | 10 | #include "config.h" 11 | #include "common.h" 12 | #include "compat.h" 13 | 14 | #include "util/util.h" 15 | #include "util/strlist.h" 16 | #include "tar/tar.h" 17 | #include "tar/format.h" 18 | #include "xfrm/compress.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | /* options.c */ 27 | extern bool dont_skip; 28 | extern bool keep_time; 29 | extern bool no_tail_pack; 30 | extern bool no_symlink_retarget; 31 | extern sqfs_writer_cfg_t cfg; 32 | extern char *root_becomes; 33 | extern strlist_t excludedirs; 34 | 35 | void process_args(int argc, char **argv); 36 | 37 | /* process_tarball.c */ 38 | int process_tarball(sqfs_dir_iterator_t *it, sqfs_writer_t *sqfs); 39 | 40 | #endif /* TAR2SQFS_H */ 41 | -------------------------------------------------------------------------------- /bin/tar2sqfs/test/test_tar_sqfs.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | TARDIR="@abs_top_srcdir@/lib/tar/test/data" 6 | TARDIR2="@abs_top_srcdir@/bin/tar2sqfs/test" 7 | SHA512FILE="$TARDIR2/sqfs.sha512" 8 | TAR2SQFS="@abs_top_builddir@/tar2sqfs" 9 | 10 | if [ ! -f "$TAR2SQFS" -a -f "${TAR2SQFS}.exe" ]; then 11 | TAR2SQFS="${TAR2SQFS}.exe" 12 | fi 13 | 14 | # process tar files used for conformance tests 15 | for filename in $(find "$TARDIR" -name "*.tar" | grep -v ".*/file-size/.*"); do 16 | dir="$(dirname $filename | sed -n -e 's;.*/test/;test_tar/;p')" 17 | imgname="$dir/$(basename $filename .tar).sqfs" 18 | 19 | mkdir -p "$dir" 20 | "$TAR2SQFS" --defaults mtime=0 -c gzip -q "$imgname" < "$filename" 21 | done 22 | 23 | # edge case test 24 | filename="$TARDIR2/simple.tar" 25 | imgname="./test_tar/root-becomes.sqfs" 26 | 27 | "$TAR2SQFS" --root-becomes foo --defaults mtime=0 \ 28 | -c gzip -q "$imgname" < "$filename" 29 | 30 | # verify 31 | sha512sum -c "$SHA512FILE" 32 | 33 | # cleanup 34 | rm -rf "./test_tar" 35 | -------------------------------------------------------------------------------- /lib/tar/test/tar_big_file.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_big_file.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "util/test.h" 10 | #include "sqfs/io.h" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | tar_header_decoded_t hdr; 15 | sqfs_istream_t *fp; 16 | int ret; 17 | (void)argc; (void)argv; 18 | 19 | ret = sqfs_istream_open_file(&fp, 20 | STRVALUE(TESTPATH) "/" STRVALUE(TESTFILE), 21 | 0); 22 | TEST_EQUAL_I(ret, 0); 23 | TEST_NOT_NULL(fp); 24 | TEST_ASSERT(read_header(fp, &hdr) == 0); 25 | TEST_EQUAL_UI(hdr.mode, S_IFREG | 0644); 26 | TEST_EQUAL_UI(hdr.uid, 01750); 27 | TEST_EQUAL_UI(hdr.gid, 01750); 28 | TEST_EQUAL_UI(hdr.actual_size, 8589934592); 29 | TEST_EQUAL_UI(hdr.mtime, 1542959190); 30 | TEST_STR_EQUAL(hdr.name, "big-file.bin"); 31 | TEST_ASSERT(!hdr.unknown_record); 32 | clear_header(&hdr); 33 | sqfs_drop(fp); 34 | return EXIT_SUCCESS; 35 | } 36 | -------------------------------------------------------------------------------- /lib/util/src/source_date_epoch.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * source_date_epoch.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "util/util.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | sqfs_u32 get_source_date_epoch(void) 14 | { 15 | const char *str, *ptr; 16 | sqfs_u32 x, tval = 0; 17 | 18 | str = getenv("SOURCE_DATE_EPOCH"); 19 | 20 | if (str == NULL || *str == '\0') 21 | return 0; 22 | 23 | for (ptr = str; *ptr != '\0'; ++ptr) { 24 | if (!isdigit(*ptr)) 25 | goto fail_nan; 26 | 27 | x = (*ptr) - '0'; 28 | 29 | if (tval > (UINT32_MAX - x) / 10) 30 | goto fail_ov; 31 | 32 | tval = tval * 10 + x; 33 | } 34 | 35 | return tval; 36 | fail_ov: 37 | fprintf(stderr, "WARNING: SOURCE_DATE_EPOCH=%s does not fit into " 38 | "32 bit integer\n", str); 39 | return 0; 40 | fail_nan: 41 | fprintf(stderr, "WARNING: SOURCE_DATE_EPOCH=%s is not a positive " 42 | "number\n", str); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /bin/sqfs2tar/src/sqfs2tar.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * sqfs2tar.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef SQFS2TAR_H 8 | #define SQFS2TAR_H 9 | 10 | #include "config.h" 11 | #include "common.h" 12 | 13 | #include "util/util.h" 14 | #include "util/strlist.h" 15 | #include "tar/tar.h" 16 | #include "xfrm/compress.h" 17 | #include "xfrm/wrap.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /* options.c */ 28 | extern bool dont_skip; 29 | extern bool keep_as_dir; 30 | extern bool no_xattr; 31 | extern bool no_links; 32 | 33 | extern char *root_becomes; 34 | extern strlist_t subdirs; 35 | extern int compressor; 36 | 37 | extern const char *filename; 38 | 39 | void process_args(int argc, char **argv); 40 | 41 | /* iterator.c */ 42 | sqfs_dir_iterator_t *tar_compat_iterator_create(const char *filename); 43 | 44 | #endif /* SQFS2TAR_H */ 45 | -------------------------------------------------------------------------------- /lib/compat/src/path_to_windows.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * path_to_windows.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #include 11 | #include 12 | 13 | #if defined(_WIN32) || defined(__WINDOWS__) 14 | WCHAR *path_to_windows(const char *input) 15 | { 16 | WCHAR *wpath, *ptr; 17 | DWORD length; 18 | 19 | length = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); 20 | if (length <= 0) { 21 | w32_perror("Converting UTF-8 path to UTF-16"); 22 | return NULL; 23 | } 24 | 25 | wpath = calloc(sizeof(wpath[0]), length + 1); 26 | if (wpath == NULL) { 27 | fprintf(stderr, 28 | "Converting UTF-8 path to UTF-16: out of memory\n"); 29 | return NULL; 30 | } 31 | 32 | MultiByteToWideChar(CP_UTF8, 0, input, -1, wpath, length + 1); 33 | wpath[length] = '\0'; 34 | 35 | for (ptr = wpath; *ptr != '\0'; ++ptr) { 36 | if (*ptr == '/') 37 | *ptr = '\\'; 38 | } 39 | 40 | return wpath; 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /include/compress_cli.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * compress_cli.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef COMPRESS_CLI_H 8 | #define COMPRESS_CLI_H 9 | 10 | #include "sqfs/compressor.h" 11 | #include "sqfs/super.h" 12 | #include "sqfs/block.h" 13 | #include "sqfs/error.h" 14 | #include "sqfs/io.h" 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | void compressor_print_available(void); 21 | 22 | SQFS_COMPRESSOR compressor_get_default(void); 23 | 24 | int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, 25 | SQFS_COMPRESSOR id, 26 | size_t block_size, char *options); 27 | 28 | void compressor_print_help(SQFS_COMPRESSOR id); 29 | 30 | /* 31 | Create an liblzo2 based LZO compressor. 32 | 33 | XXX: This must be in libcommon instead of libsquashfs for legal reasons. 34 | */ 35 | int lzo_compressor_create(const sqfs_compressor_config_t *cfg, 36 | sqfs_compressor_t **out); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif /* COMPRESS_CLI_H */ 43 | -------------------------------------------------------------------------------- /lib/fstree/src/stats.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * stats.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "fstree.h" 10 | #include 11 | 12 | static void count_dfs(const tree_node_t *n, fstree_stats_t *out) 13 | { 14 | switch (n->mode & S_IFMT) { 15 | case S_IFSOCK: 16 | case S_IFIFO: 17 | out->num_ipc += 1; 18 | break; 19 | case S_IFLNK: 20 | if (n->flags & FLAG_LINK_IS_HARD) { 21 | out->num_links += 1; 22 | } else { 23 | out->num_slinks += 1; 24 | } 25 | break; 26 | case S_IFREG: 27 | out->num_files += 1; 28 | break; 29 | case S_IFBLK: 30 | case S_IFCHR: 31 | out->num_devices += 1; 32 | break; 33 | case S_IFDIR: 34 | out->num_dirs += 1; 35 | for (n = n->data.children; n != NULL; n = n->next) { 36 | count_dfs(n, out); 37 | } 38 | break; 39 | default: 40 | break; 41 | } 42 | } 43 | 44 | void fstree_collect_stats(const fstree_t *fs, fstree_stats_t *out) 45 | { 46 | memset(out, 0, sizeof(*out)); 47 | 48 | count_dfs(fs->root, out); 49 | } 50 | -------------------------------------------------------------------------------- /lib/tar/test/tar_fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_fuzz.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "sqfs/io.h" 10 | #include "tar/tar.h" 11 | #include "common.h" 12 | 13 | #include 14 | #include 15 | 16 | int main(int argc, char **argv) 17 | { 18 | tar_header_decoded_t hdr; 19 | sqfs_istream_t *fp; 20 | int ret; 21 | 22 | if (argc != 2) { 23 | fputs("usage: tar_fuzz \n", stderr); 24 | return EXIT_FAILURE; 25 | } 26 | 27 | ret = sqfs_istream_open_file(&fp, argv[1], 0); 28 | if (ret) { 29 | sqfs_perror("stdint", NULL, ret); 30 | return EXIT_FAILURE; 31 | } 32 | 33 | for (;;) { 34 | ret = read_header(fp, &hdr); 35 | if (ret > 0) 36 | break; 37 | if (ret < 0) 38 | goto fail; 39 | 40 | ret = sqfs_istream_skip(fp, hdr.record_size); 41 | 42 | clear_header(&hdr); 43 | if (ret < 0) 44 | goto fail; 45 | } 46 | 47 | sqfs_drop(fp); 48 | return EXIT_SUCCESS; 49 | fail: 50 | sqfs_drop(fp); 51 | return EXIT_FAILURE; 52 | } 53 | -------------------------------------------------------------------------------- /packages/APKBUILD: -------------------------------------------------------------------------------- 1 | # Contributor: Ryan Barnett 2 | # Maintainer: Ryan Barnett 3 | pkgname=squashfs-tools-ng 4 | pkgver=1.1.2 5 | pkgrel=0 6 | pkgdesc="A new set of tools and libraries for working with SquashFS images" 7 | url="https://infraroot.at/projects/squashfs-tools-ng/index.html" 8 | arch="all" 9 | license="GPL-3.0-or-later" 10 | makedepends="automake libselinux-dev lz4-dev lzo-dev xz-dev zlib-dev zstd-dev libbz2-dev" 11 | subpackages="$pkgname-dev $pkgname-libs $pkgname-doc" 12 | source="https://infraroot.at/pub/squashfs/squashfs-tools-ng-$pkgver.tar.gz" 13 | 14 | build() { 15 | ./configure \ 16 | --build=$CBUILD \ 17 | --host=$CHOST \ 18 | --prefix=/usr \ 19 | --sysconfdir=/etc \ 20 | --mandir=/usr/share/man \ 21 | --localstatedir=/var 22 | make 23 | } 24 | 25 | check() { 26 | make check 27 | } 28 | 29 | package() { 30 | make DESTDIR="$pkgdir" install 31 | } 32 | 33 | sha512sums="3f66cd9034997104e2d3281e271e8ccfbdd6ecaa98313636dcfd5251717e173ceede27b4a94342b011707fc1e96884ec733423f978697c6420915d96c153cf3e squashfs-tools-ng-1.1.2.tar.gz" 34 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | AM_CPPFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE 4 | AM_CFLAGS = $(WARN_CFLAGS) 5 | 6 | if WITH_LZO 7 | AM_CPPFLAGS += -DWITH_LZO 8 | endif 9 | 10 | if CUSTOM_ALLOC 11 | else 12 | AM_CPPFLAGS += -DNO_CUSTOM_ALLOC 13 | endif 14 | 15 | noinst_LTLIBRARIES = 16 | noinst_LIBRARIES = 17 | noinst_PROGRAMS = 18 | bin_PROGRAMS = 19 | lib_LTLIBRARIES = 20 | dist_man1_MANS = 21 | check_PROGRAMS = 22 | check_SCRIPTS = 23 | pkgconfig_DATA = 24 | 25 | EXTRA_DIST = autogen.sh README.md CHANGELOG.md COPYING.md licenses doc 26 | TESTS = 27 | 28 | include lib/sqfs/Makemodule.am 29 | include lib/util/Makemodule.am 30 | include lib/xfrm/Makemodule.am 31 | 32 | include lib/fstree/Makemodule.am 33 | include lib/common/Makemodule.am 34 | include lib/tar/Makemodule.am 35 | include lib/compat/Makemodule.am 36 | include bin/gensquashfs/Makemodule.am 37 | include bin/rdsquashfs/Makemodule.am 38 | include bin/sqfs2tar/Makemodule.am 39 | include bin/sqfsdiff/Makemodule.am 40 | include bin/tar2sqfs/Makemodule.am 41 | 42 | include extras/Makemodule.am 43 | 44 | if HAVE_DOXYGEN 45 | @DX_RULES@ 46 | 47 | MOSTLYCLEANFILES = $(DX_CLEANFILES) 48 | endif 49 | -------------------------------------------------------------------------------- /lib/tar/src/record_to_memory.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * record_to_memory.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "tar/tar.h" 10 | #include "internal.h" 11 | #include 12 | 13 | char *record_to_memory(sqfs_istream_t *fp, size_t size) 14 | { 15 | char *buffer = malloc(size + 1); 16 | int ret; 17 | 18 | if (buffer == NULL) 19 | goto fail_errno; 20 | 21 | ret = sqfs_istream_read(fp, buffer, size); 22 | if (ret < 0) { 23 | sqfs_perror(fp->get_filename(fp), "reading tar record", ret); 24 | goto fail; 25 | } 26 | 27 | if ((size_t)ret < size) { 28 | fputs("Reading tar record: unexpected end-of-file.\n", stderr); 29 | goto fail; 30 | } 31 | 32 | if (size % 512) { 33 | ret = sqfs_istream_skip(fp, 512 - (size % 512)); 34 | if (ret) { 35 | sqfs_perror(fp->get_filename(fp), 36 | "skipping tar padding", ret); 37 | goto fail; 38 | } 39 | } 40 | 41 | buffer[size] = '\0'; 42 | return buffer; 43 | fail_errno: 44 | perror("reading tar record"); 45 | goto fail; 46 | fail: 47 | free(buffer); 48 | return NULL; 49 | } 50 | -------------------------------------------------------------------------------- /lib/util/src/is_memory_zero.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * is_memory_zero.c 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | 10 | #include 11 | 12 | #define U64THRESHOLD (128) 13 | 14 | static bool test_u8(const unsigned char *blob, size_t size) 15 | { 16 | while (size--) { 17 | if (*(blob++) != 0) 18 | return false; 19 | } 20 | 21 | return true; 22 | } 23 | 24 | bool is_memory_zero(const void *blob, size_t size) 25 | { 26 | const sqfs_u64 *u64ptr; 27 | size_t diff; 28 | 29 | if (size < U64THRESHOLD) 30 | return test_u8(blob, size); 31 | 32 | diff = (uintptr_t)blob % sizeof(sqfs_u64); 33 | 34 | if (diff != 0) { 35 | diff = sizeof(sqfs_u64) - diff; 36 | 37 | if (!test_u8(blob, diff)) 38 | return false; 39 | 40 | blob = (const char *)blob + diff; 41 | size -= diff; 42 | } 43 | 44 | u64ptr = blob; 45 | 46 | while (size >= sizeof(sqfs_u64)) { 47 | if (*(u64ptr++) != 0) 48 | return false; 49 | 50 | size -= sizeof(sqfs_u64); 51 | } 52 | 53 | return test_u8((const unsigned char *)u64ptr, size); 54 | } 55 | -------------------------------------------------------------------------------- /lib/compat/src/mockups.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * mockups.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #include 11 | 12 | #ifdef _WIN32 13 | int fchownat(int dirfd, const char *path, int uid, int gid, int flags) 14 | { 15 | if (dirfd != AT_FDCWD) { 16 | fputs("[FIXME] fchownat stub only supports AT_FDCWD!\n", 17 | stderr); 18 | return -1; 19 | } 20 | 21 | if (flags != 0 && flags != AT_SYMLINK_NOFOLLOW) { 22 | fputs("[FIXME] fchownat stub used with an unknown flag!\n", 23 | stderr); 24 | return -1; 25 | } 26 | 27 | (void)path; 28 | (void)uid; 29 | (void)gid; 30 | return 0; 31 | } 32 | 33 | int fchmodat(int dirfd, const char *path, int mode, int flags) 34 | { 35 | if (dirfd != AT_FDCWD) { 36 | fputs("[FIXME] fchmodat stub only supports AT_FDCWD!\n", 37 | stderr); 38 | return -1; 39 | } 40 | 41 | if (flags != 0 && flags != AT_SYMLINK_NOFOLLOW) { 42 | fputs("[FIXME] fchmodat stub used with an unknown flag!\n", 43 | stderr); 44 | return -1; 45 | } 46 | 47 | (void)path; 48 | (void)mode; 49 | return 0; 50 | } 51 | #endif 52 | -------------------------------------------------------------------------------- /lib/tar/src/internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * internal.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef INTERNAL_H 8 | #define INTERNAL_H 9 | 10 | #include "config.h" 11 | 12 | #include "tar/tar.h" 13 | #include "tar/format.h" 14 | #include "util/util.h" 15 | #include "sqfs/error.h" 16 | #include "common.h" 17 | 18 | enum { 19 | PAX_SIZE = 0x001, 20 | PAX_UID = 0x002, 21 | PAX_GID = 0x004, 22 | PAX_DEV_MAJ = 0x008, 23 | PAX_DEV_MIN = 0x010, 24 | PAX_NAME = 0x020, 25 | PAX_SLINK_TARGET = 0x040, 26 | PAX_MTIME = 0x100, 27 | PAX_SPARSE_SIZE = 0x400, 28 | 29 | PAX_SPARSE_GNU_1_X = 0x800, 30 | }; 31 | 32 | enum { 33 | ETV_UNKNOWN = 0, 34 | ETV_V7_UNIX, 35 | ETV_PRE_POSIX, 36 | ETV_POSIX, 37 | }; 38 | 39 | sparse_map_t *read_gnu_old_sparse(sqfs_istream_t *fp, tar_header_t *hdr); 40 | 41 | sparse_map_t *read_gnu_new_sparse(sqfs_istream_t *fp, 42 | tar_header_decoded_t *out); 43 | 44 | char *record_to_memory(sqfs_istream_t *fp, size_t size); 45 | 46 | int read_pax_header(sqfs_istream_t *fp, sqfs_u64 entsize, 47 | unsigned int *set_by_pax, 48 | tar_header_decoded_t *out); 49 | 50 | #endif /* INTERNAL_H */ 51 | -------------------------------------------------------------------------------- /scripts/coverity.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COVERITY_PATH="$HOME/Downloads/cov-analysis-linux64-2022.12.2" 4 | TOKEN=$(cat "$HOME/.coverity/squashfs-tools-ng") 5 | EMAIL=$(git log --follow --pretty=format:"%ae" -- coverity.sh | head -n 1) 6 | 7 | DESCRIPTION=$(git describe --always --tags --dirty) 8 | VERSION=$(grep AC_INIT configure.ac | grep -o \\[[0-9.]*\\] | tr -d []) 9 | 10 | export PATH="$COVERITY_PATH/bin:$PATH" 11 | 12 | if [ $# -eq 1 ]; then 13 | case "$1" in 14 | --32bit) 15 | ./autogen.sh 16 | ./configure CFLAGS="-m32" CXXFLAGS="-m32" LDFLAGS="-m32" 17 | DESCRIPTION="$DESCRIPTION-32bit" 18 | ;; 19 | *) 20 | echo "Unknown option `$1`" >&2 21 | exit 1 22 | ;; 23 | esac 24 | else 25 | ./autogen.sh 26 | ./configure 27 | fi 28 | 29 | make clean 30 | cov-build --dir cov-int make -j 31 | tar czvf squashfs-tools-ng.tgz cov-int 32 | 33 | echo "Uploading tarball with the following settings:" 34 | echo "Email: $EMAIL" 35 | echo "Version: $VERSION" 36 | echo "Description: $DESCRIPTION" 37 | 38 | curl --form token="$TOKEN" \ 39 | --form email="$EMAIL" \ 40 | --form file=@squashfs-tools-ng.tgz \ 41 | --form version="$VERSION" \ 42 | --form description="$DESCRIPTION" \ 43 | https://scan.coverity.com/builds?project=squashfs-tools-ng 44 | -------------------------------------------------------------------------------- /licenses/hash_table.txt: -------------------------------------------------------------------------------- 1 | Copyright © 1988-2004 Keith Packard and Bart Massey 2 | Copyright © 2010 Valve Software 3 | Copyright © 2009,2012 Intel Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice (including the next 13 | paragraph) shall be included in all copies or substantial portions of the 14 | Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/util/src/canonicalize_name.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * canonicalize_name.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | 10 | static void normalize_slashes(char *filename) 11 | { 12 | char *dst = filename, *src = filename; 13 | 14 | while (*src == '/') 15 | ++src; 16 | 17 | while (*src != '\0') { 18 | if (*src == '/') { 19 | while (*src == '/') 20 | ++src; 21 | if (*src == '\0') 22 | break; 23 | *(dst++) = '/'; 24 | } else { 25 | *(dst++) = *(src++); 26 | } 27 | } 28 | 29 | *dst = '\0'; 30 | } 31 | 32 | int canonicalize_name(char *filename) 33 | { 34 | char *dst = filename, *src = filename; 35 | 36 | normalize_slashes(filename); 37 | 38 | while (*src != '\0') { 39 | if (src[0] == '.') { 40 | if (src[1] == '\0') 41 | break; 42 | if (src[1] == '/') { 43 | src += 2; 44 | continue; 45 | } 46 | if (src[1] == '.' && (src[2] == '/' || src[2] == '\0')) 47 | return -1; 48 | } 49 | 50 | while (*src != '\0' && *src != '/') 51 | *(dst++) = *(src++); 52 | 53 | if (*src == '/') 54 | *(dst++) = *(src++); 55 | } 56 | 57 | *dst = '\0'; 58 | normalize_slashes(filename); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /lib/sqfs/src/comp/internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * internal.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef INTERNAL_H 8 | #define INTERNAL_H 9 | 10 | #include "config.h" 11 | 12 | #include "sqfs/predef.h" 13 | #include "sqfs/compressor.h" 14 | #include "sqfs/error.h" 15 | #include "sqfs/block.h" 16 | #include "sqfs/io.h" 17 | #include "util/util.h" 18 | 19 | SQFS_INTERNAL 20 | int sqfs_generic_write_options(sqfs_file_t *file, const void *data, 21 | size_t size); 22 | 23 | SQFS_INTERNAL 24 | int sqfs_generic_read_options(sqfs_file_t *file, void *data, size_t size); 25 | 26 | SQFS_INTERNAL 27 | int xz_compressor_create(const sqfs_compressor_config_t *cfg, 28 | sqfs_compressor_t **out); 29 | 30 | SQFS_INTERNAL 31 | int gzip_compressor_create(const sqfs_compressor_config_t *cfg, 32 | sqfs_compressor_t **out); 33 | 34 | SQFS_INTERNAL 35 | int lz4_compressor_create(const sqfs_compressor_config_t *cfg, 36 | sqfs_compressor_t **out); 37 | 38 | SQFS_INTERNAL 39 | int zstd_compressor_create(const sqfs_compressor_config_t *cfg, 40 | sqfs_compressor_t **out); 41 | 42 | SQFS_INTERNAL 43 | int lzma_compressor_create(const sqfs_compressor_config_t *cfg, 44 | sqfs_compressor_t **out); 45 | 46 | #endif /* INTERNAL_H */ 47 | -------------------------------------------------------------------------------- /bin/tar2sqfs/src/tar2sqfs.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar2sqfs.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "tar2sqfs.h" 8 | 9 | int main(int argc, char **argv) 10 | { 11 | sqfs_istream_t *input_file = NULL; 12 | tar_iterator_opts topts = { 0 }; 13 | sqfs_dir_iterator_t *tar = NULL; 14 | int status = EXIT_FAILURE; 15 | sqfs_writer_t sqfs; 16 | int ret; 17 | 18 | process_args(argc, argv); 19 | 20 | ret = istream_open_stdin(&input_file); 21 | if (ret) { 22 | sqfs_perror("stdint", "creating stream wrapper", ret); 23 | return EXIT_FAILURE; 24 | } 25 | 26 | topts.excludedirs = excludedirs.strings; 27 | topts.num_excludedirs = excludedirs.count; 28 | 29 | tar = tar_open_stream(input_file, &topts); 30 | sqfs_drop(input_file); 31 | if (tar == NULL) { 32 | fputs("Creating tar stream: out-of-memory\n", stderr); 33 | return EXIT_FAILURE; 34 | } 35 | 36 | memset(&sqfs, 0, sizeof(sqfs)); 37 | if (sqfs_writer_init(&sqfs, &cfg)) 38 | goto out_it; 39 | 40 | if (process_tarball(tar, &sqfs)) 41 | goto out; 42 | 43 | if (fstree_post_process(&sqfs.fs)) 44 | goto out; 45 | 46 | if (sqfs_writer_finish(&sqfs, &cfg)) 47 | goto out; 48 | 49 | status = EXIT_SUCCESS; 50 | out: 51 | sqfs_writer_cleanup(&sqfs, status); 52 | out_it: 53 | sqfs_drop(tar); 54 | return status; 55 | } 56 | -------------------------------------------------------------------------------- /licenses/LZ4.txt: -------------------------------------------------------------------------------- 1 | LZ4 Library 2 | Copyright (c) 2011-2016, Yann Collet 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /lib/fstree/Makemodule.am: -------------------------------------------------------------------------------- 1 | libfstree_a_SOURCES = include/fstree.h lib/fstree/src/fstree.c \ 2 | lib/fstree/src/post_process.c lib/fstree/src/get_path.c \ 3 | lib/fstree/src/hardlink.c lib/fstree/src/stats.c 4 | 5 | noinst_LIBRARIES += libfstree.a 6 | 7 | test_mknode_simple_SOURCES = lib/fstree/test/mknode_simple.c 8 | test_mknode_simple_LDADD = libfstree.a libsquashfs.la libutil.a libcompat.a 9 | 10 | test_mknode_dir_SOURCES = lib/fstree/test/mknode_dir.c 11 | test_mknode_dir_LDADD = libfstree.a libsquashfs.la libutil.a libcompat.a 12 | 13 | test_gen_inode_numbers_SOURCES = lib/fstree/test/gen_inode_numbers.c 14 | test_gen_inode_numbers_LDADD = libcommon.a libfstree.a libsquashfs.la \ 15 | libutil.a libcompat.a 16 | 17 | test_add_by_path_SOURCES = lib/fstree/test/add_by_path.c 18 | test_add_by_path_LDADD = libcommon.a libfstree.a libsquashfs.la \ 19 | libutil.a libcompat.a 20 | 21 | test_get_path_SOURCES = lib/fstree/test/get_path.c 22 | test_get_path_LDADD = libcommon.a libfstree.a libsquashfs.la \ 23 | libutil.a libcompat.a 24 | 25 | test_fstree_sort_SOURCES = lib/fstree/test/fstree_sort.c 26 | test_fstree_sort_LDADD = libcommon.a libfstree.a libsquashfs.la \ 27 | libutil.a libcompat.a 28 | 29 | FSTREE_TESTS = \ 30 | test_mknode_simple test_mknode_dir test_gen_inode_numbers \ 31 | test_add_by_path test_get_path test_fstree_sort 32 | 33 | check_PROGRAMS += $(FSTREE_TESTS) 34 | TESTS += $(FSTREE_TESTS) 35 | -------------------------------------------------------------------------------- /lib/tar/test/tar_xattr.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_xattr.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "util/test.h" 10 | #include "sqfs/xattr.h" 11 | #include "sqfs/io.h" 12 | 13 | int main(int argc, char **argv) 14 | { 15 | tar_header_decoded_t hdr; 16 | sqfs_istream_t *fp; 17 | char buffer[6]; 18 | int ret; 19 | (void)argc; (void)argv; 20 | 21 | ret = sqfs_istream_open_file(&fp, 22 | STRVALUE(TESTPATH) "/" STRVALUE(TESTFILE), 23 | 0); 24 | TEST_EQUAL_I(ret, 0); 25 | TEST_NOT_NULL(fp); 26 | TEST_ASSERT(read_header(fp, &hdr) == 0); 27 | TEST_EQUAL_UI(hdr.mode, S_IFREG | 0644); 28 | TEST_EQUAL_UI(hdr.uid, 01750); 29 | TEST_EQUAL_UI(hdr.gid, 01750); 30 | TEST_EQUAL_UI(hdr.actual_size, 5); 31 | TEST_EQUAL_UI(hdr.mtime, 1543094477); 32 | TEST_STR_EQUAL(hdr.name, "input.txt"); 33 | TEST_ASSERT(!hdr.unknown_record); 34 | TEST_ASSERT(sqfs_istream_read(fp, buffer, 5) == 5); 35 | buffer[5] = '\0'; 36 | TEST_STR_EQUAL(buffer, "test\n"); 37 | 38 | TEST_NOT_NULL(hdr.xattr); 39 | TEST_STR_EQUAL(hdr.xattr->key, "user.mime_type"); 40 | TEST_STR_EQUAL((const char *)hdr.xattr->value, "text/plain"); 41 | TEST_EQUAL_UI(hdr.xattr->value_len, 10); 42 | TEST_NULL(hdr.xattr->next); 43 | 44 | clear_header(&hdr); 45 | sqfs_drop(fp); 46 | return EXIT_SUCCESS; 47 | } 48 | -------------------------------------------------------------------------------- /scripts/w32devenv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | VERSION=$(grep AC_INIT configure.ac | grep -o \\[[0-9.]*\\] | tr -d []) 6 | 7 | W64_DIR="$(pwd)/w32deps" 8 | W64_PREFIX="x86_64-w64-mingw32" 9 | 10 | mkdir -p "$W64_DIR" 11 | 12 | ################################ get binaries ################################ 13 | 14 | PKG_DIR="squashfs-tools-ng-${VERSION}-mingw64" 15 | PKG_TAR="${PKG_DIR}.zip" 16 | PKG_URL="https://infraroot.at/pub/squashfs/windows" 17 | PKG_HASH="029d75c28af656e3deb35dac1e433b30e278f42077a8fea3e2e9d4dc34dc458c" 18 | 19 | [ -f "$W64_DIR/$PKG_TAR" ] || { 20 | curl -s -L "$PKG_URL/$PKG_TAR" > "$W64_DIR/$PKG_TAR" 21 | echo "$PKG_HASH $W64_DIR/$PKG_TAR" | sha256sum -c --quiet "-" 22 | } 23 | 24 | [ -d "$W64_DIR/$PKG_DIR" ] || { 25 | unzip "$W64_DIR/$PKG_TAR" -d "$W64_DIR" 26 | } 27 | 28 | pushd "$W64_DIR/$PKG_DIR" 29 | rm bin/*.exe 30 | rm bin/libsquashfs.dll 31 | rm -r include/sqfs 32 | rm lib/libsquashfs.dll.a 33 | rm lib/libsquashfs.a 34 | 35 | mv bin "$W64_DIR" 36 | mv lib "$W64_DIR" 37 | mv include "$W64_DIR" 38 | popd 39 | 40 | ################################ build 64 bit ################################ 41 | 42 | export PKG_CONFIG_PATH="$W64_DIR/lib/pkgconfig" 43 | 44 | ./autogen.sh 45 | ./configure CFLAGS="-O2" LZO_CFLAGS="-I$W64_DIR/include" \ 46 | LZO_LIBS="-L$W64_DIR/lib -llzo2" \ 47 | BZIP2_CFLAGS="-I$W64_DIR/include" \ 48 | BZIP2_LIBS="-L$W64_DIR/lib -lbz2" \ 49 | --prefix="$W64_DIR" --host="$W64_PREFIX" 50 | -------------------------------------------------------------------------------- /licenses/xxhash.txt: -------------------------------------------------------------------------------- 1 | xxHash - Extremely Fast Hash algorithm 2 | Copyright (C) 2012-2016, Yann Collet. 3 | 4 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /lib/sqfs/src/xattr/xattr_writer.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * xattr_writer.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef XATTR_WRITER_H 8 | #define XATTR_WRITER_H 9 | 10 | #define SQFS_BUILDING_DLL 11 | #include "config.h" 12 | 13 | #include "sqfs/xattr_writer.h" 14 | #include "sqfs/meta_writer.h" 15 | #include "sqfs/super.h" 16 | #include "sqfs/xattr.h" 17 | #include "sqfs/error.h" 18 | #include "sqfs/block.h" 19 | #include "sqfs/io.h" 20 | 21 | #include "util/str_table.h" 22 | #include "util/rbtree.h" 23 | #include "util/array.h" 24 | #include "util/util.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | #define XATTR_INITIAL_PAIR_CAP 128 32 | 33 | #define MK_PAIR(key, value) (((sqfs_u64)(key) << 32UL) | (sqfs_u64)(value)) 34 | #define GET_KEY(pair) ((pair >> 32UL) & 0x0FFFFFFFFUL) 35 | #define GET_VALUE(pair) (pair & 0x0FFFFFFFFUL) 36 | 37 | 38 | typedef struct kv_block_desc_t { 39 | struct kv_block_desc_t *next; 40 | size_t start; 41 | size_t count; 42 | 43 | sqfs_u64 start_ref; 44 | size_t size_bytes; 45 | } kv_block_desc_t; 46 | 47 | struct sqfs_xattr_writer_t { 48 | sqfs_object_t base; 49 | 50 | str_table_t keys; 51 | str_table_t values; 52 | 53 | array_t kv_pairs; 54 | 55 | size_t kv_start; 56 | 57 | rbtree_t kv_block_tree; 58 | kv_block_desc_t *kv_block_first; 59 | kv_block_desc_t *kv_block_last; 60 | size_t num_blocks; 61 | }; 62 | 63 | #endif /* XATTR_WRITER_H */ 64 | -------------------------------------------------------------------------------- /lib/tar/test/tar_sparse_gnu.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_sparse_gnu.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "util/test.h" 10 | #include "sqfs/io.h" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | tar_header_decoded_t hdr; 15 | sparse_map_t *sparse; 16 | sqfs_istream_t *fp; 17 | int ret; 18 | (void)argc; (void)argv; 19 | 20 | TEST_ASSERT(chdir(TEST_PATH) == 0); 21 | 22 | ret = sqfs_istream_open_file(&fp, "sparse-files/gnu-small.tar", 0); 23 | TEST_EQUAL_I(ret, 0); 24 | TEST_NOT_NULL(fp); 25 | TEST_ASSERT(read_header(fp, &hdr) == 0); 26 | TEST_EQUAL_UI(hdr.mode, S_IFREG | 0644); 27 | TEST_EQUAL_UI(hdr.uid, 01750); 28 | TEST_EQUAL_UI(hdr.gid, 01750); 29 | TEST_EQUAL_UI(hdr.actual_size, 524288); 30 | TEST_EQUAL_UI(hdr.record_size, 8192); 31 | TEST_STR_EQUAL(hdr.name, "input.bin"); 32 | TEST_ASSERT(!hdr.unknown_record); 33 | 34 | sparse = hdr.sparse; 35 | TEST_NOT_NULL(sparse); 36 | TEST_EQUAL_UI(sparse->offset, 0); 37 | TEST_EQUAL_UI(sparse->count, 4096); 38 | 39 | sparse = sparse->next; 40 | TEST_NOT_NULL(sparse); 41 | TEST_EQUAL_UI(sparse->offset, 262144); 42 | TEST_EQUAL_UI(sparse->count, 4096); 43 | 44 | sparse = sparse->next; 45 | TEST_NOT_NULL(sparse); 46 | TEST_EQUAL_UI(sparse->offset, 524288); 47 | TEST_EQUAL_UI(sparse->count, 0); 48 | 49 | TEST_NULL(sparse->next); 50 | 51 | clear_header(&hdr); 52 | sqfs_drop(fp); 53 | return EXIT_SUCCESS; 54 | } 55 | -------------------------------------------------------------------------------- /doc/mainpage.dox: -------------------------------------------------------------------------------- 1 | /** 2 | * @mainpage libsquashfs API reference 3 | * 4 | * @section intro Introduction 5 | * 6 | * The libsquashfs library attempts to encapsulate the actual core of the 7 | * SquashFS reading and writing logic of the squashfs-tools-ng package, 8 | * while trying to offer a generic API that should cover a broad variety of 9 | * applications that might want to make use SquashFS. 10 | * 11 | * All disk I/O is abstracted away through the \ref sqfs_file_t interface. A 12 | * reference implementation that uses native file I/O can be instatiated 13 | * using @ref sqfs_file_open. Providing a custom implementation allows reading 14 | * or writing SquashFS images to something other than regular files, embedding 15 | * SquashFS in a custom container format or applying custom transformations on 16 | * the raw byte level. 17 | * 18 | * If want to get started with reading SquashFS images, a good starting point 19 | * would be the @ref sqfs_data_reader_t and @ref sqfs_dir_reader_t that 20 | * provide an interface for browsing a SquashFS directory tree and reading 21 | * data contained within. 22 | * 23 | * A few helper structures are need for that tough, specifically the SquashFS 24 | * super block (see @ref sqfs_super_t) that can be read from a 25 | * @ref sqfs_file_t using @ref sqfs_super_read. 26 | * 27 | * A decompressor (see @ref sqfs_compressor_t) is also needed, which can be 28 | * created using @ref sqfs_compressor_config_init and 29 | * @ref sqfs_compressor_create. 30 | * 31 | * @example list_files.c 32 | */ 33 | -------------------------------------------------------------------------------- /lib/common/test/fstree_cli.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * fstree_cli.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "common.h" 10 | #include "util/test.h" 11 | #include "util/util.h" 12 | 13 | int main(int argc, char **argv) 14 | { 15 | fstree_defaults_t fs; 16 | char *str; 17 | (void)argc; (void)argv; 18 | 19 | str = strdup("mtime=1337,uid=1000,gid=100,mode=0321"); 20 | TEST_NOT_NULL(str); 21 | TEST_ASSERT(parse_fstree_defaults(&fs, str) == 0); 22 | free(str); 23 | TEST_EQUAL_UI(fs.mtime, 1337); 24 | TEST_EQUAL_UI(fs.uid, 1000); 25 | TEST_EQUAL_UI(fs.gid, 100); 26 | TEST_EQUAL_UI(fs.mode, S_IFDIR | 0321); 27 | 28 | TEST_ASSERT(parse_fstree_defaults(&fs, NULL) == 0); 29 | if (fs.mtime != 0) { 30 | TEST_EQUAL_UI(fs.mtime, get_source_date_epoch()); 31 | } 32 | TEST_EQUAL_UI(fs.uid, 0); 33 | TEST_EQUAL_UI(fs.gid, 0); 34 | TEST_EQUAL_UI(fs.mode, S_IFDIR | 0755); 35 | 36 | str = strdup("mode=07777"); 37 | TEST_NOT_NULL(str); 38 | TEST_ASSERT(parse_fstree_defaults(&fs, str) == 0); 39 | free(str); 40 | 41 | str = strdup("mode=017777"); 42 | TEST_NOT_NULL(str); 43 | TEST_ASSERT(parse_fstree_defaults(&fs, str) != 0); 44 | free(str); 45 | 46 | str = strdup("mtime=-12"); 47 | TEST_NOT_NULL(str); 48 | TEST_ASSERT(parse_fstree_defaults(&fs, str) != 0); 49 | free(str); 50 | 51 | str = strdup("mtime=4294967296"); 52 | TEST_NOT_NULL(str); 53 | TEST_ASSERT(parse_fstree_defaults(&fs, str) != 0); 54 | free(str); 55 | 56 | return EXIT_SUCCESS; 57 | } 58 | -------------------------------------------------------------------------------- /licenses/zstd.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | * Neither the name Facebook nor the names of its contributors may be used to 14 | endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | DIE=0 4 | 5 | (autoreconf --version) < /dev/null > /dev/null 2>&1 || { 6 | echo 7 | echo "You must have autoconf installed to compile this package." 8 | echo "Download the appropriate package for your distribution," 9 | echo "or see http://www.gnu.org/software/autoconf" 10 | DIE=1 11 | } 12 | 13 | (libtoolize --version) < /dev/null > /dev/null 2>&1 || 14 | (glibtoolize --version) < /dev/null > /dev/null 2>&1 || { 15 | echo 16 | echo "You must have libtool installed to compile this package." 17 | echo "Download the appropriate package for your distribution," 18 | echo "or see http://www.gnu.org/software/libtool" 19 | DIE=1 20 | } 21 | 22 | (automake --version) < /dev/null > /dev/null 2>&1 || { 23 | echo 24 | echo "You must have automake installed to compile this package." 25 | echo "Download the appropriate package for your distribution," 26 | echo "or see http://www.gnu.org/software/automake" 27 | DIE=1 28 | } 29 | 30 | if ! test -f "$(aclocal --print-ac-dir)"/pkg.m4; then 31 | echo 32 | echo "You must have pkg-config installed to compile this package." 33 | echo "Download the appropriate package for your distribution," 34 | echo "or see https://www.freedesktop.org/wiki/Software/pkg-config/" 35 | DIE=1 36 | fi 37 | 38 | if test "$DIE" -eq 1; then 39 | exit 1 40 | fi 41 | 42 | autoreconf --force --install --symlink 43 | 44 | if ! grep -q pkg.m4 aclocal.m4; then 45 | cat < 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/super.h" 11 | #include "sqfs/io.h" 12 | #include "compat.h" 13 | 14 | int sqfs_super_write(const sqfs_super_t *super, sqfs_file_t *file) 15 | { 16 | sqfs_super_t copy; 17 | 18 | copy.magic = htole32(super->magic); 19 | copy.inode_count = htole32(super->inode_count); 20 | copy.modification_time = htole32(super->modification_time); 21 | copy.block_size = htole32(super->block_size); 22 | copy.fragment_entry_count = htole32(super->fragment_entry_count); 23 | copy.compression_id = htole16(super->compression_id); 24 | copy.block_log = htole16(super->block_log); 25 | copy.flags = htole16(super->flags); 26 | copy.id_count = htole16(super->id_count); 27 | copy.version_major = htole16(super->version_major); 28 | copy.version_minor = htole16(super->version_minor); 29 | copy.root_inode_ref = htole64(super->root_inode_ref); 30 | copy.bytes_used = htole64(super->bytes_used); 31 | copy.id_table_start = htole64(super->id_table_start); 32 | copy.xattr_id_table_start = htole64(super->xattr_id_table_start); 33 | copy.inode_table_start = htole64(super->inode_table_start); 34 | copy.directory_table_start = htole64(super->directory_table_start); 35 | copy.fragment_table_start = htole64(super->fragment_table_start); 36 | copy.export_table_start = htole64(super->export_table_start); 37 | 38 | return file->write_at(file, 0, ©, sizeof(copy)); 39 | } 40 | -------------------------------------------------------------------------------- /lib/sqfs/src/super.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * super.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/super.h" 11 | #include "sqfs/error.h" 12 | 13 | #include 14 | 15 | int sqfs_super_init(sqfs_super_t *super, size_t block_size, sqfs_u32 mtime, 16 | SQFS_COMPRESSOR compressor) 17 | { 18 | unsigned int i; 19 | 20 | if (block_size & (block_size - 1)) 21 | return SQFS_ERROR_SUPER_BLOCK_SIZE; 22 | 23 | if (block_size < SQFS_MIN_BLOCK_SIZE) 24 | return SQFS_ERROR_SUPER_BLOCK_SIZE; 25 | 26 | if (block_size > SQFS_MAX_BLOCK_SIZE) 27 | return SQFS_ERROR_SUPER_BLOCK_SIZE; 28 | 29 | memset(super, 0, sizeof(*super)); 30 | super->magic = SQFS_MAGIC; 31 | super->modification_time = mtime; 32 | super->block_size = block_size; 33 | super->compression_id = compressor; 34 | super->flags = SQFS_FLAG_NO_FRAGMENTS | SQFS_FLAG_NO_XATTRS; 35 | super->flags |= SQFS_FLAG_NO_DUPLICATES; 36 | super->version_major = SQFS_VERSION_MAJOR; 37 | super->version_minor = SQFS_VERSION_MINOR; 38 | super->bytes_used = sizeof(*super); 39 | super->id_table_start = 0xFFFFFFFFFFFFFFFFUL; 40 | super->xattr_id_table_start = 0xFFFFFFFFFFFFFFFFUL; 41 | super->inode_table_start = 0xFFFFFFFFFFFFFFFFUL; 42 | super->directory_table_start = 0xFFFFFFFFFFFFFFFFUL; 43 | super->fragment_table_start = 0xFFFFFFFFFFFFFFFFUL; 44 | super->export_table_start = 0xFFFFFFFFFFFFFFFFUL; 45 | 46 | for (i = block_size; i != 0x01; i >>= 1) 47 | super->block_log += 1; 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /lib/tar/test/tar_xattr_bin.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_xattr_bin.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "util/test.h" 10 | #include "sqfs/xattr.h" 11 | #include "sqfs/io.h" 12 | 13 | static const uint8_t value[] = { 14 | 0x00, 0x00, 0x00, 0x02, 15 | 0x00, 0x30, 0x00, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x00, 19 | }; 20 | 21 | int main(int argc, char **argv) 22 | { 23 | tar_header_decoded_t hdr; 24 | sqfs_istream_t *fp; 25 | char buffer[6]; 26 | int ret; 27 | (void)argc; (void)argv; 28 | 29 | ret = sqfs_istream_open_file(&fp, 30 | STRVALUE(TESTPATH) "/" STRVALUE(TESTFILE), 31 | 0); 32 | TEST_EQUAL_I(ret, 0); 33 | TEST_NOT_NULL(fp); 34 | TEST_ASSERT(read_header(fp, &hdr) == 0); 35 | TEST_EQUAL_UI(hdr.mode, S_IFREG | 0644); 36 | TEST_EQUAL_UI(hdr.uid, 01750); 37 | TEST_EQUAL_UI(hdr.gid, 01750); 38 | TEST_EQUAL_UI(hdr.actual_size, 5); 39 | TEST_EQUAL_UI(hdr.mtime, 1543094477); 40 | TEST_STR_EQUAL(hdr.name, "input.txt"); 41 | TEST_ASSERT(!hdr.unknown_record); 42 | TEST_ASSERT(sqfs_istream_read(fp, buffer, 5) == 5); 43 | buffer[5] = '\0'; 44 | TEST_STR_EQUAL(buffer, "test\n"); 45 | 46 | TEST_NOT_NULL(hdr.xattr); 47 | TEST_STR_EQUAL(hdr.xattr->key, "security.capability"); 48 | TEST_EQUAL_UI(hdr.xattr->value_len, sizeof(value)); 49 | TEST_ASSERT(memcmp(hdr.xattr->value, value, sizeof(value)) == 0); 50 | TEST_NULL(hdr.xattr->next); 51 | 52 | clear_header(&hdr); 53 | sqfs_drop(fp); 54 | return EXIT_SUCCESS; 55 | } 56 | -------------------------------------------------------------------------------- /lib/common/src/parse_size.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * parse_size.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "common.h" 8 | #include "util/parse.h" 9 | 10 | #include 11 | #include 12 | 13 | int parse_size(const char *what, size_t *out, const char *str, 14 | size_t reference) 15 | { 16 | sqfs_u64 val; 17 | size_t diff; 18 | int ret; 19 | 20 | ret = parse_uint(str, -1, &diff, 0, SIZE_MAX, &val); 21 | if (ret == SQFS_ERROR_OVERFLOW) 22 | goto fail_ov; 23 | if (ret != 0) 24 | goto fail_nan; 25 | 26 | *out = val; 27 | 28 | switch (str[diff]) { 29 | case 'k': 30 | case 'K': 31 | if (SZ_MUL_OV(*out, 1024, out)) 32 | goto fail_ov; 33 | ++diff; 34 | break; 35 | case 'm': 36 | case 'M': 37 | if (SZ_MUL_OV(*out, 1048576, out)) 38 | goto fail_ov; 39 | ++diff; 40 | break; 41 | case 'g': 42 | case 'G': 43 | if (SZ_MUL_OV(*out, 1073741824, out)) 44 | goto fail_ov; 45 | ++diff; 46 | break; 47 | case '%': 48 | if (reference == 0) 49 | goto fail_suffix; 50 | 51 | if (SZ_MUL_OV(*out, reference, out)) 52 | goto fail_ov; 53 | 54 | *out /= 100; 55 | break; 56 | case '\0': 57 | break; 58 | default: 59 | goto fail_suffix; 60 | } 61 | 62 | if (str[diff] != '\0') 63 | goto fail_suffix; 64 | 65 | return 0; 66 | fail_nan: 67 | fprintf(stderr, "%s: '%s' is not a number.\n", what, str); 68 | return -1; 69 | fail_ov: 70 | fprintf(stderr, "%s: numeric overflow parsing '%s'.\n", what, str); 71 | return -1; 72 | fail_suffix: 73 | fprintf(stderr, "%s: unknown suffix in '%s'.\n", what, str); 74 | return -1; 75 | } 76 | -------------------------------------------------------------------------------- /packages/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Build a package for a specific distribution using a Docker image. 4 | # 5 | # ./build DISTRO RELEASE 6 | # 7 | # From a given DISTRO:RELEASE it create a new local Docker image named 8 | # DISTRO-builder:RELEASE and installs tools required to build a 9 | # package (it does not install package build depends). 10 | # 11 | # It also creates a builder user to prevent from building packages as 12 | # root. 13 | # 14 | # Once the image is setup, it starts a docker image and run 15 | # build-helper to build the packages. The packages files are stored in 16 | # _OUT/DISTRO/RELEASE. 17 | # 18 | 19 | 20 | vendor="$1" 21 | release="$2" 22 | 23 | if test -z "$vendor" -o -z "$release"; then 24 | cat<&2 25 | $0 VENDOR RELEASE 26 | EOF 27 | exit 1 28 | fi 29 | 30 | source_dir=$(git rev-parse --show-toplevel) 31 | output_dir=$source_dir/_out 32 | empty_dir=$output__dir/_empty 33 | 34 | if test "$vendor" = "opensuse"; then 35 | vendor=opensuse/leap 36 | pkg_dir=$output_dir/$vendor-$release 37 | else 38 | pkg_dir=$output_dir/$vendor/$release 39 | fi 40 | 41 | image=$vendor-builder:$release 42 | 43 | mkdir -p $pkg_dir 44 | mkdir -p $output_dir/_empty 45 | 46 | # Build docker image 47 | docker build -t $image -f packages/Dockerfile \ 48 | --build-arg vendor="$vendor" \ 49 | --build-arg release="$release" \ 50 | . 51 | 52 | docker_args="-v $source_dir:/source-ro:ro -v $empty_dir:/source-ro/_out:ro" 53 | docker_args="$docker_args -v $pkg_dir:/output:rw" 54 | docker_args="$docker_args -v $source_dir/packages/build-helper:/build-helper" 55 | docker_args="$docker_args --rm" 56 | 57 | docker run -it $docker_args $image /build-helper 58 | -------------------------------------------------------------------------------- /include/xfrm/wrap.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * wrap.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef XFRM_WRAP_H 8 | #define XFRM_WRAP_H 9 | 10 | #include "sqfs/predef.h" 11 | #include "xfrm/stream.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /** 18 | * @brief Create an input stream that transparently decodes data. 19 | * 20 | * @memberof sqfs_istream_t 21 | * 22 | * This function creates an input stream that wraps an underlying input stream 23 | * that is encoded/compressed and transparently decodes the data when reading 24 | * from it. 25 | * 26 | * @param strm A pointer to another stream that should be wrapped. 27 | * @param xfrm The transformation stream to use. 28 | * 29 | * @return A pointer to an input stream on success, NULL on failure. 30 | */ 31 | SQFS_INTERNAL sqfs_istream_t *istream_xfrm_create(sqfs_istream_t *strm, 32 | xfrm_stream_t *xfrm); 33 | 34 | /** 35 | * @brief Create an output stream that transparently encodes data. 36 | * 37 | * @memberof sqfs_ostream_t 38 | * 39 | * This function creates an output stream that transparently encodes 40 | * (e.g. compresses) all data appended to it and writes it to an 41 | * underlying, wrapped output stream. 42 | * 43 | * @param strm A pointer to another stream that should be wrapped. 44 | * @param xfrm The transformation stream to use. 45 | * 46 | * @return A pointer to an output stream on success, NULL on failure. 47 | */ 48 | SQFS_INTERNAL sqfs_ostream_t *ostream_xfrm_create(sqfs_ostream_t *strm, 49 | xfrm_stream_t *xfrm); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif /* XFRM_WRAP_H */ 56 | -------------------------------------------------------------------------------- /lib/util/src/strlist.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * strlist.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/strlist.h" 9 | #include "util/util.h" 10 | #include "compat.h" 11 | 12 | #include 13 | 14 | void strlist_cleanup(strlist_t *list) 15 | { 16 | for (size_t i = 0; i < list->count; ++i) 17 | free(list->strings[i]); 18 | 19 | free(list->strings); 20 | memset(list, 0, sizeof(*list)); 21 | } 22 | 23 | int strlist_init_copy(strlist_t *dst, const strlist_t *src) 24 | { 25 | memset(dst, 0, sizeof(*dst)); 26 | 27 | dst->strings = alloc_array(sizeof(char *), src->capacity); 28 | if (dst->strings == NULL) 29 | return -1; 30 | 31 | dst->count = src->count; 32 | dst->capacity = src->capacity; 33 | 34 | for (size_t i = 0; i < src->count; ++i) { 35 | dst->strings[i] = strdup(src->strings[i]); 36 | 37 | if (dst->strings[i] == NULL) { 38 | dst->count = i; 39 | strlist_cleanup(dst); 40 | return -1; 41 | } 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | int strlist_append(strlist_t *list, const char *str) 48 | { 49 | if (list->count == list->capacity) { 50 | size_t new_cap = list->capacity ? (list->capacity * 2) : 128; 51 | size_t new_sz; 52 | char **new; 53 | 54 | if (SZ_MUL_OV(new_cap, sizeof(char *), &new_sz)) 55 | return -1; 56 | 57 | new = realloc(list->strings, new_sz); 58 | if (new == NULL) 59 | return -1; 60 | 61 | list->capacity = new_cap; 62 | list->strings = new; 63 | } 64 | 65 | list->strings[list->count] = strdup(str); 66 | if (list->strings[list->count] == NULL) 67 | return -1; 68 | 69 | list->count += 1; 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /lib/tar/test/data/CREDITS: -------------------------------------------------------------------------------- 1 | The tar archives in this directory have been obtained from here: 2 | 3 | https://github.com/mgorny/tar-test-inputs 4 | 5 | git commit hash a2110a6 6 | 7 | This repository was linked in the following article on interoperability of 8 | various different tar programs: 9 | 10 | https://dev.gentoo.org/~mgorny/articles/portability-of-tar-features.html 11 | 12 | The original intention of the example archives was to test various tar programs 13 | for interoperability with each others extensions and format quirks. 14 | 15 | The following have been removed since there is no intention in adding support 16 | for those features: 17 | 18 | - volume-label tests 19 | - multi-volume tests 20 | - longe user + group names 21 | - sun tar samples 22 | - star samples 23 | - file flags tests 24 | 25 | In addition to that, the files in "file-size" are truncated, since we are only 26 | interested in parsing the header. 27 | 28 | The following addtional files have been added: 29 | - xattr/xattr-shily-binary.tar 30 | Created from xattr/xattr-shily.tar by manually patching in a capability 31 | xattr key/value pair. 32 | - tar/format-acceptance/link_filled.tar 33 | Contributed in GitHub issue #64. A tar ball that contains a hard link 34 | where the 100 byte target field is completely filled without containing 35 | a null-terminator. 36 | - iterator/sparse.tar 37 | Derived from sparse/gnu.tar and contains some test data for testing the 38 | tar iterator implementation. 39 | - write/simple.tar 40 | Created using the tar writer to verify that it works as intended. Used 41 | for testing the tar writer to check if it still produces identical 42 | output. 43 | -------------------------------------------------------------------------------- /m4/compiler.m4: -------------------------------------------------------------------------------- 1 | dnl Copyright (C) 2008-2011 Free Software Foundation, Inc. 2 | dnl This file is free software; the Free Software Foundation 3 | dnl gives unlimited permission to copy and/or distribute it, 4 | dnl with or without modifications, as long as this notice is preserved. 5 | 6 | dnl From Simon Josefsson 7 | dnl -- derivated from coreutils m4/warnings.m4 8 | 9 | # UL_AS_VAR_APPEND(VAR, VALUE) 10 | # ---------------------------- 11 | # Provide the functionality of AS_VAR_APPEND if Autoconf does not have it. 12 | m4_ifdef([AS_VAR_APPEND], 13 | [m4_copy([AS_VAR_APPEND], [UL_AS_VAR_APPEND])], 14 | [m4_define([UL_AS_VAR_APPEND], 15 | [AS_VAR_SET([$1], [AS_VAR_GET([$1])$2])])]) 16 | 17 | # UL_ADD_WARN(COMPILER_OPTION [, VARNAME]) 18 | # ------------------------ 19 | # Adds parameter to WARN_CFLAGS (or to $VARNAME) if the compiler supports it. 20 | AC_DEFUN([UL_WARN_ADD], [ 21 | m4_define([warnvarname], m4_default([$2],WARN_CFLAGS)) 22 | AS_VAR_PUSHDEF([ul_Warn], [ul_cv_warn_$1])dnl 23 | AC_CACHE_CHECK([whether compiler handles $1], m4_defn([ul_Warn]), [ 24 | # store AC_LANG_WERROR status, then turn it on 25 | save_ac_[]_AC_LANG_ABBREV[]_werror_flag="${ac_[]_AC_LANG_ABBREV[]_werror_flag}" 26 | AC_LANG_WERROR 27 | 28 | ul_save_CPPFLAGS="$CPPFLAGS" 29 | CPPFLAGS="-Werror ${CPPFLAGS} $1" 30 | AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])], 31 | [AS_VAR_SET(ul_Warn, [yes])], 32 | [AS_VAR_SET(ul_Warn, [no])]) 33 | # restore AC_LANG_WERROR 34 | ac_[]_AC_LANG_ABBREV[]_werror_flag="${save_ac_[]_AC_LANG_ABBREV[]_werror_flag}" 35 | 36 | CPPFLAGS="$ul_save_CPPFLAGS" 37 | ]) 38 | AS_VAR_IF(ul_Warn, [yes], [UL_AS_VAR_APPEND(warnvarname, [" $1"])]) 39 | ]) 40 | 41 | -------------------------------------------------------------------------------- /lib/util/test/epoch.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * epoch.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | #include "util/test.h" 10 | 11 | #if defined(_WIN32) || defined(__WINDOWS__) 12 | static void setenv(const char *key, const char *value, int overwrite) 13 | { 14 | char buffer[128]; 15 | (void)overwrite; 16 | 17 | snprintf(buffer, sizeof(buffer) - 1, "%s=%s", key, value); 18 | buffer[sizeof(buffer) - 1] = '\0'; 19 | 20 | _putenv(buffer); 21 | } 22 | 23 | static void unsetenv(const char *key) 24 | { 25 | setenv(key, "", 0); 26 | } 27 | #endif 28 | 29 | int main(int argc, char **argv) 30 | { 31 | sqfs_u32 ts; 32 | (void)argc; (void)argv; 33 | 34 | unsetenv("SOURCE_DATE_EPOCH"); 35 | ts = get_source_date_epoch(); 36 | TEST_EQUAL_UI(ts, 0); 37 | 38 | setenv("SOURCE_DATE_EPOCH", "1337", 1); 39 | ts = get_source_date_epoch(); 40 | TEST_EQUAL_UI(ts, 1337); 41 | 42 | setenv("SOURCE_DATE_EPOCH", "0xCAFE", 1); 43 | ts = get_source_date_epoch(); 44 | TEST_EQUAL_UI(ts, 0); 45 | 46 | setenv("SOURCE_DATE_EPOCH", "foobar", 1); 47 | ts = get_source_date_epoch(); 48 | TEST_EQUAL_UI(ts, 0); 49 | 50 | setenv("SOURCE_DATE_EPOCH", "-12", 1); 51 | ts = get_source_date_epoch(); 52 | TEST_EQUAL_UI(ts, 0); 53 | 54 | setenv("SOURCE_DATE_EPOCH", "12", 1); 55 | ts = get_source_date_epoch(); 56 | TEST_EQUAL_UI(ts, 12); 57 | 58 | setenv("SOURCE_DATE_EPOCH", "4294967295", 1); 59 | ts = get_source_date_epoch(); 60 | TEST_EQUAL_UI(ts, 0xFFFFFFFF); 61 | 62 | setenv("SOURCE_DATE_EPOCH", "4294967296", 1); 63 | ts = get_source_date_epoch(); 64 | TEST_EQUAL_UI(ts, 0); 65 | 66 | return EXIT_SUCCESS; 67 | } 68 | -------------------------------------------------------------------------------- /lib/fstree/src/hardlink.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * hardlink.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "fstree.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | static int resolve_link(fstree_t *fs, tree_node_t *node) 16 | { 17 | tree_node_t *start = node; 18 | 19 | for (;;) { 20 | if (!S_ISLNK(node->mode) || !(node->flags & FLAG_LINK_IS_HARD)) 21 | break; 22 | 23 | if (node->flags & FLAG_LINK_RESOVED) { 24 | node = node->data.target_node; 25 | } else { 26 | node = fstree_get_node_by_path(fs, fs->root, 27 | node->data.target, 28 | false, false); 29 | if (node == NULL) 30 | return -1; 31 | } 32 | 33 | if (node == start) { 34 | errno = EMLINK; 35 | return -1; 36 | } 37 | } 38 | 39 | if (S_ISDIR(node->mode)) { 40 | errno = EPERM; 41 | return -1; 42 | } 43 | 44 | if (node->link_count == 0xFFFFFFFF) { 45 | errno = EMLINK; 46 | return -1; 47 | } 48 | 49 | start->flags |= FLAG_LINK_RESOVED; 50 | start->data.target_node = node; 51 | 52 | node->link_count++; 53 | return 0; 54 | } 55 | 56 | int fstree_resolve_hard_links(fstree_t *fs) 57 | { 58 | while (fs->links_unresolved != NULL) { 59 | tree_node_t *n = fs->links_unresolved; 60 | 61 | if (resolve_link(fs, n)) { 62 | char *path = fstree_get_path(n); 63 | fprintf(stderr, 64 | "Resolving hard link '%s' -> '%s': %s\n", 65 | path == NULL ? n->name : path, n->data.target, 66 | strerror(errno)); 67 | free(path); 68 | return -1; 69 | } 70 | 71 | fs->links_unresolved = n->next_by_type; 72 | n->next_by_type = NULL; 73 | } 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /packages/Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile fo build a package for following Linux distributions: 2 | # 3 | # 4 | # * alpine 5 | # * archlinux 6 | # * centos 7 | # * fedora 8 | # * debian 9 | # * ubuntu 10 | # * opensuse 11 | # 12 | 13 | ARG vendor 14 | ARG release 15 | ARG version=1.0.4 16 | 17 | FROM $vendor:$release 18 | # Args are not globaly scoped 19 | ARG vendor 20 | ARG release 21 | ARG version=1.0.4 22 | 23 | # Install tools required to build a package for several distributions. 24 | # 25 | # Create a user and add it to sudoers. 26 | RUN case $vendor in \ 27 | alpine) \ 28 | apk add alpine-sdk sudo ;\ 29 | ;; \ 30 | archlinux) \ 31 | pacman -Sy; \ 32 | pacman -S --noconfirm fakeroot binutils namcap sudo ;\ 33 | ;; \ 34 | centos|fedora) \ 35 | yum install -y rpm-build spectool sudo ;\ 36 | ;; \ 37 | debian|ubuntu) \ 38 | apt-get update ;\ 39 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 40 | -o Dpkg::Options::=--force-confdef \ 41 | -o APT::Install-Recommends=no \ 42 | build-essential \ 43 | ca-certificates \ 44 | devscripts \ 45 | equivs \ 46 | libdistro-info-perl \ 47 | sudo \ 48 | wget \ 49 | ;\ 50 | ;; \ 51 | opensuse|opensuse/leap) \ 52 | zypper install -y rpm-build sudo wget ;\ 53 | ;; \ 54 | *) \ 55 | echo "Unsupported vendor '$vendor' (version: '$version')"; \ 56 | exit 1; \ 57 | ;; \ 58 | esac; \ 59 | case $vendor in \ 60 | alpine) adduser -G abuild -s /bin/ash -D builder ;; \ 61 | *) useradd -m -s /bin/sh builder ;; \ 62 | esac; \ 63 | echo 'builder ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/builder; \ 64 | chmod 0400 /etc/sudoers.d/builder 65 | 66 | USER builder 67 | WORKDIR /home/builder 68 | 69 | ENV vendor=$vendor 70 | ENV release=$release 71 | ENV version=$version 72 | -------------------------------------------------------------------------------- /lib/tar/test/tar_simple.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_simple.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "util/test.h" 10 | #include "sqfs/io.h" 11 | 12 | #ifndef TESTUID 13 | #define TESTUID 1000 14 | #endif 15 | 16 | #ifndef TESTGID 17 | #define TESTGID TESTUID 18 | #endif 19 | 20 | #ifndef TESTFNAME 21 | #define TESTFNAME input.txt 22 | #endif 23 | 24 | #ifndef TESTTS 25 | #define TESTTS 1542905892 26 | #endif 27 | 28 | #ifdef LONG_NAME_TEST 29 | static const char *fname = 30 | "012345678901234567890123456789/012345678901234567890123456789/" 31 | "012345678901234567890123456789/012345678901234567890123456789/" 32 | "012345678901234567890123456789/input.txt"; 33 | #else 34 | static const char *fname = STRVALUE(TESTFNAME); 35 | #endif 36 | 37 | int main(int argc, char **argv) 38 | { 39 | tar_header_decoded_t hdr; 40 | sqfs_istream_t *fp; 41 | char buffer[6]; 42 | sqfs_s64 ts; 43 | int ret; 44 | (void)argc; (void)argv; 45 | 46 | ret = sqfs_istream_open_file(&fp, 47 | STRVALUE(TESTPATH) "/" STRVALUE(TESTFILE), 48 | 0); 49 | TEST_EQUAL_I(ret, 0); 50 | TEST_NOT_NULL(fp); 51 | TEST_ASSERT(read_header(fp, &hdr) == 0); 52 | TEST_EQUAL_UI(hdr.mode, S_IFREG | 0644); 53 | TEST_EQUAL_UI(hdr.uid, TESTUID); 54 | TEST_EQUAL_UI(hdr.gid, TESTGID); 55 | TEST_EQUAL_UI(hdr.actual_size, 5); 56 | 57 | ts = TESTTS; 58 | TEST_EQUAL_UI(hdr.mtime, ts); 59 | TEST_STR_EQUAL(hdr.name, fname); 60 | TEST_ASSERT(!hdr.unknown_record); 61 | 62 | TEST_ASSERT(sqfs_istream_read(fp, buffer, 5) == 5); 63 | buffer[5] = '\0'; 64 | TEST_STR_EQUAL(buffer, "test\n"); 65 | clear_header(&hdr); 66 | sqfs_drop(fp); 67 | return EXIT_SUCCESS; 68 | } 69 | -------------------------------------------------------------------------------- /lib/tar/src/number.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * number.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "tar/format.h" 10 | 11 | #include 12 | #include 13 | 14 | static int read_octal(const char *str, int digits, sqfs_u64 *out) 15 | { 16 | sqfs_u64 result = 0; 17 | 18 | while (digits > 0 && isspace(*str)) { 19 | ++str; 20 | --digits; 21 | } 22 | 23 | while (digits > 0 && *str >= '0' && *str <= '7') { 24 | if (result > 0x1FFFFFFFFFFFFFFFUL) { 25 | fputs("numeric overflow parsing tar header\n", stderr); 26 | return -1; 27 | } 28 | 29 | result = (result << 3) | (*(str++) - '0'); 30 | --digits; 31 | } 32 | 33 | *out = result; 34 | return 0; 35 | } 36 | 37 | static int read_binary(const char *str, int digits, sqfs_u64 *out) 38 | { 39 | sqfs_u64 x, ov, result = 0; 40 | bool first = true; 41 | 42 | while (digits > 0) { 43 | x = *((const unsigned char *)str++); 44 | --digits; 45 | 46 | if (first) { 47 | first = false; 48 | if (x == 0xFF) { 49 | result = 0xFFFFFFFFFFFFFFFFUL; 50 | } else { 51 | x &= 0x7F; 52 | result = 0; 53 | if (digits > 7 && x != 0) 54 | goto fail_ov; 55 | } 56 | } 57 | 58 | ov = (result >> 56) & 0xFF; 59 | 60 | if (ov != 0 && ov != 0xFF) 61 | goto fail_ov; 62 | 63 | result = (result << 8) | x; 64 | } 65 | 66 | *out = result; 67 | return 0; 68 | fail_ov: 69 | fputs("numeric overflow parsing tar header\n", stderr); 70 | return -1; 71 | } 72 | 73 | int read_number(const char *str, int digits, sqfs_u64 *out) 74 | { 75 | if (*((const unsigned char *)str) & 0x80) 76 | return read_binary(str, digits, out); 77 | 78 | return read_octal(str, digits, out); 79 | } 80 | -------------------------------------------------------------------------------- /lib/util/test/hex_decode.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * hex_decode.c 4 | * 5 | * Copyright (C) 2022 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | #include "util/test.h" 10 | 11 | static const struct { 12 | int result; 13 | const char *in; 14 | const char *out; 15 | } test_vec[] = { 16 | { 0, "", NULL }, 17 | { -1, "A", NULL }, 18 | { 0, "AA", "\xAA" }, 19 | { 0, "0A", "\x0A" }, 20 | { 0, "A0", "\xA0" }, 21 | { -1, "A0B", NULL }, 22 | { 0, "A0BC", "\xA0\xBC" }, 23 | { 0, "0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF" }, 24 | { 0, "0123456789abcdef", "\x01\x23\x45\x67\x89\xAB\xCD\xEF" }, 25 | { -1, "0123456789ABCDEFGH", NULL }, 26 | { -1, "0123456789abcdefgh", NULL }, 27 | }; 28 | 29 | int main(int argc, char **argv) 30 | { 31 | sqfs_u8 buffer[256]; 32 | size_t i, j; 33 | (void)argc; (void)argv; 34 | 35 | for (i = 0; i < sizeof(test_vec) / sizeof(test_vec[0]); ++i) { 36 | size_t in_len = strlen(test_vec[i].in); 37 | size_t out_len = in_len / 2; 38 | int ret; 39 | 40 | /* initialize the buffer */ 41 | for (j = 0; j < sizeof(buffer); ++j) { 42 | buffer[j] = (j % 2) ? 0xAA : 0x55; 43 | } 44 | 45 | /* convert */ 46 | ret = hex_decode(test_vec[i].in, in_len, 47 | buffer, sizeof(buffer)); 48 | 49 | /* make sure pattern is un-touched after expected offset */ 50 | for (j = out_len; j < sizeof(buffer); ++j) { 51 | TEST_ASSERT(buffer[j] == ((j % 2) ? 0xAA : 0x55)); 52 | } 53 | 54 | /* check result */ 55 | if (test_vec[i].result == 0) { 56 | TEST_ASSERT(ret == 0); 57 | ret = memcmp(buffer, test_vec[i].out, out_len); 58 | TEST_ASSERT(ret == 0); 59 | } else { 60 | TEST_ASSERT(ret != 0); 61 | } 62 | } 63 | 64 | return EXIT_SUCCESS; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /lib/util/test/xxhash.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * xxhash.c 4 | * 5 | * Copyright (C) 2020 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/util.h" 10 | #include "util/test.h" 11 | 12 | static const struct { 13 | const char *plaintext; 14 | size_t psize; 15 | sqfs_u32 digest; 16 | } test_vectors[] = { 17 | { 18 | .plaintext = "\x9e", 19 | .psize = 1, 20 | .digest = 0xB85CBEE5, 21 | }, 22 | { 23 | .plaintext = "\x9e\xff\x1f\x4b\x5e\x53\x2f\xdd" 24 | "\xb5\x54\x4d\x2a\x95\x2b", 25 | .psize = 14, 26 | .digest = 0xE5AA0AB4, 27 | }, 28 | { 29 | .plaintext = "\x9e\xff\x1f\x4b\x5e\x53\x2f\xdd" 30 | "\xb5\x54\x4d\x2a\x95\x2b\x57\xae" 31 | "\x5d\xba\x74\xe9\xd3\xa6\x4c\x98" 32 | "\x30\x60\xc0\x80\x00\x00\x00\x00" 33 | "\x00\x00\x00\x00\x00\x00\x00\x00" 34 | "\x00\x00\x00\x00\x00\x00\x00\x00" 35 | "\x00\x00\x00\x00\x00\x00\x00\x00" 36 | "\x00\x00\x00\x00\x00\x00\x00\x00" 37 | "\x00\x00\x00\x00\x00\x00\x00\x00" 38 | "\x00\x00\x00\x00\x00\x00\x00\x00" 39 | "\x00\x00\x00\x00\x00\x00\x00\x00" 40 | "\x00\x00\x00\x00\x00\x00\x00\x00" 41 | "\x00\x00\x00\x00\x00", 42 | .psize = 101, 43 | .digest = 0x018F52BC, 44 | }, 45 | }; 46 | 47 | int main(int argc, char **argv) 48 | { 49 | sqfs_u32 hash; 50 | size_t i; 51 | (void)argc; (void)argv; 52 | 53 | for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); ++i) { 54 | hash = xxh32(test_vectors[i].plaintext, test_vectors[i].psize); 55 | 56 | if (hash != test_vectors[i].digest) { 57 | fprintf(stderr, "Test case " PRI_SZ " failed!\n", i); 58 | fprintf(stderr, "Expected result: 0x%08X\n", 59 | test_vectors[i].digest); 60 | fprintf(stderr, "Actual result: 0x%08X\n", hash); 61 | return EXIT_FAILURE; 62 | } 63 | } 64 | 65 | return EXIT_SUCCESS; 66 | } 67 | -------------------------------------------------------------------------------- /include/util/rbtree.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * rbtree.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef SQFS_RBTREE_H 8 | #define SQFS_RBTREE_H 9 | 10 | #include "config.h" 11 | #include "sqfs/predef.h" 12 | #include "mempool.h" 13 | #include "compat.h" 14 | 15 | #include 16 | 17 | typedef struct rbtree_node_t { 18 | struct rbtree_node_t *left; 19 | struct rbtree_node_t *right; 20 | sqfs_u32 value_offset; 21 | sqfs_u32 is_red : 1; 22 | sqfs_u32 pad0 : 31; 23 | 24 | sqfs_u8 data[]; 25 | } rbtree_node_t; 26 | 27 | typedef struct rbtree_t { 28 | rbtree_node_t *root; 29 | 30 | #ifndef NO_CUSTOM_ALLOC 31 | mem_pool_t *pool; 32 | #endif 33 | 34 | int (*key_compare)(const void *ctx, 35 | const void *lhs, const void *hrs); 36 | 37 | size_t key_size; 38 | size_t key_size_padded; 39 | 40 | size_t value_size; 41 | 42 | void *key_context; 43 | } rbtree_t; 44 | 45 | static SQFS_INLINE void *rbtree_node_key(rbtree_node_t *n) 46 | { 47 | return n->data; 48 | } 49 | 50 | static SQFS_INLINE void *rbtree_node_value(rbtree_node_t *n) 51 | { 52 | return n->data + n->value_offset; 53 | } 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | SQFS_INTERNAL int rbtree_init(rbtree_t *tree, size_t keysize, size_t valuesize, 60 | int(*key_compare)(const void *, const void *, 61 | const void *)); 62 | 63 | SQFS_INTERNAL void rbtree_cleanup(rbtree_t *tree); 64 | 65 | SQFS_INTERNAL int rbtree_copy(const rbtree_t *tree, rbtree_t *out); 66 | 67 | SQFS_INTERNAL int rbtree_insert(rbtree_t *tree, const void *key, 68 | const void *value); 69 | 70 | SQFS_INTERNAL rbtree_node_t *rbtree_lookup(const rbtree_t *tree, 71 | const void *key); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif /* TOOLS_RBTREE_H */ 78 | 79 | -------------------------------------------------------------------------------- /lib/fstree/test/get_path.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * get_path.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "fstree.h" 10 | #include "common.h" 11 | #include "util/test.h" 12 | 13 | static sqfs_dir_entry_t *mkentry(const char *name) 14 | { 15 | sqfs_dir_entry_t *ent = sqfs_dir_entry_create(name, S_IFDIR | 0750, 0); 16 | TEST_NOT_NULL(ent); 17 | ent->uid = 1000; 18 | ent->gid = 100; 19 | return ent; 20 | } 21 | 22 | int main(int argc, char **argv) 23 | { 24 | tree_node_t *a, *b, *c, *d; 25 | fstree_defaults_t fsd; 26 | sqfs_dir_entry_t *ent; 27 | fstree_t fs; 28 | char *str; 29 | (void)argc; (void)argv; 30 | 31 | TEST_ASSERT(parse_fstree_defaults(&fsd, NULL) == 0); 32 | TEST_ASSERT(fstree_init(&fs, &fsd) == 0); 33 | 34 | ent = mkentry("foo"); 35 | a = fstree_add_generic(&fs, ent, NULL); 36 | free(ent); 37 | ent = mkentry("foo/bar"); 38 | b = fstree_add_generic(&fs, ent, NULL); 39 | free(ent); 40 | ent = mkentry("foo/bar/baz"); 41 | c = fstree_add_generic(&fs, ent, NULL); 42 | free(ent); 43 | ent = mkentry("foo/bar/baz/dir"); 44 | d = fstree_add_generic(&fs, ent, NULL); 45 | free(ent); 46 | 47 | str = fstree_get_path(fs.root); 48 | TEST_NOT_NULL(str); 49 | TEST_STR_EQUAL(str, "/"); 50 | free(str); 51 | 52 | str = fstree_get_path(a); 53 | TEST_NOT_NULL(str); 54 | TEST_STR_EQUAL(str, "/foo"); 55 | free(str); 56 | 57 | str = fstree_get_path(b); 58 | TEST_NOT_NULL(str); 59 | TEST_STR_EQUAL(str, "/foo/bar"); 60 | free(str); 61 | 62 | str = fstree_get_path(c); 63 | TEST_NOT_NULL(str); 64 | TEST_STR_EQUAL(str, "/foo/bar/baz"); 65 | free(str); 66 | 67 | str = fstree_get_path(d); 68 | TEST_NOT_NULL(str); 69 | TEST_STR_EQUAL(str, "/foo/bar/baz/dir"); 70 | free(str); 71 | 72 | fstree_cleanup(&fs); 73 | return EXIT_SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /packages/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: David Oberhollenzer 2 | 3 | pkgname=('squashfs-tools-ng' 'squashfs-tools-ng-doc') 4 | pkgver=1.1.2 5 | pkgrel=1 6 | epoch= 7 | pkgdesc='A new set of tools and libraries for working with SquashFS images' 8 | url='https://infraroot.at/projects/squashfs-tools-ng/index.html' 9 | arch=('x86_64') 10 | license=('GPL3' 'LGPL3') 11 | depends=('lzo' 'lz4' 'xz' 'zstd' 'zlib' 'attr' 'bzip2') 12 | source=(https://infraroot.at/pub/squashfs/${pkgname}-${pkgver}.tar.xz{,.asc}) 13 | sha512sums=('3f66cd9034997104e2d3281e271e8ccfbdd6ecaa98313636dcfd5251717e173ceede27b4a94342b011707fc1e96884ec733423f978697c6420915d96c153cf3e' 14 | 'SKIP' 15 | ) 16 | validpgpkeys=('13063F723C9E584AEACD5B9BBCE5DC3C741A02D1') 17 | groups=() 18 | makedepends=( 19 | 'fakeroot' 20 | 'binutils' 21 | 'autoconf' 22 | 'automake' 23 | 'autogen' 24 | 'libtool' 25 | 'pkgconf' 26 | 'm4' 27 | 'make' 28 | 'gcc' 29 | 'doxygen') 30 | # 31 | checkdepends=() 32 | optdepends=('squashfs-tools') 33 | provides=() 34 | conflicts=() 35 | replaces=() 36 | backup=() 37 | options=() 38 | install= 39 | changelog= 40 | noextract=() 41 | 42 | prepare() { 43 | cd "$pkgname-$pkgver" 44 | } 45 | 46 | build() { 47 | cd "$pkgname-$pkgver" 48 | ./configure --prefix=/usr 49 | make 50 | make doxygen-doc 51 | } 52 | 53 | check() { 54 | cd "$pkgname-$pkgver" 55 | make -k check 56 | } 57 | 58 | package_squashfs-tools-ng() { 59 | #depends=('zstd' 'attr' 'zlib' 'xz' 'lzo' 'bzip2' ) 60 | cd "$pkgname-$pkgver" 61 | make DESTDIR="$pkgdir/" install 62 | } 63 | 64 | package_squashfs-tools-ng-doc() { 65 | arch=('any') 66 | optdepend=() 67 | depends=() 68 | cd "$pkgbase-$pkgver" 69 | install -d "$pkgdir/usr/share/doc/$pkgbase" 70 | cp -a doxygen-doc/* "$pkgdir/usr/share/doc/$pkgbase" 71 | } 72 | -------------------------------------------------------------------------------- /bin/sqfsdiff/src/extract.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * extract.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "sqfsdiff.h" 8 | 9 | static int extract(sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode, 10 | const char *prefix, const char *path, size_t block_size) 11 | { 12 | char *ptr, *temp; 13 | sqfs_ostream_t *fp; 14 | sqfs_istream_t *in; 15 | int ret; 16 | 17 | temp = alloca(strlen(prefix) + strlen(path) + 2); 18 | sprintf(temp, "%s/%s", prefix, path); 19 | 20 | ptr = strrchr(temp, '/'); 21 | if (ptr != NULL) { 22 | *ptr = '\0'; 23 | if (mkdir_p(temp)) 24 | return -1; 25 | *ptr = '/'; 26 | } 27 | 28 | ret = sqfs_ostream_open_file(&fp, temp, SQFS_FILE_OPEN_OVERWRITE); 29 | if (ret) { 30 | sqfs_perror(temp, NULL, ret); 31 | return -1; 32 | } 33 | 34 | ret = sqfs_data_reader_create_stream(data, inode, path, &in); 35 | if (ret) { 36 | sqfs_drop(fp); 37 | return -1; 38 | } 39 | 40 | do { 41 | ret = sqfs_istream_splice(in, fp, block_size); 42 | if (ret < 0) 43 | sqfs_perror(path, "splicing data", ret); 44 | } while (ret > 0); 45 | 46 | sqfs_drop(in); 47 | 48 | if (ret == 0) 49 | ret = fp->flush(fp); 50 | 51 | if (ret) { 52 | sqfs_perror(fp->get_filename(fp), NULL, ret); 53 | sqfs_drop(fp); 54 | return -1; 55 | } 56 | 57 | sqfs_drop(fp); 58 | return 0; 59 | } 60 | 61 | int extract_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, 62 | const sqfs_inode_generic_t *new, 63 | const char *path) 64 | { 65 | if (old != NULL) { 66 | if (extract(sd->sqfs_old.data, old, "old", 67 | path, sd->sqfs_old.super.block_size)) 68 | return -1; 69 | } 70 | 71 | if (new != NULL) { 72 | if (extract(sd->sqfs_new.data, new, "new", 73 | path, sd->sqfs_new.super.block_size)) 74 | return -1; 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /lib/common/test/istream_mem.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * istream_mem.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/test.h" 10 | #include "sqfs/io.h" 11 | #include "common.h" 12 | 13 | static const size_t end0 = 449; /* region 1: filled with 'A' */ 14 | static const size_t end1 = 521; /* region 2: filled with 'B' */ 15 | static const size_t end2 = 941; /* region 3: filled with 'C' */ 16 | 17 | static unsigned char data[941]; 18 | 19 | static unsigned char byte_at_offset(size_t off) 20 | { 21 | if (off < end0) 22 | return 'A'; 23 | if (off < end1) 24 | return 'B'; 25 | return 'C'; 26 | } 27 | 28 | static void init_buffer(void) 29 | { 30 | for (size_t i = 0; i < end2; ++i) 31 | data[i] = byte_at_offset(i); 32 | } 33 | 34 | int main(int argc, char **argv) 35 | { 36 | size_t i, diff, size; 37 | bool eat_all = true; 38 | const sqfs_u8 *ptr; 39 | sqfs_istream_t *in; 40 | int ret; 41 | (void)argc; (void)argv; 42 | 43 | init_buffer(); 44 | 45 | in = istream_memory_create("memstream.txt", 61, data, sizeof(data)); 46 | TEST_NOT_NULL(in); 47 | TEST_EQUAL_UI(((sqfs_object_t *)in)->refcount, 1); 48 | 49 | TEST_STR_EQUAL(in->get_filename(in), "memstream.txt"); 50 | 51 | for (i = 0; i < end2; i += diff) { 52 | ret = in->get_buffered_data(in, &ptr, &size, 61); 53 | TEST_EQUAL_I(ret, 0); 54 | 55 | if ((end2 - i) >= 61) { 56 | TEST_NOT_NULL(ptr); 57 | TEST_EQUAL_UI(size, 61); 58 | } else { 59 | TEST_NOT_NULL(ptr); 60 | TEST_EQUAL_UI(size, (end2 - i)); 61 | } 62 | 63 | for (size_t j = 0; j < size; ++j) { 64 | TEST_EQUAL_UI(ptr[j], byte_at_offset(i + j)); 65 | } 66 | 67 | diff = eat_all ? size : (size / 2); 68 | eat_all = !eat_all; 69 | in->advance_buffer(in, diff); 70 | } 71 | 72 | sqfs_drop(in); 73 | return EXIT_SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /bin/sqfsdiff/src/compare_files.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * compare_files.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "sqfsdiff.h" 8 | 9 | static unsigned char old_buf[MAX_WINDOW_SIZE]; 10 | static unsigned char new_buf[MAX_WINDOW_SIZE]; 11 | 12 | static int read_blob(const char *prefix, const char *path, 13 | sqfs_data_reader_t *rd, const sqfs_inode_generic_t *inode, 14 | void *buffer, sqfs_u64 offset, size_t size) 15 | { 16 | ssize_t ret; 17 | 18 | ret = sqfs_data_reader_read(rd, inode, offset, buffer, size); 19 | ret = (ret < 0 || (size_t)ret < size) ? -1 : 0; 20 | 21 | if (ret) { 22 | fprintf(stderr, "Failed to read %s from %s\n", 23 | path, prefix); 24 | return -1; 25 | } 26 | 27 | return 0; 28 | } 29 | 30 | int compare_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, 31 | const sqfs_inode_generic_t *new, const char *path) 32 | { 33 | sqfs_u64 offset, diff, oldsz, newsz; 34 | int status = 0, ret; 35 | 36 | sqfs_inode_get_file_size(old, &oldsz); 37 | sqfs_inode_get_file_size(new, &newsz); 38 | 39 | if (oldsz != newsz) 40 | goto out_different; 41 | 42 | if (sd->compare_flags & COMPARE_NO_CONTENTS) 43 | return 0; 44 | 45 | for (offset = 0; offset < oldsz; offset += diff) { 46 | diff = oldsz - offset; 47 | 48 | if (diff > MAX_WINDOW_SIZE) 49 | diff = MAX_WINDOW_SIZE; 50 | 51 | ret = read_blob(sd->old_path, path, 52 | sd->sqfs_old.data, old, old_buf, offset, diff); 53 | if (ret) 54 | return -1; 55 | 56 | ret = read_blob(sd->new_path, path, 57 | sd->sqfs_new.data, new, new_buf, offset, diff); 58 | if (ret) 59 | return -1; 60 | 61 | if (memcmp(old_buf, new_buf, diff) != 0) 62 | goto out_different; 63 | } 64 | 65 | return status; 66 | out_different: 67 | if (sd->compare_flags & COMPARE_EXTRACT_FILES) { 68 | if (extract_files(sd, old, new, path)) 69 | return -1; 70 | } 71 | return 1; 72 | } 73 | -------------------------------------------------------------------------------- /bin/sqfsdiff/src/sqfsdiff.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * sqfsdiff.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef DIFFTOOL_H 8 | #define DIFFTOOL_H 9 | 10 | #include "config.h" 11 | #include "common.h" 12 | #include "util/util.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define MAX_WINDOW_SIZE (1024 * 1024 * 4) 20 | 21 | typedef struct { 22 | sqfs_compressor_config_t cfg; 23 | sqfs_compressor_t *cmp; 24 | sqfs_super_t super; 25 | sqfs_file_t *file; 26 | sqfs_id_table_t *idtbl; 27 | sqfs_dir_reader_t *dr; 28 | sqfs_tree_node_t *root; 29 | sqfs_data_reader_t *data; 30 | 31 | sqfs_compressor_config_t options; 32 | bool have_options; 33 | } sqfs_state_t; 34 | 35 | typedef struct { 36 | const char *old_path; 37 | const char *new_path; 38 | int compare_flags; 39 | sqfs_state_t sqfs_old; 40 | sqfs_state_t sqfs_new; 41 | bool compare_super; 42 | const char *extract_dir; 43 | } sqfsdiff_t; 44 | 45 | enum { 46 | COMPARE_NO_PERM = 0x01, 47 | COMPARE_NO_OWNER = 0x02, 48 | COMPARE_NO_CONTENTS = 0x04, 49 | COMPARE_TIMESTAMP = 0x08, 50 | COMPARE_INODE_NUM = 0x10, 51 | COMPARE_EXTRACT_FILES = 0x20, 52 | }; 53 | 54 | int compare_dir_entries(sqfsdiff_t *sd, sqfs_tree_node_t *old, 55 | sqfs_tree_node_t *new); 56 | 57 | char *node_path(const sqfs_tree_node_t *n); 58 | 59 | int compare_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, 60 | const sqfs_inode_generic_t *new, const char *path); 61 | 62 | int node_compare(sqfsdiff_t *sd, sqfs_tree_node_t *a, sqfs_tree_node_t *b); 63 | 64 | int compare_super_blocks(const sqfs_super_t *a, const sqfs_super_t *b); 65 | 66 | int extract_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, 67 | const sqfs_inode_generic_t *new, 68 | const char *path); 69 | 70 | void process_options(sqfsdiff_t *sd, int argc, char **argv); 71 | 72 | #endif /* DIFFTOOL_H */ 73 | -------------------------------------------------------------------------------- /lib/util/test/base64_decode.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * base64_decode.c 4 | * 5 | * Copyright (C) 2022 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | #include "util/test.h" 10 | 11 | static const struct { 12 | int result; 13 | const char *in; 14 | const char *out; 15 | } test_vec[] = { 16 | { 0, "", "" }, 17 | { 0, "Zg", "f" }, 18 | { 0, "Zg==", "f" }, 19 | { 0, "Zm8=", "fo" }, 20 | { 0, "Zm9v", "foo" }, 21 | { 0, "Zm9vYg==", "foob" }, 22 | { 0, "Zm9vYmE=", "fooba" }, 23 | { 0, "Zm9vYmFy", "foobar" }, 24 | { 0, "TGV0J3MgYWxsIGxvdmUgTGFpbiEK", "Let's all love Lain!\n" }, 25 | { -1, "Zg==X", "XX" }, 26 | }; 27 | 28 | int main(int argc, char **argv) 29 | { 30 | sqfs_u8 buffer[256]; 31 | size_t i, j; 32 | (void)argc; (void)argv; 33 | 34 | for (i = 0; i < sizeof(test_vec) / sizeof(test_vec[0]); ++i) { 35 | const size_t in_len = strlen(test_vec[i].in); 36 | const size_t out_len = strlen(test_vec[i].out); 37 | size_t real_out; 38 | int ret; 39 | 40 | /* initialize the buffer */ 41 | for (j = 0; j < sizeof(buffer); ++j) { 42 | buffer[j] = (j % 2) ? 0xAA : 0x55; 43 | } 44 | 45 | /* convert */ 46 | real_out = sizeof(buffer); 47 | ret = base64_decode(test_vec[i].in, in_len, buffer, &real_out); 48 | 49 | /* make sure pattern is un-touched after expected offset */ 50 | j = (in_len / 4) * 3; 51 | if (in_len % 4) 52 | j += 3; 53 | 54 | for (; j < sizeof(buffer); ++j) { 55 | TEST_ASSERT(buffer[j] == ((j % 2) ? 0xAA : 0x55)); 56 | } 57 | 58 | /* check result */ 59 | if (test_vec[i].result == 0) { 60 | TEST_ASSERT(ret == 0); 61 | TEST_EQUAL_UI(real_out, out_len); 62 | ret = memcmp(buffer, test_vec[i].out, out_len); 63 | TEST_ASSERT(ret == 0); 64 | } else { 65 | TEST_ASSERT(ret != 0); 66 | TEST_EQUAL_UI(real_out, 0); 67 | } 68 | 69 | fprintf(stderr, "CASE %lu OK\n", (unsigned long)i); 70 | } 71 | 72 | return EXIT_SUCCESS; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /lib/sqfs/src/write_table.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * write_table.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/meta_writer.h" 11 | #include "sqfs/error.h" 12 | #include "sqfs/super.h" 13 | #include "sqfs/table.h" 14 | #include "sqfs/block.h" 15 | #include "sqfs/io.h" 16 | #include "util/util.h" 17 | 18 | #include 19 | 20 | int sqfs_write_table(sqfs_file_t *file, sqfs_compressor_t *cmp, 21 | const void *data, size_t table_size, sqfs_u64 *start) 22 | { 23 | size_t block_count, list_size, diff, blkidx = 0; 24 | sqfs_u64 off, *locations; 25 | sqfs_meta_writer_t *m; 26 | int ret; 27 | 28 | block_count = table_size / SQFS_META_BLOCK_SIZE; 29 | if ((table_size % SQFS_META_BLOCK_SIZE) != 0) 30 | ++block_count; 31 | 32 | locations = alloc_array(sizeof(sqfs_u64), block_count); 33 | 34 | if (locations == NULL) 35 | return SQFS_ERROR_ALLOC; 36 | 37 | /* Write actual data */ 38 | m = sqfs_meta_writer_create(file, cmp, 0); 39 | if (m == NULL) { 40 | ret = SQFS_ERROR_ALLOC; 41 | goto out_idx; 42 | } 43 | 44 | while (table_size > 0) { 45 | locations[blkidx++] = htole64(file->get_size(file)); 46 | 47 | diff = SQFS_META_BLOCK_SIZE; 48 | if (diff > table_size) 49 | diff = table_size; 50 | 51 | ret = sqfs_meta_writer_append(m, data, diff); 52 | if (ret) 53 | goto out; 54 | 55 | data = (const char *)data + diff; 56 | table_size -= diff; 57 | } 58 | 59 | ret = sqfs_meta_writer_flush(m); 60 | if (ret) 61 | goto out; 62 | 63 | /* write location list */ 64 | *start = file->get_size(file); 65 | 66 | list_size = sizeof(sqfs_u64) * block_count; 67 | 68 | off = file->get_size(file); 69 | 70 | ret = file->write_at(file, off, locations, list_size); 71 | if (ret) 72 | goto out; 73 | 74 | /* cleanup */ 75 | ret = 0; 76 | out: 77 | sqfs_drop(m); 78 | out_idx: 79 | free(locations); 80 | return ret; 81 | } 82 | -------------------------------------------------------------------------------- /lib/util/src/filename_sane.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * filename_sane.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | 10 | #include 11 | 12 | #if defined(_WIN32) || defined(__WINDOWS__) || defined(TEST_WIN32) 13 | #ifdef _MSC_VER 14 | #define strncasecmp _strnicmp 15 | #define strcasecmp _stricmp 16 | #endif 17 | 18 | static const char *bad_names[] = { 19 | "CON", "PRN", "AUX", "NUL", 20 | "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", 21 | "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", 22 | }; 23 | 24 | static bool is_allowed_by_os(const char *name) 25 | { 26 | size_t len, i; 27 | 28 | for (i = 0; i < sizeof(bad_names) / sizeof(bad_names[0]); ++i) { 29 | len = strlen(bad_names[i]); 30 | 31 | if (strncasecmp(name, bad_names[i], len) != 0) 32 | continue; 33 | 34 | if (name[len] == '\0') 35 | return false; 36 | 37 | if (name[len] == '.' && strchr(name + len + 1, '.') == NULL) 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | #else 44 | static bool is_allowed_by_os(const char *name) 45 | { 46 | (void)name; 47 | return true; 48 | } 49 | #endif 50 | 51 | bool is_filename_sane(const char *name, bool check_os_specific) 52 | { 53 | if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) 54 | return false; 55 | 56 | if (check_os_specific && !is_allowed_by_os(name)) 57 | return false; 58 | 59 | while (*name != '\0') { 60 | if (*name == '/') 61 | return false; 62 | 63 | #if defined(_WIN32) || defined(__WINDOWS__) || defined(TEST_WIN32) 64 | if (check_os_specific) { 65 | if (*name == '<' || *name == '>' || *name == ':') 66 | return false; 67 | if (*name == '"' || *name == '|' || *name == '?') 68 | return false; 69 | if (*name == '*' || *name == '\\' || *name <= 31) 70 | return false; 71 | } 72 | #endif 73 | 74 | ++name; 75 | } 76 | 77 | return true; 78 | } 79 | -------------------------------------------------------------------------------- /bin/gensquashfs/src/selinux.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * selinux.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "mkfs.h" 8 | 9 | #define XATTR_NAME_SELINUX "security.selinux" 10 | #define XATTR_VALUE_SELINUX "system_u:object_r:unlabeled_t:s0" 11 | 12 | #ifdef WITH_SELINUX 13 | int selinux_relable_node(void *sehnd, sqfs_xattr_writer_t *xwr, 14 | tree_node_t *node, const char *path) 15 | { 16 | char *context = NULL; 17 | int ret; 18 | 19 | if (selabel_lookup(sehnd, &context, path, node->mode) < 0) { 20 | context = strdup(XATTR_VALUE_SELINUX); 21 | if (context == NULL) 22 | goto fail; 23 | } 24 | 25 | ret = sqfs_xattr_writer_add_kv(xwr, XATTR_NAME_SELINUX, 26 | context, strlen(context)); 27 | free(context); 28 | 29 | if (ret) 30 | sqfs_perror(node->name, "storing SELinux xattr", ret); 31 | 32 | return ret; 33 | fail: 34 | perror("relabeling files"); 35 | return -1; 36 | } 37 | 38 | void *selinux_open_context_file(const char *filename) 39 | { 40 | struct selabel_handle *sehnd; 41 | struct selinux_opt seopts[] = { 42 | { SELABEL_OPT_PATH, filename }, 43 | }; 44 | 45 | sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1); 46 | if (sehnd == NULL) 47 | perror(filename); 48 | 49 | return sehnd; 50 | } 51 | 52 | void selinux_close_context_file(void *sehnd) 53 | { 54 | selabel_close(sehnd); 55 | } 56 | #else 57 | int selinux_relable_node(void *sehnd, sqfs_xattr_writer_t *xwr, 58 | tree_node_t *node, const char *path) 59 | { 60 | (void)sehnd; (void)xwr; (void)node; (void)path; 61 | fputs("Built without SELinux support, cannot add SELinux labels\n", 62 | stderr); 63 | return -1; 64 | } 65 | 66 | void *selinux_open_context_file(const char *filename) 67 | { 68 | (void)filename; 69 | fputs("Built without SELinux support, cannot open contexts file\n", 70 | stderr); 71 | return NULL; 72 | } 73 | 74 | void selinux_close_context_file(void *sehnd) 75 | { 76 | (void)sehnd; 77 | } 78 | #endif 79 | -------------------------------------------------------------------------------- /include/common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * common.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef COMMON_H 8 | #define COMMON_H 9 | 10 | #include "config.h" 11 | 12 | #include "sqfs/xattr_reader.h" 13 | #include "sqfs/inode.h" 14 | #include "sqfs/table.h" 15 | #include "sqfs/data_reader.h" 16 | #include "sqfs/dir_reader.h" 17 | #include "sqfs/block.h" 18 | #include "sqfs/xattr.h" 19 | #include "sqfs/dir.h" 20 | #include "sqfs/io.h" 21 | 22 | #include "simple_writer.h" 23 | #include "compress_cli.h" 24 | #include "dir_tree.h" 25 | #include "compat.h" 26 | #include "fstree.h" 27 | 28 | #include 29 | 30 | void sqfs_perror(const char *file, const char *action, int error_code); 31 | 32 | /* A common implementation of the '--version' command line flag. */ 33 | void print_version(const char *progname); 34 | 35 | /* 36 | Parse a number optionally followed by a KMG suffix (case insensitive). Prints 37 | an error message to stderr and returns -1 on failure, 0 on success. 38 | 39 | The "what" string is used to prefix error messages (perror style). 40 | 41 | If reference is non-zero, the suffix '%' can be used to compute the result as 42 | a multiple of the reference value. 43 | */ 44 | int parse_size(const char *what, size_t *out, const char *str, 45 | size_t reference); 46 | 47 | void print_size(sqfs_u64 size, char *buffer, bool round_to_int); 48 | 49 | /* 50 | Parse a comma separated list (e.g. "uid=...,gid=..." of defaults for 51 | fstree nodes. Used for command line parsing. Returns 0 on success, 52 | -1 on failure. Prints an error message to stderr on failure. 53 | */ 54 | int parse_fstree_defaults(fstree_defaults_t *out, char *str); 55 | 56 | int istream_open_stdin(sqfs_istream_t **out); 57 | 58 | int ostream_open_stdout(sqfs_ostream_t **out); 59 | 60 | sqfs_istream_t *istream_memory_create(const char *name, size_t bufsz, 61 | const void *data, size_t size); 62 | 63 | #endif /* COMMON_H */ 64 | -------------------------------------------------------------------------------- /lib/util/test/str_table.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * str_table.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/str_table.h" 10 | #include "util/parse.h" 11 | #include "compat.h" 12 | #include "util/test.h" 13 | #include "sqfs/io.h" 14 | 15 | static char *strings[1000]; 16 | 17 | static int read_strings(void) 18 | { 19 | sqfs_istream_t *fp; 20 | ssize_t ret; 21 | char *line; 22 | int i; 23 | 24 | i = sqfs_istream_open_file(&fp, "words.txt", 0); 25 | TEST_EQUAL_I(i, 0); 26 | TEST_NOT_NULL(fp); 27 | 28 | for (i = 0; i < 1000; ++i) { 29 | ret = istream_get_line(fp, &line, NULL, 0); 30 | TEST_EQUAL_I(ret, 0); 31 | 32 | strings[i] = line; 33 | } 34 | 35 | sqfs_drop(fp); 36 | return 0; 37 | } 38 | 39 | int main(int argc, char **argv) 40 | { 41 | str_table_t table; 42 | size_t i, j, idx; 43 | const char *str; 44 | (void)argc; (void)argv; 45 | 46 | TEST_ASSERT(chdir(TEST_PATH) == 0); 47 | 48 | if (read_strings()) 49 | return EXIT_FAILURE; 50 | 51 | TEST_ASSERT(str_table_init(&table) == 0); 52 | 53 | for (i = 0; i < 1000; ++i) { 54 | TEST_ASSERT(str_table_get_index(&table, strings[i], &idx) == 0); 55 | 56 | TEST_EQUAL_UI(idx, i); 57 | 58 | for (j = 0; j <= i; ++j) { 59 | str = str_table_get_string(&table, j); 60 | 61 | TEST_NOT_NULL(str); 62 | TEST_ASSERT(str != strings[i]); 63 | TEST_STR_EQUAL(str, strings[j]); 64 | } 65 | 66 | for (; j < 1000; ++j) 67 | TEST_NULL(str_table_get_string(&table, j)); 68 | } 69 | 70 | for (i = 0; i < 1000; ++i) { 71 | TEST_ASSERT(str_table_get_index(&table, strings[i], &idx) == 0); 72 | TEST_EQUAL_UI(idx, i); 73 | 74 | str = str_table_get_string(&table, i); 75 | 76 | TEST_NOT_NULL(str); 77 | TEST_ASSERT(str != strings[i]); 78 | TEST_STR_EQUAL(str, strings[i]); 79 | } 80 | 81 | str_table_cleanup(&table); 82 | 83 | for (i = 0; i < 1000; ++i) 84 | free(strings[i]); 85 | 86 | return EXIT_SUCCESS; 87 | } 88 | -------------------------------------------------------------------------------- /include/util/array.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * array.h 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #ifndef ARRAY_H 8 | #define ARRAY_H 9 | 10 | #include "sqfs/predef.h" 11 | #include "sqfs/error.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | typedef struct { 18 | /* sizeof a single element */ 19 | size_t size; 20 | 21 | /* total number of elements available */ 22 | size_t count; 23 | 24 | /* actually used number of elements available */ 25 | size_t used; 26 | 27 | void *data; 28 | } array_t; 29 | 30 | static SQFS_INLINE void *array_get(array_t *array, size_t index) 31 | { 32 | if (index >= array->used) 33 | return NULL; 34 | 35 | return (char *)array->data + array->size * index; 36 | } 37 | 38 | static SQFS_INLINE int array_set(array_t *array, size_t index, const void *data) 39 | { 40 | if (index >= array->used) 41 | return SQFS_ERROR_OUT_OF_BOUNDS; 42 | 43 | memcpy((char *)array->data + array->size * index, data, array->size); 44 | return 0; 45 | } 46 | 47 | static SQFS_INLINE void array_sort_range(array_t *array, size_t start, 48 | size_t count, 49 | int (*compare_fun)(const void *a, 50 | const void *b)) 51 | { 52 | if (start < array->used) { 53 | if (count > (array->used - start)) 54 | count = array->used - start; 55 | 56 | qsort((char *)array->data + array->size * start, count, 57 | array->size, compare_fun); 58 | } 59 | } 60 | 61 | #ifdef __cplusplus 62 | extern "C" { 63 | #endif 64 | 65 | SQFS_INTERNAL int array_init(array_t *array, size_t size, size_t capacity); 66 | 67 | SQFS_INTERNAL int array_init_copy(array_t *array, const array_t *src); 68 | 69 | SQFS_INTERNAL void array_cleanup(array_t *array); 70 | 71 | SQFS_INTERNAL int array_append(array_t *array, const void *data); 72 | 73 | SQFS_INTERNAL int array_set_capacity(array_t *array, size_t capacity); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif /* ARRAY_H */ 80 | -------------------------------------------------------------------------------- /lib/common/src/compress.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * compress.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compress_cli.h" 9 | 10 | #include 11 | #include 12 | 13 | static int cmp_ids[] = { 14 | SQFS_COMP_XZ, 15 | SQFS_COMP_ZSTD, 16 | SQFS_COMP_GZIP, 17 | SQFS_COMP_LZ4, 18 | SQFS_COMP_LZO, 19 | }; 20 | 21 | SQFS_COMPRESSOR compressor_get_default(void) 22 | { 23 | sqfs_compressor_config_t cfg; 24 | sqfs_compressor_t *temp; 25 | size_t i; 26 | int ret; 27 | 28 | for (i = 0; i < sizeof(cmp_ids) / sizeof(cmp_ids[0]); ++i) { 29 | sqfs_compressor_config_init(&cfg, cmp_ids[i], 30 | SQFS_DEFAULT_BLOCK_SIZE, 0); 31 | 32 | ret = sqfs_compressor_create(&cfg, &temp); 33 | 34 | if (ret == 0) { 35 | sqfs_drop(temp); 36 | return cmp_ids[i]; 37 | } 38 | } 39 | 40 | #ifdef WITH_LZO 41 | return SQFS_COMP_LZO; 42 | #else 43 | assert(0); 44 | #endif 45 | } 46 | 47 | void compressor_print_available(void) 48 | { 49 | sqfs_compressor_config_t cfg; 50 | sqfs_compressor_t *temp; 51 | bool have_compressor; 52 | int i, ret, defcomp; 53 | const char *name; 54 | 55 | defcomp = compressor_get_default(); 56 | 57 | fputs("Available SquashFS block compressors:\n", stdout); 58 | 59 | for (i = SQFS_COMP_MIN; i <= SQFS_COMP_MAX; ++i) { 60 | sqfs_compressor_config_init(&cfg, i, 61 | SQFS_DEFAULT_BLOCK_SIZE, 0); 62 | 63 | ret = sqfs_compressor_create(&cfg, &temp); 64 | have_compressor = false; 65 | 66 | if (ret == 0) { 67 | sqfs_drop(temp); 68 | have_compressor = true; 69 | } else { 70 | #ifdef WITH_LZO 71 | if (i == SQFS_COMP_LZO) 72 | have_compressor = true; 73 | #endif 74 | } 75 | 76 | if (have_compressor) { 77 | name = sqfs_compressor_name_from_id(i); 78 | 79 | if (defcomp == i) { 80 | printf("\t%s (default)\n", name); 81 | } else { 82 | printf("\t%s\n", name); 83 | } 84 | } 85 | } 86 | 87 | fputc('\n', stdout); 88 | } 89 | -------------------------------------------------------------------------------- /lib/tar/test/data/file-size/12-digit.tar: -------------------------------------------------------------------------------- 1 | big-file.bin000644 001750 001750 10000000000013375730126 014134 0ustar00mgornymgorny000000 000000 -------------------------------------------------------------------------------- /lib/tar/test/data/long-paths/ustar.tar: -------------------------------------------------------------------------------- 1 | 012345678901234567890123456789/012345678901234567890123456789/input.txt000644 001750 001750 00000000005 13375567346 033463 0ustar00mgornymgorny000000 000000 012345678901234567890123456789/012345678901234567890123456789/012345678901234567890123456789test 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/format-acceptance/gnu-g.tar: -------------------------------------------------------------------------------- 1 | input.txt0000644000175000017500000000000513375560044014561 0ustar mgornymgorny1337556176213375561750test 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/format-acceptance/gnu.tar: -------------------------------------------------------------------------------- 1 | input.txt0000644000175000017500000000000513375560044012370 0ustar mgornymgornytest 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/format-acceptance/ustar.tar: -------------------------------------------------------------------------------- 1 | input.txt000644 001750 001750 00000000005 13375560044 013650 0ustar00mgornymgorny000000 000000 test 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/format-acceptance/v7.tar: -------------------------------------------------------------------------------- 1 | input.txt000644 001750 001750 00000000005 13375560044 006461 test 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/large-mtime/12-digit.tar: -------------------------------------------------------------------------------- 1 | input.txt000644 001750 001750 00000000005 100000000000013623 0ustar00mgornymgorny000000 000000 test 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/file-size/pax.tar: -------------------------------------------------------------------------------- 1 | ./PaxHeaders.7839/big-file.bin0000644000000000000000000000015513375730126013066 xustar0019 size=8589934592 2 | 30 mtime=1542959190.916897254 3 | 30 atime=1542959522.512018391 4 | 30 ctime=1542959190.916897254 5 | big-file.bin0000644000175000017500000000000013375730126014133 0ustar00mgornymgorny00000000000000 -------------------------------------------------------------------------------- /lib/tar/test/data/user-group-largenum/8-digit.tar: -------------------------------------------------------------------------------- 1 | input.txt000644 400000004000000000000000005 13376036700 011334 0ustar00000000 000000 test 2 | -------------------------------------------------------------------------------- /lib/tar/test/data/format-acceptance/ustar-pre-posix.tar: -------------------------------------------------------------------------------- 1 | input.txt000644 001750 001750 00000000005 13375560044 013610 0ustar mgornymgorny000000 000000 test 2 | -------------------------------------------------------------------------------- /lib/compat/src/w32_wmain.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * w32_wmain.c 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "compat.h" 9 | 10 | #include 11 | #include 12 | 13 | #ifdef _WIN32 14 | #define WIN32_LEAN_AND_MEAN 15 | #include 16 | #include 17 | 18 | #undef main 19 | 20 | int main(int argc, char **argv) 21 | { 22 | WCHAR *cmdline, **argList; 23 | int i, ret, utf8_argc; 24 | char **utf8_argv; 25 | (void)argc; 26 | (void)argv; 27 | 28 | /* get the UTF-16 encoded command line arguments */ 29 | cmdline = GetCommandLineW(); 30 | argList = CommandLineToArgvW(cmdline, &utf8_argc); 31 | if (argList == NULL) 32 | goto fail_oom; 33 | 34 | /* convert to UTF-8 */ 35 | utf8_argv = calloc(sizeof(utf8_argv[0]), utf8_argc); 36 | if (utf8_argv == NULL) 37 | goto fail_oom; 38 | 39 | for (i = 0; i < utf8_argc; ++i) { 40 | DWORD length = WideCharToMultiByte(CP_UTF8, 0, argList[i], 41 | -1, NULL, 0, NULL, NULL); 42 | if (length <= 0) 43 | goto fail_conv; 44 | 45 | utf8_argv[i] = calloc(1, length + 1); 46 | if (utf8_argv[i] == NULL) 47 | goto fail_oom; 48 | 49 | WideCharToMultiByte(CP_UTF8, 0, argList[i], -1, 50 | utf8_argv[i], length + 1, NULL, NULL); 51 | utf8_argv[i][length] = '\0'; 52 | } 53 | 54 | LocalFree(argList); 55 | argList = NULL; 56 | 57 | /* call the actual main function */ 58 | ret = sqfs_tools_main(utf8_argc, utf8_argv); 59 | 60 | /* cleanup */ 61 | for (i = 0; i < utf8_argc; ++i) 62 | free(utf8_argv[i]); 63 | 64 | free(utf8_argv); 65 | return ret; 66 | fail_conv: 67 | w32_perror("Converting UTF-16 argument to UTF-8"); 68 | goto fail; 69 | fail_oom: 70 | fputs("out of memory\n", stderr); 71 | goto fail; 72 | fail: 73 | if (utf8_argv != NULL) { 74 | for (i = 0; i < utf8_argc; ++i) 75 | free(utf8_argv[i]); 76 | free(utf8_argv); 77 | } 78 | if (argList != NULL) { 79 | LocalFree(argList); 80 | } 81 | return EXIT_FAILURE; 82 | } 83 | #endif 84 | -------------------------------------------------------------------------------- /lib/tar/src/read_sparse_map_old.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * read_sparse_map_old.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "internal.h" 9 | 10 | #include 11 | #include 12 | 13 | static int parse(const gnu_old_sparse_t *in, size_t count, 14 | sparse_map_t **head, sparse_map_t **tail) 15 | { 16 | sparse_map_t *node; 17 | sqfs_u64 off, sz; 18 | 19 | while (count--) { 20 | if (!isdigit(in->offset[0]) || !isdigit(in->numbytes[0])) 21 | return 1; 22 | if (read_number(in->offset, sizeof(in->offset), &off)) 23 | return -1; 24 | if (read_number(in->numbytes, sizeof(in->numbytes), &sz)) 25 | return -1; 26 | ++in; 27 | 28 | node = calloc(1, sizeof(*node)); 29 | if (node == NULL) { 30 | perror("parsing GNU sparse header"); 31 | return -1; 32 | } 33 | 34 | node->offset = off; 35 | node->count = sz; 36 | 37 | if ((*head) == NULL) { 38 | (*head) = (*tail) = node; 39 | } else { 40 | (*tail)->next = node; 41 | (*tail) = node; 42 | } 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | sparse_map_t *read_gnu_old_sparse(sqfs_istream_t *fp, tar_header_t *hdr) 49 | { 50 | sparse_map_t *list = NULL, *end = NULL; 51 | gnu_old_sparse_record_t sph; 52 | int ret; 53 | 54 | ret = parse(hdr->tail.gnu.sparse, 4, &list, &end); 55 | if (ret < 0) 56 | goto fail; 57 | 58 | if (ret > 0 || hdr->tail.gnu.isextended == 0) 59 | return list; 60 | 61 | do { 62 | ret = sqfs_istream_read(fp, &sph, sizeof(sph)); 63 | if (ret < 0) { 64 | sqfs_perror(fp->get_filename(fp), 65 | "reading old GNU sparse list", ret); 66 | goto fail; 67 | } 68 | 69 | if ((size_t)ret < sizeof(sph)) 70 | goto fail_eof; 71 | 72 | ret = parse(sph.sparse, 21, &list, &end); 73 | if (ret < 0) 74 | goto fail; 75 | } while (ret == 0 && sph.isextended != 0); 76 | 77 | return list; 78 | fail_eof: 79 | fputs("reading GNU sparse header: unexpected end-of-file\n", stderr); 80 | fail: 81 | free_sparse_list(list); 82 | return NULL; 83 | } 84 | -------------------------------------------------------------------------------- /include/tar/tar.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef TAR_H 8 | #define TAR_H 9 | 10 | #include "config.h" 11 | #include "compat.h" 12 | #include "sqfs/io.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | typedef struct sparse_map_t { 19 | struct sparse_map_t *next; 20 | sqfs_u64 offset; 21 | sqfs_u64 count; 22 | } sparse_map_t; 23 | 24 | typedef struct { 25 | char *name; 26 | char *link_target; 27 | sparse_map_t *sparse; 28 | sqfs_u64 actual_size; 29 | sqfs_u64 record_size; 30 | bool unknown_record; 31 | bool is_hard_link; 32 | sqfs_xattr_t *xattr; 33 | 34 | sqfs_u16 mode; 35 | sqfs_u64 uid; 36 | sqfs_u64 gid; 37 | sqfs_u64 devno; 38 | sqfs_s64 mtime; 39 | } tar_header_decoded_t; 40 | 41 | typedef struct { 42 | char **excludedirs; 43 | size_t num_excludedirs; 44 | } tar_iterator_opts; 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | /* 51 | Returns < 0 on failure, > 0 if cannot encode, 0 on success. 52 | Prints error/warning messages to stderr. 53 | 54 | The counter is an incremental record counter used if additional 55 | headers need to be generated. 56 | */ 57 | int write_tar_header(sqfs_ostream_t *fp, const sqfs_dir_entry_t *ent, 58 | const char *link_target, const sqfs_xattr_t *xattr, 59 | unsigned int counter); 60 | 61 | /* round up to block size and skip the entire entry */ 62 | int read_header(sqfs_istream_t *fp, tar_header_decoded_t *out); 63 | 64 | void clear_header(tar_header_decoded_t *hdr); 65 | 66 | sqfs_dir_iterator_t *tar_open_stream(sqfs_istream_t *stream, 67 | tar_iterator_opts *opts); 68 | 69 | /* 70 | Write zero bytes to an output file to padd it to the tar record size. 71 | Returns 0 on success. On failure, prints error message to stderr. 72 | */ 73 | int padd_file(sqfs_ostream_t *fp, sqfs_u64 size); 74 | 75 | void free_sparse_list(sparse_map_t *sparse); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif /* TAR_H */ 82 | -------------------------------------------------------------------------------- /bin/rdsquashfs/src/rdsquashfs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * rdsquashfs.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef RDSQUASHFS_H 8 | #define RDSQUASHFS_H 9 | 10 | #include "config.h" 11 | #include "common.h" 12 | #include "util/util.h" 13 | #include "sqfs/xattr.h" 14 | 15 | #ifdef _WIN32 16 | #define WIN32_LEAN_AND_MEAN 17 | #include 18 | #endif 19 | #ifdef HAVE_SYS_XATTR_H 20 | #include 21 | 22 | #if defined(__APPLE__) && defined(__MACH__) 23 | #define lsetxattr(path, name, value, size, flags) \ 24 | setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW) 25 | #endif 26 | #endif 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | enum UNPACK_FLAGS { 37 | UNPACK_CHMOD = 0x01, 38 | UNPACK_CHOWN = 0x02, 39 | UNPACK_QUIET = 0x04, 40 | UNPACK_NO_SPARSE = 0x08, 41 | UNPACK_SET_XATTR = 0x10, 42 | UNPACK_SET_TIMES = 0x20, 43 | }; 44 | 45 | enum { 46 | OP_NONE = 0, 47 | OP_LS, 48 | OP_CAT, 49 | OP_UNPACK, 50 | OP_DESCRIBE, 51 | OP_RDATTR, 52 | OP_STAT, 53 | }; 54 | 55 | typedef struct { 56 | int op; 57 | int rdtree_flags; 58 | int flags; 59 | char *cmdpath; 60 | const char *unpack_root; 61 | const char *image_name; 62 | } options_t; 63 | 64 | void list_files(const sqfs_tree_node_t *node); 65 | 66 | int stat_file(const sqfs_tree_node_t *node); 67 | 68 | int restore_fstree(sqfs_tree_node_t *root, int flags); 69 | 70 | int update_tree_attribs(sqfs_xattr_reader_t *xattr, 71 | const sqfs_tree_node_t *root, int flags); 72 | 73 | int fill_unpacked_files(size_t blk_sz, const sqfs_tree_node_t *root, 74 | sqfs_data_reader_t *data, int flags); 75 | 76 | int describe_tree(const sqfs_tree_node_t *root, const char *unpack_root); 77 | 78 | int dump_xattrs(sqfs_xattr_reader_t *xattr, const sqfs_inode_generic_t *inode); 79 | 80 | void process_command_line(options_t *opt, int argc, char **argv); 81 | 82 | #endif /* RDSQUASHFS_H */ 83 | -------------------------------------------------------------------------------- /include/util/str_table.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * str_table.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef STR_TABLE_H 8 | #define STR_TABLE_H 9 | 10 | #include "sqfs/predef.h" 11 | #include "array.h" 12 | #include "hash_table.h" 13 | 14 | typedef struct { 15 | size_t index; 16 | size_t refcount; 17 | char string[]; 18 | } str_bucket_t; 19 | 20 | /* Stores strings in a hash table and assigns an incremental, unique ID to 21 | each string. Subsequent additions return the existing ID. The ID can be 22 | used for (hopefully) constant time lookup of the original string. */ 23 | typedef struct { 24 | /* an array that resolves index to bucket pointer */ 25 | array_t bucket_ptrs; 26 | 27 | /* hash table with the string buckets attached */ 28 | struct hash_table *ht; 29 | 30 | /* the next ID we are going to allocate */ 31 | size_t next_index; 32 | } str_table_t; 33 | 34 | /* the number of strings currently stored in the table */ 35 | static SQFS_INLINE size_t str_table_count(const str_table_t *table) 36 | { 37 | return table->next_index; 38 | } 39 | 40 | /* `size` is the number of hash table buckets to use internally. */ 41 | SQFS_INTERNAL int str_table_init(str_table_t *table); 42 | 43 | SQFS_INTERNAL void str_table_cleanup(str_table_t *table); 44 | 45 | SQFS_INTERNAL int str_table_copy(str_table_t *dst, const str_table_t *src); 46 | 47 | /* Resolve a string to an incremental, unique ID. */ 48 | SQFS_INTERNAL 49 | int str_table_get_index(str_table_t *table, const char *str, size_t *idx); 50 | 51 | /* Resolve a unique ID to the string it represents. 52 | Returns NULL if the ID is unknown, i.e. out of bounds. */ 53 | SQFS_INTERNAL 54 | const char *str_table_get_string(const str_table_t *table, size_t index); 55 | 56 | SQFS_INTERNAL void str_table_add_ref(str_table_t *table, size_t index); 57 | 58 | SQFS_INTERNAL void str_table_del_ref(str_table_t *table, size_t index); 59 | 60 | SQFS_INTERNAL 61 | size_t str_table_get_ref_count(const str_table_t *table, size_t index); 62 | 63 | #endif /* STR_TABLE_H */ 64 | -------------------------------------------------------------------------------- /lib/util/test/canonicalize_name.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * canonicalize_name.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | #include "util/test.h" 10 | 11 | static const struct { 12 | const char *in; 13 | const char *out; 14 | } must_work[] = { 15 | { "", "" }, 16 | { "/", "" }, 17 | { "\\", "\\" }, 18 | { "///", "" }, 19 | { "\\\\\\", "\\\\\\" }, 20 | { "/\\//\\\\/", "\\/\\\\" }, 21 | { "foo/bar/test", "foo/bar/test" }, 22 | { "foo\\bar\\test", "foo\\bar\\test" }, 23 | { "/foo/bar/test/", "foo/bar/test" }, 24 | { "\\foo\\bar\\test\\", "\\foo\\bar\\test\\" }, 25 | { "///foo//bar//test///", "foo/bar/test" }, 26 | { "./foo/././bar/test/./.", "foo/bar/test" }, 27 | { "./foo/././", "foo" }, 28 | { ".", "" }, 29 | { "./", "" }, 30 | { "./.", "" }, 31 | { "foo/.../bar", "foo/.../bar" }, 32 | { "foo/.test/bar", "foo/.test/bar" }, 33 | }; 34 | 35 | static const char *must_not_work[] = { 36 | "..", 37 | "foo/../bar", 38 | "../foo/bar", 39 | "foo/bar/..", 40 | "foo/bar/../", 41 | }; 42 | 43 | int main(int argc, char **argv) 44 | { 45 | char buffer[512]; 46 | size_t i; 47 | (void)argc; (void)argv; 48 | 49 | for (i = 0; i < sizeof(must_work) / sizeof(must_work[0]); ++i) { 50 | strcpy(buffer, must_work[i].in); 51 | 52 | if (canonicalize_name(buffer)) { 53 | fprintf(stderr, "Test case rejected: '%s'\n", 54 | must_work[i].in); 55 | return EXIT_FAILURE; 56 | } 57 | 58 | if (strcmp(buffer, must_work[i].out) != 0) { 59 | fprintf(stderr, "Expected result: %s\n", 60 | must_work[i].out); 61 | fprintf(stderr, "Actual result: %s\n", buffer); 62 | return EXIT_FAILURE; 63 | } 64 | } 65 | 66 | for (i = 0; i < sizeof(must_not_work) / sizeof(must_not_work[0]); ++i) { 67 | strcpy(buffer, must_not_work[i]); 68 | 69 | if (canonicalize_name(buffer) == 0) { 70 | fprintf(stderr, "Test case accepted: '%s'\n", 71 | must_not_work[i]); 72 | fprintf(stderr, "Transformed into: '%s'\n", buffer); 73 | return EXIT_FAILURE; 74 | } 75 | } 76 | 77 | return EXIT_SUCCESS; 78 | } 79 | -------------------------------------------------------------------------------- /lib/sqfs/src/io/stream_api.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * stream_api.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/io.h" 11 | 12 | #include 13 | 14 | sqfs_s32 sqfs_istream_read(sqfs_istream_t *strm, void *data, size_t size) 15 | { 16 | sqfs_s32 total = 0; 17 | 18 | if (size > 0x7FFFFFFF) 19 | size = 0x7FFFFFFF; 20 | 21 | while (size > 0) { 22 | const sqfs_u8 *ptr; 23 | size_t diff; 24 | int ret; 25 | 26 | ret = strm->get_buffered_data(strm, &ptr, &diff, size); 27 | if (ret > 0) 28 | break; 29 | if (ret < 0) 30 | return ret; 31 | 32 | if (diff > size) 33 | diff = size; 34 | 35 | memcpy(data, ptr, diff); 36 | strm->advance_buffer(strm, diff); 37 | data = (char *)data + diff; 38 | size -= diff; 39 | total += diff; 40 | } 41 | 42 | return total; 43 | } 44 | 45 | int sqfs_istream_skip(sqfs_istream_t *strm, sqfs_u64 size) 46 | { 47 | while (size > 0) { 48 | const sqfs_u8 *ptr; 49 | size_t diff; 50 | int ret; 51 | 52 | ret = strm->get_buffered_data(strm, &ptr, &diff, size); 53 | if (ret < 0) 54 | return ret; 55 | if (ret > 0) 56 | break; 57 | 58 | if ((sqfs_u64)diff > size) 59 | diff = size; 60 | 61 | size -= diff; 62 | strm->advance_buffer(strm, diff); 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | sqfs_s32 sqfs_istream_splice(sqfs_istream_t *in, sqfs_ostream_t *out, 69 | sqfs_u32 size) 70 | { 71 | sqfs_s32 total = 0; 72 | 73 | if (size > 0x7FFFFFFF) 74 | size = 0x7FFFFFFF; 75 | 76 | while (size > 0) { 77 | const sqfs_u8 *ptr; 78 | size_t diff; 79 | int ret; 80 | 81 | ret = in->get_buffered_data(in, &ptr, &diff, size); 82 | if (ret < 0) 83 | return ret; 84 | if (ret > 0) 85 | break; 86 | 87 | if (diff > size) 88 | diff = size; 89 | 90 | ret = out->append(out, ptr, diff); 91 | if (ret) 92 | return ret; 93 | 94 | total += diff; 95 | size -= diff; 96 | in->advance_buffer(in, diff); 97 | } 98 | 99 | return total; 100 | } 101 | -------------------------------------------------------------------------------- /lib/sqfs/src/read_table.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * read_table.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/meta_reader.h" 11 | #include "sqfs/error.h" 12 | #include "sqfs/table.h" 13 | #include "sqfs/block.h" 14 | #include "sqfs/io.h" 15 | #include "util/util.h" 16 | 17 | #include 18 | 19 | int sqfs_read_table(sqfs_file_t *file, sqfs_compressor_t *cmp, 20 | size_t table_size, sqfs_u64 location, sqfs_u64 lower_limit, 21 | sqfs_u64 upper_limit, void **out) 22 | { 23 | size_t diff, block_count, blk_idx = 0; 24 | sqfs_u64 start, *locations; 25 | sqfs_meta_reader_t *m; 26 | void *data, *ptr; 27 | int err; 28 | 29 | data = malloc(table_size); 30 | if (data == NULL) 31 | return SQFS_ERROR_ALLOC; 32 | 33 | /* restore list from image */ 34 | block_count = table_size / SQFS_META_BLOCK_SIZE; 35 | 36 | if ((table_size % SQFS_META_BLOCK_SIZE) != 0) 37 | ++block_count; 38 | 39 | locations = alloc_array(sizeof(sqfs_u64), block_count); 40 | 41 | if (locations == NULL) { 42 | err = SQFS_ERROR_ALLOC; 43 | goto fail_data; 44 | } 45 | 46 | err = file->read_at(file, location, locations, 47 | sizeof(sqfs_u64) * block_count); 48 | if (err) 49 | goto fail_idx; 50 | 51 | /* Read the actual data */ 52 | m = sqfs_meta_reader_create(file, cmp, lower_limit, upper_limit); 53 | if (m == NULL) { 54 | err = SQFS_ERROR_ALLOC; 55 | goto fail_idx; 56 | } 57 | 58 | ptr = data; 59 | 60 | while (table_size > 0) { 61 | start = le64toh(locations[blk_idx++]); 62 | 63 | err = sqfs_meta_reader_seek(m, start, 0); 64 | if (err) 65 | goto fail; 66 | 67 | diff = SQFS_META_BLOCK_SIZE; 68 | if (diff > table_size) 69 | diff = table_size; 70 | 71 | err = sqfs_meta_reader_read(m, ptr, diff); 72 | if (err) 73 | goto fail; 74 | 75 | ptr = (char *)ptr + diff; 76 | table_size -= diff; 77 | } 78 | 79 | sqfs_drop(m); 80 | free(locations); 81 | *out = data; 82 | return 0; 83 | fail: 84 | sqfs_drop(m); 85 | fail_idx: 86 | free(locations); 87 | fail_data: 88 | free(data); 89 | *out = NULL; 90 | return err; 91 | } 92 | -------------------------------------------------------------------------------- /lib/compat/src/getopt.c: -------------------------------------------------------------------------------- 1 | #include "compat.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef HAVE_GETOPT 9 | char *optarg; 10 | int optind=1, opterr=1, optopt, optpos, optreset=0; 11 | 12 | void __getopt_msg(const char *a, const char *b, const char *c, size_t l) 13 | { 14 | fputs(a, stderr); 15 | fwrite(b, strlen(b), 1, stderr); 16 | fwrite(c, 1, l, stderr); 17 | putc('\n', stderr); 18 | } 19 | 20 | int getopt(int argc, char * const argv[], const char *optstring) 21 | { 22 | int i; 23 | wchar_t c, d; 24 | int k, l; 25 | char *optchar; 26 | 27 | if (!optind || __optreset) { 28 | optreset = 0; 29 | optpos = 0; 30 | optind = 1; 31 | } 32 | 33 | if (optind >= argc || !argv[optind]) 34 | return -1; 35 | 36 | if (argv[optind][0] != '-') { 37 | if (optstring[0] == '-') { 38 | optarg = argv[optind++]; 39 | return 1; 40 | } 41 | return -1; 42 | } 43 | 44 | if (!argv[optind][1]) 45 | return -1; 46 | 47 | if (argv[optind][1] == '-' && !argv[optind][2]) 48 | return optind++, -1; 49 | 50 | if (!optpos) optpos++; 51 | if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) { 52 | k = 1; 53 | c = 0xfffd; /* replacement char */ 54 | } 55 | optchar = argv[optind]+optpos; 56 | optpos += k; 57 | 58 | if (!argv[optind][optpos]) { 59 | optind++; 60 | optpos = 0; 61 | } 62 | 63 | if (optstring[0] == '-' || optstring[0] == '+') 64 | optstring++; 65 | 66 | i = 0; 67 | d = 0; 68 | do { 69 | l = mbtowc(&d, optstring+i, MB_LEN_MAX); 70 | if (l>0) i+=l; else i++; 71 | } while (l && d != c); 72 | 73 | if (d != c || c == ':') { 74 | optopt = c; 75 | if (optstring[0] != ':' && opterr) 76 | __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); 77 | return '?'; 78 | } 79 | if (optstring[i] == ':') { 80 | optarg = 0; 81 | if (optstring[i+1] != ':' || optpos) { 82 | optarg = argv[optind++] + optpos; 83 | optpos = 0; 84 | } 85 | if (optind > argc) { 86 | optopt = c; 87 | if (optstring[0] == ':') return ':'; 88 | if (opterr) __getopt_msg(argv[0], 89 | ": option requires an argument: ", 90 | optchar, k); 91 | return '?'; 92 | } 93 | } 94 | return c; 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /lib/fstree/test/mknode_dir.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * mknode_dir.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "fstree.h" 10 | #include "util/test.h" 11 | 12 | static sqfs_dir_entry_t *mkentry(const char *name) 13 | { 14 | sqfs_dir_entry_t *ent = sqfs_dir_entry_create(name, S_IFDIR | 0654, 0); 15 | TEST_NOT_NULL(ent); 16 | ent->uid = 123; 17 | ent->gid = 456; 18 | ent->rdev = 789; 19 | ent->size = 4096; 20 | return ent; 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | fstree_defaults_t defaults; 26 | tree_node_t *root, *a, *b; 27 | sqfs_dir_entry_t *ent; 28 | fstree_t fs; 29 | int ret; 30 | (void)argc; (void)argv; 31 | 32 | memset(&defaults, 0, sizeof(defaults)); 33 | ret = fstree_init(&fs, &defaults); 34 | TEST_EQUAL_I(ret, 0); 35 | 36 | ent = mkentry("rootdir"); 37 | root = fstree_add_generic(&fs, ent, NULL); 38 | free(ent); 39 | TEST_NOT_NULL(root); 40 | TEST_ASSERT(root->parent == fs.root); 41 | TEST_EQUAL_UI(root->uid, 123); 42 | TEST_EQUAL_UI(root->gid, 456); 43 | TEST_EQUAL_UI(root->mode, (S_IFDIR | 0654)); 44 | TEST_EQUAL_UI(root->link_count, 2); 45 | TEST_ASSERT(root->name >= (char *)root->payload); 46 | TEST_STR_EQUAL(root->name, "rootdir"); 47 | TEST_NULL(root->data.children); 48 | TEST_NULL(root->next); 49 | 50 | ent = mkentry("rootdir/adir"); 51 | a = fstree_add_generic(&fs, ent, NULL); 52 | free(ent); 53 | TEST_NOT_NULL(a); 54 | TEST_ASSERT(a->parent == root); 55 | TEST_NULL(a->next); 56 | TEST_EQUAL_UI(a->link_count, 2); 57 | TEST_EQUAL_UI(root->link_count, 3); 58 | TEST_ASSERT(root->data.children == a); 59 | TEST_ASSERT(root->parent == fs.root); 60 | TEST_NULL(root->next); 61 | 62 | ent = mkentry("rootdir/bdir"); 63 | b = fstree_add_generic(&fs, ent, NULL); 64 | free(ent); 65 | TEST_NOT_NULL(b); 66 | TEST_ASSERT(a->parent == root); 67 | TEST_ASSERT(b->parent == root); 68 | TEST_EQUAL_UI(b->link_count, 2); 69 | TEST_ASSERT(root->data.children == a); 70 | TEST_ASSERT(a->next == b); 71 | TEST_EQUAL_UI(root->link_count, 4); 72 | TEST_NULL(b->next); 73 | TEST_ASSERT(root->parent == fs.root); 74 | TEST_NULL(root->next); 75 | 76 | fstree_cleanup(&fs); 77 | return EXIT_SUCCESS; 78 | } 79 | -------------------------------------------------------------------------------- /lib/sqfs/test/istream_skip.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * istream_skip.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "sqfs/io.h" 10 | #include "util/test.h" 11 | #include "common.h" 12 | 13 | static const sqfs_u64 end0 = 449; /* region 1: filled with 'A' */ 14 | static const sqfs_u64 end1 = 521; /* region 2: filled with 'B' */ 15 | static const sqfs_u64 end2 = 941; /* region 3: filled with 'C' */ 16 | 17 | static sqfs_u8 rd_buffer[941]; 18 | 19 | static sqfs_u8 byte_at_offset(sqfs_u64 off) 20 | { 21 | if (off < end0) 22 | return 'A'; 23 | if (off < end1) 24 | return 'B'; 25 | return 'C'; 26 | } 27 | 28 | static void init_rd_buffer(void) 29 | { 30 | for (size_t i = 0; i < end2; ++i) 31 | rd_buffer[i] = byte_at_offset(i); 32 | } 33 | 34 | int main(int argc, char **argv) 35 | { 36 | sqfs_u8 read_buffer[61]; 37 | sqfs_u64 read_off = 0; 38 | sqfs_istream_t *dummy; 39 | (void)argc; (void)argv; 40 | 41 | init_rd_buffer(); 42 | dummy = istream_memory_create("dummy file", 103, 43 | rd_buffer, sizeof(rd_buffer)); 44 | TEST_NOT_NULL(dummy); 45 | 46 | /* region 1 */ 47 | while (read_off < end0) { 48 | size_t read_diff = end0 - read_off; 49 | 50 | if (read_diff > sizeof(read_buffer)) 51 | read_diff = sizeof(read_buffer); 52 | 53 | int ret = sqfs_istream_read(dummy, read_buffer, read_diff); 54 | TEST_ASSERT(ret > 0); 55 | TEST_ASSERT((size_t)ret <= read_diff); 56 | 57 | for (int i = 0; i < ret; ++i) { 58 | TEST_EQUAL_UI(read_buffer[i], 'A'); 59 | } 60 | 61 | read_off += ret; 62 | } 63 | 64 | /* region 2 */ 65 | { 66 | int ret = sqfs_istream_skip(dummy, end2 - end1); 67 | TEST_EQUAL_I(ret, 0); 68 | read_off += (end2 - end1); 69 | } 70 | 71 | /* region 3 */ 72 | for (;;) { 73 | size_t read_diff = sizeof(read_buffer); 74 | 75 | int ret = sqfs_istream_read(dummy, read_buffer, read_diff); 76 | TEST_ASSERT(ret >= 0); 77 | TEST_ASSERT((size_t)ret <= read_diff); 78 | 79 | if (ret == 0) { 80 | TEST_EQUAL_UI(read_off, end2); 81 | break; 82 | } 83 | 84 | for (int i = 0; i < ret; ++i) { 85 | TEST_EQUAL_UI(read_buffer[i], 'C'); 86 | } 87 | 88 | read_off += ret; 89 | TEST_ASSERT(read_off <= end2); 90 | } 91 | 92 | sqfs_drop(dummy); 93 | return EXIT_SUCCESS; 94 | } 95 | -------------------------------------------------------------------------------- /lib/common/src/dir_tree.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * dir_tree.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "common.h" 8 | 9 | #include 10 | #include 11 | 12 | void sqfs_dir_tree_destroy(sqfs_tree_node_t *root) 13 | { 14 | sqfs_tree_node_t *it; 15 | 16 | if (!root) 17 | return; 18 | 19 | while (root->children != NULL) { 20 | it = root->children; 21 | root->children = it->next; 22 | 23 | sqfs_dir_tree_destroy(it); 24 | } 25 | 26 | free(root->inode); 27 | free(root); 28 | } 29 | 30 | int sqfs_tree_node_get_path(const sqfs_tree_node_t *node, char **out) 31 | { 32 | const sqfs_tree_node_t *it; 33 | size_t clen, len = 0; 34 | char *str, *ptr; 35 | 36 | *out = NULL; 37 | 38 | if (node == NULL) 39 | return SQFS_ERROR_ARG_INVALID; 40 | 41 | for (it = node; it->parent != NULL; it = it->parent) { 42 | if (it->parent == node) 43 | return SQFS_ERROR_LINK_LOOP; 44 | 45 | /* non-root nodes must have a valid name */ 46 | clen = strlen((const char *)it->name); 47 | 48 | if (clen == 0) 49 | return SQFS_ERROR_CORRUPTED; 50 | 51 | if (strchr((const char *)it->name, '/') != NULL) 52 | return SQFS_ERROR_CORRUPTED; 53 | 54 | if (it->name[0] == '.') { 55 | if (clen == 1 || (clen == 2 && it->name[1] == '.')) 56 | return SQFS_ERROR_CORRUPTED; 57 | } 58 | 59 | /* compute total path length */ 60 | if (SZ_ADD_OV(clen, 1, &clen)) 61 | return SQFS_ERROR_OVERFLOW; 62 | 63 | if (SZ_ADD_OV(len, clen, &len)) 64 | return SQFS_ERROR_OVERFLOW; 65 | } 66 | 67 | /* root node must not have a name */ 68 | if (it->name[0] != '\0') 69 | return SQFS_ERROR_ARG_INVALID; 70 | 71 | /* generate the path */ 72 | if (node->parent == NULL) { 73 | str = strdup("/"); 74 | if (str == NULL) 75 | return SQFS_ERROR_ALLOC; 76 | } else { 77 | if (SZ_ADD_OV(len, 1, &len)) 78 | return SQFS_ERROR_OVERFLOW; 79 | 80 | str = malloc(len); 81 | if (str == NULL) 82 | return SQFS_ERROR_ALLOC; 83 | 84 | ptr = str + len - 1; 85 | *ptr = '\0'; 86 | 87 | for (it = node; it->parent != NULL; it = it->parent) { 88 | len = strlen((const char *)it->name); 89 | ptr -= len; 90 | 91 | memcpy(ptr, (const char *)it->name, len); 92 | *(--ptr) = '/'; 93 | } 94 | } 95 | 96 | *out = str; 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /lib/sqfs/test/stream_splice.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * stream_splice.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/test.h" 10 | #include "sqfs/io.h" 11 | #include "common.h" 12 | 13 | static const sqfs_u64 end0 = 449; /* region 1: filled with 'A' */ 14 | static const sqfs_u64 end1 = 521; /* region 2: filled with 'B' */ 15 | static const sqfs_u64 end2 = 941; /* region 3: filled with 'C' */ 16 | 17 | static sqfs_u8 rd_buffer[941]; 18 | 19 | static sqfs_u8 byte_at_offset(sqfs_u64 off) 20 | { 21 | if (off < end0) 22 | return 'A'; 23 | if (off < end1) 24 | return 'B'; 25 | return 'C'; 26 | } 27 | 28 | static void init_rd_buffer(void) 29 | { 30 | for (size_t i = 0; i < end2; ++i) 31 | rd_buffer[i] = byte_at_offset(i); 32 | } 33 | 34 | /*****************************************************************************/ 35 | 36 | static int out_append(sqfs_ostream_t *strm, const void *data, size_t size); 37 | 38 | static sqfs_u64 out_offset = 0; 39 | 40 | static sqfs_ostream_t out = { 41 | { 1, NULL, NULL }, 42 | out_append, 43 | NULL, 44 | NULL, 45 | }; 46 | 47 | static int out_append(sqfs_ostream_t *strm, const void *data, size_t size) 48 | { 49 | const sqfs_u8 *ptr = data; 50 | 51 | TEST_ASSERT(strm == &out); 52 | TEST_ASSERT(size > 0); 53 | 54 | while (size--) { 55 | sqfs_u8 x = *(ptr++); 56 | sqfs_u8 y = byte_at_offset(out_offset++); 57 | 58 | TEST_EQUAL_UI(x, y); 59 | TEST_ASSERT(out_offset <= end2); 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | /*****************************************************************************/ 66 | 67 | int main(int argc, char **argv) 68 | { 69 | sqfs_u64 total = 0; 70 | sqfs_istream_t *in; 71 | sqfs_s32 ret; 72 | (void)argc; (void)argv; 73 | 74 | init_rd_buffer(); 75 | in = istream_memory_create("memory_in", 109, 76 | rd_buffer, sizeof(rd_buffer)); 77 | TEST_NOT_NULL(in); 78 | 79 | for (;;) { 80 | ret = sqfs_istream_splice(in, &out, 211); 81 | TEST_ASSERT(ret >= 0); 82 | 83 | if (ret == 0) 84 | break; 85 | 86 | total += ret; 87 | TEST_ASSERT(total <= end2); 88 | TEST_ASSERT(out_offset <= end2); 89 | TEST_EQUAL_UI(total, out_offset); 90 | } 91 | 92 | TEST_EQUAL_UI(total, end2); 93 | TEST_EQUAL_UI(out_offset, end2); 94 | sqfs_drop(in); 95 | return EXIT_SUCCESS; 96 | } 97 | -------------------------------------------------------------------------------- /bin/sqfsdiff/src/compare_dir.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * compare_dir.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "sqfsdiff.h" 8 | 9 | static int print_omitted(sqfsdiff_t *sd, bool is_old, sqfs_tree_node_t *n) 10 | { 11 | char *path = node_path(n); 12 | 13 | if (path == NULL) 14 | return -1; 15 | 16 | fprintf(stdout, "%c %s\n", is_old ? '<' : '>', path); 17 | 18 | if ((sd->compare_flags & COMPARE_EXTRACT_FILES) && 19 | S_ISREG(n->inode->base.mode)) { 20 | if (extract_files(sd, is_old ? n->inode : NULL, 21 | is_old ? NULL : n->inode, path)) { 22 | free(path); 23 | return -1; 24 | } 25 | } 26 | 27 | free(path); 28 | 29 | for (n = n->children; n != NULL; n = n->next) { 30 | if (print_omitted(sd, is_old, n)) 31 | return -1; 32 | } 33 | 34 | return 0; 35 | } 36 | 37 | int compare_dir_entries(sqfsdiff_t *sd, sqfs_tree_node_t *old, 38 | sqfs_tree_node_t *new) 39 | { 40 | sqfs_tree_node_t *old_it = old->children, *old_prev = NULL; 41 | sqfs_tree_node_t *new_it = new->children, *new_prev = NULL; 42 | int ret, result = 0; 43 | 44 | while (old_it != NULL || new_it != NULL) { 45 | if (old_it != NULL && new_it != NULL) { 46 | ret = strcmp((const char *)old_it->name, 47 | (const char *)new_it->name); 48 | } else if (old_it == NULL) { 49 | ret = 1; 50 | } else { 51 | ret = -1; 52 | } 53 | 54 | if (ret < 0) { 55 | result = 1; 56 | 57 | if (print_omitted(sd, true, old_it)) 58 | return -1; 59 | 60 | if (old_prev == NULL) { 61 | old->children = old_it->next; 62 | sqfs_dir_tree_destroy(old_it); 63 | old_it = old->children; 64 | } else { 65 | old_prev->next = old_it->next; 66 | sqfs_dir_tree_destroy(old_it); 67 | old_it = old_prev->next; 68 | } 69 | } else if (ret > 0) { 70 | result = 1; 71 | 72 | if (print_omitted(sd, false, new_it)) 73 | return -1; 74 | 75 | if (new_prev == NULL) { 76 | new->children = new_it->next; 77 | sqfs_dir_tree_destroy(new_it); 78 | new_it = new->children; 79 | } else { 80 | new_prev->next = new_it->next; 81 | sqfs_dir_tree_destroy(new_it); 82 | new_it = new_prev->next; 83 | } 84 | } else { 85 | old_prev = old_it; 86 | old_it = old_it->next; 87 | 88 | new_prev = new_it; 89 | new_it = new_it->next; 90 | } 91 | } 92 | 93 | return result; 94 | } 95 | -------------------------------------------------------------------------------- /include/tar/format.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * format.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef TAR_FORMAT_H 8 | #define TAR_FORMAT_H 9 | 10 | #include "sqfs/predef.h" 11 | 12 | typedef struct { 13 | char offset[12]; 14 | char numbytes[12]; 15 | } gnu_old_sparse_t; 16 | 17 | typedef struct { 18 | gnu_old_sparse_t sparse[21]; 19 | char isextended; 20 | char padding[7]; 21 | } gnu_old_sparse_record_t; 22 | 23 | typedef struct { 24 | char name[100]; 25 | char mode[8]; 26 | char uid[8]; 27 | char gid[8]; 28 | char size[12]; 29 | char mtime[12]; 30 | char chksum[8]; 31 | char typeflag; 32 | char linkname[100]; 33 | char magic[6]; 34 | char version[2]; 35 | char uname[32]; 36 | char gname[32]; 37 | char devmajor[8]; 38 | char devminor[8]; 39 | union { 40 | struct { 41 | char prefix[155]; 42 | char padding[12]; 43 | } posix; 44 | 45 | struct { 46 | char atime[12]; 47 | char ctime[12]; 48 | char offset[12]; 49 | char deprecated[4]; 50 | char unused; 51 | gnu_old_sparse_t sparse[4]; 52 | char isextended; 53 | char realsize[12]; 54 | char padding[17]; 55 | } gnu; 56 | } tail; 57 | } tar_header_t; 58 | 59 | #define TAR_TYPE_FILE '0' 60 | #define TAR_TYPE_LINK '1' 61 | #define TAR_TYPE_SLINK '2' 62 | #define TAR_TYPE_CHARDEV '3' 63 | #define TAR_TYPE_BLOCKDEV '4' 64 | #define TAR_TYPE_DIR '5' 65 | #define TAR_TYPE_FIFO '6' 66 | 67 | #define TAR_TYPE_GNU_SLINK 'K' 68 | #define TAR_TYPE_GNU_PATH 'L' 69 | #define TAR_TYPE_GNU_SPARSE 'S' 70 | 71 | #define TAR_TYPE_PAX 'x' 72 | #define TAR_TYPE_PAX_GLOBAL 'g' 73 | 74 | #define TAR_MAGIC "ustar" 75 | #define TAR_VERSION "00" 76 | 77 | #define TAR_MAGIC_OLD "ustar " 78 | #define TAR_VERSION_OLD " " 79 | 80 | #define TAR_RECORD_SIZE (512) 81 | 82 | /* artificially imposed implementation limits */ 83 | #define TAR_MAX_SYMLINK_LEN (65536) 84 | #define TAR_MAX_PATH_LEN (65536) 85 | #define TAR_MAX_PAX_LEN (65536) 86 | #define TAR_MAX_SPARSE_ENT (65536) 87 | 88 | #ifdef __cplusplus 89 | extern "C" { 90 | #endif 91 | 92 | int read_number(const char *str, int digits, sqfs_u64 *out); 93 | 94 | unsigned int tar_compute_checksum(const tar_header_t *hdr); 95 | 96 | #ifdef __cplusplus 97 | } 98 | #endif 99 | 100 | #endif /* TAR_FORMAT_H */ 101 | -------------------------------------------------------------------------------- /include/simple_writer.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * simple_writer.h 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #ifndef SIMPLE_WRITER_H 8 | #define SIMPLE_WRITER_H 9 | 10 | #include "config.h" 11 | 12 | #include "sqfs/block_processor.h" 13 | #include "sqfs/block_writer.h" 14 | #include "sqfs/xattr_writer.h" 15 | #include "sqfs/meta_writer.h" 16 | #include "sqfs/frag_table.h" 17 | #include "sqfs/dir_writer.h" 18 | #include "sqfs/compressor.h" 19 | #include "sqfs/id_table.h" 20 | #include "sqfs/error.h" 21 | #include "sqfs/io.h" 22 | 23 | #include "fstree.h" 24 | 25 | typedef struct { 26 | const char *filename; 27 | sqfs_block_writer_t *blkwr; 28 | sqfs_frag_table_t *fragtbl; 29 | sqfs_block_processor_t *data; 30 | sqfs_dir_writer_t *dirwr; 31 | sqfs_meta_writer_t *dm; 32 | sqfs_meta_writer_t *im; 33 | sqfs_compressor_t *cmp; 34 | sqfs_compressor_t *uncmp; 35 | sqfs_id_table_t *idtbl; 36 | sqfs_file_t *outfile; 37 | sqfs_super_t super; 38 | fstree_t fs; 39 | sqfs_xattr_writer_t *xwr; 40 | } sqfs_writer_t; 41 | 42 | typedef struct { 43 | const char *filename; 44 | char *fs_defaults; 45 | char *comp_extra; 46 | size_t block_size; 47 | size_t devblksize; 48 | size_t max_backlog; 49 | size_t num_jobs; 50 | 51 | int outmode; 52 | SQFS_COMPRESSOR comp_id; 53 | 54 | bool exportable; 55 | bool no_xattr; 56 | bool quiet; 57 | } sqfs_writer_cfg_t; 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | void sqfs_writer_cfg_init(sqfs_writer_cfg_t *cfg); 64 | 65 | int sqfs_writer_init(sqfs_writer_t *sqfs, const sqfs_writer_cfg_t *wrcfg); 66 | 67 | int sqfs_writer_finish(sqfs_writer_t *sqfs, const sqfs_writer_cfg_t *cfg); 68 | 69 | void sqfs_writer_cleanup(sqfs_writer_t *sqfs, int status); 70 | 71 | /* 72 | High level helper function to serialize an entire file system tree to 73 | a squashfs inode table and directory table. The super block is update 74 | accordingly. 75 | 76 | The function internally creates two meta data writers and uses 77 | meta_writer_write_inode to serialize the inode table of the fstree. 78 | 79 | Returns 0 on success. Prints error messages to stderr on failure. 80 | The filename is used to prefix error messages. 81 | */ 82 | int sqfs_serialize_fstree(const char *filename, sqfs_writer_t *wr); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif /* SIMPLE_WRITER_H */ 89 | -------------------------------------------------------------------------------- /lib/util/src/base64_decode.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * base64_decode.c 4 | * 5 | * Copyright (C) 2022 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | #include "util/test.h" 10 | 11 | #include 12 | 13 | static int base64_digit(int c) 14 | { 15 | if (isupper(c)) 16 | return c - 'A'; 17 | if (islower(c)) 18 | return c - 'a' + 26; 19 | if (isdigit(c)) 20 | return c - '0' + 52; 21 | if (c == '+') 22 | return 62; 23 | if (c == '/' || c == '-') 24 | return 63; 25 | return -1; 26 | } 27 | 28 | int base64_decode(const char *in, size_t in_len, sqfs_u8 *out, size_t *out_len) 29 | { 30 | int i1, i2, i3, i4; 31 | size_t count = 0; 32 | 33 | while (in_len >= 4) { 34 | i1 = base64_digit(*(in++)); 35 | i2 = base64_digit(*(in++)); 36 | i3 = *(in++); 37 | i4 = *(in++); 38 | in_len -= 4; 39 | 40 | if (i1 < 0 || i2 < 0 || count >= *out_len) 41 | goto fail; 42 | 43 | out[count++] = (i1 << 2) | (i2 >> 4); 44 | 45 | if (i3 == '=' || i3 == '_') { 46 | if ((i4 != '=' && i4 != '_') || in_len > 0) 47 | goto fail; 48 | break; 49 | } 50 | 51 | i3 = base64_digit(i3); 52 | if (i3 < 0 || count >= *out_len) 53 | goto fail; 54 | 55 | out[count++] = ((i2 & 0x0F) << 4) | (i3 >> 2); 56 | 57 | if (i4 == '=' || i4 == '_') { 58 | if (in_len > 0) 59 | goto fail; 60 | break; 61 | } 62 | 63 | i4 = base64_digit(i4); 64 | if (i4 < 0 || count >= *out_len) 65 | goto fail; 66 | 67 | out[count++] = ((i3 & 0x3) << 6) | i4; 68 | } 69 | 70 | /* libarchive has this bizarre bastardization of truncated base64 */ 71 | if (in_len > 0) { 72 | if (in_len == 1) 73 | goto fail; 74 | 75 | i1 = base64_digit(*(in++)); 76 | i2 = base64_digit(*(in++)); 77 | in_len -= 2; 78 | 79 | if (i1 < 0 || i2 < 0 || count >= *out_len) 80 | goto fail; 81 | 82 | out[count++] = (i1 << 2) | (i2 >> 4); 83 | 84 | if (in_len > 0) { 85 | i3 = *(in++); 86 | --in_len; 87 | 88 | if (i3 != '=' && i3 != '_') { 89 | i3 = base64_digit(i3); 90 | if (i3 < 0 || count >= *out_len) 91 | goto fail; 92 | 93 | out[count++] = ((i2 & 0x0F) << 4) | (i3 >> 2); 94 | } 95 | } 96 | } 97 | 98 | *out_len = count; 99 | return 0; 100 | fail: 101 | *out_len = 0; 102 | return -1; 103 | } 104 | -------------------------------------------------------------------------------- /bin/rdsquashfs/src/dump_xattrs.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * dump_xattrs.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "rdsquashfs.h" 8 | 9 | static void print_hex(const sqfs_u8 *value, size_t len) 10 | { 11 | printf("0x"); 12 | 13 | while (len--) 14 | printf("%02X", *(value++)); 15 | } 16 | 17 | static bool is_printable(const sqfs_u8 *value, size_t len) 18 | { 19 | size_t utf8_cont = 0; 20 | sqfs_u8 x; 21 | 22 | while (len--) { 23 | x = *(value++); 24 | 25 | if (utf8_cont > 0) { 26 | if ((x & 0xC0) != 0x80) 27 | return false; 28 | 29 | --utf8_cont; 30 | } else { 31 | if (x < 0x80) { 32 | if (x < 0x20) { 33 | if (x >= 0x07 && x <= 0x0D) 34 | continue; 35 | if (x == 0x00) 36 | continue; 37 | return false; 38 | } 39 | 40 | if (x == 0x7F) 41 | return false; 42 | } 43 | 44 | if ((x & 0xE0) == 0xC0) { 45 | utf8_cont = 1; 46 | } else if ((x & 0xF0) == 0xE0) { 47 | utf8_cont = 2; 48 | } else if ((x & 0xF8) == 0xF0) { 49 | utf8_cont = 3; 50 | } else if ((x & 0xFC) == 0xF8) { 51 | utf8_cont = 4; 52 | } else if ((x & 0xFE) == 0xFC) { 53 | utf8_cont = 5; 54 | } 55 | 56 | if (utf8_cont > 0 && len < utf8_cont) 57 | return false; 58 | } 59 | } 60 | 61 | return true; 62 | } 63 | 64 | int dump_xattrs(sqfs_xattr_reader_t *xattr, const sqfs_inode_generic_t *inode) 65 | { 66 | sqfs_xattr_t *list; 67 | sqfs_u32 index; 68 | 69 | if (xattr == NULL) 70 | return 0; 71 | 72 | sqfs_inode_get_xattr_index(inode, &index); 73 | 74 | if (sqfs_xattr_reader_read_all(xattr, index, &list)) { 75 | fprintf(stderr, "Error loading xattr entries list #%08X\n", 76 | index); 77 | return -1; 78 | } 79 | 80 | for (const sqfs_xattr_t *ent = list; ent != NULL; ent = ent->next) { 81 | size_t key_len = strlen(ent->key); 82 | 83 | if (is_printable((const sqfs_u8 *)ent->key, key_len)) { 84 | printf("%s=", ent->key); 85 | } else { 86 | print_hex((const sqfs_u8 *)ent->key, key_len); 87 | } 88 | 89 | if (is_printable(ent->value, ent->value_len)) { 90 | printf("%s\n", ent->value); 91 | } else { 92 | print_hex(ent->value, ent->value_len); 93 | printf("\n"); 94 | } 95 | } 96 | 97 | sqfs_xattr_list_free(list); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /lib/common/src/perror.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * print_version.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "common.h" 8 | 9 | #include 10 | 11 | void sqfs_perror(const char *file, const char *action, int error_code) 12 | { 13 | os_error_t syserror; 14 | const char *errstr; 15 | 16 | switch (error_code) { 17 | case SQFS_ERROR_ALLOC: 18 | errstr = "out of memory"; 19 | break; 20 | case SQFS_ERROR_IO: 21 | errstr = "I/O error"; 22 | break; 23 | case SQFS_ERROR_COMPRESSOR: 24 | errstr = "internal compressor error"; 25 | break; 26 | case SQFS_ERROR_INTERNAL: 27 | errstr = "internal error"; 28 | break; 29 | case SQFS_ERROR_CORRUPTED: 30 | errstr = "data corrupted"; 31 | break; 32 | case SQFS_ERROR_UNSUPPORTED: 33 | errstr = "unknown or not supported"; 34 | break; 35 | case SQFS_ERROR_OVERFLOW: 36 | errstr = "numeric overflow"; 37 | break; 38 | case SQFS_ERROR_OUT_OF_BOUNDS: 39 | errstr = "location out of bounds"; 40 | break; 41 | case SFQS_ERROR_SUPER_MAGIC: 42 | errstr = "wrong magic value in super block"; 43 | break; 44 | case SFQS_ERROR_SUPER_VERSION: 45 | errstr = "wrong squashfs version in super block"; 46 | break; 47 | case SQFS_ERROR_SUPER_BLOCK_SIZE: 48 | errstr = "invalid block size specified in super block"; 49 | break; 50 | case SQFS_ERROR_NOT_DIR: 51 | errstr = "target is not a directory"; 52 | break; 53 | case SQFS_ERROR_NO_ENTRY: 54 | errstr = "no such file or directory"; 55 | break; 56 | case SQFS_ERROR_LINK_LOOP: 57 | errstr = "hard link loop detected"; 58 | break; 59 | case SQFS_ERROR_NOT_FILE: 60 | errstr = "target is not a file"; 61 | break; 62 | case SQFS_ERROR_ARG_INVALID: 63 | errstr = "invalid argument"; 64 | break; 65 | case SQFS_ERROR_SEQUENCE: 66 | errstr = "illegal oder of operations"; 67 | break; 68 | default: 69 | errstr = "libsquashfs returned an unknown error code"; 70 | break; 71 | } 72 | 73 | syserror = get_os_error_state(); 74 | if (file != NULL) 75 | fprintf(stderr, "%s: ", file); 76 | 77 | if (action != NULL) 78 | fprintf(stderr, "%s: ", action); 79 | 80 | fprintf(stderr, "%s.\n", errstr); 81 | set_os_error_state(syserror); 82 | 83 | if (error_code == SQFS_ERROR_IO) { 84 | #if defined(_WIN32) || defined(__WINDOWS__) 85 | w32_perror("OS error"); 86 | #else 87 | perror("OS error"); 88 | #endif 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/common/Makemodule.am: -------------------------------------------------------------------------------- 1 | libcommon_a_SOURCES = include/common.h include/simple_writer.h \ 2 | include/compress_cli.h include/dir_tree.h \ 3 | lib/common/src/print_version.c \ 4 | lib/common/src/compress.c lib/common/src/comp_opt.c \ 5 | lib/common/src/parse_size.c lib/common/src/print_size.c \ 6 | lib/common/src/writer/init.c lib/common/src/writer/cleanup.c \ 7 | lib/common/src/writer/serialize_fstree.c lib/common/src/writer/finish.c\ 8 | lib/common/src/fstree_cli.c lib/common/src/perror.c \ 9 | lib/common/src/dir_tree.c lib/common/src/read_tree.c \ 10 | lib/common/src/stream.c lib/common/src/dir_tree_iterator.c \ 11 | include/dir_tree_iterator.h lib/common/src/dir_tree_iterator.c 12 | libcommon_a_CFLAGS = $(AM_CFLAGS) $(LZO_CFLAGS) 13 | 14 | if WITH_LZO 15 | libcommon_a_SOURCES += lib/common/src/comp_lzo.c 16 | endif 17 | 18 | noinst_LIBRARIES += libcommon.a 19 | 20 | test_istream_mem_SOURCES = lib/common/test/istream_mem.c 21 | test_istream_mem_LDADD = libcommon.a libsquashfs.la libcompat.a 22 | test_istream_mem_CPPFLAGS = $(AM_CPPFLAGS) 23 | 24 | test_fstree_cli_SOURCES = lib/common/test/fstree_cli.c 25 | test_fstree_cli_LDADD = libcommon.a libutil.a libcompat.a 26 | 27 | test_get_node_path_SOURCES = lib/common/test/get_node_path.c 28 | test_get_node_path_LDADD = libcommon.a libsquashfs.la libcompat.a 29 | 30 | test_dir_tree_iterator_SOURCES = lib/common/test/dir_tree_iterator.c 31 | test_dir_tree_iterator_LDADD = libcommon.a libsquashfs.la libutil.a libcompat.a 32 | test_dir_tree_iterator_CPPFLAGS = $(AM_CPPFLAGS) 33 | test_dir_tree_iterator_CPPFLAGS += -DTESTPATH=$(top_srcdir)/lib/sqfs/test/testdir 34 | 35 | test_dir_tree_iterator2_SOURCES = lib/common/test/dir_tree_iterator2.c 36 | test_dir_tree_iterator2_LDADD = libcommon.a libsquashfs.la libutil.a libcompat.a 37 | test_dir_tree_iterator2_CPPFLAGS = $(AM_CPPFLAGS) 38 | test_dir_tree_iterator2_CPPFLAGS += -DTESTPATH=$(top_srcdir)/lib/sqfs/test/testdir 39 | 40 | test_dir_tree_iterator3_SOURCES = lib/common/test/dir_tree_iterator3.c 41 | test_dir_tree_iterator3_LDADD = libcommon.a libsquashfs.la libutil.a libcompat.a 42 | test_dir_tree_iterator3_CPPFLAGS = $(AM_CPPFLAGS) 43 | test_dir_tree_iterator3_CPPFLAGS += -DTESTPATH=$(top_srcdir)/lib/sqfs/test/testdir 44 | 45 | LIBCOMMON_TESTS = \ 46 | test_istream_mem test_fstree_cli test_get_node_path \ 47 | test_dir_tree_iterator test_dir_tree_iterator2 test_dir_tree_iterator3 48 | 49 | check_PROGRAMS += $(LIBCOMMON_TESTS) 50 | TESTS += $(LIBCOMMON_TESTS) 51 | -------------------------------------------------------------------------------- /lib/tar/test/tar_sparse.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * tar_sparse.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "tar/tar.h" 9 | #include "util/test.h" 10 | #include "sqfs/io.h" 11 | 12 | static void test_case_sparse(const char *path) 13 | { 14 | tar_header_decoded_t hdr; 15 | sparse_map_t *sparse; 16 | sqfs_istream_t *fp; 17 | int ret; 18 | 19 | ret = sqfs_istream_open_file(&fp, path, 0); 20 | TEST_EQUAL_I(ret, 0); 21 | TEST_NOT_NULL(fp); 22 | TEST_ASSERT(read_header(fp, &hdr) == 0); 23 | TEST_EQUAL_UI(hdr.mode, S_IFREG | 0644); 24 | TEST_EQUAL_UI(hdr.uid, 01750); 25 | TEST_EQUAL_UI(hdr.gid, 01750); 26 | TEST_EQUAL_UI(hdr.actual_size, 2097152); 27 | TEST_EQUAL_UI(hdr.record_size, 32768); 28 | TEST_STR_EQUAL(hdr.name, "input.bin"); 29 | TEST_ASSERT(!hdr.unknown_record); 30 | 31 | sparse = hdr.sparse; 32 | TEST_NOT_NULL(sparse); 33 | TEST_EQUAL_UI(sparse->offset, 0); 34 | TEST_EQUAL_UI(sparse->count, 4096); 35 | 36 | sparse = sparse->next; 37 | TEST_NOT_NULL(sparse); 38 | TEST_EQUAL_UI(sparse->offset, 262144); 39 | TEST_EQUAL_UI(sparse->count, 4096); 40 | 41 | sparse = sparse->next; 42 | TEST_NOT_NULL(sparse); 43 | TEST_EQUAL_UI(sparse->offset, 524288); 44 | TEST_EQUAL_UI(sparse->count, 4096); 45 | 46 | sparse = sparse->next; 47 | TEST_NOT_NULL(sparse); 48 | TEST_EQUAL_UI(sparse->offset, 786432); 49 | TEST_EQUAL_UI(sparse->count, 4096); 50 | 51 | sparse = sparse->next; 52 | TEST_NOT_NULL(sparse); 53 | TEST_EQUAL_UI(sparse->offset, 1048576); 54 | TEST_EQUAL_UI(sparse->count, 4096); 55 | 56 | sparse = sparse->next; 57 | TEST_NOT_NULL(sparse); 58 | TEST_EQUAL_UI(sparse->offset, 1310720); 59 | TEST_EQUAL_UI(sparse->count, 4096); 60 | 61 | sparse = sparse->next; 62 | TEST_NOT_NULL(sparse); 63 | TEST_EQUAL_UI(sparse->offset, 1572864); 64 | TEST_EQUAL_UI(sparse->count, 4096); 65 | 66 | sparse = sparse->next; 67 | TEST_NOT_NULL(sparse); 68 | TEST_EQUAL_UI(sparse->offset, 1835008); 69 | TEST_EQUAL_UI(sparse->count, 4096); 70 | 71 | sparse = sparse->next; 72 | TEST_NOT_NULL(sparse); 73 | TEST_EQUAL_UI(sparse->offset, 2097152); 74 | TEST_EQUAL_UI(sparse->count, 0); 75 | 76 | sparse = sparse->next; 77 | TEST_NULL(sparse); 78 | 79 | clear_header(&hdr); 80 | sqfs_drop(fp); 81 | } 82 | 83 | int main(int argc, char **argv) 84 | { 85 | (void)argc; (void)argv; 86 | test_case_sparse( STRVALUE(TESTPATH) "/" STRVALUE(TESTFILE) ); 87 | return EXIT_SUCCESS; 88 | } 89 | -------------------------------------------------------------------------------- /lib/common/src/fstree_cli.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * fstree_cli.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "common.h" 9 | #include "util/util.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | enum { 17 | DEF_UID = 0, 18 | DEF_GID, 19 | DEF_MODE, 20 | DEF_MTIME, 21 | }; 22 | 23 | static const char *defaults[] = { 24 | [DEF_UID] = "uid", 25 | [DEF_GID] = "gid", 26 | [DEF_MODE] = "mode", 27 | [DEF_MTIME] = "mtime", 28 | NULL 29 | }; 30 | 31 | int parse_fstree_defaults(fstree_defaults_t *sb, char *subopts) 32 | { 33 | char *value; 34 | long lval; 35 | int i; 36 | 37 | memset(sb, 0, sizeof(*sb)); 38 | sb->mode = S_IFDIR | 0755; 39 | sb->mtime = get_source_date_epoch(); 40 | 41 | if (subopts == NULL) 42 | return 0; 43 | 44 | while (*subopts != '\0') { 45 | i = getsubopt(&subopts, (char *const *)defaults, &value); 46 | 47 | if (value == NULL) { 48 | fprintf(stderr, "Missing value for option %s\n", 49 | defaults[i]); 50 | return -1; 51 | } 52 | 53 | switch (i) { 54 | case DEF_UID: 55 | lval = strtol(value, NULL, 0); 56 | if (lval < 0) 57 | goto fail_uv; 58 | if (lval > (long)INT32_MAX) 59 | goto fail_ov; 60 | sb->uid = lval; 61 | break; 62 | case DEF_GID: 63 | lval = strtol(value, NULL, 0); 64 | if (lval < 0) 65 | goto fail_uv; 66 | if (lval > (long)INT32_MAX) 67 | goto fail_ov; 68 | sb->gid = lval; 69 | break; 70 | case DEF_MODE: 71 | lval = strtol(value, NULL, 0); 72 | if (lval < 0) 73 | goto fail_uv; 74 | if (lval > 07777) 75 | goto fail_ov; 76 | sb->mode = S_IFDIR | (sqfs_u16)lval; 77 | break; 78 | case DEF_MTIME: 79 | errno = 0; 80 | lval = strtol(value, NULL, 0); 81 | if (lval < 0) 82 | goto fail_uv; 83 | if (sizeof(long) > sizeof(sqfs_u32)) { 84 | if (lval > (long)UINT32_MAX) 85 | goto fail_ov; 86 | } else if (errno != 0) { 87 | goto fail_ov; 88 | } 89 | sb->mtime = lval; 90 | break; 91 | default: 92 | fprintf(stderr, "Unknown option '%s'\n", value); 93 | return -1; 94 | } 95 | } 96 | return 0; 97 | fail_uv: 98 | fprintf(stderr, "%s: value must be positive\n", defaults[i]); 99 | return -1; 100 | fail_ov: 101 | fprintf(stderr, "%s: value too large\n", defaults[i]); 102 | return -1; 103 | } 104 | -------------------------------------------------------------------------------- /lib/util/test/filename_sane.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-3.0-or-later */ 2 | /* 3 | * filename_sane.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/util.h" 9 | #include "util/test.h" 10 | 11 | static const char *must_work[] = { 12 | "foobar", 13 | "test.txt", 14 | #if !defined(_WIN32) && !defined(__WINDOWS__) && !defined(TEST_WIN32) 15 | "\\foo", "foo\\", "foo\\bar", 16 | #endif 17 | NULL, 18 | }; 19 | 20 | static const char *must_not_work[] = { 21 | ".", 22 | "..", 23 | "/foo", 24 | "foo/", 25 | "foo/bar", 26 | NULL, 27 | }; 28 | 29 | static const char *must_not_work_here[] = { 30 | #if defined(_WIN32) || defined(__WINDOWS__) || defined(TEST_WIN32) 31 | "\\foo", "foo\\", "foo\\bar", 32 | "foo", "fo:o", "fo\"o", 33 | "fo|o", "fo?o", "fo*o", "fo\ro", 34 | "CON", "PRN", "AUX", "NUL", 35 | "COM1", "COM2", "LPT1", "LPT2", 36 | "con", "prn", "aux", "nul", 37 | "com1", "com2", "lpt1", "lpt2", 38 | "AUX.txt", "aux.txt", "NUL.txt", "nul.txt", 39 | #endif 40 | NULL, 41 | }; 42 | 43 | int main(int argc, char **argv) 44 | { 45 | size_t i; 46 | (void)argc; (void)argv; 47 | 48 | for (i = 0; must_work[i] != NULL; ++i) { 49 | if (!is_filename_sane(must_work[i], false)) { 50 | fprintf(stderr, "%s was rejected!\n", must_work[i]); 51 | return EXIT_FAILURE; 52 | } 53 | 54 | if (!is_filename_sane(must_work[i], true)) { 55 | fprintf(stderr, 56 | "%s was rejected when testing for " 57 | "OS specific stuff!\n", must_work[i]); 58 | return EXIT_FAILURE; 59 | } 60 | } 61 | 62 | for (i = 0; must_not_work[i] != NULL; ++i) { 63 | if (is_filename_sane(must_not_work[i], false)) { 64 | fprintf(stderr, "%s was accepted!\n", 65 | must_not_work[i]); 66 | return EXIT_FAILURE; 67 | } 68 | 69 | if (is_filename_sane(must_not_work[i], true)) { 70 | fprintf(stderr, 71 | "%s was accepted when testing for " 72 | "OS specific stuff!\n", must_not_work[i]); 73 | return EXIT_FAILURE; 74 | } 75 | } 76 | 77 | for (i = 0; must_not_work_here[i] != NULL; ++i) { 78 | if (!is_filename_sane(must_not_work_here[i], false)) { 79 | fprintf(stderr, 80 | "%s was rejected in the generic test!\n", 81 | must_not_work_here[i]); 82 | return EXIT_FAILURE; 83 | } 84 | 85 | if (is_filename_sane(must_not_work_here[i], true)) { 86 | fprintf(stderr, 87 | "%s was accepted when testing for " 88 | "OS specific stuff!\n", must_not_work_here[i]); 89 | return EXIT_FAILURE; 90 | } 91 | } 92 | 93 | return EXIT_SUCCESS; 94 | } 95 | -------------------------------------------------------------------------------- /lib/sqfs/src/io/unix.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * unix.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #define SQFS_BUILDING_DLL 8 | #include "config.h" 9 | 10 | #include "sqfs/io.h" 11 | #include "sqfs/error.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int sqfs_native_file_open(sqfs_file_handle_t *out, const char *filename, 19 | sqfs_u32 flags) 20 | { 21 | int open_mode; 22 | 23 | *out = -1; 24 | 25 | if (flags & ~SQFS_FILE_OPEN_ALL_FLAGS) 26 | return SQFS_ERROR_UNSUPPORTED; 27 | 28 | if (flags & SQFS_FILE_OPEN_READ_ONLY) { 29 | open_mode = O_RDONLY; 30 | } else { 31 | open_mode = O_CREAT | O_RDWR; 32 | 33 | if (flags & SQFS_FILE_OPEN_OVERWRITE) { 34 | open_mode |= O_TRUNC; 35 | } else { 36 | open_mode |= O_EXCL; 37 | } 38 | } 39 | 40 | *out = open(filename, open_mode, 0644); 41 | 42 | return (*out < 0) ? SQFS_ERROR_IO : 0; 43 | } 44 | 45 | void sqfs_native_file_close(sqfs_file_handle_t fd) 46 | { 47 | while (close(fd) != 0 && errno == EINTR) 48 | ; 49 | } 50 | 51 | int sqfs_native_file_duplicate(sqfs_file_handle_t in, sqfs_file_handle_t *out) 52 | { 53 | *out = dup(in); 54 | return (*out < 0) ? SQFS_ERROR_IO : 0; 55 | } 56 | 57 | int sqfs_native_file_seek(sqfs_file_handle_t fd, 58 | sqfs_s64 offset, sqfs_u32 flags) 59 | { 60 | int whence; 61 | off_t off; 62 | 63 | switch (flags & SQFS_FILE_SEEK_TYPE_MASK) { 64 | case SQFS_FILE_SEEK_START: whence = SEEK_SET; break; 65 | case SQFS_FILE_SEEK_CURRENT: whence = SEEK_CUR; break; 66 | case SQFS_FILE_SEEK_END: whence = SEEK_END; break; 67 | default: return SQFS_ERROR_UNSUPPORTED; 68 | } 69 | 70 | if (flags & ~(SQFS_FILE_SEEK_FLAG_MASK | SQFS_FILE_SEEK_TYPE_MASK)) 71 | return SQFS_ERROR_UNSUPPORTED; 72 | 73 | off = lseek(fd, offset, whence); 74 | if (off == ((off_t)-1)) { 75 | if (errno == ESPIPE) 76 | return SQFS_ERROR_UNSUPPORTED; 77 | return SQFS_ERROR_IO; 78 | } 79 | 80 | if (flags & SQFS_FILE_SEEK_TRUNCATE) { 81 | while (ftruncate(fd, off) != 0) { 82 | if (errno != EINTR) 83 | return SQFS_ERROR_IO; 84 | } 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | int sqfs_native_file_get_size(sqfs_file_handle_t hnd, sqfs_u64 *out) 91 | { 92 | struct stat sb; 93 | 94 | if (fstat(hnd, &sb)) { 95 | *out = 0; 96 | return SQFS_ERROR_IO; 97 | } 98 | 99 | *out = sb.st_size; 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /lib/compat/src/getopt_long.c: -------------------------------------------------------------------------------- 1 | #include "compat.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef HAVE_GETOPT_LONG 11 | static void permute(char *const *argv, int dest, int src) 12 | { 13 | char **av = (char **)argv; 14 | char *tmp = av[src]; 15 | int i; 16 | for (i=src; i>dest; i--) 17 | av[i] = av[i-1]; 18 | av[dest] = tmp; 19 | } 20 | 21 | int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) 22 | { 23 | optarg = 0; 24 | if (longopts && argv[optind][0] == '-' && 25 | (argv[optind][1] == '-' && argv[optind][2])) 26 | { 27 | int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':'; 28 | int i, cnt, match; 29 | char *arg, *opt, *start = argv[optind]+1; 30 | for (cnt=i=0; longopts[i].name; i++) { 31 | const char *name = longopts[i].name; 32 | opt = start; 33 | if (*opt == '-') opt++; 34 | while (*opt && *opt != '=' && *opt == *name) 35 | name++, opt++; 36 | if (*opt && *opt != '=') continue; 37 | arg = opt; 38 | match = i; 39 | if (!*name) { 40 | cnt = 1; 41 | break; 42 | } 43 | cnt++; 44 | } 45 | if (cnt==1) { 46 | i = match; 47 | opt = arg; 48 | optind++; 49 | if (*opt == '=') { 50 | if (!longopts[i].has_arg) { 51 | optopt = longopts[i].val; 52 | if (colon || !opterr) 53 | return '?'; 54 | __getopt_msg(argv[0], 55 | ": option does not take an argument: ", 56 | longopts[i].name, 57 | strlen(longopts[i].name)); 58 | return '?'; 59 | } 60 | optarg = opt+1; 61 | } else if (longopts[i].has_arg == required_argument) { 62 | if (!(optarg = argv[optind])) { 63 | optopt = longopts[i].val; 64 | if (colon) return ':'; 65 | if (!opterr) return '?'; 66 | __getopt_msg(argv[0], 67 | ": option requires an argument: ", 68 | longopts[i].name, 69 | strlen(longopts[i].name)); 70 | return '?'; 71 | } 72 | optind++; 73 | } 74 | if (idx) *idx = i; 75 | if (longopts[i].flag) { 76 | *longopts[i].flag = longopts[i].val; 77 | return 0; 78 | } 79 | return longopts[i].val; 80 | } 81 | if (argv[optind][1] == '-') { 82 | optopt = 0; 83 | if (!colon && opterr) 84 | __getopt_msg(argv[0], cnt ? 85 | ": option is ambiguous: " : 86 | ": unrecognized option: ", 87 | argv[optind]+2, 88 | strlen(argv[optind]+2)); 89 | optind++; 90 | return '?'; 91 | } 92 | } 93 | return getopt(argc, argv, optstring); 94 | } 95 | #endif 96 | -------------------------------------------------------------------------------- /lib/util/src/split_line.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * split_line.c 4 | * 5 | * Copyright (C) 2023 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | #include "util/parse.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | static split_line_t *append_arg(split_line_t *in, char *arg) 15 | { 16 | split_line_t *out = realloc(in, sizeof(*in) + 17 | (in->count + 1) * sizeof(char *)); 18 | 19 | if (out == NULL) { 20 | free(in); 21 | return NULL; 22 | } 23 | 24 | out->args[out->count++] = arg; 25 | return out; 26 | } 27 | 28 | static int is_sep(const char *sep, int c) 29 | { 30 | return strchr(sep, c) != NULL && c != '\0'; 31 | } 32 | 33 | int split_line(char *line, size_t len, const char *sep, split_line_t **out) 34 | { 35 | split_line_t *split = calloc(1, sizeof(*split)); 36 | char *src = line, *dst = line; 37 | 38 | if (split == NULL) 39 | return SPLIT_LINE_ALLOC; 40 | 41 | while (len > 0 && is_sep(sep, *src)) { 42 | ++src; 43 | --len; 44 | } 45 | 46 | while (len > 0 && *src != '\0') { 47 | split = append_arg(split, dst); 48 | if (split == NULL) 49 | return SPLIT_LINE_ALLOC; 50 | 51 | if (*src == '"') { 52 | ++src; 53 | --len; 54 | 55 | while (len > 0 && *src != '\0' && *src != '"') { 56 | if (src[0] == '\\') { 57 | if (len < 2) 58 | goto fail_esc; 59 | if (src[1] != '"' && src[1] != '\\') 60 | goto fail_esc; 61 | 62 | *(dst++) = src[1]; 63 | src += 2; 64 | len -= 2; 65 | } else { 66 | *(dst++) = *(src++); 67 | --len; 68 | } 69 | } 70 | 71 | if (len == 0 || *src != '"') 72 | goto fail_quote; 73 | ++src; 74 | --len; 75 | } else { 76 | while (len > 0 && !is_sep(sep, *src) && *src != '\0') { 77 | *(dst++) = *(src++); 78 | --len; 79 | } 80 | } 81 | 82 | while (len > 0 && is_sep(sep, *src)) { 83 | ++src; 84 | --len; 85 | } 86 | 87 | *(dst++) = '\0'; 88 | } 89 | 90 | *out = split; 91 | return SPLIT_LINE_OK; 92 | fail_esc: 93 | free(split); 94 | return SPLIT_LINE_ESCAPE; 95 | fail_quote: 96 | free(split); 97 | return SPLIT_LINE_UNMATCHED_QUOTE; 98 | } 99 | 100 | void split_line_remove_front(split_line_t *split, size_t count) 101 | { 102 | if (count < split->count) { 103 | for (size_t i = count, j = 0; i < split->count; ++i, ++j) 104 | split->args[j] = split->args[i]; 105 | split->count -= count; 106 | } else { 107 | split->count = 0; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /lib/util/src/parse_int.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * alloc.c 4 | * 5 | * Copyright (C) 2019 David Oberhollenzer 6 | */ 7 | #include "config.h" 8 | 9 | #include "util/parse.h" 10 | #include "sqfs/error.h" 11 | 12 | #include 13 | 14 | static int parse(const char *in, size_t len, size_t *diff, 15 | sqfs_u64 base, sqfs_u64 vmin, sqfs_u64 vmax, sqfs_u64 *out) 16 | { 17 | /* init result */ 18 | if (diff != NULL) 19 | *diff = 0; 20 | *out = 0; 21 | 22 | /* sequence has at least 1 digit */ 23 | if (len == 0 || !isdigit(*in)) 24 | return SQFS_ERROR_CORRUPTED; 25 | 26 | /* parse sequence */ 27 | while (len > 0 && isdigit(*in)) { 28 | sqfs_u64 x = *in - '0'; 29 | if (x >= base) 30 | break; 31 | 32 | if ((*out) >= (0xFFFFFFFFFFFFFFFFULL / base)) 33 | return SQFS_ERROR_OVERFLOW; 34 | 35 | (*out) *= base; 36 | 37 | if ((*out) > (0xFFFFFFFFFFFFFFFFULL - x)) 38 | return SQFS_ERROR_OVERFLOW; 39 | 40 | (*out) += x; 41 | 42 | --len; 43 | ++in; 44 | if (diff != NULL) 45 | ++(*diff); 46 | } 47 | 48 | /* range check */ 49 | if ((vmin < vmax) && ((*out < vmin) || (*out > vmax))) 50 | return SQFS_ERROR_OUT_OF_BOUNDS; 51 | 52 | /* if diff is not used, entire must have been processed */ 53 | if (diff == NULL && (len > 0 && *in != '\0')) 54 | return SQFS_ERROR_CORRUPTED; 55 | 56 | return 0; 57 | } 58 | 59 | int parse_uint(const char *in, size_t len, size_t *diff, 60 | sqfs_u64 vmin, sqfs_u64 vmax, sqfs_u64 *out) 61 | { 62 | return parse(in, len, diff, 10, vmin, vmax, out); 63 | } 64 | 65 | int parse_uint_oct(const char *in, size_t len, size_t *diff, 66 | sqfs_u64 vmin, sqfs_u64 vmax, sqfs_u64 *out) 67 | { 68 | return parse(in, len, diff, 8, vmin, vmax, out); 69 | } 70 | 71 | int parse_int(const char *in, size_t len, size_t *diff, 72 | sqfs_s64 vmin, sqfs_s64 vmax, sqfs_s64 *out) 73 | { 74 | bool negative = false; 75 | sqfs_u64 temp; 76 | int ret; 77 | 78 | if (len > 0 && *in == '-') { 79 | ++in; 80 | --len; 81 | negative = true; 82 | } 83 | 84 | ret = parse_uint(in, len, diff, 0, 0, &temp); 85 | if (ret) 86 | return ret; 87 | 88 | if (temp >= 0x7FFFFFFFFFFFFFFFULL) 89 | return SQFS_ERROR_OVERFLOW; 90 | 91 | if (negative) { 92 | if (diff != NULL) 93 | (*diff) += 1; 94 | *out = -((sqfs_s64)temp); 95 | } else { 96 | *out = (sqfs_s64)temp; 97 | } 98 | 99 | if ((vmin < vmax) && ((*out < vmin) || (*out > vmax))) 100 | return SQFS_ERROR_OUT_OF_BOUNDS; 101 | 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /include/util/w32threadwrap.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-3.0-or-later */ 2 | /* 3 | * w32threadwrap.h 4 | * 5 | * Copyright (C) 2021 David Oberhollenzer 6 | */ 7 | #ifndef W32THREADWRAP_H 8 | #define W32THREADWRAP_H 9 | 10 | #include "sqfs/predef.h" 11 | 12 | #define WIN32_LEAN_AND_MEAN 13 | #define VC_EXTRALEAN 14 | #include 15 | 16 | typedef unsigned int sigset_t; 17 | typedef HANDLE pthread_t; 18 | typedef CRITICAL_SECTION pthread_mutex_t; 19 | typedef CONDITION_VARIABLE pthread_cond_t; 20 | 21 | static inline int pthread_create(pthread_t *thread, const void *attr, 22 | LPTHREAD_START_ROUTINE proc, LPVOID arg) 23 | { 24 | HANDLE hnd = CreateThread(NULL, 0, proc, arg, 0, 0); 25 | (void)attr; 26 | 27 | if (hnd == NULL) 28 | return -1; 29 | 30 | *thread = hnd; 31 | return 0; 32 | } 33 | 34 | static int pthread_join(pthread_t thread, void **retval) 35 | { 36 | WaitForSingleObject(thread, INFINITE); 37 | CloseHandle(thread); 38 | if (retval != NULL) 39 | *retval = NULL; 40 | return 0; 41 | } 42 | 43 | static inline int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr) 44 | { 45 | (void)attr; 46 | InitializeCriticalSection(mutex); 47 | return 0; 48 | } 49 | 50 | static inline int pthread_mutex_lock(pthread_mutex_t *mutex) 51 | { 52 | EnterCriticalSection(mutex); 53 | return 0; 54 | } 55 | 56 | static inline int pthread_mutex_unlock(pthread_mutex_t *mutex) 57 | { 58 | LeaveCriticalSection(mutex); 59 | return 0; 60 | } 61 | 62 | static inline void pthread_mutex_destroy(pthread_mutex_t *mutex) 63 | { 64 | DeleteCriticalSection(mutex); 65 | } 66 | 67 | static inline int pthread_cond_init(pthread_cond_t *cond, const void *attr) 68 | { 69 | (void)attr; 70 | InitializeConditionVariable(cond); 71 | return 0; 72 | } 73 | 74 | static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mtx) 75 | { 76 | return SleepConditionVariableCS(cond, mtx, INFINITE) != 0; 77 | } 78 | 79 | static inline int pthread_cond_broadcast(pthread_cond_t *cond) 80 | { 81 | WakeAllConditionVariable(cond); 82 | return 0; 83 | } 84 | 85 | static inline void pthread_cond_destroy(pthread_cond_t *cond) 86 | { 87 | (void)cond; 88 | } 89 | 90 | #define SIG_SETMASK (0) 91 | 92 | static inline int sigfillset(sigset_t *set) 93 | { 94 | *set = 0xFFFFFFFF; 95 | return 0; 96 | } 97 | 98 | static inline int pthread_sigmask(int how, const sigset_t *set, 99 | const sigset_t *old) 100 | { 101 | (void)how; (void)set; (void)old; 102 | return 0; 103 | } 104 | 105 | #endif /* W32THREADWRAP_H */ 106 | --------------------------------------------------------------------------------