mirror of
https://github.com/ventoy/Ventoy.git
synced 2025-12-14 07:46:20 +00:00
initial commit
This commit is contained in:
22
SQUASHFS/SRC/build_lz4.sh
Normal file
22
SQUASHFS/SRC/build_lz4.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
LIBDIR=$PWD/../LIB/LZ4
|
||||
|
||||
rm -rf $LIBDIR
|
||||
rm -rf lz4-1.8.1.2
|
||||
tar -xf lz4-1.8.1.2.tar.gz
|
||||
|
||||
|
||||
cd lz4-1.8.1.2
|
||||
make && PREFIX=$LIBDIR make install
|
||||
|
||||
cd ..
|
||||
rm -rf lz4-1.8.1.2
|
||||
|
||||
if [ -d $LIBDIR ]; then
|
||||
echo -e "\n========== SUCCESS ============\n"
|
||||
else
|
||||
echo -e "\n========== FAILED ============\n"
|
||||
fi
|
||||
|
||||
|
||||
22
SQUASHFS/SRC/build_lzma.sh
Normal file
22
SQUASHFS/SRC/build_lzma.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
LIBDIR=$PWD/../LIB/LZMA
|
||||
|
||||
rm -rf $LIBDIR
|
||||
rm -rf liblzma-master
|
||||
unzip liblzma-master.zip
|
||||
|
||||
cd liblzma-master
|
||||
./configure --prefix=$LIBDIR --disable-xz --disable-xzdec --disable-lzmadec --disable-lzmainfo --enable-small
|
||||
make -j 8 && make install
|
||||
|
||||
cd ..
|
||||
rm -rf liblzma-master
|
||||
|
||||
if [ -d $LIBDIR ]; then
|
||||
echo -e "\n========== SUCCESS ============\n"
|
||||
else
|
||||
echo -e "\n========== FAILED ============\n"
|
||||
fi
|
||||
|
||||
|
||||
24
SQUASHFS/SRC/build_lzo.sh
Normal file
24
SQUASHFS/SRC/build_lzo.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
LIBDIR=$PWD/../LIB/LZO
|
||||
LZODIR=lzo-2.08
|
||||
|
||||
rm -rf $LIBDIR
|
||||
rm -rf $LZODIR
|
||||
tar -xf ${LZODIR}.tar.gz
|
||||
|
||||
|
||||
cd $LZODIR
|
||||
./configure --prefix=$LIBDIR --disable-shared
|
||||
|
||||
make && make install
|
||||
|
||||
cd ..
|
||||
rm -rf $LZODIR
|
||||
|
||||
if [ -d $LIBDIR ]; then
|
||||
echo -e "\n========== SUCCESS ============\n"
|
||||
else
|
||||
echo -e "\n========== FAILED ============\n"
|
||||
fi
|
||||
|
||||
23
SQUASHFS/SRC/build_zstd.sh
Normal file
23
SQUASHFS/SRC/build_zstd.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
LIBDIR=$PWD/../LIB/ZSTD
|
||||
ZSTDDIR=zstd-1.4.4
|
||||
|
||||
rm -rf $LIBDIR
|
||||
rm -rf $ZSTDDIR
|
||||
tar -xf ${ZSTDDIR}.tar.gz
|
||||
|
||||
|
||||
cd $ZSTDDIR
|
||||
PREFIX=$LIBDIR ZSTD_LIB_COMPRESSION=0 make
|
||||
PREFIX=$LIBDIR ZSTD_LIB_COMPRESSION=0 make install
|
||||
|
||||
cd ..
|
||||
rm -rf $ZSTDDIR
|
||||
|
||||
if [ -d $LIBDIR ]; then
|
||||
echo -e "\n========== SUCCESS ============\n"
|
||||
else
|
||||
echo -e "\n========== FAILED ============\n"
|
||||
fi
|
||||
|
||||
BIN
SQUASHFS/SRC/liblzma-master.zip
Normal file
BIN
SQUASHFS/SRC/liblzma-master.zip
Normal file
Binary file not shown.
BIN
SQUASHFS/SRC/lz4-1.8.1.2.tar.gz
Normal file
BIN
SQUASHFS/SRC/lz4-1.8.1.2.tar.gz
Normal file
Binary file not shown.
BIN
SQUASHFS/SRC/lzo-2.08.tar.gz
Normal file
BIN
SQUASHFS/SRC/lzo-2.08.tar.gz
Normal file
Binary file not shown.
BIN
SQUASHFS/SRC/zstd-1.4.4.tar.gz
Normal file
BIN
SQUASHFS/SRC/zstd-1.4.4.tar.gz
Normal file
Binary file not shown.
162
SQUASHFS/squashfs-tools-4.4/ACKNOWLEDGEMENTS
Normal file
162
SQUASHFS/squashfs-tools-4.4/ACKNOWLEDGEMENTS
Normal file
@@ -0,0 +1,162 @@
|
||||
ACKNOWLEDGEMENTS
|
||||
|
||||
Thanks to everyone who have downloaded Squashfs. I appreciate people
|
||||
using it, and any feedback you have.
|
||||
|
||||
The following have provided useful feedback, which has guided
|
||||
some of the extra features in squashfs. This is a randomly ordered
|
||||
(roughly in chronological order) list, which is updated when
|
||||
I remember...
|
||||
|
||||
Acknowledgements for Squashfs 4.3
|
||||
---------------------------------
|
||||
|
||||
Thanks to Bruno Wolff III and Andy Lutomirski for useful feedback
|
||||
during the long development process of Squashfs 4.3.
|
||||
|
||||
Acknowledgements for Squashfs 4.2
|
||||
---------------------------------
|
||||
|
||||
Thanks to Lasse Collin (http://tukaani.org/xz/) for mainlining XZ
|
||||
decompression support.
|
||||
|
||||
Acknowledgements for Squashfs 4.1
|
||||
---------------------------------
|
||||
|
||||
Thanks to Chan Jeong <chan.jeong@lge.com> and LG for the patches to support LZO
|
||||
compression.
|
||||
|
||||
Acknowledgements for Squashfs 4.0
|
||||
---------------------------------
|
||||
|
||||
Thanks to Tim Bird and CELF (Consumer Electronics Linux Forum) for helping
|
||||
fund mainstreaming of Squashfs into the 2.6.29 kernel and the
|
||||
changes to the Squashfs tools to support the new 4.0 file system layout.
|
||||
|
||||
Acknowledgements for Squashfs-3.3
|
||||
------------------------------------
|
||||
|
||||
Peter Korsgaard and others sent patches updating Squashfs to changes in the
|
||||
VFS interface for 2.6.22/2.6.23/2.6.24-rc1. Peter also sent some small patches
|
||||
for the Squashfs kernel code.
|
||||
|
||||
Vito Di Leo sent a patch extending Mksquashfs to support regex filters.
|
||||
While his patched worked, it unfortunately made it easy to make Mksquashfs
|
||||
perform unpredictably with poorly choosen regex expressions. It, however,
|
||||
encouraged myself to add support for wildcard pattern matching and regex
|
||||
filters in a different way.
|
||||
|
||||
Acknowledgements for Squashfs-3.2-r2
|
||||
------------------------------------
|
||||
|
||||
Junjiro Okajima discovered a couple of SMP issues, thanks.
|
||||
|
||||
Junjiro Okajima and Tomas Matejicek have produced some good LZMA patches
|
||||
for Squashfs.
|
||||
|
||||
Acknowledgements for Squashfs-3.2
|
||||
---------------------------------
|
||||
|
||||
Peter Korsgaard sent a patch updating Squashfs to changes in the VFS interface
|
||||
in Linux 2.6.20.
|
||||
|
||||
Acknowledgements for Squashfs-3.1
|
||||
---------------------------------
|
||||
|
||||
Kenneth Duda and Ed Swierk of Arastra Inc. identified numerous bugs with
|
||||
Squashfs, and provided patches which were the basis for some of the
|
||||
fixes. In particular they identified the fragment rounding bug, the
|
||||
NFS bug, the initrd bug, and helped identify the 4K stack overflow bug.
|
||||
|
||||
Scott James Remnant (Ubuntu) also identified the fragment rounding bug,
|
||||
and he also provided a patch.
|
||||
|
||||
Ming Zhang identified the Lseek bug in Mksquashfs. His tests on the
|
||||
performance of Mksquashfs on SMP systems encouraged the rewrite of
|
||||
Mksquashfs.
|
||||
|
||||
Peter Korsgaard, Daniel Olivera and Zilvinas Valinskas noticed
|
||||
Squashfs 3.0 didn't compile on Linux-2.6.18-rc[1-4] due to changes
|
||||
in the Linux VFS interfaces, and provided patches.
|
||||
|
||||
Tomas Matejicek (SLAX) suggested the -force option on Unsquashfs, and noticed
|
||||
Unsquashfs didn't return the correct exit status.
|
||||
|
||||
Yann Le Doare reported a kernel oops and provided a Qemu image that led
|
||||
to the identification of the simultaneously accessing multiply mounted Squashfs
|
||||
filesystems bug.
|
||||
|
||||
|
||||
Older acknowledgements
|
||||
----------------------
|
||||
|
||||
Mark Robson - pointed out early on that initrds didn't work
|
||||
|
||||
Adam Warner - pointed out that greater than 2GB filesystems didn't work.
|
||||
|
||||
John Sutton - raised the problem when archiving the entire filesystem
|
||||
(/) there was no way to prevent /proc being archived. This prompted
|
||||
exclude files.
|
||||
|
||||
Martin Mueller (LinuxTV) - noticed that the filesystem length in the
|
||||
superblock doesn't match the output filesystem length. This is due to
|
||||
padding to a 4K boundary. This prompted the addition of the -nopad option.
|
||||
He also reported a problem where 32K block filesystems hung when used as
|
||||
initrds.
|
||||
|
||||
Arkadiusz Patyk (Polish Linux Distribution - PLD) reported a problem where 32K
|
||||
block filesystems hung when used as a root filesystem mounted as a loopback
|
||||
device.
|
||||
|
||||
David Fox (Lindows) noticed that the exit codes returned by Mksquashfs were
|
||||
wrong. He also noticed that a lot of time was spent in the duplicate scan
|
||||
routine.
|
||||
|
||||
Cameron Rich complained that Squashfs did not support FIFOs or sockets.
|
||||
|
||||
Steve Chadsey and Thomas Weissmuller noticed that files larger than the
|
||||
available memory could not be compressed by Mksquashfs.
|
||||
|
||||
"Ptwahyu" and "Hoan" (I have no full names and I don't like giving people's
|
||||
email addresses), noticed that Mksquashfs 1.3 SEGV'd occasionally. Even though
|
||||
I had already noticed this bug, it is useful to be informed by other people.
|
||||
|
||||
Don Elwell, Murray Jensen and Cameron Rich, have all sent in patches. Thanks,
|
||||
I have not had time to do anything about them yet...
|
||||
|
||||
Drew Scott Daniels has been a good advocate for Squashfs.
|
||||
|
||||
Erik Andersen has made some nice suggestions, unfortunately, I have
|
||||
not had time to implement anything.
|
||||
|
||||
Artemiy I. Pavlov has written a useful LDP mini-howto for Squashfs
|
||||
(http://linuxdoc.artemio.net/squashfs).
|
||||
|
||||
Yves Combe reported the Apple G5 bug, when using Squashfs for
|
||||
his PPC Knoppix-mib livecd project.
|
||||
|
||||
Jaco Greeff (mklivecd project, and maintainer of the Mandrake
|
||||
squashfs-tools package) suggested the new mksquashfs -ef option, and the
|
||||
standalone build for mksquashfs.
|
||||
|
||||
Mike Schaudies made a donation.
|
||||
|
||||
Arkadiusz Patyk from the Polish Linux Distribution reported that Squashfs
|
||||
didn't work on amd64 machines. He gave me an account on a PLD amd64 machine
|
||||
which allowed myself to track down these bugs.
|
||||
|
||||
Miles Roper, Peter Kjellerstedt and Willy Tarreau reported that release 2.1 did
|
||||
not compile with gcc < 3.x.
|
||||
|
||||
Marcel J.E. Mol reported lack of kernel memory issues when using Squashfs
|
||||
on small memory embedded systems. This prompted the addition of the embedded
|
||||
system kernel configuration options.
|
||||
|
||||
Era Scarecrow noticed that Mksquashfs had not been updated to reflect that
|
||||
smaller than 4K blocks are no longer supported.
|
||||
|
||||
Kenichi Shima reported the Kconfig file had not been updated to 2.2.
|
||||
|
||||
Aaron Ten Clay made a donation!
|
||||
|
||||
Tomas Matejicek (SLAX) made a donation!
|
||||
664
SQUASHFS/squashfs-tools-4.4/CHANGES
Normal file
664
SQUASHFS/squashfs-tools-4.4/CHANGES
Normal file
@@ -0,0 +1,664 @@
|
||||
SQUASHFS CHANGE LOG
|
||||
|
||||
4.4 29 AUG 2019 Reproducible builds, new compressors,
|
||||
CVE fixes, security hardening and new options
|
||||
for Mksquashfs/Unsquashfs.
|
||||
|
||||
1. Overall improvements:
|
||||
|
||||
1.1 Mksquashfs now generates reproducible images by default.
|
||||
1.2 Mkfs time and file timestamps can also be specified.
|
||||
1.3 Support for the Zstandard (ZSTD) compression algorithm.
|
||||
1.4 CVE-2015-4645 and CVE-2015-4646 have been fixed.
|
||||
|
||||
2. Mksquashfs improvements and major bug fixes:
|
||||
|
||||
2.1 Pseudo files now support symbolic links.
|
||||
2.2 New -mkfs-time option.
|
||||
2.3 New -all-time option.
|
||||
2.4 New -root-mode option.
|
||||
2.5 New -quiet option.
|
||||
2.6 New -noId option.
|
||||
2.7 New -offset option.
|
||||
2.8 Update lz4 wrapper to use new functions introduced
|
||||
in 1.7.0.
|
||||
2.9 Bug fix, don't allow "/" pseudo filenames.
|
||||
2.10 Bug fix, allow quoting of pseudo files, to
|
||||
better handle filenames with spaces.
|
||||
2.11 Fix compilation with glibc 2.25+.
|
||||
|
||||
3. Unsquashfs improvements and major bug fixes:
|
||||
|
||||
3.1 CVE-2015-4645 and CVE-2015-4646 have been fixed.
|
||||
3.2 Unsquashfs has been further hardened against corrupted
|
||||
filestems.
|
||||
3.3 Unsquashfs is now more strict about error handling.
|
||||
3.4 New -ignore-errors option.
|
||||
3.5 New -strict-errors option.
|
||||
3.6 New -lln[umeric] option.
|
||||
3.7 New -lc option.
|
||||
3.8 New -llc option.
|
||||
3.9 New -mkfs-time option.
|
||||
3.10 New -UTC option.
|
||||
3.11 New -offset option.
|
||||
3.12 New -quiet option.
|
||||
3.13 Update lz4 wrapper to use new functions introduced
|
||||
in 1.7.0.
|
||||
3.14 Bug fix, fatal and non-fatal errors now set the exit
|
||||
code to 1.
|
||||
3.15 Bug fix, fix time setting for symlinks.
|
||||
3.16 Bug fix, try to set sticky-bit when running as a
|
||||
user process.
|
||||
3.17 Fix compilation with glibc 2.25+.
|
||||
|
||||
4.3 12 MAY 2014 New compressor options, new Mksquashfs/Unsquashfs
|
||||
functionality, duplicate checking optimisations,
|
||||
stability improvements (option/file parsing,
|
||||
buffer/memory overflow checks, filesystem hardening
|
||||
on corrupted filesystems), CVE fixes.
|
||||
|
||||
Too many changes to do the traditional custom changelog. But, this
|
||||
is now unnecessary, so instead list most significant 15% of commits
|
||||
from git changelog in chronological order.
|
||||
|
||||
- unsquashfs: add checks for corrupted data in opendir functions
|
||||
- unsquashfs: completely empty filesystems incorrectly generate an error
|
||||
- unsquashfs: fix open file limit
|
||||
- mksquashfs: Use linked list to store directory entries rather
|
||||
- mksquashfs: Remove qsort and add a bottom up linked list merge sort
|
||||
- mksquashfs: optimise lookup_inode2() for dirs
|
||||
- pseudo: fix handling of modify pseudo files
|
||||
- pseudo: fix handling of directory pseudo files
|
||||
- xattr: Fix ERROR() so that it is synchronised with the progress bar
|
||||
- mksquashfs/sort: Fix INFO() so that it is synced with the progress bar
|
||||
- mksquashfs: Add -progress to force progress bar when using -info
|
||||
- error.h: consolidate the various error macros into one header file
|
||||
- mksquashfs: fix stack overflow in write_fragment_table()
|
||||
- mksquashfs: move list allocation from off the stack
|
||||
- unsquashfs: fix oversight in directory permission setting
|
||||
- mksquashfs: dynamically allocate recovery_file
|
||||
- mksquashfs: dynamically allocate buffer in subpathname()
|
||||
- mksquashfs: dynamically allocate buffer in pathname()
|
||||
- unsquashfs: fix CVE-2012-4024
|
||||
- unsquashfs: fix CVE-2012-4025
|
||||
- mksquashfs: fix potential stack overflow in get_component()
|
||||
- mksquashfs: add parse_number() helper for numeric command line options
|
||||
- mksquasfs: check return value of fstat() in reader_read_file()
|
||||
- mksquashfs: dynamically allocate filename in old_add_exclude()
|
||||
- unsquashfs: dynamically allocate pathname in dir_scan()
|
||||
- unsquashfs: dynamically allocate pathname in pre_scan()
|
||||
- sort: dynamically allocate filename in add_sort_list()
|
||||
- mksquashfs: fix dir_scan() exit if lstat of source directory fails
|
||||
- pseudo: fix memory leak in read_pseudo_def() if exec_file() fails
|
||||
- pseudo: dynamically allocate path in dump_pseudo()
|
||||
- mksquashfs: dynamically allocate path in display_path2()
|
||||
- mksquashfs: dynamically allocate b_buffer in getbase()
|
||||
- pseudo: fix potential stack overflow in get_component()
|
||||
- pseudo: avoid buffer overflow in read_pseudo_def() using sscanf()
|
||||
- pseudo: dynamically allocate filename in exec_file()
|
||||
- pseudo: avoid buffer overflow in read_sort_file() using fscanf()
|
||||
- sort: tighten up sort file parsing
|
||||
- unsquashfs: fix name under-allocation in process_extract_files()
|
||||
- unsquashfs: avoid buffer overflow in print_filename() using sprintf()
|
||||
- Fix some limits in the file parsing routines
|
||||
- pseudo: Rewrite pseudo file processing
|
||||
- read_fs: fix small memory leaks in read_filesystem()
|
||||
- mksquashfs: fix fclose leak in reader_read_file() on I/O error
|
||||
- mksquashfs: fix frag struct leak in write_file_{process|blocks|frag}
|
||||
- unsquashfs_xattr: fix memory leak in write_xattr()
|
||||
- read_xattrs: fix xattr free in get_xattr() in error path
|
||||
- unsquashfs: add -user-xattrs option to only extract user.xxx xattrs
|
||||
- unsquashfs: add code to only print "not superuser" error message once
|
||||
- unsquashfs: check for integer overflow in user input
|
||||
- mksquashfs: check for integer overflow in user input
|
||||
- mksquashfs: fix "new" variable leak in dir_scan1()
|
||||
- read_fs: prevent buffer {over|under}flow in read_block() with
|
||||
corrupted filesystems
|
||||
- read_fs: check metadata blocks are expected size in scan_inode_table()
|
||||
- read_fs: check the root inode block is found in scan_inode_table()
|
||||
- read_fs: Further harden scan_inode_table() against corrupted
|
||||
filesystems
|
||||
- unsquashfs: prevent buffer {over|under}flow in read_block() with
|
||||
corrupted filesystems
|
||||
- read_xattrs: harden xattr data reading against corrupted filesystems
|
||||
- unsquash-[23]: harden frag table reading against corrupted filesystems
|
||||
- unsquash-4.c: harden uid/gid & frag table reading against corruption
|
||||
- unsquashfs: harden inode/directory table reading against corruption
|
||||
- mksquashfs: improve out of space in output filesystem handling
|
||||
- mksquashfs: flag lseek error in writer as probable out of space
|
||||
- mksquashfs: flag lseek error in write_destination as probable out of
|
||||
space
|
||||
- mksquashfs: print file being squashed when ^\ (SIGQUIT) typed
|
||||
- mksquashfs: make EXIT_MKSQUASHFS() etc restore via new restore thread
|
||||
- mksquashfs: fix recursive restore failure check
|
||||
- info: dump queue and cache status if ^\ hit twice within one second
|
||||
- mksquashfs: fix rare race condition in "locked fragment" queueing
|
||||
- lz4: add experimental support for lz4 compression
|
||||
- lz4: add support for lz4 "high compression"
|
||||
- lzo_wrapper: new implementation with compression options
|
||||
- gzip_wrapper: add compression options
|
||||
- mksquashfs: redo -comp <compressor> parsing
|
||||
- mksquashfs: display compressor options when -X option isn't recognised
|
||||
- mksquashfs: add -Xhelp option
|
||||
- mksquashfs/unsquashfs: fix mtime signedness
|
||||
- Mksquashfs: optimise duplicate checking when appending
|
||||
- Mksquashfs: introduce additional per CPU fragment process threads
|
||||
- Mksquashfs: significantly optimise fragment duplicate checking
|
||||
- read_fs: scan_inode_table(), fix memory leak on filesystem corruption
|
||||
- pseudo: add_pseudo(), fix use of freed variable
|
||||
- mksquashfs/unsquashfs: exclude/extract/pseudo files, fix handling of
|
||||
leaf name
|
||||
- mksquashfs: rewrite default queue size so it's based on physical mem
|
||||
- mksquashfs: add a new -mem <mbytes> option
|
||||
- mksquashfs: fix limit on the number of dynamic pseudo files
|
||||
- mksquashfs: make -mem take a normal byte value, optionally with a
|
||||
K, M or G
|
||||
|
||||
4.2 28 FEB 2011 XZ compression, and compression options support
|
||||
|
||||
1. Filesystem improvements:
|
||||
|
||||
1.1 Added XZ compression
|
||||
1.2 Added compression options support
|
||||
|
||||
2. Miscellaneous improvements/bug fixes
|
||||
|
||||
1.1 Add missing NO_XATTR filesystem flag to indicate no-xattrs
|
||||
option was specified and no xattrs should be stored when
|
||||
appending.
|
||||
1.2 Add suppport in Unquashfs -stat option for displaying
|
||||
NO_XATTR flag.
|
||||
1.3 Remove checkdata entry from Unsquashfs -stat option if a 4.0
|
||||
filesystem - checkdata is no longer supported.
|
||||
1.4 Fix appending bug when appending to an empty filesystem - this
|
||||
would be incorrectly treated as an error.
|
||||
1.5 Use glibc sys/xattr.h include rather than using attr/xattr.h
|
||||
which isn't present by default on some distributions.
|
||||
1.6 Unsquashfs, fix block calculation error with regular files when
|
||||
file size is between 2^32-block_size+1 and 2^32-1.
|
||||
1.7 Unsquashfs, fix sparse file writing when holes are larger than
|
||||
2^31-1.
|
||||
1.8 Add external CFLAGS and LDFLAGS support to Makefile, and allow
|
||||
build options to be specified on command line. Also don't
|
||||
over-write passed in CFLAGS definition.
|
||||
|
||||
|
||||
4.1 19 SEPT 2010 Major filesystem and tools improvements
|
||||
|
||||
1. Filesystem improvements:
|
||||
|
||||
1.1 Extended attribute support
|
||||
1.2 New compression framework
|
||||
1.3 Support for LZO compression
|
||||
1.4 Support for LZMA compression (not yet in mainline)
|
||||
|
||||
2. Mksquashfs improvements:
|
||||
|
||||
1.1 Enhanced pseudo file support
|
||||
1.2 New options for choosing compression algorithm used
|
||||
1.3 New options for controlling extended attributes
|
||||
1.4 Fix misalignment issues with memcpy etc. seen on ARM
|
||||
1.5 Fix floating point error in progress_bar when max == 0
|
||||
1.6 Removed use of get_nproc() call unavailable in ulibc
|
||||
1.7 Reorganised help text
|
||||
|
||||
3. Unsquashfs improvements:
|
||||
|
||||
1.1 New options for controlling extended attributes
|
||||
1.2 Fix misalignment issues with memcpy etc. seen on ARM
|
||||
1.3 Fix floating point error in progress_bar when max == 0
|
||||
1.4 Removed use of get_nproc() call unavailable in ulibc
|
||||
|
||||
|
||||
4.0 5 APR 2009 Major filesystems improvements
|
||||
|
||||
1. Kernel code improvements:
|
||||
|
||||
1.1 Fixed little endian layout adopted. All swapping macros
|
||||
removed, and in-line swapping added for big-endian
|
||||
architectures.
|
||||
1.2 Kernel code substantially improved and restructured.
|
||||
1.3 Kernel code split into separate files along functional lines.
|
||||
1.4 Vmalloc usage removed, and code changed to use separately
|
||||
allocated 4K buffers
|
||||
|
||||
2. Unsquashfs improvements:
|
||||
|
||||
2.1 Support for 4.0 filesystems added.
|
||||
2.2 Swapping macros rewritten.
|
||||
2.3 Unsquashfs code restructured and split into separate files.
|
||||
|
||||
3. Mksquashfs improvements:
|
||||
|
||||
3.1 Swapping macros rewritten. Fixed little-endian layout allows
|
||||
code to be optimised and only added at compile time for
|
||||
big endian systems.
|
||||
3.2 Support for pseudo files added.
|
||||
|
||||
3.4 26 AUG 2008 Performance improvements to Unsquashfs, Mksquashfs
|
||||
and the kernel code. Plus many small bug fixes.
|
||||
|
||||
1. Kernel code improvements:
|
||||
|
||||
1.1 Internal Squashfs kernel metadata and fragment cache
|
||||
implementations have been merged and optimised. Spinlocks are
|
||||
now used, locks are held for smaller periods and wakeups have
|
||||
been minimised. Small race condition fixed where if two or
|
||||
more processes tried to read the same cache block
|
||||
simultaneously they would both read and decompress it. 10-20%+
|
||||
speed improvement has been seen on tests.
|
||||
1.2 NFS export code rewritten following VFS changes in
|
||||
linux-2.6.24.
|
||||
1.3 New patches for linux-2.6.25, linux-2.6.26, and linux-2.6.27.
|
||||
Fixed patch for linux-2.6.24.
|
||||
1.4 Fixed small buffer_head leak in squashfs_read_data when
|
||||
handling badly corrupted filesystems.
|
||||
1.5 Fixed bug in get_dir_index_using_offset.
|
||||
|
||||
2. Unsquashfs improvements:
|
||||
|
||||
2.1 Unsquashfs has been parallelised. Filesystem reading, writing
|
||||
and decompression is now multi-threaded. Up to 40% speed
|
||||
improvement seen on tests.
|
||||
2.2 Unsquashfs now has a progress bar. Use -no-progress to
|
||||
disable it.
|
||||
2.3 Fixed small bug where unistd.h wasn't being included on
|
||||
some distributions, leading to lseek being used rather than
|
||||
lseek64 - which meant on these distributions Unsquashfs
|
||||
couldn't unsquash filesystems larger than 4GB.
|
||||
|
||||
3. Mksquashfs improvements:
|
||||
|
||||
3.1 Removed some small remaining parallelisation bottlenecks.
|
||||
Depending on source filesystem, up to 10%+ speed improvement.
|
||||
3.2 Progress bar improved, and moved to separate thread.
|
||||
3.3 Sparse file handling bug in Mksquashfs 3.3 fixed.
|
||||
3.4 Two rare appending restore bugs fixed (when ^C hit twice).
|
||||
|
||||
|
||||
3.3 1 NOV 2007 Increase in block size, sparse file support,
|
||||
Mksquashfs and Unsquashfs extended to use
|
||||
pattern matching in exclude/extract files, plus
|
||||
many more improvements and bug fixes.
|
||||
|
||||
1. Filesystem improvements:
|
||||
|
||||
1.1. Maximum block size has been increased to 1Mbyte, and the
|
||||
default block size has been increased to 128 Kbytes.
|
||||
This improves compression.
|
||||
|
||||
1.2. Sparse files are now supported. Sparse files are files
|
||||
which have large areas of unallocated data commonly called
|
||||
holes. These files are now detected by Squashfs and stored
|
||||
more efficiently. This improves compression and read
|
||||
performance for sparse files.
|
||||
|
||||
2. Mksquashfs improvements:
|
||||
|
||||
2.1. Exclude files have been extended to use wildcard pattern
|
||||
matching and regular expressions. Support has also been
|
||||
added for non-anchored excludes, which means it is
|
||||
now possible to specify excludes which match anywhere
|
||||
in the filesystem (i.e. leaf files), rather than always
|
||||
having to specify exclude files starting from the root
|
||||
directory (anchored excludes).
|
||||
|
||||
2.2. Recovery files are now created when appending to existing
|
||||
Squashfs filesystems. This allows the original filesystem
|
||||
to be recovered if Mksquashfs aborts unexpectedly
|
||||
(i.e. power failure).
|
||||
|
||||
3. Unsquashfs improvements:
|
||||
|
||||
3.1. Multiple extract files can now be specified on the
|
||||
command line, and the files/directories to be extracted can
|
||||
now also be given in a file.
|
||||
|
||||
3.2. Extract files have been extended to use wildcard pattern
|
||||
matching and regular expressions.
|
||||
|
||||
3.3. Filename printing has been enhanced and Unquashfs can
|
||||
now display filenames with file attributes
|
||||
('ls -l' style output).
|
||||
|
||||
3.4. A -stat option has been added which displays the filesystem
|
||||
superblock information.
|
||||
|
||||
3.5. Unsquashfs now supports 1.x filesystems.
|
||||
|
||||
4. Miscellaneous improvements/bug fixes:
|
||||
|
||||
4.1. Squashfs kernel code improved to use SetPageError in
|
||||
squashfs_readpage() if I/O error occurs.
|
||||
|
||||
4.2. Fixed Squashfs kernel code bug preventing file
|
||||
seeking beyond 2GB.
|
||||
|
||||
4.3. Mksquashfs now detects file size changes between
|
||||
first phase directory scan and second phase filesystem create.
|
||||
It also deals better with file I/O errors.
|
||||
|
||||
|
||||
3.2-r2 15 JAN 2007 Kernel patch update and progress bar bug fix
|
||||
|
||||
1. Kernel patches 2.6.19/2.6.20 have been updated to use
|
||||
const structures and mutexes rather than older semaphores.
|
||||
2. Minor SMP bug fixes.
|
||||
3. Progress bar broken on x86-64. Fixed.
|
||||
|
||||
3.2 2 JAN 2007 NFS support, improvements to the Squashfs-tools, major
|
||||
bug fixes, lots of small improvements/bug fixes, and new
|
||||
kernel patches.
|
||||
|
||||
Improvements:
|
||||
|
||||
1. Squashfs filesystems can now be exported via NFS.
|
||||
2. Unsquashfs now supports 2.x filesystems.
|
||||
3. Mksquashfs now displays a progress bar.
|
||||
4. Squashfs kernel code has been hardened against accidently or
|
||||
maliciously corrupted Squashfs filesystems.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
5. Race condition occurring on S390 in readpage() fixed.
|
||||
6. Odd behaviour of MIPS memcpy in read_data() routine worked-around.
|
||||
7. Missing cache_flush in Squashfs symlink_readpage() added.
|
||||
|
||||
|
||||
3.1-r2 30 AUG 2006 Mksquashfs -sort bug fix
|
||||
|
||||
A code optimisation after testing unfortunately
|
||||
broke sorting in Mksquashfs. This has been fixed.
|
||||
|
||||
3.1 19 AUG 2006 This release has some major improvements to
|
||||
the squashfs-tools, a couple of major bug
|
||||
fixes, lots of small improvements/bug fixes,
|
||||
and new kernel patches.
|
||||
|
||||
|
||||
1. Mksquashfs has been rewritten to be multi-threaded. It
|
||||
has the following improvements
|
||||
|
||||
1.1. Parallel compression. By default as many compression and
|
||||
fragment compression threads are created as there are available
|
||||
processors. This significantly speeds up performance on SMP
|
||||
systems.
|
||||
1.2. File input and filesystem output is peformed in parallel on
|
||||
separate threads to maximise I/O performance. Even on single
|
||||
processor systems this speeds up performance by at least 10%.
|
||||
1.3. Appending has been significantly improved, and files within the
|
||||
filesystem being appended to are no longer scanned and
|
||||
checksummed. This significantly improves append time for large
|
||||
filesystems.
|
||||
1.4. File duplicate checking has been optimised, and split into two
|
||||
separate phases. Only files which are considered possible
|
||||
duplicates after the first phase are checksummed and cached in
|
||||
memory.
|
||||
1.5 The use of swap memory was found to significantly impact
|
||||
performance. The amount of memory used to cache files is now a
|
||||
command line option, by default this is 512 Mbytes.
|
||||
|
||||
2. Unsquashfs has the following improvements
|
||||
|
||||
2.1 Unsquashfs now allows you to specify the filename or the
|
||||
directory within the Squashfs filesystem that is to be
|
||||
extracted, rather than always extracting the entire filesystem.
|
||||
2.2 A new -force option has been added which forces Unsquashfs to
|
||||
output to the destination directory even if files and directories
|
||||
already exist in the destination directory. This allows you to
|
||||
update an already existing directory tree, or to Unsquashfs to
|
||||
a partially filled directory tree. Without the -force option
|
||||
Unsquashfs will refuse to output.
|
||||
|
||||
3. The following major bug fixes have been made
|
||||
|
||||
3.1 A fragment table rounding bug has been fixed in Mksquashfs.
|
||||
Previously if the number of fragments in the filesystem
|
||||
were a multiple of 512, Mksquashfs would generate an
|
||||
incorrect filesystem.
|
||||
3.2 A rare SMP bug which occurred when simultaneously acccessing
|
||||
multiply mounted Squashfs filesystems has been fixed.
|
||||
|
||||
4. Miscellaneous improvements/bug fixes
|
||||
|
||||
4.1 Kernel code stack usage has been reduced. This is to ensure
|
||||
Squashfs works with 4K stacks.
|
||||
4.2 Readdir (Squashfs kernel code) has been fixed to always
|
||||
return 0, rather than the number of directories read. Squashfs
|
||||
should now interact better with NFS.
|
||||
4.3 Lseek bug in Mksquashfs when appending to larger than 4GB
|
||||
filesystems fixed.
|
||||
4.4 Squashfs 2.x initrds can now been mounted.
|
||||
4.5 Unsquashfs exit status fixed.
|
||||
4.6 New patches for linux-2.6.18 and linux-2.4.33.
|
||||
|
||||
|
||||
3.0 15 MAR 2006 Major filesystem improvements
|
||||
|
||||
1. Filesystems are no longer limited to 4 GB. In
|
||||
theory 2^64 or 4 exabytes is now supported.
|
||||
2. Files are no longer limited to 4 GB. In theory the maximum
|
||||
file size is 4 exabytes.
|
||||
3. Metadata (inode table and directory tables) are no longer
|
||||
restricted to 16 Mbytes.
|
||||
4. Hardlinks are now suppported.
|
||||
5. Nlink counts are now supported.
|
||||
6. Readdir now returns '.' and '..' entries.
|
||||
7. Special support for files larger than 256 MB has been added to
|
||||
the Squashfs kernel code for faster read access.
|
||||
8. Inode numbers are now stored within the inode rather than being
|
||||
computed from inode location on disk (this is not so much an
|
||||
improvement, but a change forced by the previously listed
|
||||
improvements).
|
||||
|
||||
2.2-r2 8 SEPT 2005 Second release of 2.2, this release fixes a couple
|
||||
of small bugs, a couple of small documentation
|
||||
mistakes, and adds a patch for kernel 2.6.13.
|
||||
|
||||
1. Mksquashfs now deletes the output filesystem image file if an
|
||||
error occurs whilst generating the filesystem. Previously on
|
||||
error the image file was left empty or partially written.
|
||||
2. Updated mksquashfs so that it doesn't allow you to generate
|
||||
filesystems with block sizes smaller than 4K. Squashfs hasn't
|
||||
supported block sizes less than 4K since 2.0-alpha.
|
||||
3. Mksquashfs now ignores missing files/directories in sort files.
|
||||
This was the original behaviour before 2.2.
|
||||
4. Fixed small mistake in fs/Kconfig where the version was still
|
||||
listed as 2.0.
|
||||
5. Updated ACKNOWLEDGEMENTS file.
|
||||
|
||||
|
||||
2.2 3 JUL 2005 This release has some small improvements, bug fixes
|
||||
and patches for new kernels.
|
||||
|
||||
1. Sort routine re-worked and debugged from release 2.1. It now allows
|
||||
you to give Mkisofs style sort files and checks for filenames that
|
||||
don't match anything. Sort priority has also been changed to
|
||||
conform to Mkisofs usage, highest priority files are now placed
|
||||
at the start of the filesystem (this means they will be on the
|
||||
inside of a CD or DVD).
|
||||
2. New Configure options for embedded systems (memory constrained
|
||||
systems). See INSTALL file for further details.
|
||||
3. Directory index bug fixed where chars were treated as signed on
|
||||
some architectures. A file would not be found in the rare case
|
||||
that the filename started with a chracter greater than 127.
|
||||
4. Bug introduced into the read_data() routine when sped up to use data
|
||||
block queueing fixed. If the second or later block resulted in an
|
||||
I/O error this was not checked.
|
||||
5. Append bug introduced in 2.1 fixed. The code to compute the new
|
||||
compressed and uncompressed directory parts after appending was
|
||||
wrong.
|
||||
6. Metadata block length read routine altered to not perform a
|
||||
misaligned short read. This was to fix reading on an ARM7 running
|
||||
uCLinux without a misaligned read interrupt handler.
|
||||
7. Checkdata bug introduced in 2.1 fixed.
|
||||
|
||||
|
||||
2.1-r2 15 DEC 2004 Code changed so it can be compiled with gcc 2.x
|
||||
|
||||
1. In some of the code added for release 2.1 I unknowingly used some
|
||||
gcc extensions only supported by 3.x compilers. I have received
|
||||
a couple of reports that the 2.1 release doesn't build on 2.x and so
|
||||
people are clearly still using gcc 2.x. The code has been
|
||||
rewritten to remove these extensions.
|
||||
|
||||
2.1 10 DEC 2004 Significantly improved directory handling plus numerous
|
||||
other smaller improvements
|
||||
|
||||
1. Fast indexed directories implemented. These speed up directory
|
||||
operations (ls, file lookup etc.) significantly for directories
|
||||
larger than 8 KB.
|
||||
2. All directories are now sorted in alphabetical order. This again
|
||||
speeds up directory operations, and in some cases it also results in
|
||||
a small compression improvement (greater data similarity between
|
||||
files with alphabetically similar names).
|
||||
3. Maximum directory size increased from 512 KB to 128 MB.
|
||||
4. Duplicate fragment checking and appending optimised in mksquashfs,
|
||||
depending on filesystem, this is now up to 25% faster.
|
||||
5. Mksquashfs help information reformatted and reorganised.
|
||||
6. The Squashfs version and release date is now printed at kernel
|
||||
boot-time or module insertion. This addition will hopefully help
|
||||
to reduce the growing problem where the Squashfs version supported
|
||||
by a kernel is unknown and the kernel source is unavailable.
|
||||
7. New PERFORMANCE.README file.
|
||||
8. New -2.0 mksquashfs option.
|
||||
9. CHANGES file reorganised.
|
||||
10. README file reorganised, clarified and updated to include the 2.0
|
||||
mksquashfs options.
|
||||
11. New patch for Linux 2.6.9.
|
||||
12. New patch for Linux 2.4.28.
|
||||
|
||||
2.0r2 29 AUG 2004 Workaround for kernel bug in kernels 2.6.8 and newer
|
||||
added
|
||||
|
||||
1. New patch for kernel 2.6.8.1. This includes a workaround for a
|
||||
kernel bug introduced in 2.6.7bk14, which is present in all later
|
||||
versions of the kernel.
|
||||
|
||||
If you're using a 2.6.8 kernel or later then you must use this
|
||||
2.6.8.1 patch. If you've experienced hangs or oopses using Squashfs
|
||||
with a 2.6.8 or later kernel then you've hit this bug, and this
|
||||
patch will fix it.
|
||||
|
||||
It is worth mentioning that this kernel bug potentially affects
|
||||
other filesystems. If you receive odd results with other
|
||||
filesystems you may be experiencing this bug with that filesystem.
|
||||
I submitted a patch but this has not yet gone into the
|
||||
kernel, hopefully the bug will be fixed in later kernels.
|
||||
|
||||
2.0 13 JULY 2004 A couple of new options, and some bug fixes
|
||||
|
||||
1. New mksquashfs -all-root, -root-owned, -force-uid, and -force-gid
|
||||
options. These allow the uids/gids of files in the generated
|
||||
filesystem to be specified, overriding the uids/gids in the
|
||||
source filesystem.
|
||||
2. Initrds are now supported for kernels 2.6.x.
|
||||
3. amd64 bug fixes. If you use an amd64, please read the README-AMD64
|
||||
file.
|
||||
4. Check-data and gid bug fixes. With 2.0-alpha when mounting 1.x
|
||||
filesystems in certain cases file gids were corrupted.
|
||||
5. New patch for Linux 2.6.7.
|
||||
|
||||
2.0-ALPHA 21 MAY 2004 Filesystem changes and compression improvements
|
||||
|
||||
1. Squashfs 2.0 has added the concept of fragment blocks.
|
||||
Files smaller than the file block size and optionally the
|
||||
remainder of files that do not fit fully into a block (i.e. the
|
||||
last 32K in a 96K file) are packed into shared fragments and
|
||||
compressed together. This achieves on average 5 - 20% better
|
||||
compression than Squashfs 1.x.
|
||||
2. The maximum block size has been increased to 64K (in the ALPHA
|
||||
version of Squashfs 2.0).
|
||||
3. The maximum number of UIDs has been increased to 256 (from 48 in
|
||||
1.x).
|
||||
4. The maximum number of GIDs has been increased to 256 (from 15 in
|
||||
1.x).
|
||||
5. Removal of sleep_on() function call in 2.6.x patch, to allow Squashfs
|
||||
to work on the Fedora rc2 kernel.
|
||||
6. Numerous small bug fixes have been made.
|
||||
|
||||
1.3r3 18 JAN 2004 Third release of 1.3, this adds a new mksquashfs option,
|
||||
some bug fixes, and extra patches for new kernels
|
||||
|
||||
1. New mksquashfs -ef exclude option. This option reads the exclude
|
||||
dirs/files from an exclude file, one exclude dir/file per line. This
|
||||
avoids the command line size limit when using the -e exclude option,
|
||||
2. When appending to existing filesystems, if mksquashfs experiences a
|
||||
fatal error (e.g. out of space when adding to the destination), the
|
||||
original filesystem is restored,
|
||||
3. Mksquashfs now builds standalone, without the kernel needing to be
|
||||
patched.
|
||||
4. Bug fix in the kernel squashfs filesystem, where the pages being
|
||||
filled were not kmapped. This seems to only have caused problems
|
||||
on an Apple G5,
|
||||
5. New patch for Linux 2.4.24,
|
||||
|
||||
6. New patch for Linux 2.6.1, this replaces the patch for 2.6.0-test7.
|
||||
|
||||
1.3r2 14 OCT 2003 Second release of 1.3, bug fixes and extra patches for
|
||||
new kernels
|
||||
|
||||
1. Bug fix in routine that adds files to the filesystem being
|
||||
generated in mksquashfs. This bug was introduced in 1.3
|
||||
(not enough testing...) when I rewrote it to handle files larger
|
||||
than available memory. This bug caused a SEGV, so if you've ever
|
||||
got that, it is now fixed,
|
||||
2. Long running bug where ls -s and du reported wrong block size
|
||||
fixed. I'm pretty sure this used to work many kernel versions ago
|
||||
(2.4.7) but it broke somewhere along the line since then,
|
||||
3. New patch for Linux 2.4.22,
|
||||
4. New patch for 2.6.0-test7, this replaces the patch for 2.6.0-test1.
|
||||
|
||||
1.3 29 JUL 2003 FIFO/Socket support added plus optimisations and
|
||||
improvements
|
||||
|
||||
1. FIFOs and Socket inodes are now supported,
|
||||
2. Mksquashfs can now compress files larger than available
|
||||
memory,
|
||||
3. File duplicate check routine optimised,
|
||||
4. Exit codes fixed in Mksquashfs,
|
||||
5. Patch for Linux 2.4.21,
|
||||
6. Patch for Linux 2.6.0-test1. Hopefully, this will work for
|
||||
the next few releases of 2.6.0-testx, otherwise, I'll be
|
||||
releasing a lot of updates to the 2.6.0 patch...
|
||||
|
||||
1.2 13 MAR 2003 Append feature and new mksquashfs options added
|
||||
|
||||
Mksquashfs can now add to existing squashfs filesystems. Three extra
|
||||
options "-noappend", "-keep-as-directory", and "root-becomes"
|
||||
have been added.
|
||||
|
||||
The append option with file duplicate detection, means squashfs can be
|
||||
used as a simple versioning archiving filesystem. A squashfs
|
||||
filesystem can be created with for example the linux-2.4.19 source.
|
||||
Appending the linux-2.4.20 source will create a filesystem with the
|
||||
two source trees, but only the changed files will take extra room,
|
||||
the unchanged files will be detected as duplicates.
|
||||
|
||||
See the README file for usage changes.
|
||||
|
||||
1.1b 16 JAN 2003 Bug fix release
|
||||
|
||||
Fixed readpage deadlock bug. This was a rare deadlock bug that
|
||||
happened when pushing pages into the page cache when using greater
|
||||
than 4K blocks. I never got this bug when I tested the filesystem,
|
||||
but two people emailed me on the same day about the problem!
|
||||
I fixed it by using a page cache function that wasn't there when
|
||||
I originally did the work, which was nice :-)
|
||||
|
||||
1.1 8 JAN 2003 Added features
|
||||
|
||||
1. Kernel squashfs can now mount different byte order filesystems.
|
||||
2. Additional features added to mksquashfs. Mksquashfs now supports
|
||||
exclude files and multiple source files/directories can be
|
||||
specified. A nopad option has also been added, which
|
||||
informs mksquashfs not to pad filesystems to a multiple of 4K.
|
||||
See README for mksquashfs usage changes.
|
||||
3. Greater than 2GB filesystems bug fix. Filesystems greater than 2GB
|
||||
can now be created.
|
||||
|
||||
1.0c 14 NOV 2002 Bug fix release
|
||||
|
||||
Fixed bugs with initrds and device nodes
|
||||
|
||||
1.0 23 OCT 2002 Initial release
|
||||
339
SQUASHFS/squashfs-tools-4.4/COPYING
Normal file
339
SQUASHFS/squashfs-tools-4.4/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
44
SQUASHFS/squashfs-tools-4.4/INSTALL
Normal file
44
SQUASHFS/squashfs-tools-4.4/INSTALL
Normal file
@@ -0,0 +1,44 @@
|
||||
INSTALLING SQUASHFS
|
||||
|
||||
1. Kernel support
|
||||
-----------------
|
||||
|
||||
This release is for 2.6.29 and newer kernels. Kernel patching is not necessary.
|
||||
|
||||
Extended attribute support requires 2.6.35 or newer kernels. But
|
||||
file systems with extended attributes can be mounted on 2.6.29 and
|
||||
newer kernels (the extended attributes will be ignored with a warning).
|
||||
|
||||
LZO compression support requires 2.6.36 or newer kernels.
|
||||
|
||||
XZ compression support requires 2.6.38 or newer kernels.
|
||||
|
||||
LZ4 compression support requires 3.11 or newer kernels.
|
||||
|
||||
ZSTD compression support requires 4.14 or newer kernels.
|
||||
|
||||
2. Building squashfs tools
|
||||
--------------------------
|
||||
|
||||
The squashfs-tools directory contains the source code for the Mksquashfs and
|
||||
Unsquashfs programs. These can be compiled by typing make (or sudo make
|
||||
install to install in /usr/local/bin) within that directory.
|
||||
|
||||
2.1 Compressors supported
|
||||
|
||||
By default the Makefile is configured to build Mksquashfs and Unsquashfs
|
||||
with GZIP suppport. Read the Makefile in squashfs-tools for instructions on
|
||||
building LZO, LZ4, XZ and ZSTD compression support.
|
||||
|
||||
2.2 Extended attribute support
|
||||
|
||||
By default the Makefile is configured to build Mksquashfs and Unsquashfs
|
||||
with extended attribute support. Read the Makefile in squashfs-tools for
|
||||
instructions on how to disable extended attribute support, if not supported
|
||||
by your distribution/C library, or if it is not needed.
|
||||
|
||||
2.3 Reproducible builds
|
||||
|
||||
By default the Makefile is configured to build Mksquashfs with reproducible
|
||||
output as default. Read the Makefile in squashfs-tools for instructions
|
||||
on how to disable reproducible output as default if desired.
|
||||
15
SQUASHFS/squashfs-tools-4.4/README
Normal file
15
SQUASHFS/squashfs-tools-4.4/README
Normal file
@@ -0,0 +1,15 @@
|
||||
GitHub
|
||||
|
||||
This is now the main development repository for Squashfs-Tools.
|
||||
|
||||
There are older repositories on Sourceforge and kernel.org. These
|
||||
are currently out of date, but should be updated in the near future.
|
||||
|
||||
The kernel directories are obsolete, all kernel code is now in
|
||||
mainline at www.kernel.org.
|
||||
|
||||
kernel-2.4: If you still need Squashfs support in the 2.4 kernel
|
||||
then use the squashfs 3.2-r2 release. This is the last release
|
||||
that has a Mksquashfs which generates filesystems mountable with
|
||||
Squashfs patched 2.4 kernels. This release has patches for 2.4
|
||||
kernels (but they have not been updated since the 3.1 release).
|
||||
316
SQUASHFS/squashfs-tools-4.4/README-4.4
Normal file
316
SQUASHFS/squashfs-tools-4.4/README-4.4
Normal file
@@ -0,0 +1,316 @@
|
||||
SQUASHFS 4.4 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2019 Phillip Lougher <phillip@squashfs.org.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs 4.4. This is the first release in over 5 years, and
|
||||
there are substantial improvements: reproducible builds, new compressors,
|
||||
CVE fixes, security hardening and new options for Mksquashfs/Unsquashfs.
|
||||
|
||||
Please see the INSTALL file for instructions on installing the tools,
|
||||
and the USAGE file for documentation on how to use the tools.
|
||||
|
||||
Summary of changes (and sections below)
|
||||
---------------------------------------
|
||||
|
||||
1. Mksquashfs now generates reproducible images by default. Mkfs time and
|
||||
file timestamps can also be specified.
|
||||
|
||||
2. Support for the Zstandard (ZSTD) compression algorithm has been added.
|
||||
|
||||
3. Pseudo files now support symbolic links.
|
||||
|
||||
4. CVE-2015-4645 and CVE-2015-4646 have been fixed.
|
||||
|
||||
5. Unsquashfs has been further hardened against corrupted filestems.
|
||||
|
||||
6. Unsquashfs is now more strict about error handling.
|
||||
|
||||
7. Miscellaneous new options and major bug fixes for Mksquashfs.
|
||||
|
||||
8. Miscellaneous new options and major bug fixes for Unsquashfs.
|
||||
|
||||
9. Squashfs-tools 4.4 is compatible with all earlier 4.x filesystems
|
||||
and releases.
|
||||
|
||||
|
||||
1. Introducing reproducible builds
|
||||
----------------------------------
|
||||
|
||||
Ever since Mksquashfs was parallelised back in 2006, there
|
||||
has been a certain randomness in how fragments and multi-block
|
||||
files are ordered in the output filesystem even if the input
|
||||
remains the same.
|
||||
|
||||
This is because the multiple parallel threads can be scheduled
|
||||
differently between Mksquashfs runs. For example, the thread
|
||||
given fragment 10 to compress may finish before the thread
|
||||
given fragment 9 to compress on one run (writing fragment 10
|
||||
to the output filesystem before fragment 9), but, on the next
|
||||
run it could be vice-versa. There are many different scheduling
|
||||
scenarios here, all of which can have a knock on effect causing
|
||||
different scheduling and ordering later in the filesystem too.
|
||||
|
||||
Mkquashfs doesn't care about the ordering of fragments and
|
||||
multi-block files within the filesystem, as this does not
|
||||
affect the correctness of the filesystem.
|
||||
|
||||
In fact not caring about the ordering, as it doesn't matter, allows
|
||||
Mksquashfs to run as fast as possible, maximising CPU and I/O
|
||||
performance.
|
||||
|
||||
But, in the last couple of years, Squashfs has become used in
|
||||
scenarios (cloud etc) where this randomness is causing problems.
|
||||
Specifically this appears to be where downloaders, installers etc.
|
||||
try to work out the differences between Squashfs filesystem
|
||||
updates to minimise the amount of data that needs to transferred
|
||||
to update an image.
|
||||
|
||||
Additionally, in the last couple of years has arisen the notion
|
||||
of reproducible builds, that is the same source and build
|
||||
environment etc should be able to (re-)generate identical
|
||||
output. This is usually for verification and security, allowing
|
||||
binaries/distributions to be checked for malicious activity.
|
||||
See https://reproducible-builds.org/ for more information.
|
||||
|
||||
Mksquashfs now generates reproducible images by default.
|
||||
Images generated by Mksquashfs will be ordered identically to
|
||||
previous runs if the same input has been supplied, and the
|
||||
same options used.
|
||||
|
||||
1.1.1 Dealing with timestamps
|
||||
|
||||
Timestamps embedded in the filesystem will stiil cause differences.
|
||||
Each new run of Mksquashfs will produce a different mkfs (make filesystem)
|
||||
timestamp in the super-block. Moreover if any file timestamps have changed
|
||||
(even if the content hasn't), this will produce a difference.
|
||||
|
||||
To prevent timestamps from producing differences, the following
|
||||
new Mksquashfs options have been added.
|
||||
|
||||
1.1.2 -mkfs-time <time>
|
||||
|
||||
This option takes a positive time value (which is the number
|
||||
of seconds since the epoch of 1970-01-01 00:00:00 UTC), and sets
|
||||
the file system timestamp to that.
|
||||
|
||||
Squashfs uses an unsigned 32-bit integer to store time, and the
|
||||
time given should be in that range.
|
||||
|
||||
Obviously you can use the date command to convert dates into
|
||||
this value, i.e.
|
||||
|
||||
% mksquashfs source source.sqsh -mkfs-time $(date +%s -d "Jan 1 2019 19:00")
|
||||
|
||||
1.1.3 -all-time <time>
|
||||
|
||||
This option takes a positive time value (which is the number
|
||||
of seconds since the epoch of 1970-01-01 00:00:00 UTC), and sets
|
||||
the timestamp on all files to that (but not the mkfs time).
|
||||
|
||||
1.1.4 environment variable SOURCE_DATE_EPOCH
|
||||
|
||||
As an alternative to the above command line options, you can
|
||||
set the environment variable SOURCE_DATE_EPOCH to a time value.
|
||||
|
||||
This value will be used to set the mkfs time. Also any
|
||||
file timestamps which are after SOURCE_DATE_EPOCH will be
|
||||
clamped to SOURCE_DATE_EPOCH.
|
||||
|
||||
See https://reproducible-builds.org/docs/source-date-epoch/
|
||||
for more information.
|
||||
|
||||
Note: both SOURCE_DATE_EPOCH and the command line options cannot
|
||||
be used at the same time. They are different ways to do the same thing,
|
||||
and both have FORCE sematics which mean they can't be over-ridden
|
||||
elsewhere (otherwise it would defeat the purpose).
|
||||
|
||||
1.1.5 -not-reproducible
|
||||
|
||||
This option tells Mksquashfs that the files do not have to be
|
||||
strictly ordered. This will make Mksquashfs behave like version 4.3.
|
||||
|
||||
|
||||
2. Zstandard (ZSTD) compression added
|
||||
-------------------------------------
|
||||
|
||||
This is named zstd. It supports the following
|
||||
compression options.
|
||||
|
||||
zstd
|
||||
-Xcompression-level <compression-level>
|
||||
<compression-level> should be 1 .. 22 (default 15)
|
||||
|
||||
|
||||
3. Pseudo file symbolic link support added
|
||||
------------------------------------------
|
||||
|
||||
Pseudo definition
|
||||
|
||||
Filename s mode uid gid symlink
|
||||
|
||||
uid and gid can be either specified as a decimal number, or by name.
|
||||
|
||||
Note mode is ignored, as symlinks always have "rwxrwxrwx" permissions.
|
||||
|
||||
For example:
|
||||
|
||||
symlink s 0 root root example
|
||||
|
||||
creates a symlink "symlink" to file "example" with root uid/gid.
|
||||
|
||||
|
||||
4. CVE-2015-2015-4645 and CVE-2015-4646
|
||||
---------------------------------------
|
||||
|
||||
These CVEs were raised due to Unsquashfs having variable overflow and
|
||||
stack overflow in a number of vulnerable functions.
|
||||
|
||||
All instances of variable overflow and stack overflow have been
|
||||
removed.
|
||||
|
||||
|
||||
5. Unsquashfs hardened against corrupted filestems
|
||||
--------------------------------------------------
|
||||
|
||||
The filesystem super-block values and filesystem metadata tables
|
||||
are further sanity checked. More importantly, these values are now
|
||||
checked for validity against other values in the metadata tables, and
|
||||
these values must match.
|
||||
|
||||
|
||||
6. Unsquashfs is now more strict about error handling
|
||||
-----------------------------------------------------
|
||||
|
||||
Unsquashfs splits errors into two categories: fatal errors and non-fatal
|
||||
errors. In this release a significant number of errors that were previously
|
||||
non-fatal have been hardened to fatal.
|
||||
|
||||
Fatal errors are those which cause Unsquashfs to abort instantly.
|
||||
These are generally due to failure to read the filesystem (corruption),
|
||||
and/or failure to write files to the output filesystem, due to I/O error
|
||||
or out of space. Generally anything which is unexpected is a fatal error.
|
||||
|
||||
Non-fatal errors are generally where support is lacking in the
|
||||
output filesystem, and it can be considered to be an expected failure.
|
||||
This includes the inability to write extended attributes (xattrs) to
|
||||
a filesystem that doesn't support them, the inability to create files on
|
||||
filesystem that doesn't support them (i.e. symbolic links on VFAT), and the
|
||||
inability to execute privileged operations as a user-process.
|
||||
|
||||
The user may well know the filesystem cannot support certain operations
|
||||
and would prefer Unsquashfs to ignore then without aborting.
|
||||
|
||||
Two new options have been added:
|
||||
|
||||
6.1. -ignore-errors
|
||||
|
||||
This makes Unsquashfs behave like previous versions, and treats more
|
||||
errors as non-fatal.
|
||||
|
||||
6.2. -strict-errors
|
||||
|
||||
This makes Unsquashfs treat every error as fatal, and it will abort
|
||||
instantly.
|
||||
|
||||
|
||||
7. Miscellaneous new options and major bug fixes for Mksquashfs
|
||||
---------------------------------------------------------------
|
||||
|
||||
7.1. -root-mode <mode>
|
||||
|
||||
This sets the permissions of the root directory to the octal <mode>.
|
||||
This is mostly intended for when multiple sources are specified on
|
||||
the command line. In this instance Mksquashfs produces a dummy top level
|
||||
directory with permissions 0777 (rwxrwxrwx). This option allows the
|
||||
permissions to be changed. But the option can also be used when a single
|
||||
source is specified.
|
||||
|
||||
7.2. -quiet
|
||||
|
||||
This suppresses all output from Mksquashfs, except the progress bar.
|
||||
|
||||
The progress bar can disabled with -no-progress to produce completely
|
||||
silent output.
|
||||
|
||||
This new option is useful for scripts.
|
||||
|
||||
7.3. -noId
|
||||
|
||||
This is similar to the pre-existing -noI option, except, it specifies that
|
||||
only the Id table (uids and gids) should be uncompressed. This option was
|
||||
added to enable a use-case where uids and gids need to be updated after
|
||||
filesystem generation.
|
||||
|
||||
7.4. -offset <offset>
|
||||
|
||||
This option skips <offset> bytes at the beginning of the output filesystem.
|
||||
|
||||
Optionally a suffix of K, M or G can be given to specify Kbytes, Mbytes or
|
||||
Gbytes respectively.
|
||||
|
||||
7.5. Update lz4 wrapper to use new functions introduced in 1.7.0
|
||||
|
||||
7.5. Bug fix, don't allow "/" pseudo filenames
|
||||
|
||||
7.6. Bug fix, allow quoting of pseudo files, to better handle filenames with
|
||||
spaces
|
||||
|
||||
7.7. Fix compilation with glibc 2.25+
|
||||
|
||||
|
||||
8. Miscellaneous new options and major bug fixes for Unsquashfs
|
||||
---------------------------------------------------------------
|
||||
|
||||
8.1. -lln[umeric]
|
||||
|
||||
This is similar to the "-lls" option but displays uids and gids numerically.
|
||||
|
||||
8.2. -lc option
|
||||
|
||||
This is similar to the "-ls" option except it only displays files and empty
|
||||
directories.
|
||||
|
||||
8.3. -llc option
|
||||
|
||||
As "-llc" option but displays file attributes.
|
||||
|
||||
8.4. -offset <offset>
|
||||
|
||||
This option skips <offset> bytes at the beginning of the input filesystem.
|
||||
|
||||
Optionally a suffix of K, M or G can be given to specify Kbytes, Mbytes or
|
||||
Gbytes respectively.
|
||||
|
||||
8.5. -quiet
|
||||
|
||||
This suppresses all output from Unsquashfs, except the progress bar.
|
||||
|
||||
The progress bar can disabled with -no-progress to produce completely
|
||||
silent output.
|
||||
|
||||
This new option is useful for scripts.
|
||||
|
||||
8.6. -UTC
|
||||
|
||||
This option makes Unsquashfs display all times in the UTC time zone rather
|
||||
than using the default local time zone.
|
||||
|
||||
8.7. Update lz4 wrapper to use new functions introduced in 1.7.0
|
||||
|
||||
8.8. Bug fix, fatal and non-fatal errors now set the exit code to 1
|
||||
|
||||
8.9. Bug fix, fix time setting for symlinks
|
||||
|
||||
8.10. Bug fix, try to set sticky-bit when running as a user process
|
||||
|
||||
8.11. Fix compilation with glibc 2.25+
|
||||
|
||||
|
||||
9. Compatiblity
|
||||
---------------
|
||||
|
||||
Mksquashfs 4.4 generates 4.0 filesystems. These filesystems are fully
|
||||
compatible/interchangable with filesystems generated by Mksquashfs 4.x and are
|
||||
mountable on 2.6.29 and later kernels.
|
||||
15
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/DONATIONS
Normal file
15
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/DONATIONS
Normal file
@@ -0,0 +1,15 @@
|
||||
Help sponsor Squashfs development!
|
||||
|
||||
Maintaining and improving Squashfs is a lot of work, but Squashfs is one of
|
||||
the only widely used Linux file systems that has no company backing. Squashfs
|
||||
development is funded soley by the author, partially supported by donations
|
||||
from companies and individuals that want to improve Squashfs for themselves
|
||||
and others.
|
||||
|
||||
There's lots of exciting new improvements to Squashfs in the pipeline, and
|
||||
if your company is a serious user of Squashfs, please consider accelerating
|
||||
development of Squashfs by donating.
|
||||
|
||||
Donatations can be made from the Squashfs sourceforge homepage, or if you
|
||||
prefer by contacting the author privately.
|
||||
|
||||
177
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/PERFORMANCE.README
Normal file
177
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/PERFORMANCE.README
Normal file
@@ -0,0 +1,177 @@
|
||||
* Obsolete *
|
||||
|
||||
This file is now largely obsolete, considering
|
||||
it refers to Squashfs 2.1 (which was released in 2006)
|
||||
and older releases.
|
||||
|
||||
GENERAL INFORMATION ON PERFORMANCE TESTS
|
||||
----------------------------------------
|
||||
|
||||
The following performance tests were based on two file sets: the
|
||||
liveCD filesystem from the Ubuntu liveCD (Warty release), and the
|
||||
liveCD filesystem from the Damn Small Linux liveCD (release 0.8.4).
|
||||
The Ubuntu liveCD filesystem was used to test filesystem performance
|
||||
from CDROM and hard disk for Zisofs, Cloop, Squashfs 2.0 and Squashfs2.1.
|
||||
CRAMFS filesystem performance could not be tested for this filesystem
|
||||
bacause it exceeds the maximum supported size of CRAMFS. To test
|
||||
CRAMFS performance against Squashfs, the liveCD filesystem from
|
||||
Damn Small Linux was used.
|
||||
|
||||
NOTE: the usual warnings apply to these results, they are provided for
|
||||
illustrative purposes only, and due to different hardware and/or file data, you
|
||||
may obtain different results. As such the results are provided "as is" without
|
||||
any warranty (either express or implied) and you assume all risks as to their
|
||||
quality and accuracy.
|
||||
|
||||
1. Ubuntu liveCD performance tests
|
||||
|
||||
ext3 uncompressed size 1.4 GB
|
||||
Zisofs compressed size 589.81 MB
|
||||
Cloop compressed size 471.89 MB
|
||||
Squashfs2.0 compressed size 448.58 MB
|
||||
Squashfs2.1 compressed size 448.58 MB
|
||||
|
||||
1.1 Performance tests from CDROM
|
||||
|
||||
1.1.1 Directory Lookup performance
|
||||
|
||||
Time taken to perform "ls -lR --color=alawys | cat > /dev/null" on filesystem
|
||||
mounted from CDROM
|
||||
|
||||
Zisofs 49.88 seconds (User 2.60 secs, Sys 11.19 secs)
|
||||
Cloop 20.80 seconds (User 2.71 secs, Sys 13.50 secs)
|
||||
Squashfs2.0 16.56 seconds (User 2.42 secs, Sys 10.37 secs)
|
||||
Squashfs2.1 10.14 seconds (User 2.48 secs, Sys 4.44 secs)
|
||||
|
||||
1.1.2 Sequential I/O performance
|
||||
|
||||
Time taken to perform "tar cf - | cat > /dev/null" on filesystem mounted
|
||||
from CDROM
|
||||
|
||||
Zisofs 27 minutes 28.54 seconds (User 3.00 secs, Sys 1 min 4.80 secs)
|
||||
Cloop 5 minutes 55.72 seconds (User 2.90 secs, Sys 3 min 37.90 secs)
|
||||
Squashfs2.0 5 minutes 20.87 seconds (User 2.33 secs, Sys 56.98 secs)
|
||||
Squashfs2.1 5 minutes 15.46 seconds (user 2.28 secs, Sys 51.12 secs)
|
||||
|
||||
1.1.3 Random I/O performance
|
||||
|
||||
Random access pattern generated by "find /mnt -type f -printf "%s %p\n" | sort
|
||||
-g | awk '{ printf $2 }' > /tmp/sort
|
||||
|
||||
Time taken to perform "cpio -o --quiet -H newc < /tmp/sort > /dev/null"
|
||||
on filesystem mounted from CDROM
|
||||
|
||||
Zisofs 101 minutes 29.65 seconds (User 5.33 secs, Sys 1 min 17.20 secs)
|
||||
Cloop 35 minutes 27.51 seconds (user 5.93 secs, Sys 4 mins 30.23 secs)
|
||||
Squashfs2.0 21 minutes 53.05 seconds (user 5.71 secs, Sys 2 mins 36.59 secs)
|
||||
Squashfs2.1 21 minutes 46.99 seconds (User 5.80 secs, Sys 2 mins 31.88 secs)
|
||||
|
||||
|
||||
1.2 Performance tests from Hard disk
|
||||
|
||||
1.2.1 Directory Lookup performance
|
||||
|
||||
Time taken to perform "ls -lR --color=alawys | cat > /dev/null" on filesystem
|
||||
mounted from Hard disk
|
||||
|
||||
Zisofs 17.29 seconds (User 2.62 secs, Sys 11.08 secs)
|
||||
Cloop 16.46 seconds (User 2.63 secs, Sys 13.41 secs)
|
||||
Squashfs2.0 13.75 seconds (User 2.44 secs, Sys 11.00 secs)
|
||||
Squashfs2.1 6.94 seconds (User 2.44 secs, Sys 4.48 secs)
|
||||
|
||||
1.2.2 Sequential I/O performance
|
||||
|
||||
Time taken to perform "tar cf - | cat > /dev/null" on filesystem mounted
|
||||
from Hard disk
|
||||
|
||||
Zisofs 1 minute 21.47 seconds (User 2.73 secs, Sys 54.44 secs)
|
||||
Cloop 1 minute 34.06 seconds (user 2.85 secs, Sys 1 min 12.13 secs)
|
||||
Squashfs2.0 1 minute 21.22 seconds (User 2.42 secs, Sys 56.21 secs)
|
||||
Squashfs2.1 1 minute 15.46 seconds (User 2.36 secs, Sys 49.78 secs)
|
||||
|
||||
1.2.3 Random I/O performance
|
||||
|
||||
Random access pattern generated by "find /mnt -type f -printf "%s %p\n" | sort
|
||||
-g | awk '{ printf $2 }' > /tmp/sort
|
||||
|
||||
Time taken to perform "cpio -o --quiet -H newc < /tmp/sort > /dev/null"
|
||||
on filesystem mounted from Hard disk
|
||||
|
||||
Zisofs 11 minutes 13.64 seconds (User 5.08 secs, Sys 52.62 secs)
|
||||
Cloop 5 minutes 37.93 seconds (user 6 secs, Sys 2 mins 22.38 secs)
|
||||
Squashfs2.0 5 minutes 7.11 seconds (user 5.63 secs, Sys 2 mins 35.23 secs)
|
||||
Squashfs2.1 5 minutes 1.87 seconds (User 5.71 secs, Sys 2 mins 29.98 secs)
|
||||
|
||||
|
||||
2. Damn Small Linux liveCD performance tests
|
||||
|
||||
ext3 uncompressed size 126 MB
|
||||
CRAMFS compressed size 52.19 MB
|
||||
Squashfs2.0 compressed size 46.52 MB
|
||||
Squashfs2.1 compressed size 46.52 MB
|
||||
|
||||
2.1 Performance tests from CDROM
|
||||
|
||||
2.1.1 Directory Lookup performance
|
||||
|
||||
Time taken to perform "ls -lR --color=alawys | cat > /dev/null" on filesystem
|
||||
mounted from CDROM
|
||||
|
||||
CRAMFS 10.85 seconds (User 0.39 secs, Sys 0.98 secs)
|
||||
Squashfs2.0 2.97 seconds (User 0.36 secs, Sys 2.15 secs)
|
||||
Squashfs2.1 2.43 seconds (User 0.40 secs, Sys 1.42 secs)
|
||||
|
||||
2.1.2 Sequential I/O performance
|
||||
|
||||
Time taken to perform "tar cf - | cat > /dev/null" on filesystem mounted
|
||||
from CDROM
|
||||
|
||||
CRAMFS 55.38 seconds (User 0.34 secs, Sys 6.98 secs)
|
||||
Squashfs2.0 35.99 seconds (User 0.30 secs, Sys 6.35 secs)
|
||||
Squashfs2.1 33.83 seconds (User 0.26 secs, Sys 5.56 secs)
|
||||
|
||||
2.1.3 Random I/O performance
|
||||
|
||||
Random access pattern generated by "find /mnt -type f -printf "%s %p\n" | sort
|
||||
-g | awk '{ printf $2 }' > /tmp/sort
|
||||
|
||||
Time taken to perform "cpio -o --quiet -H newc < /tmp/sort > /dev/null"
|
||||
on filesystem mounted from CDROM
|
||||
|
||||
|
||||
CRAMFS 3 minutes 1.68 seconds (User 0.54 secs, Sys 9.51 secs)
|
||||
Squashfs2.0 1 minute 39.45 seconds (User 0.57 secs, Sys 13.14 secs)
|
||||
Squashfs2.1 1 minute 38.41 seconds (User 0.58 secs, Sys 13.08 secs)
|
||||
|
||||
2.2 Performance tests from Hard disk
|
||||
|
||||
2.2.1 Directory Lookup performance
|
||||
|
||||
Time taken to perform "ls -lR --color=alawys | cat > /dev/null" on filesystem
|
||||
mounted from Hard disk
|
||||
|
||||
CRAMFS 1.77 seconds (User 0.53 secs, Sys 1.21 secs)
|
||||
Squashfs2.0 2.67 seconds (User 0.41 secs, Sys 2.25 secs)
|
||||
Squashfs2.1 1.87 seconds (User 0.41 secs, Sys 1.46 secs)
|
||||
|
||||
2.2.2 Sequential I/O performance
|
||||
|
||||
Time taken to perform "tar cf - | cat > /dev/null" on filesystem mounted
|
||||
from Hard disk
|
||||
|
||||
CRAMFS 6.80 seconds (User 0.36 secs, Sys 6.02 secs)
|
||||
Squashfs2.0 7.23 seconds (User 0.29 secs, Sys 6.62 secs)
|
||||
Squashfs2.1 6.53 seconds (User 0.31 secs, Sys 5.82 secs)
|
||||
|
||||
2.2.3 Random I/O performance
|
||||
|
||||
Random access pattern generated by "find /mnt -type f -printf "%s %p\n" | sort
|
||||
-g | awk '{ printf $2 }' > /tmp/sort
|
||||
|
||||
Time taken to perform "cpio -o --quiet -H newc < /tmp/sort > /dev/null"
|
||||
on filesystem mounted from Hard disk
|
||||
|
||||
|
||||
CRAMFS 28.55 seconds (User 0.49 secs, Sys 6.49 secs)
|
||||
Squashfs2.0 25.44 seconds (User 0.58 secs, Sys 13.17 secs)
|
||||
Squashfs2.1 24.72 seconds (User 0.56 secs, Sys 13.15 secs)
|
||||
161
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-2.0
Normal file
161
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-2.0
Normal file
@@ -0,0 +1,161 @@
|
||||
NOTE: This the original README for version 2.0. It is retained as it
|
||||
contains information about the fragment design. A description of the new 2.0
|
||||
mksquashfs options has been added to the main README file, and that
|
||||
file should now be consulted for these.
|
||||
|
||||
SQUASHFS 2.0 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2004 Phillip Lougher (plougher@users.sourceforge.net)
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to the final release of Squashfs version 2.0! A lot of changes to the
|
||||
filesystem have been made under the bonnet (hood). Squashfs 2.0 uses fragment
|
||||
blocks and larger blocks (64K) to improve compression ratio by about 5 - 20%
|
||||
over Squashfs 1.0 depending on the files being compressed. Using fragment
|
||||
blocks allows Squashfs 2.0 to achieve better compression than cloop and similar
|
||||
compression to tgz files while retaining the I/O efficiency of a compressed
|
||||
filesystem.
|
||||
|
||||
Detailed changes:
|
||||
|
||||
1. Squashfs 2.0 has added the concept of fragment blocks (see later discussion).
|
||||
Files smaller than the file block size (64K in Squashfs 2.0) and optionally
|
||||
the remainder of files that do not fit fully into a block (i.e. the last 32K
|
||||
in a 96K file) are packed into shared fragments and compressed together.
|
||||
This achieves on average 5 - 20% better compression than Squashfs 1.x.
|
||||
|
||||
2. The maximum block size has been increased to 64K.
|
||||
|
||||
3. The maximum number of UIDs has been increased to 256 (from 48 in 1.x).
|
||||
|
||||
4. The maximum number of GIDs has been increased to 256 (from 15 in 1.x).
|
||||
|
||||
5. New mksquashfs -all-root, -root-owned, -force-uid, and -force-gid
|
||||
options. These allow the uids/gids of files in the generated
|
||||
filesystem to be specified, overriding the uids/gids in the
|
||||
source filesystem.
|
||||
|
||||
6. Initrds are now supported for kernels 2.6.x.
|
||||
|
||||
7. Removal of sleep_on() function call in 2.6.x patch, to allow Squashfs
|
||||
to work on the Fedora rc2 kernel.
|
||||
|
||||
8. AMD64, check-data and gid bug fixes.
|
||||
|
||||
9. Numerous small bug fixes have been made.
|
||||
|
||||
10. New patch for Linux 2.6.7.
|
||||
|
||||
|
||||
New Squashfs 2.0 options
|
||||
------------------------
|
||||
|
||||
-noF or -noFragmentCompression
|
||||
|
||||
Do not compress the fragments. Added for compatibility with noI and
|
||||
noD, probably not that useful.
|
||||
|
||||
-no-fragments
|
||||
|
||||
Do not use fragment blocks, and rather generate a filesystem
|
||||
similar to a Squashfs 1.x filesystem. It will of course still
|
||||
be a Squashfs 2.0 filesystem but without fragments, and so
|
||||
it won't be mountable on a Squashfs 1.x system.
|
||||
|
||||
-always-use-fragments
|
||||
|
||||
By default only small files less than the block size are packed into
|
||||
fragment blocks. The ends of files which do not fit fully into a block,
|
||||
are NOT by default packed into fragments. To illustrate this, a
|
||||
100K file has an initial 64K block and a 36K remainder. This
|
||||
36K remainder is not packed into a fragment by default. This is
|
||||
because to do so leads to a 10 - 20% drop in sequential I/O
|
||||
performance, as a disk head seek is needed to seek to the initial
|
||||
file data and another disk seek is need to seek to the fragment
|
||||
block.
|
||||
|
||||
Specify this option if you want file remainders to be packed into
|
||||
fragment blocks. Doing so may increase the compression obtained
|
||||
BUT at the expense of I/O speed.
|
||||
|
||||
-no-duplicates
|
||||
|
||||
Do not detect duplicate files.
|
||||
|
||||
-all-root
|
||||
-root-owned
|
||||
|
||||
These options (both do exactly the same thing), force all file
|
||||
uids/gids in the generated Squashfs filesystem to be root.
|
||||
This allows root owned filesystems to be built without root access
|
||||
on the host machine.
|
||||
|
||||
-force-uid uid
|
||||
|
||||
This option forces all files in the generated Squashfs filesystem to
|
||||
be owned by the specified uid. The uid can be specified either by
|
||||
name (i.e. "root") or by number.
|
||||
|
||||
-force-gid gid
|
||||
|
||||
This option forces all files in the generated Squashfs filesystem to
|
||||
be group owned by the specified gid. The gid can be specified either by
|
||||
name (i.e. "root") or by number.
|
||||
|
||||
|
||||
Compression improvements example
|
||||
--------------------------------
|
||||
|
||||
The following is the compression results obtained compressing the 2.6.6
|
||||
linux kernel source using CRAMFS, Cloop (with iso filesystem), Squashfs 1.3 and
|
||||
Squashfs 2.0 (results generated using big-endian filesystems).
|
||||
|
||||
In decreasing order of size:
|
||||
|
||||
CRAMFS 62791680 bytes (59.9M)
|
||||
Squashfs 1.x 51351552 bytes (48.9M)
|
||||
Cloop 46118681 bytes (44.0M)
|
||||
Squashfs 2.0 45604854 bytes (43.5M)
|
||||
|
||||
|
||||
The Squashfs 1.x filesystem is 12.6% larger than the new 2.0 filesystem.
|
||||
The cloop filesystem is 1.1% larger than the Squashfs 2.0 filesystem.
|
||||
|
||||
|
||||
Fragment blocks in Squashfs 2.0
|
||||
-------------------------------
|
||||
|
||||
Squashfs like all other compressed filesystems compresses files individually
|
||||
on a block by block basis. This is performed to allow mounting and
|
||||
de-compression of files on a block by block basis without requiring the entire
|
||||
filesystem to be decompressed. This is in contrast to data-based compression
|
||||
schemes which compress without understanding the underlying filesystem (i.e.
|
||||
cloop and tgz files) and which, therefore, do not compress files individually.
|
||||
Each approach has advantages and disadvantages, data-based systems have better
|
||||
compression because compression is always performed at the maximum block size
|
||||
(64K in cloop) irrespective of the size of each file (which could be less than
|
||||
the block size). Compressed filesystems tend to be faster at I/O because
|
||||
they understand the filesystem and therefore employ better caching stategies
|
||||
and read less un-needed data from the filesystem.
|
||||
|
||||
Fragment blocks in Squashfs 2.0 solves this problem by packing files (and
|
||||
optionally the ends of files) which are smaller than the block size into
|
||||
shared blocks, which are compressed together. For example five files each of
|
||||
10K will be packed into one shared fragment of 50K and compressed together,
|
||||
rather than being compressed in five 10K blocks.
|
||||
|
||||
This scheme produces a hybrid filesystem, retaining the I/O efficiency
|
||||
of a compressed filesystem, while obtaining the compression efficiency
|
||||
of data-based schemes by compressing small files together.
|
||||
|
||||
|
||||
Squashfs 1.x and Squashfs 2.0 compatibility
|
||||
-------------------------------------------
|
||||
|
||||
Appending to Squashfs 1.x filesystems is not supported. If you wish to append
|
||||
to 1.x filesystems, then either use the original mksquashfs, or convert them
|
||||
to Squashfs 2.0 by mounting the filesystem and running the 2.0 mksquashfs
|
||||
on the mounted filesystem.
|
||||
|
||||
Mounting Squashfs 1.x filesystems IS supported by the 2.0 kernel patch.
|
||||
18
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-2.0-AMD64
Normal file
18
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-2.0-AMD64
Normal file
@@ -0,0 +1,18 @@
|
||||
Information for amd64 users
|
||||
---------------------------
|
||||
|
||||
All previous releases of Squashfs (2.0-alpha and older) generate incorrect
|
||||
filesystems on amd64 machines. These filesystems work correctly on amd64
|
||||
machines, but cannot be mounted on non-amd64 machines. Likewise, filesystems
|
||||
generated on non amd64 machines could not be mounted on amd64 machines.
|
||||
This bug was caused by the different size of the "time_t" definition used in
|
||||
SquashFS filesystem structures.
|
||||
|
||||
This bug is now fixed in this release. However, all amd64 filesystems
|
||||
generated by previous releases will not be mountable on amd64 machines
|
||||
with this release. If you have pre-existing amd64 generated filesystems,
|
||||
it is important that you recreate the filesystem. This can be performed
|
||||
by mounting the filesystem using a kernel with the original patch
|
||||
(i.e. a 2.0-alpha or older patch) and running the SquashFS 2.0
|
||||
(i.e. this release) mksquashfs tool to create a new SquashFS filesystem.
|
||||
|
||||
87
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-2.1
Normal file
87
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-2.1
Normal file
@@ -0,0 +1,87 @@
|
||||
SQUASHFS 2.1 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2004 Phillip Lougher (plougher@users.sourceforge.net)
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs version 2.1-r2. Squashfs 2.1 introduces indexed
|
||||
directories which considerably speed up directory lookup (ls, find etc.) for
|
||||
directories which are greater than 8K in size. All directories are now also
|
||||
sorted alphabetically which further speeds up directory lookup. Many smaller
|
||||
improvements have also been made to this release, please see the CHANGES file
|
||||
entry for detailed changes.
|
||||
|
||||
1. DIRECTORY SPEED IMPROVEMENT EXAMPLES
|
||||
---------------------------------------
|
||||
|
||||
To give an indication of the directory speed improvements a number of test
|
||||
results are shown here. There is in addition a new PERFORMANCE.README file
|
||||
which gives details of I/O and lookup performance for Squashfs 2.1 against
|
||||
the Zisofs, Cloop and CRAMFS filesystems.
|
||||
|
||||
example 1:
|
||||
|
||||
Filesystems generated from a single directory of 72,784 files (2.6 MB
|
||||
directory size). Each file is 10 bytes in size (the test is directory
|
||||
lookup and so the file size isn't an issue). The ext3 uncompressed
|
||||
directory size is 288 MB (presumably because of one file per block).
|
||||
|
||||
Zisofs compressed size 153.50 MB
|
||||
Cloop (isofs) compressed size 1.74 MB
|
||||
Squashfs2.1 compressed size 612 KB (0.60 MB)
|
||||
|
||||
Time taken to perform "ls -lR --color=always | cat > /dev/null" on
|
||||
filesystems mounted on hard disk.
|
||||
|
||||
Zisofs 35 minutes 7.895 seconds (User 7.868 secs, Sys 34 mins 5.621 secs)
|
||||
Cloop 35 minutes 12.765 seconds (User 7.771 secs, Sys 34 mins 3.869 secs)
|
||||
Squashfs2.1 19 seconds (User 5.119 secs, Sys 14.547 secs)
|
||||
|
||||
example 2:
|
||||
|
||||
Filesystems were generated from the Ubuntu Warty livecd (original uncompressed
|
||||
size on ext3 is 1.4 GB).
|
||||
|
||||
Zisofs compressed size 589.81 MB
|
||||
Cloop (isofs) compressed size 471.19 MB
|
||||
Squashfs2.0 compressed size 448.58 MB
|
||||
Squashfs2.1 compressed size 448.58 MB
|
||||
|
||||
Time taken to perform "ls -lR --color=always | cat > /dev/null" on
|
||||
filesystems mounted on hard disk.
|
||||
|
||||
Zisofs 49.875 seconds (User time 2.589 secs, Sys 11.194 secs)
|
||||
Cloop 20.797 seconds (User time 2.706 secs, Sys 13.496 secs)
|
||||
Squashfs2.0 16.556 seconds (User time 2.424 secs, Sys 10.371 secs)
|
||||
Squashfs2.1 10.143 seconds (User time 2.475 secs, Sys 4.440 secs)
|
||||
|
||||
|
||||
NOTE: the usual warnings apply to these results, they are provided for
|
||||
illustrative purposes only, and due to different hardware and/or file data, you
|
||||
may obtain different results. As such the results are provided "as is" without
|
||||
any warranty (either express or implied) and you assume all risks as to their
|
||||
quality and accuracy.
|
||||
|
||||
2. NEW MKSQUASHFS OPTIONS
|
||||
-------------------------
|
||||
|
||||
There is only one extra option "-2.0". This tells mksquashfs to generate
|
||||
a filesystem which is mountable with Squashfs version 2.0.
|
||||
|
||||
3. APPENDING AND MOUNTING SQUASHFS 2.0 FILESYSTEMS
|
||||
--------------------------------------------------
|
||||
|
||||
Mounting 2.0 filesystems is supported by Squashfs 2.1. In addition
|
||||
mksquashfs v2.1 can append to 2.0 filesystems, although the generated
|
||||
filesystem will still be a 2.0 filesystem.
|
||||
|
||||
4. DONATIONS
|
||||
------------
|
||||
|
||||
If you find Squashfs useful then please consider making a donation,
|
||||
particularly if you use Squashfs in a commercial product. Please consider
|
||||
giving something back especially if you're making money from it.
|
||||
|
||||
Off the Squashfs subject somewhat I'm currently looking for another
|
||||
job doing Linux kernel or filesystems work. If you know of any such
|
||||
work that can be performed from the UK then please get in touch. Thanks.
|
||||
60
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.0
Normal file
60
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.0
Normal file
@@ -0,0 +1,60 @@
|
||||
SQUASHFS 3.0 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2006 Phillip Lougher <phillip@lougher.org.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to the first release of Squashfs version 3.0. Squashfs 3.0 has the
|
||||
the following improvements to 2.x.
|
||||
|
||||
1. Filesystems are no longer limited to 4 GB. In
|
||||
theory 2^64 or 4 exabytes is now supported.
|
||||
|
||||
2. Files are no longer limited to 4 GB. In theory the maximum
|
||||
file size is 4 exabytes.
|
||||
|
||||
3. Metadata (inode table and directory tables) are no longer
|
||||
restricted to 16 Mbytes.
|
||||
|
||||
4. Hardlinks are now suppported.
|
||||
|
||||
5. Nlink counts are now supported.
|
||||
|
||||
6. Readdir now returns '.' and '..' entries.
|
||||
|
||||
7. Special support for files larger than 256 MB has been added to
|
||||
the Squashfs kernel code for faster read access.
|
||||
|
||||
8. Inode numbers are now stored within the inode rather than being
|
||||
computed from inode location on disk (this is not so much an
|
||||
improvement, but a change forced by the previously listed
|
||||
improvements).
|
||||
|
||||
There is a new Unsquashfs utility (in squashfs-tools) than can be used to
|
||||
decompress a filesystem without mounting it.
|
||||
|
||||
Squashfs 3.0 supports 2.x filesystems. Support for 1.x filesystems
|
||||
will be added in the future.
|
||||
|
||||
1. UNSQUASHFS
|
||||
-------------
|
||||
|
||||
Unsquashfs has the following options:
|
||||
|
||||
SYNTAX: unsquashfs [-ls | -dest] filesystem
|
||||
-version print version, licence and copyright information
|
||||
-info print files as they are unsquashed
|
||||
-ls list filesystem only
|
||||
-dest <pathname> unsquash to <pathname>, default "squashfs-root"
|
||||
|
||||
The "-ls" option can be used to list the contents of a filesystem without
|
||||
decompressing the filesystem data itself.
|
||||
|
||||
The "-info" option forces Unsquashfs to print each file as it is decompressed.
|
||||
|
||||
The "-dest" option specifies the directory that is used to decompress
|
||||
the filesystem data. If this option is not given then the filesystem is
|
||||
decompressed to the directory "squashfs-root" in the current working directory.
|
||||
|
||||
Unsquashfs can decompress 3.0 filesystems. Support for 2.x and 1.x
|
||||
filesystems will be added in the future.
|
||||
158
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.1
Normal file
158
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.1
Normal file
@@ -0,0 +1,158 @@
|
||||
SQUASHFS 3.1 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2006 Phillip Lougher <phillip@lougher.org.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs version 3.1-r2. Squashfs 3.1 has major improvements to
|
||||
the Squashfs tools (Mksquashfs and Unsquashfs), some major bug fixes, new
|
||||
kernel patches, and various other smaller improvements and bug fixes.
|
||||
Please see the CHANGES file for a detailed list.
|
||||
|
||||
1. MKSQUASHFS
|
||||
-------------
|
||||
|
||||
Mksquashfs has been rewritten and it is now multi-threaded. It offers
|
||||
the following improvements:
|
||||
|
||||
1. Parallel compression. By default as many compression and fragment
|
||||
compression threads are created as there are available processors.
|
||||
This significantly speeds up performance on SMP systems.
|
||||
|
||||
2. File input and filesystem output is peformed in parallel on separate
|
||||
threads to maximise I/O performance. Even on single processor systems
|
||||
this speeds up performance by at least 10%.
|
||||
|
||||
3. Appending has been significantly improved, and files within the
|
||||
filesystem being appended to are no longer scanned and checksummed. This
|
||||
significantly improves append time for large filesystems.
|
||||
|
||||
4. File duplicate checking has been optimised, and split into two separate
|
||||
phases. Only files which are considered possible duplicates after the
|
||||
first phase are checksummed and cached in memory.
|
||||
|
||||
5. The use of swap memory was found to significantly impact performance. The
|
||||
amount of memory used to cache the file is now a command line option, by default
|
||||
this is 512 Mbytes.
|
||||
|
||||
1.1 NEW COMMAND LINE OPTIONS
|
||||
----------------------------
|
||||
|
||||
The new Mksquashfs program has a couple of extra command line options
|
||||
which can be used to control the new features:
|
||||
|
||||
-processors <processors>
|
||||
|
||||
This specifies the number of processors used by Mksquashfs.
|
||||
By default this is the number of available processors.
|
||||
|
||||
-read_queue <size in Mbytes>
|
||||
|
||||
This specifies the size of the file input queue used by the reader thread.
|
||||
This defaults to 64 Mbytes.
|
||||
|
||||
-write_queue <size in Mbytes>
|
||||
|
||||
This specifies the size of the filesystem output queue used by the
|
||||
writer thread. It also specifies the maximum cache used in file
|
||||
duplicate detection (the output queue is shared between these tasks).
|
||||
This defaults to 512 Mbytes.
|
||||
|
||||
1.2 PERFORMANCE RESULTS
|
||||
-----------------------
|
||||
|
||||
The following results give an indication of the speed improvements. Two
|
||||
example filesystems were tested, a liveCD filesystem (about 1.8 Gbytes
|
||||
uncompressed), and my home directory consisting largely of text files
|
||||
(about 1.3 Gbytes uncompressed). Tests were run on a single core
|
||||
and a dual core system.
|
||||
|
||||
Dual Core (AMDx2 3800+) system:
|
||||
Source directories on ext3.
|
||||
|
||||
LiveCD, old mksquashfs:
|
||||
|
||||
real 11m48.401s
|
||||
user 9m27.056s
|
||||
sys 0m15.281s
|
||||
|
||||
LiveCD, new par_mksquashfs:
|
||||
|
||||
real 4m8.736s
|
||||
user 7m11.771s
|
||||
sys 0m27.749s
|
||||
|
||||
"Home", old mksquashfs:
|
||||
|
||||
real 4m34.360s
|
||||
user 3m54.007s
|
||||
sys 0m32.155s
|
||||
|
||||
"Home", new par_mksquashfs:
|
||||
|
||||
real 1m27.381s
|
||||
user 2m7.304s
|
||||
sys 0m17.234s
|
||||
|
||||
Single Core PowerBook (PowerPC G4 1.5 GHz Ubuntu Linux)
|
||||
Source directories on ext3.
|
||||
|
||||
LiveCD, old mksquashs:
|
||||
|
||||
real 11m38.472s
|
||||
user 9m6.137s
|
||||
sys 0m23.799s
|
||||
|
||||
LiveCD, par_mksquashfs:
|
||||
|
||||
real 10m5.572s
|
||||
user 8m59.921s
|
||||
sys 0m16.145s
|
||||
|
||||
"Home", old mksquashfs:
|
||||
|
||||
real 3m42.298s
|
||||
user 2m49.478s
|
||||
sys 0m13.675s
|
||||
|
||||
"Home", new par_mksquashfs:
|
||||
|
||||
real 3m9.178s
|
||||
user 2m50.699s
|
||||
sys 0m9.069s
|
||||
|
||||
I'll be interested in any performance results obtained, especially from SMP
|
||||
machines larger than my dual-core AMD box, as this will give an indication of
|
||||
the scalability of the code. Obviously, I'm also interested in any problems,
|
||||
deadlocks, low performance etc.
|
||||
|
||||
2. UNSQUASHFS
|
||||
-------------
|
||||
|
||||
Unsquashfs now allows you to specify the filename or directory that is to be
|
||||
extracted from the Squashfs filesystem, rather than always extracting the
|
||||
entire filesystem. It also has a new "-force" option, and all options can be
|
||||
specified in a short form (-i rather than -info).
|
||||
|
||||
The Unsquashfs usage info is now:
|
||||
|
||||
SYNTAX: ./unsquashfs [options] filesystem [directory or file to extract]
|
||||
-v[ersion] print version, licence and copyright information
|
||||
-i[nfo] print files as they are unsquashed
|
||||
-l[s] list filesystem only
|
||||
-d[est] <pathname> unsquash to <pathname>, default "squashfs-root"
|
||||
-f[orce] if file already exists then overwrite
|
||||
|
||||
To extract a subset of the filesystem, the filename or directory
|
||||
tree that is to be extracted can now be specified on the command line. The
|
||||
file/directory should be specified using the full path to the file/directory
|
||||
as it appears within the Squashfs filesystem. The file/directory will also be
|
||||
extracted to that position within the specified destination directory.
|
||||
|
||||
The new "-force" option forces Unsquashfs to output to the destination
|
||||
directory even if files or directories already exist. This allows you
|
||||
to update an existing directory tree, or to Unsquashfs to a partially
|
||||
filled directory. Without the "-force" option, Unsquashfs will
|
||||
refuse to overwrite any existing files, or to create any directories if they
|
||||
already exist. This is done to protect data in case of mistakes, and
|
||||
so the "-force" option should be used with caution.
|
||||
33
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.2
Normal file
33
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.2
Normal file
@@ -0,0 +1,33 @@
|
||||
SQUASHFS 3.2 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2007 Phillip Lougher <phillip@lougher.org.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs version 3.2. Squashfs 3.2 has support for NFS exporting,
|
||||
some improvements to the Squashfs tools (Mksquashfs and Unsquashfs), some
|
||||
major bug fixes, new kernel patches, and various other smaller improvements
|
||||
and bug fixes. Please see the CHANGES file for a detailed list.
|
||||
|
||||
1. MKSQUASHFS
|
||||
-------------
|
||||
|
||||
New command line options:
|
||||
|
||||
-no-exports
|
||||
|
||||
Squashfs now supports NFS exports. By default the additional
|
||||
information necessary is added to the filesystem by Mksquashfs. If you
|
||||
do not wish this extra information, then this option can be specified.
|
||||
This will save a couple of bytes per file, and the filesystem
|
||||
will be identical to Squashfs 3.1.
|
||||
|
||||
-no-progress
|
||||
|
||||
Mksquashfs by default now displays a progress bar. This option disables
|
||||
it.
|
||||
|
||||
2. UNSQUASHFS
|
||||
-------------
|
||||
|
||||
Unsquashfs now supports Squashfs 2.x filesystems.
|
||||
169
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.3
Normal file
169
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-3.3
Normal file
@@ -0,0 +1,169 @@
|
||||
SQUASHFS 3.3 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2007 Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to another release of Squashfs. This is the 22nd release in just
|
||||
over five years of work. Squashfs 3.3 has lots of nice improvements,
|
||||
both to the filesystem itself (bigger blocks, and sparse files), but
|
||||
also to the Squashfs-tools Mksquashfs and Unsquashfs. As usual the
|
||||
CHANGES file has a detailed list of all the improvements.
|
||||
|
||||
Following is a description of the changes to the Squashfs tools, usage
|
||||
guides to the new options, and a summary of the new options.
|
||||
|
||||
1. MKSQUASHFS - EXTENDED EXCLUDE FILE HANDLING
|
||||
----------------------------------------------
|
||||
|
||||
1. Extended wildcard pattern matching now supported in exclude files
|
||||
|
||||
Enabled by specifying -wildcards option
|
||||
|
||||
Supports both anchored and non-anchored exclude files.
|
||||
|
||||
1.1 Anchored excludes
|
||||
|
||||
Similar to existing exclude files except with wildcards. Exclude
|
||||
file matches from root of source directories.
|
||||
|
||||
Examples:
|
||||
|
||||
1. mksquashfs example image.sqsh -wildcards -e 'test/*.gz'
|
||||
|
||||
Exclude all files matching "*.gz" in the top level directory "test".
|
||||
|
||||
2. mksquashfs example image.sqsh -wildcards -e '*/[Tt]est/example*'
|
||||
|
||||
Exclude all files beginning with "example" inside directories called
|
||||
"Test" or "test", that occur inside any top level directory.
|
||||
|
||||
Using extended wildcards, negative matching is also possible.
|
||||
|
||||
3. mksquashfs example image.sqsh -wildcards -e 'test/!(*data*).gz'
|
||||
|
||||
Exclude all files matching "*.gz" in top level directory "test",
|
||||
except those with "data" in the name.
|
||||
|
||||
1.2 Non-anchored excludes
|
||||
|
||||
By default excludes match from the top level directory, but it is
|
||||
often useful to exclude a file matching anywhere in the source directories.
|
||||
For this non-anchored excludes can be used, specified by pre-fixing the
|
||||
exclude with "...".
|
||||
|
||||
Examples:
|
||||
|
||||
1. mksquashfs example image.sqsh -wildcards -e '... *.gz'
|
||||
|
||||
Exclude files matching "*.gz" anywhere in the source directories.
|
||||
For example this will match "example.gz", "test/example.gz", and
|
||||
"test/test/example.gz".
|
||||
|
||||
2. mksquashfs example image.sqsh -wildcards -e '... [Tt]est/*.gz'
|
||||
|
||||
Exclude files matching "*.gz" inside directories called "Test" or
|
||||
"test" that occur anywhere in the source directories.
|
||||
|
||||
Again, using extended wildcards, negative matching is also possible.
|
||||
|
||||
3. mksquashfs example image.sqsh -wildcards -e '... !(*data*).gz'
|
||||
|
||||
Exclude all files matching "*.gz" anywhere in the source directories,
|
||||
except those with "data" in the name.
|
||||
|
||||
2. Regular expression pattern matching now supported in exclude files
|
||||
|
||||
Enabled by specifying -regex option. Identical behaviour to wild
|
||||
card pattern matching, except patterns are considered to be regular
|
||||
expressions.
|
||||
|
||||
Supports both anchored and non-anchored exclude files.
|
||||
|
||||
|
||||
2. MKSQUASHFS - NEW RECOVERY FILE FEATURE
|
||||
-----------------------------------------
|
||||
|
||||
Recovery files are now created when appending to existing Squashfs
|
||||
filesystems. This allows the original filesystem to be recovered
|
||||
if Mksquashfs aborts unexpectedly (i.e. power failure).
|
||||
|
||||
The recovery files are called squashfs_recovery_xxx_yyy, where
|
||||
"xxx" is the name of the filesystem being appended to, and "yyy" is a
|
||||
number to guarantee filename uniqueness (the PID of the parent Mksquashfs
|
||||
process).
|
||||
|
||||
Normally if Mksquashfs exits correctly the recovery file is deleted to
|
||||
avoid cluttering the filesystem. If Mksquashfs aborts, the "-recover"
|
||||
option can be used to recover the filesystem, giving the previously
|
||||
created recovery file as a parameter, i.e.
|
||||
|
||||
mksquashfs dummy image.sqsh -recover squashfs_recovery_image.sqsh_1234
|
||||
|
||||
The writing of the recovery file can be disabled by specifying the
|
||||
"-no-recovery" option.
|
||||
|
||||
|
||||
3. UNSQUASHFS - EXTENDED EXTRACT FILE HANDLING
|
||||
----------------------------------------------
|
||||
|
||||
1. Multiple extract files can now be specified on the command line, and the
|
||||
files/directories to be extracted can now also be given in a file.
|
||||
|
||||
To specify a file containing the extract files use the "-e[f]" option.
|
||||
|
||||
2. Extended wildcard pattern matching now supported in extract files
|
||||
|
||||
Enabled by default. Similar to existing extract files except with
|
||||
wildcards.
|
||||
|
||||
Examples:
|
||||
|
||||
1. unsquashfs image.sqsh 'test/*.gz'
|
||||
|
||||
Extract all files matching "*.gz" in the top level directory "test".
|
||||
|
||||
2. unsquashfs image.sqsh '[Tt]est/example*'
|
||||
|
||||
Extract all files beginning with "example" inside top level directories
|
||||
called "Test" or "test".
|
||||
|
||||
Using extended wildcards, negative matching is also possible.
|
||||
|
||||
3. unsquashfs image.sqsh 'test/!(*data*).gz'
|
||||
|
||||
Extract all files matching "*.gz" in top level directory "test",
|
||||
except those with "data" in the name.
|
||||
|
||||
3. Regular expression pattern matching now supported in extract files
|
||||
|
||||
Enabled by specifying -r[egex] option. Identical behaviour to wild
|
||||
card pattern matching, except patterns are considered to be regular
|
||||
expressions.
|
||||
|
||||
4. UNSQUASHFS - EXTENDED FILENAME PRINTING
|
||||
------------------------------------------
|
||||
|
||||
Filename printing has been enhanced and Unquashfs can now display filenames
|
||||
with file attributes ('ls -l' style output).
|
||||
|
||||
New options:
|
||||
|
||||
-ll[s]
|
||||
|
||||
list filesystem with file attributes, but don't unsquash
|
||||
|
||||
-li[nfo]
|
||||
|
||||
print files as they are unsquashed with file attributes
|
||||
|
||||
|
||||
5. UNSQUASHFS - MISCELLANEOUS OPTIONS
|
||||
-------------------------------------
|
||||
|
||||
-s[tat]
|
||||
|
||||
Display the filesystem superblock information. This is useful to
|
||||
discover the filesystem version, byte ordering, whether it has an
|
||||
NFS export table, and what options were used to compress
|
||||
the filesystem.
|
||||
48
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.0
Normal file
48
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.0
Normal file
@@ -0,0 +1,48 @@
|
||||
SQUASHFS 4.0 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2009 Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs 4.0. This is an initial tools only release to
|
||||
support users of the 2.6.29 kernel, following the mainlining of Squashfs
|
||||
earlier this year.
|
||||
|
||||
Later releases will probably contain kernel patches supporting 4.0
|
||||
layouts for earlier kernels.
|
||||
|
||||
New Mksquashfs options
|
||||
----------------------
|
||||
|
||||
Mksquashfs now supports pseudo files, these allow fake directories, character
|
||||
and block devices to be specified and added to the Squashfs filesystem being
|
||||
built, rather than requiring them to be present in the source directories.
|
||||
This, for example, allows device nodes to be added to the filesystem without
|
||||
requiring root access.
|
||||
|
||||
Two options are supported, -p allows one pseudo file to be specified on the
|
||||
command line, and -pf allows a pseudo file to be specified containing a
|
||||
list of pseduo definitions, one per line.
|
||||
|
||||
Pseudo device nodes are specified using 7 arguments
|
||||
|
||||
Filename type mode uid gid major minor
|
||||
|
||||
Where type is either
|
||||
b - for block devices, and
|
||||
c - for character devices
|
||||
|
||||
mode is the octal mode specifier, similar to that expected by chmod.
|
||||
|
||||
Uid and gid can be either specified as a decimal number, or by name.
|
||||
|
||||
For example:
|
||||
|
||||
/dev/chr_dev c 666 root root 100 1
|
||||
/dev/blk_dev b 444 0 0 200 200
|
||||
|
||||
Directories are specified using 5 arguments
|
||||
|
||||
Filename type mode uid gid
|
||||
|
||||
Where type is d.
|
||||
265
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.1
Normal file
265
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.1
Normal file
@@ -0,0 +1,265 @@
|
||||
SQUASHFS 4.1 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2010 Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs 4.1. This is a tools only release, support for Squashfs
|
||||
file systems is in mainline (2.6.29 and later).
|
||||
|
||||
New features in Squashfs-tools 4.1
|
||||
----------------------------------
|
||||
|
||||
1. Support for extended attributes
|
||||
2. Support for LZMA and LZO compression
|
||||
3. New pseudo file features
|
||||
|
||||
Compatiblity
|
||||
------------
|
||||
|
||||
Mksquashfs 4.1 generates 4.0 filesystems. These filesystems are fully
|
||||
compatible/interchangable with filesystems generated by Mksquashfs 4.0 and are
|
||||
mountable on 2.6.29 and later kernels.
|
||||
|
||||
Extended attributes (xattrs)
|
||||
----------------------------
|
||||
|
||||
Squashfs file systems now have extended attribute support. The
|
||||
extended attribute implementation has the following features:
|
||||
|
||||
1. Layout can store up to 2^48 bytes of compressed xattr data.
|
||||
2. Number of xattrs per inode unlimited.
|
||||
3. Total size of xattr data per inode 2^48 bytes of compressed data.
|
||||
4. Up to 4 Gbytes of data per xattr value.
|
||||
5. Inline and out-of-line xattr values supported for higher performance
|
||||
in xattr scanning (listxattr & getxattr), and to allow xattr value
|
||||
de-duplication.
|
||||
6. Both whole inode xattr duplicate detection and individual xattr value
|
||||
duplicate detection supported. These can obviously nest, file C's
|
||||
xattrs can be a complete duplicate of file B, and file B's xattrs
|
||||
can be a partial duplicate of file A.
|
||||
7. Xattr name prefix types stored, allowing the redundant "user.", "trusted."
|
||||
etc. characters to be eliminated and more concisely stored.
|
||||
8. Support for files, directories, symbolic links, device nodes, fifos
|
||||
and sockets.
|
||||
|
||||
Extended attribute support is in 2.6.35 and later kernels. File systems
|
||||
with extended attributes can be mounted on 2.6.29 and later kernels, the
|
||||
extended attributes will be ignored with a warning.
|
||||
|
||||
LZMA and LZO compression
|
||||
------------------------
|
||||
|
||||
Squashfs now supports LZMA and LZO compression.
|
||||
|
||||
LZO support is in 2.6.36 and newer kernels. LZMA is not yet in mainline.
|
||||
|
||||
New Mksquashfs options
|
||||
----------------------
|
||||
|
||||
-comp <comp>
|
||||
|
||||
Select <comp> compression.
|
||||
|
||||
The compression algorithms supported by the build of Mksquashfs can be
|
||||
found by typing mksquashfs without any arguments. The compressors available
|
||||
are displayed at the end of the help message, e.g.
|
||||
|
||||
Compressors available:
|
||||
gzip (default)
|
||||
lzma
|
||||
lzo
|
||||
|
||||
The default compression used when -comp isn't specified on the command line
|
||||
is indicated by "(default)".
|
||||
|
||||
-no-xattrs
|
||||
Don't store extended attributes
|
||||
|
||||
-xattrs
|
||||
Store extended attributes
|
||||
|
||||
The default behaviour of Mksquashfs with respect to extended attribute
|
||||
storage is build time selectable. The Mksquashfs help message indicates
|
||||
whether extended attributes are stored or not, e.g.
|
||||
|
||||
-no-xattrs don't store extended attributes
|
||||
-xattrs store extended attributes (default)
|
||||
|
||||
shows that extended attributes are stored by default, and can be disabled
|
||||
by the -no-xattrs option.
|
||||
|
||||
-no-xattrs don't store extended attributes (default)
|
||||
-xattrs store extended attributes
|
||||
|
||||
shows that extended attributes are not stored by default, storage can be
|
||||
enabled by the -xattrs option.
|
||||
|
||||
|
||||
-noX
|
||||
-noXattrCompression
|
||||
Don't compress extended attributes
|
||||
|
||||
|
||||
New Unsquashfs options
|
||||
----------------------
|
||||
|
||||
-n[o-xattrs]
|
||||
Don't extract xattrs in filesystem
|
||||
|
||||
-x[attrs]
|
||||
Extract xattrs in filesystem
|
||||
|
||||
The default behaviour of Unsquashfs with respect to extended attributes
|
||||
is build time selectable. The Unsquashfs help message indicates whether
|
||||
extended attributes are stored or not, e.g.
|
||||
|
||||
-no[-xattrs] don't extract xattrs in file system
|
||||
-x[attrs] extract xattrs in file system (default)
|
||||
|
||||
shows that xattrs are extracted by default.
|
||||
|
||||
-no[-xattrs] don't extract xattrs in file system (default)
|
||||
-x[attrs] extract xattrs in file system
|
||||
|
||||
shows that xattrs are not extracted by default.
|
||||
|
||||
|
||||
New pseudo file support
|
||||
-----------------------
|
||||
|
||||
Mksquashfs supports pseudo files, these allow fake files, directories, character
|
||||
and block devices to be specified and added to the Squashfs filesystem being
|
||||
built, rather than requiring them to be present in the source directories.
|
||||
This, for example, allows device nodes to be added to the filesystem without
|
||||
requiring root access.
|
||||
|
||||
Mksquashfs 4.1 adds support for "dynamic pseudo files" and a modify operation.
|
||||
Dynamic pseudo files allow files to be dynamically created when Mksquashfs
|
||||
is run, their contents being the result of running a command or piece of
|
||||
shell script. The modifiy operation allows the mode/uid/gid of an existing
|
||||
file in the source filesystem to be modified.
|
||||
|
||||
Two Mksquashfs options are supported, -p allows one pseudo file to be specified
|
||||
on the command line, and -pf allows a pseudo file to be specified containing a
|
||||
list of pseduo definitions, one per line.
|
||||
|
||||
Pseudo operations
|
||||
-----------------
|
||||
|
||||
1. Creating a dynamic file
|
||||
--------------------------
|
||||
|
||||
Pseudo definition
|
||||
|
||||
Filename f mode uid gid command
|
||||
|
||||
mode is the octal mode specifier, similar to that expected by chmod.
|
||||
|
||||
uid and gid can be either specified as a decimal number, or by name.
|
||||
|
||||
command can be an executable or a piece of shell script, and it is executed
|
||||
by running "/bin/sh -c command". The stdout becomes the contents of
|
||||
"Filename".
|
||||
|
||||
Examples:
|
||||
|
||||
Running a basic command
|
||||
-----------------------
|
||||
|
||||
/somedir/dmesg f 444 root root dmesg
|
||||
|
||||
creates a file "/somedir/dmesg" containing the output from dmesg.
|
||||
|
||||
Executing shell script
|
||||
----------------------
|
||||
|
||||
RELEASE f 444 root root \
|
||||
if [ ! -e /tmp/ver ]; then \
|
||||
echo 0 > /tmp/ver; \
|
||||
fi; \
|
||||
ver=`cat /tmp/ver`; \
|
||||
ver=$((ver +1)); \
|
||||
echo $ver > /tmp/ver; \
|
||||
echo -n `cat /tmp/release`; \
|
||||
echo "-dev #"$ver `date` "Build host" `hostname`
|
||||
|
||||
Creates a file RELEASE containing the release name, date, build host, and
|
||||
an incrementing version number. The incrementing version is a side-effect
|
||||
of executing the shell script, and ensures every time Mksquashfs is run a
|
||||
new version number is used without requiring any other shell scripting.
|
||||
|
||||
The above example also shows that commands can be split across multiple lines
|
||||
using "\". Obviously as the script will be presented to the shell as a single
|
||||
line, a semicolon is need to separate individual shell commands within the
|
||||
shell script.
|
||||
|
||||
Reading from a device (or fifo/named socket)
|
||||
--------------------------------------------
|
||||
|
||||
input f 444 root root dd if=/dev/sda1 bs=1024 count=10
|
||||
|
||||
Copies 10K from the device /dev/sda1 into the file input. Ordinarily Mksquashfs
|
||||
given a device, fifo, or named socket will place that special file within the
|
||||
Squashfs filesystem, the above allows input from these special files to be
|
||||
captured and placed in the Squashfs filesystem.
|
||||
|
||||
2. Creating a block or character device
|
||||
---------------------------------------
|
||||
|
||||
Pseudo definition
|
||||
|
||||
Filename type mode uid gid major minor
|
||||
|
||||
Where type is either
|
||||
b - for block devices, and
|
||||
c - for character devices
|
||||
|
||||
mode is the octal mode specifier, similar to that expected by chmod.
|
||||
|
||||
uid and gid can be either specified as a decimal number, or by name.
|
||||
|
||||
For example:
|
||||
|
||||
/dev/chr_dev c 666 root root 100 1
|
||||
/dev/blk_dev b 666 0 0 200 200
|
||||
|
||||
creates a character device "/dev/chr_dev" with major:minor 100:1 and
|
||||
a block device "/dev/blk_dev" with major:minor 200:200, both with root
|
||||
uid/gid and a mode of rw-rw-rw.
|
||||
|
||||
3. Creating a directory
|
||||
-----------------------
|
||||
|
||||
Pseudo definition
|
||||
|
||||
Filename d mode uid gid
|
||||
|
||||
mode is the octal mode specifier, similar to that expected by chmod.
|
||||
|
||||
uid and gid can be either specified as a decimal number, or by name.
|
||||
|
||||
For example:
|
||||
|
||||
/pseudo_dir d 666 root root
|
||||
|
||||
creates a directory "/pseudo_dir" with root uid/gid and mode of rw-rw-rw.
|
||||
|
||||
4. Modifying attributes of an existing file
|
||||
-------------------------------------------
|
||||
|
||||
Pseudo definition
|
||||
|
||||
Filename m mode uid gid
|
||||
|
||||
mode is the octal mode specifier, similar to that expected by chmod.
|
||||
|
||||
uid and gid can be either specified as a decimal number, or by name.
|
||||
|
||||
For example:
|
||||
|
||||
dmesg m 666 root root
|
||||
|
||||
Changes the attributes of the file "dmesg" in the filesystem to have
|
||||
root uid/gid and a mode of rw-rw-rw, overriding the attributes obtained
|
||||
from the source filesystem.
|
||||
57
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.2
Normal file
57
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.2
Normal file
@@ -0,0 +1,57 @@
|
||||
SQUASHFS 4.2 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2011 Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs 4.2. This is a tools only release, support for Squashfs
|
||||
filesystems is in mainline (2.6.29 and later).
|
||||
|
||||
New features in Squashfs-tools 4.2
|
||||
----------------------------------
|
||||
|
||||
1. Support for XZ compression
|
||||
2. Support for compressor specific options
|
||||
|
||||
Compatiblity
|
||||
------------
|
||||
|
||||
Mksquashfs 4.2 generates 4.0 filesystems. These filesystems are fully
|
||||
compatible/interchangable with filesystems generated by Mksquashfs 4.0 and are
|
||||
mountable on 2.6.29 and later kernels.
|
||||
|
||||
XZ compression
|
||||
--------------
|
||||
|
||||
Squashfs now supports XZ compression.
|
||||
|
||||
XZ support is in 2.6.38 and newer kernels.
|
||||
|
||||
New Mksquashfs options
|
||||
----------------------
|
||||
|
||||
-X<compressor-option>
|
||||
|
||||
Compression algorithms can now support compression specific options. These
|
||||
options are prefixed by -X, and are passed to the compressor for handling.
|
||||
|
||||
The compression specific options supported by each compressor can be
|
||||
found by typing mksquashfs without any arguments. They are displayed at the
|
||||
end of the help message, e.g.
|
||||
|
||||
Compressors available and compressor specific options:
|
||||
gzip (no options) (default)
|
||||
lzo (no options)
|
||||
xz
|
||||
-Xbcj filter1,filter2,...,filterN
|
||||
Compress using filter1,filter2,...,filterN in turn
|
||||
(in addition to no filter), and choose the best compression.
|
||||
Available filters: x86, arm, armthumb, powerpc, sparc, ia64
|
||||
-Xdict-size <dict-size>
|
||||
Use <dict-size> as the XZ dictionary size. The dictionary size
|
||||
can be specified as a percentage of the block size, or as an
|
||||
absolute value. The dictionary size must be less than or equal
|
||||
to the block size and 8192 bytes or larger. It must also be
|
||||
storable in the xz header as either 2^n or as 2^n+2^(n+1).
|
||||
Example dict-sizes are 75%, 50%, 37.5%, 25%, or 32K, 16K, 8K
|
||||
etc.
|
||||
182
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.3
Normal file
182
SQUASHFS/squashfs-tools-4.4/RELEASE-READMEs/README-4.3
Normal file
@@ -0,0 +1,182 @@
|
||||
SQUASHFS 4.3 - A squashed read-only filesystem for Linux
|
||||
|
||||
Copyright 2002-2014 Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
|
||||
Released under the GPL licence (version 2 or later).
|
||||
|
||||
Welcome to Squashfs 4.3. This is the first release in over 3 years, and
|
||||
there are substantial improvements to stability, new compression options
|
||||
and compressors, speed optimisations, and new options for Mksquashfs/Unsquashfs.
|
||||
|
||||
This is a tools only release, support for Squashfs filesystems is
|
||||
in mainline (2.6.29 and later).
|
||||
|
||||
Changes in Squashfs-tools 4.3
|
||||
-----------------------------
|
||||
|
||||
1. Stability improvements. Better checking of user input for out of
|
||||
range/invalid values. Better handling of corrupted Squashfs filesystems
|
||||
(Mksquashfs append mode, and Unsquashfs). Better handling of buffer
|
||||
overflow/underflow.
|
||||
|
||||
2. GZIP compressor now supports compression options, allowing different
|
||||
compression levels to be used.
|
||||
|
||||
3. Rewritten LZO compressor with compression options, allowing different
|
||||
LZO algorithms and different compression levels to be used.
|
||||
|
||||
4. New LZ4 compressor (note not yet in mainline kernel)
|
||||
|
||||
5. Better default memory usage for Mksquashfs. Mksquashfs by default now
|
||||
uses 25% of physical memory.
|
||||
|
||||
6. Duplicate checking in Mksquashfs further optimised. With certain
|
||||
"problem filesystems" greater than 2x performance improvement.
|
||||
Filesystems with a lot of duplicates should see at least 10-20% speed
|
||||
improvement.
|
||||
|
||||
7. The -stat option in Unsquashfs now displays the compression options
|
||||
used to generate the original filesystem. Previously -stat only displayed
|
||||
the compression algorithm used.
|
||||
|
||||
8. The file being compressed/uncompressed in Mksquashfs/Unsquashfs is now
|
||||
displayed if CTRL-\ (SIGQUIT from keyboard) typed.
|
||||
|
||||
9. The status of the internal queues/caches in Mksquashfs/Unsquashfs is
|
||||
now displayed if CTRL-\ (SIGQUIT from keyboard) is typed twice within
|
||||
one second. Normally only useful for "power users", but it can be
|
||||
used to discover if there's any bottlenecks affecting performance
|
||||
(the bottleneck will normally be the compressors/fragment compressors).
|
||||
|
||||
10. Miscellaneous new options for Mksquashfs/Unsquashfs to fine tune behaviour.
|
||||
|
||||
11. Fixes for CVE-2012-4024 and CVE-2012-4025.
|
||||
|
||||
Compatiblity
|
||||
------------
|
||||
|
||||
Mksquashfs 4.3 generates 4.0 filesystems. These filesystems are fully
|
||||
compatible/interchangable with filesystems generated by Mksquashfs 4.0 and are
|
||||
mountable on 2.6.29 and later kernels.
|
||||
|
||||
Compressors
|
||||
-----------
|
||||
|
||||
New compression options and compressors are now supported.
|
||||
|
||||
The new options and compressors are:
|
||||
|
||||
1. gzip
|
||||
-Xcompression-level <compression-level>
|
||||
<compression-level> should be 1 .. 9 (default 9)
|
||||
-Xwindow-size <window-size>
|
||||
<window-size> should be 8 .. 15 (default 15)
|
||||
-Xstrategy strategy1,strategy2,...,strategyN
|
||||
Compress using strategy1,strategy2,...,strategyN in turn
|
||||
and choose the best compression.
|
||||
Available strategies: default, filtered, huffman_only,
|
||||
run_length_encoded and fixed
|
||||
|
||||
2. lzo
|
||||
-Xalgorithm <algorithm>
|
||||
Where <algorithm> is one of:
|
||||
lzo1x_1
|
||||
lzo1x_1_11
|
||||
lzo1x_1_12
|
||||
lzo1x_1_15
|
||||
lzo1x_999 (default)
|
||||
-Xcompression-level <compression-level>
|
||||
<compression-level> should be 1 .. 9 (default 8)
|
||||
Only applies to lzo1x_999 algorithm
|
||||
|
||||
3. lz4
|
||||
-Xhc
|
||||
Compress using LZ4 High Compression
|
||||
|
||||
The compression specific options are, obviously, specific to the compressor
|
||||
in question, and you should read the compressor documentation and check
|
||||
their web sites to understand their behaviour.
|
||||
|
||||
In general the defaults used by Mksquashfs for each compressor are optimised
|
||||
to give the best performance for each compressor, where what constitutes
|
||||
best depends on the compressor. For gzip/xz best means highest compression
|
||||
(trying multiple filters/strategies can improve compression, but this is
|
||||
extremely expensive computationally, and hence, not suitable for the defaults),
|
||||
for LZO/LZ4 best means a tradeoff between compression and (de)-compression
|
||||
overhead (LZO/LZ4 by definition are intended for weaker processors).
|
||||
|
||||
New Mksquashfs options
|
||||
----------------------
|
||||
|
||||
1. -mem <size>
|
||||
|
||||
Set the amount of memory used by Mksquashfs to <size> bytes. G/M and K
|
||||
post-fixes are supported.
|
||||
|
||||
By default Mksquashfs uses 25% of the physical memory. Increasing
|
||||
this with the -mem option can increase performance (note it does not have
|
||||
any effect on compression). Reducing it can prevent thrashing if the
|
||||
system is busy and there is not 25% of physical memory free (again, note
|
||||
it does not have any effect on compression).
|
||||
|
||||
2. -exit-on-error
|
||||
|
||||
By default Mksquashfs treats certain errors as benign, if these
|
||||
errors occur Mksquashfs prints the error on the console but continues.
|
||||
These errors are typically failure to read a file from the source filesystem.
|
||||
This is deliberate, in many cases users prefer Mksquashfs to flag
|
||||
the error but continue rather than abort what may be hours of compression.
|
||||
|
||||
But there are times where failure to read any file is considered critical,
|
||||
and users (especially in the case of automated scripts where the
|
||||
errors output to the console may be missed) prefer Mksquashfs to exit.
|
||||
|
||||
The new -exit-on-error option can be used in this scenario. This option
|
||||
makes Mksquashfs treat all benign errors as fatal.
|
||||
|
||||
3. -progress
|
||||
|
||||
By default if -info is specified, the progress bar is disabled as it gets
|
||||
in the way. Occasionally you might want the progress bar enabled whilst
|
||||
-info is enabled. This option forces Mksquashfs to output the progress
|
||||
bar when -info is specified.
|
||||
|
||||
4. -Xhelp
|
||||
|
||||
Display the usage text for the currently selected compressor.
|
||||
|
||||
New Unsquashfs options
|
||||
----------------------
|
||||
|
||||
1. -u[ser-xattrs]
|
||||
|
||||
Only write user xattrs. This forces Unsquashfs to ignore system xattrs.
|
||||
This is useful when Unsquashing a filesystem as a non-root user, and the
|
||||
filesystem contains system xattrs which are only writable by root.
|
||||
|
||||
Major bugs fixed
|
||||
----------------
|
||||
|
||||
1. If Mksquashfs ran out of space in the destination filesystem, this
|
||||
would not cause Mksquashfs to immediately abort, and Mksquashfs would
|
||||
continue to process the source filesystem. Mksquashfs now immediately
|
||||
aborts on out of space in the destination filesystem.
|
||||
|
||||
2. Unsquashfs ignored the maximum number of open files limit, and if that
|
||||
was lower than the default limit for Linux, it would run out of file
|
||||
descriptors. Unsquashfs now limits the number of open files to the
|
||||
limit currently in force (e.g. specified by setrlimit).
|
||||
|
||||
3. If huge numbers of dynamic pseudo files were specified, Mksquashfs
|
||||
could exceed the maximum number of open files limit. This was because
|
||||
Mksquashfs created all the dynamic file processes up front before
|
||||
commencing source filesystem reading and compression. Mksquashfs
|
||||
now creates the dynamic file processes on demand whilst reading
|
||||
and compressing the source filesystem, thus limiting the number of
|
||||
dynamic pseudo file processes in existence at any one time.
|
||||
|
||||
4. When outputting Unsquashfs used to set the permissions of directories
|
||||
as it recursively descended. This in hindsight had an obvious oversight,
|
||||
if a directory had only read permission (or was otherwise restricted), then
|
||||
Unsquashfs would fail to write its contents when descending into it. Fixed
|
||||
by setting directory permissions as Unsquashfs recursively unwinds.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Pseudo file example
|
||||
|
||||
# Mksquashfs supports pseudo files, these allow fake files, directories,
|
||||
# character and block devices to be specified and added to the Squashfs
|
||||
# filesystem being built, rather than requiring them to be present in the
|
||||
# source directories.
|
||||
#
|
||||
# This, for example, allows device nodes to be added to the filesystem without
|
||||
# requiring root access.
|
||||
|
||||
# Mksquashfs 4.1 adds support for "dynamic pseudo files" and a modify operation.
|
||||
# Dynamic pseudo files allow files to be dynamically created when Mksquashfs
|
||||
# is run, their contents being the result of running a command or piece of
|
||||
# shell script. The modifiy operation allows the mode/uid/gid of an existing
|
||||
# file in the source filesystem to be modified.
|
||||
|
||||
# Two Mksquashfs options are supported, -p allows one pseudo file to be
|
||||
# specified #on the command line, and -pf allows a pseudo file to be specified
|
||||
# containing a list of pseduo definitions, one per line.
|
||||
|
||||
# Pseudo file examples
|
||||
# Run mkquashfs . /tmp/img -pf pseudo-file.examples
|
||||
# to see their effect
|
||||
|
||||
# Creating dynamic file examples
|
||||
|
||||
# Create a file "dmesg" containing the output from dmesg.
|
||||
dmesg f 444 root root dmesg
|
||||
|
||||
|
||||
# Create a file RELEASE containing the release name, date, build host, and
|
||||
# an incrementing version number. The incrementing version is a side-effect
|
||||
# of executing the shell script, and ensures every time Mksquashfs is run a
|
||||
# new version number is used without requiring any other shell scripting.
|
||||
RELEASE f 444 root root \
|
||||
if [ ! -e /tmp/ver ]; then \
|
||||
echo 0 > /tmp/ver; \
|
||||
fi; \
|
||||
ver=`cat /tmp/ver`; \
|
||||
ver=$((ver +1)); \
|
||||
echo $ver > /tmp/ver; \
|
||||
echo -n "release x.x"; \
|
||||
echo "-dev #"$ver `date` "Build host" `hostname`
|
||||
|
||||
|
||||
# Copy 10K from the device /dev/sda1 into the file input. Ordinarily
|
||||
# Mksquashfs given a device, fifo, or named socket will place that special file
|
||||
# within the Squashfs filesystem, this allows input from these special
|
||||
# files to be captured and placed in the Squashfs filesystem.
|
||||
input f 444 root root dd if=/dev/sda1 bs=1024 count=10
|
||||
|
||||
|
||||
# Creating a block or character device examples
|
||||
|
||||
# Create a character device "chr_dev" with major:minor 100:1 and
|
||||
# a block device "blk_dev" with major:minor 200:200, both with root
|
||||
# uid/gid and a mode of rw-rw-rw.
|
||||
chr_dev c 666 root root 100 1
|
||||
blk_dev b 666 0 0 200 200
|
||||
|
||||
|
||||
# Creating a directory example
|
||||
|
||||
# create a directory "pseudo_dir" with root uid/gid and mode of r--r--r--.
|
||||
pseudo_dir d 444 root root
|
||||
|
||||
|
||||
# Modifying attributes of an existing file exmaple
|
||||
|
||||
# Change the attributes of the file "INSTALL" in the filesystem to have
|
||||
# root uid/gid and a mode of rw-rw-rw, overriding the attributes obtained
|
||||
# from the source filesystem.
|
||||
INSTALL m 666 root root
|
||||
|
||||
1216
SQUASHFS/squashfs-tools-4.4/USAGE
Normal file
1216
SQUASHFS/squashfs-tools-4.4/USAGE
Normal file
File diff suppressed because it is too large
Load Diff
3
SQUASHFS/squashfs-tools-4.4/kernel/README
Normal file
3
SQUASHFS/squashfs-tools-4.4/kernel/README
Normal file
@@ -0,0 +1,3 @@
|
||||
Squashfs is now in mainline at www.kernel.org.
|
||||
|
||||
These files are obsolete and not updated.
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Makefile for the linux squashfs routines.
|
||||
#
|
||||
|
||||
O_TARGET := squashfs.o
|
||||
|
||||
obj-y := inode.o squashfs2_0.o
|
||||
|
||||
obj-m := $(O_TARGET)
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
2029
SQUASHFS/squashfs-tools-4.4/kernel/kernel-2.4/fs/squashfs/inode.c
Normal file
2029
SQUASHFS/squashfs-tools-4.4/kernel/kernel-2.4/fs/squashfs/inode.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs.h
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
|
||||
#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
|
||||
#endif
|
||||
#ifdef SQUASHFS_TRACE
|
||||
#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
|
||||
#else
|
||||
#define TRACE(s, args...) {}
|
||||
#endif
|
||||
|
||||
#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
|
||||
|
||||
#define SERROR(s, args...) do { \
|
||||
if (!silent) \
|
||||
printk(KERN_ERR "SQUASHFS error: "s, ## args);\
|
||||
} while(0)
|
||||
|
||||
#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
|
||||
|
||||
#define SQUASHFS_I(INO) (&INO->u.squashfs_i)
|
||||
|
||||
#define i_size_read(INO) (INO->i_size)
|
||||
|
||||
#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
|
||||
#define SQSH_EXTERN
|
||||
extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
|
||||
long long index, unsigned int length,
|
||||
long long *next_index);
|
||||
extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
|
||||
long long block, unsigned int offset,
|
||||
int length, long long *next_block,
|
||||
unsigned int *next_offset);
|
||||
extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
|
||||
squashfs_fragment_cache *fragment);
|
||||
extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
|
||||
*s, long long start_block,
|
||||
int length);
|
||||
extern struct address_space_operations squashfs_symlink_aops;
|
||||
extern struct address_space_operations squashfs_aops;
|
||||
extern struct address_space_operations squashfs_aops_4K;
|
||||
extern struct file_operations squashfs_dir_ops;
|
||||
extern struct inode_operations squashfs_dir_inode_ops;
|
||||
#else
|
||||
#define SQSH_EXTERN static
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
|
||||
extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
|
||||
#else
|
||||
static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
|
||||
extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
|
||||
#else
|
||||
static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs2_0.c
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/squashfs_fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/zlib.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/locks.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/zlib.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include "squashfs.h"
|
||||
|
||||
static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
|
||||
static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry);
|
||||
|
||||
static struct file_operations squashfs_dir_ops_2 = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = squashfs_readdir_2
|
||||
};
|
||||
|
||||
static struct inode_operations squashfs_dir_inode_ops_2 = {
|
||||
.lookup = squashfs_lookup_2
|
||||
};
|
||||
|
||||
static unsigned char squashfs_filetype_table[] = {
|
||||
DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
|
||||
};
|
||||
|
||||
static int read_fragment_index_table_2(struct super_block *s)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
|
||||
if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
|
||||
(sblk->fragments), GFP_KERNEL))) {
|
||||
ERROR("Failed to allocate uid/gid table\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
|
||||
!squashfs_read_data(s, (char *)
|
||||
msblk->fragment_index_2,
|
||||
sblk->fragment_table_start,
|
||||
SQUASHFS_FRAGMENT_INDEX_BYTES_2
|
||||
(sblk->fragments) |
|
||||
SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
|
||||
ERROR("unable to read fragment index table\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msblk->swap) {
|
||||
int i;
|
||||
unsigned int fragment;
|
||||
|
||||
for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
|
||||
i++) {
|
||||
SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
|
||||
&msblk->fragment_index_2[i], 1);
|
||||
msblk->fragment_index_2[i] = fragment;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
|
||||
long long *fragment_start_block,
|
||||
unsigned int *fragment_size)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
|
||||
long long start_block =
|
||||
msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
|
||||
int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
|
||||
struct squashfs_fragment_entry_2 fragment_entry;
|
||||
|
||||
if (msblk->swap) {
|
||||
struct squashfs_fragment_entry_2 sfragment_entry;
|
||||
|
||||
if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
|
||||
start_block, offset,
|
||||
sizeof(sfragment_entry), &start_block,
|
||||
&offset))
|
||||
goto out;
|
||||
SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
|
||||
start_block, offset,
|
||||
sizeof(fragment_entry), &start_block,
|
||||
&offset))
|
||||
goto out;
|
||||
|
||||
*fragment_start_block = fragment_entry.start_block;
|
||||
*fragment_size = fragment_entry.size;
|
||||
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct inode *squashfs_new_inode(struct super_block *s,
|
||||
struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
struct inode *i = new_inode(s);
|
||||
|
||||
if (i) {
|
||||
i->i_ino = ino;
|
||||
i->i_mtime = sblk->mkfs_time;
|
||||
i->i_atime = sblk->mkfs_time;
|
||||
i->i_ctime = sblk->mkfs_time;
|
||||
i->i_uid = msblk->uid[inodeb->uid];
|
||||
i->i_mode = inodeb->mode;
|
||||
i->i_nlink = 1;
|
||||
i->i_size = 0;
|
||||
if (inodeb->guid == SQUASHFS_GUIDS)
|
||||
i->i_gid = i->i_uid;
|
||||
else
|
||||
i->i_gid = msblk->guid[inodeb->guid];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
|
||||
{
|
||||
struct inode *i;
|
||||
struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
unsigned int block = SQUASHFS_INODE_BLK(inode) +
|
||||
sblk->inode_table_start;
|
||||
unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
|
||||
unsigned int ino = SQUASHFS_MK_VFS_INODE(block
|
||||
- sblk->inode_table_start, offset);
|
||||
long long next_block;
|
||||
unsigned int next_offset;
|
||||
union squashfs_inode_header_2 id, sid;
|
||||
struct squashfs_base_inode_header_2 *inodeb = &id.base,
|
||||
*sinodeb = &sid.base;
|
||||
|
||||
TRACE("Entered squashfs_iget\n");
|
||||
|
||||
if (msblk->swap) {
|
||||
if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
|
||||
offset, sizeof(*sinodeb), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
|
||||
sizeof(*sinodeb));
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *) inodeb, block,
|
||||
offset, sizeof(*inodeb), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
switch(inodeb->inode_type) {
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
struct squashfs_reg_inode_header_2 *inodep = &id.reg;
|
||||
struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
|
||||
long long frag_blk;
|
||||
unsigned int frag_size;
|
||||
|
||||
if (msblk->swap) {
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
sinodep, block, offset,
|
||||
sizeof(*sinodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
inodep, block, offset,
|
||||
sizeof(*inodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
frag_blk = SQUASHFS_INVALID_BLK;
|
||||
if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
|
||||
!get_fragment_location_2(s,
|
||||
inodep->fragment, &frag_blk, &frag_size))
|
||||
goto failed_read;
|
||||
|
||||
if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
|
||||
goto failed_read1;
|
||||
|
||||
i->i_size = inodep->file_size;
|
||||
i->i_fop = &generic_ro_fops;
|
||||
i->i_mode |= S_IFREG;
|
||||
i->i_mtime = inodep->mtime;
|
||||
i->i_atime = inodep->mtime;
|
||||
i->i_ctime = inodep->mtime;
|
||||
i->i_blocks = ((i->i_size - 1) >> 9) + 1;
|
||||
i->i_blksize = PAGE_CACHE_SIZE;
|
||||
SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
|
||||
SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
|
||||
SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
|
||||
SQUASHFS_I(i)->start_block = inodep->start_block;
|
||||
SQUASHFS_I(i)->u.s1.block_list_start = next_block;
|
||||
SQUASHFS_I(i)->offset = next_offset;
|
||||
if (sblk->block_size > 4096)
|
||||
i->i_data.a_ops = &squashfs_aops;
|
||||
else
|
||||
i->i_data.a_ops = &squashfs_aops_4K;
|
||||
|
||||
TRACE("File inode %x:%x, start_block %x, "
|
||||
"block_list_start %llx, offset %x\n",
|
||||
SQUASHFS_INODE_BLK(inode), offset,
|
||||
inodep->start_block, next_block,
|
||||
next_offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
struct squashfs_dir_inode_header_2 *inodep = &id.dir;
|
||||
struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
|
||||
|
||||
if (msblk->swap) {
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
sinodep, block, offset,
|
||||
sizeof(*sinodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
inodep, block, offset,
|
||||
sizeof(*inodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
|
||||
goto failed_read1;
|
||||
|
||||
i->i_size = inodep->file_size;
|
||||
i->i_op = &squashfs_dir_inode_ops_2;
|
||||
i->i_fop = &squashfs_dir_ops_2;
|
||||
i->i_mode |= S_IFDIR;
|
||||
i->i_mtime = inodep->mtime;
|
||||
i->i_atime = inodep->mtime;
|
||||
i->i_ctime = inodep->mtime;
|
||||
SQUASHFS_I(i)->start_block = inodep->start_block;
|
||||
SQUASHFS_I(i)->offset = inodep->offset;
|
||||
SQUASHFS_I(i)->u.s2.directory_index_count = 0;
|
||||
SQUASHFS_I(i)->u.s2.parent_inode = 0;
|
||||
|
||||
TRACE("Directory inode %x:%x, start_block %x, offset "
|
||||
"%x\n", SQUASHFS_INODE_BLK(inode),
|
||||
offset, inodep->start_block,
|
||||
inodep->offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
|
||||
struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
|
||||
|
||||
if (msblk->swap) {
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
sinodep, block, offset,
|
||||
sizeof(*sinodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
|
||||
sinodep);
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
inodep, block, offset,
|
||||
sizeof(*inodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
|
||||
goto failed_read1;
|
||||
|
||||
i->i_size = inodep->file_size;
|
||||
i->i_op = &squashfs_dir_inode_ops_2;
|
||||
i->i_fop = &squashfs_dir_ops_2;
|
||||
i->i_mode |= S_IFDIR;
|
||||
i->i_mtime = inodep->mtime;
|
||||
i->i_atime = inodep->mtime;
|
||||
i->i_ctime = inodep->mtime;
|
||||
SQUASHFS_I(i)->start_block = inodep->start_block;
|
||||
SQUASHFS_I(i)->offset = inodep->offset;
|
||||
SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
|
||||
SQUASHFS_I(i)->u.s2.directory_index_offset =
|
||||
next_offset;
|
||||
SQUASHFS_I(i)->u.s2.directory_index_count =
|
||||
inodep->i_count;
|
||||
SQUASHFS_I(i)->u.s2.parent_inode = 0;
|
||||
|
||||
TRACE("Long directory inode %x:%x, start_block %x, "
|
||||
"offset %x\n",
|
||||
SQUASHFS_INODE_BLK(inode), offset,
|
||||
inodep->start_block, inodep->offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE: {
|
||||
struct squashfs_symlink_inode_header_2 *inodep =
|
||||
&id.symlink;
|
||||
struct squashfs_symlink_inode_header_2 *sinodep =
|
||||
&sid.symlink;
|
||||
|
||||
if (msblk->swap) {
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
sinodep, block, offset,
|
||||
sizeof(*sinodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
|
||||
sinodep);
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
inodep, block, offset,
|
||||
sizeof(*inodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
|
||||
goto failed_read1;
|
||||
|
||||
i->i_size = inodep->symlink_size;
|
||||
i->i_op = &page_symlink_inode_operations;
|
||||
i->i_data.a_ops = &squashfs_symlink_aops;
|
||||
i->i_mode |= S_IFLNK;
|
||||
SQUASHFS_I(i)->start_block = next_block;
|
||||
SQUASHFS_I(i)->offset = next_offset;
|
||||
|
||||
TRACE("Symbolic link inode %x:%x, start_block %llx, "
|
||||
"offset %x\n",
|
||||
SQUASHFS_INODE_BLK(inode), offset,
|
||||
next_block, next_offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
struct squashfs_dev_inode_header_2 *inodep = &id.dev;
|
||||
struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
|
||||
|
||||
if (msblk->swap) {
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
sinodep, block, offset,
|
||||
sizeof(*sinodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
|
||||
} else
|
||||
if (!squashfs_get_cached_block(s, (char *)
|
||||
inodep, block, offset,
|
||||
sizeof(*inodep), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
|
||||
goto failed_read1;
|
||||
|
||||
i->i_mode |= (inodeb->inode_type ==
|
||||
SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
|
||||
S_IFBLK;
|
||||
init_special_inode(i, i->i_mode, inodep->rdev);
|
||||
|
||||
TRACE("Device inode %x:%x, rdev %x\n",
|
||||
SQUASHFS_INODE_BLK(inode), offset,
|
||||
inodep->rdev);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE: {
|
||||
if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
|
||||
goto failed_read1;
|
||||
|
||||
i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
|
||||
? S_IFIFO : S_IFSOCK;
|
||||
init_special_inode(i, i->i_mode, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ERROR("Unknown inode type %d in squashfs_iget!\n",
|
||||
inodeb->inode_type);
|
||||
goto failed_read1;
|
||||
}
|
||||
|
||||
insert_inode_hash(i);
|
||||
return i;
|
||||
|
||||
failed_read:
|
||||
ERROR("Unable to read inode [%x:%x]\n", block, offset);
|
||||
|
||||
failed_read1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int get_dir_index_using_offset(struct super_block *s, long long
|
||||
*next_block, unsigned int *next_offset,
|
||||
long long index_start,
|
||||
unsigned int index_offset, int i_count,
|
||||
long long f_pos)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
int i, length = 0;
|
||||
struct squashfs_dir_index_2 index;
|
||||
|
||||
TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
|
||||
i_count, (unsigned int) f_pos);
|
||||
|
||||
if (f_pos == 0)
|
||||
goto finish;
|
||||
|
||||
for (i = 0; i < i_count; i++) {
|
||||
if (msblk->swap) {
|
||||
struct squashfs_dir_index_2 sindex;
|
||||
squashfs_get_cached_block(s, (char *) &sindex,
|
||||
index_start, index_offset,
|
||||
sizeof(sindex), &index_start,
|
||||
&index_offset);
|
||||
SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
|
||||
} else
|
||||
squashfs_get_cached_block(s, (char *) &index,
|
||||
index_start, index_offset,
|
||||
sizeof(index), &index_start,
|
||||
&index_offset);
|
||||
|
||||
if (index.index > f_pos)
|
||||
break;
|
||||
|
||||
squashfs_get_cached_block(s, NULL, index_start, index_offset,
|
||||
index.size + 1, &index_start,
|
||||
&index_offset);
|
||||
|
||||
length = index.index;
|
||||
*next_block = index.start_block + sblk->directory_table_start;
|
||||
}
|
||||
|
||||
*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
|
||||
|
||||
finish:
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static int get_dir_index_using_name(struct super_block *s, long long
|
||||
*next_block, unsigned int *next_offset,
|
||||
long long index_start,
|
||||
unsigned int index_offset, int i_count,
|
||||
const char *name, int size)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
int i, length = 0;
|
||||
char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
|
||||
struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
|
||||
char str[SQUASHFS_NAME_LEN + 1];
|
||||
|
||||
TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
|
||||
|
||||
strncpy(str, name, size);
|
||||
str[size] = '\0';
|
||||
|
||||
for (i = 0; i < i_count; i++) {
|
||||
if (msblk->swap) {
|
||||
struct squashfs_dir_index_2 sindex;
|
||||
squashfs_get_cached_block(s, (char *) &sindex,
|
||||
index_start, index_offset,
|
||||
sizeof(sindex), &index_start,
|
||||
&index_offset);
|
||||
SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
|
||||
} else
|
||||
squashfs_get_cached_block(s, (char *) index,
|
||||
index_start, index_offset,
|
||||
sizeof(struct squashfs_dir_index_2),
|
||||
&index_start, &index_offset);
|
||||
|
||||
squashfs_get_cached_block(s, index->name, index_start,
|
||||
index_offset, index->size + 1,
|
||||
&index_start, &index_offset);
|
||||
|
||||
index->name[index->size + 1] = '\0';
|
||||
|
||||
if (strcmp(index->name, str) > 0)
|
||||
break;
|
||||
|
||||
length = index->index;
|
||||
*next_block = index->start_block + sblk->directory_table_start;
|
||||
}
|
||||
|
||||
*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct inode *i = file->f_dentry->d_inode;
|
||||
struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
long long next_block = SQUASHFS_I(i)->start_block +
|
||||
sblk->directory_table_start;
|
||||
int next_offset = SQUASHFS_I(i)->offset, length = 0,
|
||||
dir_count;
|
||||
struct squashfs_dir_header_2 dirh;
|
||||
char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
|
||||
struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
|
||||
|
||||
TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
|
||||
|
||||
length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
|
||||
SQUASHFS_I(i)->u.s2.directory_index_start,
|
||||
SQUASHFS_I(i)->u.s2.directory_index_offset,
|
||||
SQUASHFS_I(i)->u.s2.directory_index_count,
|
||||
file->f_pos);
|
||||
|
||||
while (length < i_size_read(i)) {
|
||||
/* read directory header */
|
||||
if (msblk->swap) {
|
||||
struct squashfs_dir_header_2 sdirh;
|
||||
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
|
||||
next_block, next_offset, sizeof(sdirh),
|
||||
&next_block, &next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(sdirh);
|
||||
SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
|
||||
} else {
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
|
||||
next_block, next_offset, sizeof(dirh),
|
||||
&next_block, &next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(dirh);
|
||||
}
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
while (dir_count--) {
|
||||
if (msblk->swap) {
|
||||
struct squashfs_dir_entry_2 sdire;
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *)
|
||||
&sdire, next_block, next_offset,
|
||||
sizeof(sdire), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(sdire);
|
||||
SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
|
||||
} else {
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *)
|
||||
dire, next_block, next_offset,
|
||||
sizeof(*dire), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(*dire);
|
||||
}
|
||||
|
||||
if (!squashfs_get_cached_block(i->i_sb, dire->name,
|
||||
next_block, next_offset,
|
||||
dire->size + 1, &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += dire->size + 1;
|
||||
|
||||
if (file->f_pos >= length)
|
||||
continue;
|
||||
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
|
||||
TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
|
||||
(unsigned int) dirent, dire->name,
|
||||
dire->size + 1, (int) file->f_pos,
|
||||
dirh.start_block, dire->offset,
|
||||
squashfs_filetype_table[dire->type]);
|
||||
|
||||
if (filldir(dirent, dire->name, dire->size + 1,
|
||||
file->f_pos, SQUASHFS_MK_VFS_INODE(
|
||||
dirh.start_block, dire->offset),
|
||||
squashfs_filetype_table[dire->type])
|
||||
< 0) {
|
||||
TRACE("Filldir returned less than 0\n");
|
||||
goto finish;
|
||||
}
|
||||
file->f_pos = length;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
return 0;
|
||||
|
||||
failed_read:
|
||||
ERROR("Unable to read directory block [%llx:%x]\n", next_block,
|
||||
next_offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry)
|
||||
{
|
||||
const unsigned char *name = dentry->d_name.name;
|
||||
int len = dentry->d_name.len;
|
||||
struct inode *inode = NULL;
|
||||
struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
long long next_block = SQUASHFS_I(i)->start_block +
|
||||
sblk->directory_table_start;
|
||||
int next_offset = SQUASHFS_I(i)->offset, length = 0,
|
||||
dir_count;
|
||||
struct squashfs_dir_header_2 dirh;
|
||||
char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
|
||||
struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
|
||||
int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
|
||||
|
||||
TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
|
||||
|
||||
if (len > SQUASHFS_NAME_LEN)
|
||||
goto exit_loop;
|
||||
|
||||
length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
|
||||
SQUASHFS_I(i)->u.s2.directory_index_start,
|
||||
SQUASHFS_I(i)->u.s2.directory_index_offset,
|
||||
SQUASHFS_I(i)->u.s2.directory_index_count, name,
|
||||
len);
|
||||
|
||||
while (length < i_size_read(i)) {
|
||||
/* read directory header */
|
||||
if (msblk->swap) {
|
||||
struct squashfs_dir_header_2 sdirh;
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
|
||||
next_block, next_offset, sizeof(sdirh),
|
||||
&next_block, &next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(sdirh);
|
||||
SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
|
||||
} else {
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
|
||||
next_block, next_offset, sizeof(dirh),
|
||||
&next_block, &next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(dirh);
|
||||
}
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
while (dir_count--) {
|
||||
if (msblk->swap) {
|
||||
struct squashfs_dir_entry_2 sdire;
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *)
|
||||
&sdire, next_block,next_offset,
|
||||
sizeof(sdire), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(sdire);
|
||||
SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
|
||||
} else {
|
||||
if (!squashfs_get_cached_block(i->i_sb, (char *)
|
||||
dire, next_block,next_offset,
|
||||
sizeof(*dire), &next_block,
|
||||
&next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(*dire);
|
||||
}
|
||||
|
||||
if (!squashfs_get_cached_block(i->i_sb, dire->name,
|
||||
next_block, next_offset, dire->size + 1,
|
||||
&next_block, &next_offset))
|
||||
goto failed_read;
|
||||
|
||||
length += dire->size + 1;
|
||||
|
||||
if (sorted && name[0] < dire->name[0])
|
||||
goto exit_loop;
|
||||
|
||||
if ((len == dire->size + 1) && !strncmp(name,
|
||||
dire->name, len)) {
|
||||
squashfs_inode_t ino =
|
||||
SQUASHFS_MKINODE(dirh.start_block,
|
||||
dire->offset);
|
||||
|
||||
TRACE("calling squashfs_iget for directory "
|
||||
"entry %s, inode %x:%x, %d\n", name,
|
||||
dirh.start_block, dire->offset, ino);
|
||||
|
||||
inode = (msblk->iget)(i->i_sb, ino);
|
||||
|
||||
goto exit_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit_loop:
|
||||
d_add(dentry, inode);
|
||||
return ERR_PTR(0);
|
||||
|
||||
failed_read:
|
||||
ERROR("Unable to read directory block [%llx:%x]\n", next_block,
|
||||
next_offset);
|
||||
goto exit_loop;
|
||||
}
|
||||
|
||||
|
||||
int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
|
||||
{
|
||||
struct squashfs_super_block *sblk = &msblk->sblk;
|
||||
|
||||
msblk->iget = squashfs_iget_2;
|
||||
msblk->read_fragment_index_table = read_fragment_index_table_2;
|
||||
|
||||
sblk->bytes_used = sblk->bytes_used_2;
|
||||
sblk->uid_start = sblk->uid_start_2;
|
||||
sblk->guid_start = sblk->guid_start_2;
|
||||
sblk->inode_table_start = sblk->inode_table_start_2;
|
||||
sblk->directory_table_start = sblk->directory_table_start_2;
|
||||
sblk->fragment_table_start = sblk->fragment_table_start_2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,915 @@
|
||||
#ifndef SQUASHFS_FS
|
||||
#define SQUASHFS_FS
|
||||
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_fs.h
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
|
||||
#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_VMALLOC
|
||||
#define SQUASHFS_ALLOC(a) vmalloc(a)
|
||||
#define SQUASHFS_FREE(a) vfree(a)
|
||||
#else
|
||||
#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL)
|
||||
#define SQUASHFS_FREE(a) kfree(a)
|
||||
#endif
|
||||
#ifdef CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
|
||||
#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
|
||||
#else
|
||||
#define SQUASHFS_CACHED_FRAGMENTS 3
|
||||
#endif
|
||||
#define SQUASHFS_MAJOR 3
|
||||
#define SQUASHFS_MINOR 0
|
||||
#define SQUASHFS_MAGIC 0x73717368
|
||||
#define SQUASHFS_MAGIC_SWAP 0x68737173
|
||||
#define SQUASHFS_START 0
|
||||
|
||||
/* size of metadata (inode and directory) blocks */
|
||||
#define SQUASHFS_METADATA_SIZE 8192
|
||||
#define SQUASHFS_METADATA_LOG 13
|
||||
|
||||
/* default size of data blocks */
|
||||
#define SQUASHFS_FILE_SIZE 65536
|
||||
#define SQUASHFS_FILE_LOG 16
|
||||
|
||||
#define SQUASHFS_FILE_MAX_SIZE 65536
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_UIDS 256
|
||||
#define SQUASHFS_GUIDS 255
|
||||
|
||||
/* Max length of filename (not 255) */
|
||||
#define SQUASHFS_NAME_LEN 256
|
||||
|
||||
#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
|
||||
#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
|
||||
#define SQUASHFS_INVALID_BLK ((long long) -1)
|
||||
#define SQUASHFS_USED_BLK ((long long) -2)
|
||||
|
||||
/* Filesystem flags */
|
||||
#define SQUASHFS_NOI 0
|
||||
#define SQUASHFS_NOD 1
|
||||
#define SQUASHFS_CHECK 2
|
||||
#define SQUASHFS_NOF 3
|
||||
#define SQUASHFS_NO_FRAG 4
|
||||
#define SQUASHFS_ALWAYS_FRAG 5
|
||||
#define SQUASHFS_DUPLICATE 6
|
||||
|
||||
#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOI)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOD)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOF)
|
||||
|
||||
#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_FRAG)
|
||||
|
||||
#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_ALWAYS_FRAG)
|
||||
|
||||
#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_DUPLICATE)
|
||||
|
||||
#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_CHECK)
|
||||
|
||||
#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
|
||||
duplicate_checking) (noi | (nod << 1) | (check_data << 2) \
|
||||
| (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
|
||||
(duplicate_checking << 6))
|
||||
|
||||
/* Max number of types and file types */
|
||||
#define SQUASHFS_DIR_TYPE 1
|
||||
#define SQUASHFS_FILE_TYPE 2
|
||||
#define SQUASHFS_SYMLINK_TYPE 3
|
||||
#define SQUASHFS_BLKDEV_TYPE 4
|
||||
#define SQUASHFS_CHRDEV_TYPE 5
|
||||
#define SQUASHFS_FIFO_TYPE 6
|
||||
#define SQUASHFS_SOCKET_TYPE 7
|
||||
#define SQUASHFS_LDIR_TYPE 8
|
||||
#define SQUASHFS_LREG_TYPE 9
|
||||
|
||||
/* 1.0 filesystem type definitions */
|
||||
#define SQUASHFS_TYPES 5
|
||||
#define SQUASHFS_IPC_TYPE 0
|
||||
|
||||
/* Flag whether block is compressed or uncompressed, bit is set if block is
|
||||
* uncompressed */
|
||||
#define SQUASHFS_COMPRESSED_BIT (1 << 15)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
|
||||
(B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
|
||||
|
||||
#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \
|
||||
~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
|
||||
~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
|
||||
|
||||
/*
|
||||
* Inode number ops. Inodes consist of a compressed block number, and an
|
||||
* uncompressed offset within that block
|
||||
*/
|
||||
#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
|
||||
|
||||
#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
|
||||
|
||||
#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
|
||||
<< 16) + (B)))
|
||||
|
||||
/* Compute 32 bit VFS inode number from squashfs inode number */
|
||||
#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
|
||||
((b) >> 2) + 1))
|
||||
/* XXX */
|
||||
|
||||
/* Translate between VFS mode and squashfs mode */
|
||||
#define SQUASHFS_MODE(a) ((a) & 0xfff)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* cached data constants for filesystem */
|
||||
#define SQUASHFS_CACHED_BLKS 8
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE_LOG 64
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
|
||||
(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
|
||||
|
||||
#define SQUASHFS_MARKER_BYTE 0xff
|
||||
|
||||
/* meta index cache */
|
||||
#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
|
||||
#define SQUASHFS_META_ENTRIES 31
|
||||
#define SQUASHFS_META_NUMBER 8
|
||||
#define SQUASHFS_SLOTS 4
|
||||
|
||||
struct meta_entry {
|
||||
long long data_block;
|
||||
unsigned int index_block;
|
||||
unsigned short offset;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct meta_index {
|
||||
unsigned int inode_number;
|
||||
unsigned int offset;
|
||||
unsigned short entries;
|
||||
unsigned short skip;
|
||||
unsigned short locked;
|
||||
unsigned short pad;
|
||||
struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* definitions for structures on disk
|
||||
*/
|
||||
|
||||
typedef long long squashfs_block_t;
|
||||
typedef long long squashfs_inode_t;
|
||||
|
||||
struct squashfs_super_block {
|
||||
unsigned int s_magic;
|
||||
unsigned int inodes;
|
||||
unsigned int bytes_used_2;
|
||||
unsigned int uid_start_2;
|
||||
unsigned int guid_start_2;
|
||||
unsigned int inode_table_start_2;
|
||||
unsigned int directory_table_start_2;
|
||||
unsigned int s_major:16;
|
||||
unsigned int s_minor:16;
|
||||
unsigned int block_size_1:16;
|
||||
unsigned int block_log:16;
|
||||
unsigned int flags:8;
|
||||
unsigned int no_uids:8;
|
||||
unsigned int no_guids:8;
|
||||
unsigned int mkfs_time /* time of filesystem creation */;
|
||||
squashfs_inode_t root_inode;
|
||||
unsigned int block_size;
|
||||
unsigned int fragments;
|
||||
unsigned int fragment_table_start_2;
|
||||
long long bytes_used;
|
||||
long long uid_start;
|
||||
long long guid_start;
|
||||
long long inode_table_start;
|
||||
long long directory_table_start;
|
||||
long long fragment_table_start;
|
||||
long long unused;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_index {
|
||||
unsigned int index;
|
||||
unsigned int start_block;
|
||||
unsigned char size;
|
||||
unsigned char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define SQUASHFS_BASE_INODE_HEADER \
|
||||
unsigned int inode_type:4; \
|
||||
unsigned int mode:12; \
|
||||
unsigned int uid:8; \
|
||||
unsigned int guid:8; \
|
||||
unsigned int mtime; \
|
||||
unsigned int inode_number;
|
||||
|
||||
struct squashfs_base_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
unsigned int nlink;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
unsigned int nlink;
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
unsigned int nlink;
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
squashfs_block_t start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_lreg_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
unsigned int nlink;
|
||||
squashfs_block_t start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
long long file_size;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
unsigned int start_block;
|
||||
unsigned int parent_inode;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ldir_inode_header {
|
||||
SQUASHFS_BASE_INODE_HEADER;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size:27;
|
||||
unsigned int offset:13;
|
||||
unsigned int start_block;
|
||||
unsigned int i_count:16;
|
||||
unsigned int parent_inode;
|
||||
struct squashfs_dir_index index[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header {
|
||||
struct squashfs_base_inode_header base;
|
||||
struct squashfs_dev_inode_header dev;
|
||||
struct squashfs_symlink_inode_header symlink;
|
||||
struct squashfs_reg_inode_header reg;
|
||||
struct squashfs_lreg_inode_header lreg;
|
||||
struct squashfs_dir_inode_header dir;
|
||||
struct squashfs_ldir_inode_header ldir;
|
||||
struct squashfs_ipc_inode_header ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry {
|
||||
unsigned int offset:13;
|
||||
unsigned int type:3;
|
||||
unsigned int size:8;
|
||||
int inode_number:16;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_header {
|
||||
unsigned int count:8;
|
||||
unsigned int start_block;
|
||||
unsigned int inode_number;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_fragment_entry {
|
||||
long long start_block;
|
||||
unsigned int size;
|
||||
unsigned int unused;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
|
||||
extern int squashfs_uncompress_init(void);
|
||||
extern int squashfs_uncompress_exit(void);
|
||||
|
||||
/*
|
||||
* macros to convert each packed bitfield structure from little endian to big
|
||||
* endian and vice versa. These are needed when creating or using a filesystem
|
||||
* on a machine with different byte ordering to the target architecture.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SQUASHFS_SWAP_START \
|
||||
int bits;\
|
||||
int b_pos;\
|
||||
unsigned long long val;\
|
||||
unsigned char *s;\
|
||||
unsigned char *d;
|
||||
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
|
||||
SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
|
||||
SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
|
||||
SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
|
||||
SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
|
||||
SQUASHFS_SWAP((s)->flags, d, 288, 8);\
|
||||
SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
|
||||
SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
|
||||
SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
|
||||
SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
|
||||
SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
|
||||
SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
|
||||
SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
|
||||
SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
|
||||
SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
|
||||
SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
|
||||
SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
|
||||
SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
|
||||
SQUASHFS_SWAP((s)->unused, d, 888, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 24, 8);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_ipc_inode_header))\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header)); \
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_lreg_inode_header));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 224, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 147, 13);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
|
||||
sizeof(struct squashfs_ldir_inode_header));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 155, 13);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
|
||||
SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
|
||||
SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
|
||||
SQUASHFS_SWAP((s)->index, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->size, d, 64, 8);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
|
||||
SQUASHFS_SWAP((s)->count, d, 0, 8);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
|
||||
SQUASHFS_SWAP((s)->offset, d, 0, 13);\
|
||||
SQUASHFS_SWAP((s)->type, d, 13, 3);\
|
||||
SQUASHFS_SWAP((s)->size, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
|
||||
SQUASHFS_SWAP((s)->size, d, 64, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 2);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
16)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_INTS(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 4);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
32)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 8);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
64)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * bits / 8);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
bits)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
|
||||
|
||||
struct squashfs_base_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int type:4;
|
||||
unsigned int offset:4;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int mtime;
|
||||
unsigned int start_block;
|
||||
unsigned int file_size:32;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
unsigned int mtime;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 4);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 20, 4);
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_ipc_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->type, d, 24, 4);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 28, 4);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 43, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
|
||||
|
||||
struct squashfs_dir_index_2 {
|
||||
unsigned int index:27;
|
||||
unsigned int start_block:29;
|
||||
unsigned char size;
|
||||
unsigned char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_base_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int mtime;
|
||||
unsigned int start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size:32;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
unsigned int mtime;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ldir_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int file_size:27;
|
||||
unsigned int offset:13;
|
||||
unsigned int mtime;
|
||||
unsigned int start_block:24;
|
||||
unsigned int i_count:16;
|
||||
struct squashfs_dir_index_2 index[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_2 {
|
||||
struct squashfs_base_inode_header_2 base;
|
||||
struct squashfs_dev_inode_header_2 dev;
|
||||
struct squashfs_symlink_inode_header_2 symlink;
|
||||
struct squashfs_reg_inode_header_2 reg;
|
||||
struct squashfs_dir_inode_header_2 dir;
|
||||
struct squashfs_ldir_inode_header_2 ldir;
|
||||
struct squashfs_ipc_inode_header_2 ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_header_2 {
|
||||
unsigned int count:8;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_entry_2 {
|
||||
unsigned int offset:13;
|
||||
unsigned int type:3;
|
||||
unsigned int size:8;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_fragment_entry_2 {
|
||||
unsigned int start_block;
|
||||
unsigned int size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 24, 8);\
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_2)); \
|
||||
SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 128, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 51, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_ldir_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 59, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
|
||||
SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
|
||||
SQUASHFS_SWAP((s)->index, d, 0, 27);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
|
||||
SQUASHFS_SWAP((s)->size, d, 56, 8);\
|
||||
}
|
||||
#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
|
||||
SQUASHFS_SWAP((s)->count, d, 0, 8);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
|
||||
SQUASHFS_SWAP((s)->offset, d, 0, 13);\
|
||||
SQUASHFS_SWAP((s)->type, d, 13, 3);\
|
||||
SQUASHFS_SWAP((s)->size, d, 16, 8);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->size, d, 32, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
|
||||
sizeof(int))
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* macros used to swap each structure entry, taking into account
|
||||
* bitfields and different bitfield placing conventions on differing
|
||||
* architectures
|
||||
*/
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
/* convert from little endian to big endian */
|
||||
#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
|
||||
tbits, b_pos)
|
||||
#else
|
||||
/* convert from big endian to little endian */
|
||||
#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
|
||||
tbits, 64 - tbits - b_pos)
|
||||
#endif
|
||||
|
||||
#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
|
||||
b_pos = pos % 8;\
|
||||
val = 0;\
|
||||
s = (unsigned char *)p + (pos / 8);\
|
||||
d = ((unsigned char *) &val) + 7;\
|
||||
for(bits = 0; bits < (tbits + b_pos); bits += 8) \
|
||||
*d-- = *s++;\
|
||||
value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
|
||||
}
|
||||
|
||||
#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef SQUASHFS_FS_I
|
||||
#define SQUASHFS_FS_I
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_fs_i.h
|
||||
*/
|
||||
|
||||
struct squashfs_inode_info {
|
||||
long long start_block;
|
||||
unsigned int offset;
|
||||
union {
|
||||
struct {
|
||||
long long fragment_start_block;
|
||||
unsigned int fragment_size;
|
||||
unsigned int fragment_offset;
|
||||
long long block_list_start;
|
||||
} s1;
|
||||
struct {
|
||||
long long directory_index_start;
|
||||
unsigned int directory_index_offset;
|
||||
unsigned int directory_index_count;
|
||||
unsigned int parent_inode;
|
||||
} s2;
|
||||
} u;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef SQUASHFS_FS_SB
|
||||
#define SQUASHFS_FS_SB
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_fs_sb.h
|
||||
*/
|
||||
|
||||
#include <linux/squashfs_fs.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
struct squashfs_cache {
|
||||
long long block;
|
||||
int length;
|
||||
long long next_index;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct squashfs_fragment_cache {
|
||||
long long block;
|
||||
int length;
|
||||
unsigned int locked;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct squashfs_sb_info {
|
||||
struct squashfs_super_block sblk;
|
||||
int devblksize;
|
||||
int devblksize_log2;
|
||||
int swap;
|
||||
struct squashfs_cache *block_cache;
|
||||
struct squashfs_fragment_cache *fragment;
|
||||
int next_cache;
|
||||
int next_fragment;
|
||||
int next_meta_index;
|
||||
unsigned int *uid;
|
||||
unsigned int *guid;
|
||||
long long *fragment_index;
|
||||
unsigned int *fragment_index_2;
|
||||
unsigned int read_size;
|
||||
char *read_data;
|
||||
char *read_page;
|
||||
struct semaphore read_data_mutex;
|
||||
struct semaphore read_page_mutex;
|
||||
struct semaphore block_cache_mutex;
|
||||
struct semaphore fragment_mutex;
|
||||
struct semaphore meta_index_mutex;
|
||||
wait_queue_head_t waitq;
|
||||
wait_queue_head_t fragment_wait_queue;
|
||||
struct meta_index *meta_index;
|
||||
z_stream stream;
|
||||
struct inode *(*iget)(struct super_block *s, squashfs_inode_t
|
||||
inode);
|
||||
long long (*read_blocklist)(struct inode *inode, int
|
||||
index, int readahead_blks, char *block_list,
|
||||
unsigned short **block_p, unsigned int *bsize);
|
||||
int (*read_fragment_index_table)(struct super_block *s);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,225 @@
|
||||
SQUASHFS 4.0 FILESYSTEM
|
||||
=======================
|
||||
|
||||
Squashfs is a compressed read-only filesystem for Linux.
|
||||
It uses zlib compression to compress files, inodes and directories.
|
||||
Inodes in the system are very small and all blocks are packed to minimise
|
||||
data overhead. Block sizes greater than 4K are supported up to a maximum
|
||||
of 1Mbytes (default block size 128K).
|
||||
|
||||
Squashfs is intended for general read-only filesystem use, for archival
|
||||
use (i.e. in cases where a .tar.gz file may be used), and in constrained
|
||||
block device/memory systems (e.g. embedded systems) where low overhead is
|
||||
needed.
|
||||
|
||||
Mailing list: squashfs-devel@lists.sourceforge.net
|
||||
Web site: www.squashfs.org
|
||||
|
||||
1. FILESYSTEM FEATURES
|
||||
----------------------
|
||||
|
||||
Squashfs filesystem features versus Cramfs:
|
||||
|
||||
Squashfs Cramfs
|
||||
|
||||
Max filesystem size: 2^64 16 MiB
|
||||
Max file size: ~ 2 TiB 16 MiB
|
||||
Max files: unlimited unlimited
|
||||
Max directories: unlimited unlimited
|
||||
Max entries per directory: unlimited unlimited
|
||||
Max block size: 1 MiB 4 KiB
|
||||
Metadata compression: yes no
|
||||
Directory indexes: yes no
|
||||
Sparse file support: yes no
|
||||
Tail-end packing (fragments): yes no
|
||||
Exportable (NFS etc.): yes no
|
||||
Hard link support: yes no
|
||||
"." and ".." in readdir: yes no
|
||||
Real inode numbers: yes no
|
||||
32-bit uids/gids: yes no
|
||||
File creation time: yes no
|
||||
Xattr and ACL support: no no
|
||||
|
||||
Squashfs compresses data, inodes and directories. In addition, inode and
|
||||
directory data are highly compacted, and packed on byte boundaries. Each
|
||||
compressed inode is on average 8 bytes in length (the exact length varies on
|
||||
file type, i.e. regular file, directory, symbolic link, and block/char device
|
||||
inodes have different sizes).
|
||||
|
||||
2. USING SQUASHFS
|
||||
-----------------
|
||||
|
||||
As squashfs is a read-only filesystem, the mksquashfs program must be used to
|
||||
create populated squashfs filesystems. This and other squashfs utilities
|
||||
can be obtained from http://www.squashfs.org. Usage instructions can be
|
||||
obtained from this site also.
|
||||
|
||||
|
||||
3. SQUASHFS FILESYSTEM DESIGN
|
||||
-----------------------------
|
||||
|
||||
A squashfs filesystem consists of seven parts, packed together on a byte
|
||||
alignment:
|
||||
|
||||
---------------
|
||||
| superblock |
|
||||
|---------------|
|
||||
| datablocks |
|
||||
| & fragments |
|
||||
|---------------|
|
||||
| inode table |
|
||||
|---------------|
|
||||
| directory |
|
||||
| table |
|
||||
|---------------|
|
||||
| fragment |
|
||||
| table |
|
||||
|---------------|
|
||||
| export |
|
||||
| table |
|
||||
|---------------|
|
||||
| uid/gid |
|
||||
| lookup table |
|
||||
---------------
|
||||
|
||||
Compressed data blocks are written to the filesystem as files are read from
|
||||
the source directory, and checked for duplicates. Once all file data has been
|
||||
written the completed inode, directory, fragment, export and uid/gid lookup
|
||||
tables are written.
|
||||
|
||||
3.1 Inodes
|
||||
----------
|
||||
|
||||
Metadata (inodes and directories) are compressed in 8Kbyte blocks. Each
|
||||
compressed block is prefixed by a two byte length, the top bit is set if the
|
||||
block is uncompressed. A block will be uncompressed if the -noI option is set,
|
||||
or if the compressed block was larger than the uncompressed block.
|
||||
|
||||
Inodes are packed into the metadata blocks, and are not aligned to block
|
||||
boundaries, therefore inodes overlap compressed blocks. Inodes are identified
|
||||
by a 48-bit number which encodes the location of the compressed metadata block
|
||||
containing the inode, and the byte offset into that block where the inode is
|
||||
placed (<block, offset>).
|
||||
|
||||
To maximise compression there are different inodes for each file type
|
||||
(regular file, directory, device, etc.), the inode contents and length
|
||||
varying with the type.
|
||||
|
||||
To further maximise compression, two types of regular file inode and
|
||||
directory inode are defined: inodes optimised for frequently occurring
|
||||
regular files and directories, and extended types where extra
|
||||
information has to be stored.
|
||||
|
||||
3.2 Directories
|
||||
---------------
|
||||
|
||||
Like inodes, directories are packed into compressed metadata blocks, stored
|
||||
in a directory table. Directories are accessed using the start address of
|
||||
the metablock containing the directory and the offset into the
|
||||
decompressed block (<block, offset>).
|
||||
|
||||
Directories are organised in a slightly complex way, and are not simply
|
||||
a list of file names. The organisation takes advantage of the
|
||||
fact that (in most cases) the inodes of the files will be in the same
|
||||
compressed metadata block, and therefore, can share the start block.
|
||||
Directories are therefore organised in a two level list, a directory
|
||||
header containing the shared start block value, and a sequence of directory
|
||||
entries, each of which share the shared start block. A new directory header
|
||||
is written once/if the inode start block changes. The directory
|
||||
header/directory entry list is repeated as many times as necessary.
|
||||
|
||||
Directories are sorted, and can contain a directory index to speed up
|
||||
file lookup. Directory indexes store one entry per metablock, each entry
|
||||
storing the index/filename mapping to the first directory header
|
||||
in each metadata block. Directories are sorted in alphabetical order,
|
||||
and at lookup the index is scanned linearly looking for the first filename
|
||||
alphabetically larger than the filename being looked up. At this point the
|
||||
location of the metadata block the filename is in has been found.
|
||||
The general idea of the index is ensure only one metadata block needs to be
|
||||
decompressed to do a lookup irrespective of the length of the directory.
|
||||
This scheme has the advantage that it doesn't require extra memory overhead
|
||||
and doesn't require much extra storage on disk.
|
||||
|
||||
3.3 File data
|
||||
-------------
|
||||
|
||||
Regular files consist of a sequence of contiguous compressed blocks, and/or a
|
||||
compressed fragment block (tail-end packed block). The compressed size
|
||||
of each datablock is stored in a block list contained within the
|
||||
file inode.
|
||||
|
||||
To speed up access to datablocks when reading 'large' files (256 Mbytes or
|
||||
larger), the code implements an index cache that caches the mapping from
|
||||
block index to datablock location on disk.
|
||||
|
||||
The index cache allows Squashfs to handle large files (up to 1.75 TiB) while
|
||||
retaining a simple and space-efficient block list on disk. The cache
|
||||
is split into slots, caching up to eight 224 GiB files (128 KiB blocks).
|
||||
Larger files use multiple slots, with 1.75 TiB files using all 8 slots.
|
||||
The index cache is designed to be memory efficient, and by default uses
|
||||
16 KiB.
|
||||
|
||||
3.4 Fragment lookup table
|
||||
-------------------------
|
||||
|
||||
Regular files can contain a fragment index which is mapped to a fragment
|
||||
location on disk and compressed size using a fragment lookup table. This
|
||||
fragment lookup table is itself stored compressed into metadata blocks.
|
||||
A second index table is used to locate these. This second index table for
|
||||
speed of access (and because it is small) is read at mount time and cached
|
||||
in memory.
|
||||
|
||||
3.5 Uid/gid lookup table
|
||||
------------------------
|
||||
|
||||
For space efficiency regular files store uid and gid indexes, which are
|
||||
converted to 32-bit uids/gids using an id look up table. This table is
|
||||
stored compressed into metadata blocks. A second index table is used to
|
||||
locate these. This second index table for speed of access (and because it
|
||||
is small) is read at mount time and cached in memory.
|
||||
|
||||
3.6 Export table
|
||||
----------------
|
||||
|
||||
To enable Squashfs filesystems to be exportable (via NFS etc.) filesystems
|
||||
can optionally (disabled with the -no-exports Mksquashfs option) contain
|
||||
an inode number to inode disk location lookup table. This is required to
|
||||
enable Squashfs to map inode numbers passed in filehandles to the inode
|
||||
location on disk, which is necessary when the export code reinstantiates
|
||||
expired/flushed inodes.
|
||||
|
||||
This table is stored compressed into metadata blocks. A second index table is
|
||||
used to locate these. This second index table for speed of access (and because
|
||||
it is small) is read at mount time and cached in memory.
|
||||
|
||||
|
||||
4. TODOS AND OUTSTANDING ISSUES
|
||||
-------------------------------
|
||||
|
||||
4.1 Todo list
|
||||
-------------
|
||||
|
||||
Implement Xattr and ACL support. The Squashfs 4.0 filesystem layout has hooks
|
||||
for these but the code has not been written. Once the code has been written
|
||||
the existing layout should not require modification.
|
||||
|
||||
4.2 Squashfs internal cache
|
||||
---------------------------
|
||||
|
||||
Blocks in Squashfs are compressed. To avoid repeatedly decompressing
|
||||
recently accessed data Squashfs uses two small metadata and fragment caches.
|
||||
|
||||
The cache is not used for file datablocks, these are decompressed and cached in
|
||||
the page-cache in the normal way. The cache is used to temporarily cache
|
||||
fragment and metadata blocks which have been read as a result of a metadata
|
||||
(i.e. inode or directory) or fragment access. Because metadata and fragments
|
||||
are packed together into blocks (to gain greater compression) the read of a
|
||||
particular piece of metadata or fragment will retrieve other metadata/fragments
|
||||
which have been packed with it, these because of locality-of-reference may be
|
||||
read in the near future. Temporarily caching them ensures they are available
|
||||
for near future access without requiring an additional read and decompress.
|
||||
|
||||
In the future this internal cache may be replaced with an implementation which
|
||||
uses the kernel page cache. Because the page cache operates on page sized
|
||||
units this may introduce additional complexity in terms of locking and
|
||||
associated race conditions.
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Makefile for the linux squashfs routines.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SQUASHFS) += squashfs.o
|
||||
squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
|
||||
squashfs-y += namei.o super.o symlink.o
|
||||
#squashfs-y += squashfs2_0.o
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* block.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements the low-level routines to read and decompress
|
||||
* datablocks and metadata blocks.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Read the metadata block length, this is stored in the first two
|
||||
* bytes of the metadata block.
|
||||
*/
|
||||
static struct buffer_head *get_block_length(struct super_block *sb,
|
||||
u64 *cur_index, int *offset, int *length)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
struct buffer_head *bh;
|
||||
|
||||
bh = sb_bread(sb, *cur_index);
|
||||
if (bh == NULL)
|
||||
return NULL;
|
||||
|
||||
if (msblk->devblksize - *offset == 1) {
|
||||
*length = (unsigned char) bh->b_data[*offset];
|
||||
put_bh(bh);
|
||||
bh = sb_bread(sb, ++(*cur_index));
|
||||
if (bh == NULL)
|
||||
return NULL;
|
||||
*length |= (unsigned char) bh->b_data[0] << 8;
|
||||
*offset = 1;
|
||||
} else {
|
||||
*length = (unsigned char) bh->b_data[*offset] |
|
||||
(unsigned char) bh->b_data[*offset + 1] << 8;
|
||||
*offset += 2;
|
||||
}
|
||||
|
||||
return bh;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read and decompress a metadata block or datablock. Length is non-zero
|
||||
* if a datablock is being read (the size is stored elsewhere in the
|
||||
* filesystem), otherwise the length is obtained from the first two bytes of
|
||||
* the metadata block. A bit in the length field indicates if the block
|
||||
* is stored uncompressed in the filesystem (usually because compression
|
||||
* generated a larger block - this does occasionally happen with zlib).
|
||||
*/
|
||||
int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
|
||||
int length, u64 *next_index, int srclength)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
struct buffer_head **bh;
|
||||
int offset = index & ((1 << msblk->devblksize_log2) - 1);
|
||||
u64 cur_index = index >> msblk->devblksize_log2;
|
||||
int bytes, compressed, b = 0, k = 0, page = 0, avail;
|
||||
|
||||
|
||||
bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1,
|
||||
sizeof(*bh), GFP_KERNEL);
|
||||
if (bh == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (length) {
|
||||
/*
|
||||
* Datablock.
|
||||
*/
|
||||
bytes = -offset;
|
||||
compressed = SQUASHFS_COMPRESSED_BLOCK(length);
|
||||
length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
|
||||
if (next_index)
|
||||
*next_index = index + length;
|
||||
|
||||
TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
|
||||
index, compressed ? "" : "un", length, srclength);
|
||||
|
||||
if (length < 0 || length > srclength ||
|
||||
(index + length) > msblk->bytes_used)
|
||||
goto read_failure;
|
||||
|
||||
for (b = 0; bytes < length; b++, cur_index++) {
|
||||
bh[b] = sb_getblk(sb, cur_index);
|
||||
if (bh[b] == NULL)
|
||||
goto block_release;
|
||||
bytes += msblk->devblksize;
|
||||
}
|
||||
ll_rw_block(READ, b, bh);
|
||||
} else {
|
||||
/*
|
||||
* Metadata block.
|
||||
*/
|
||||
if ((index + 2) > msblk->bytes_used)
|
||||
goto read_failure;
|
||||
|
||||
bh[0] = get_block_length(sb, &cur_index, &offset, &length);
|
||||
if (bh[0] == NULL)
|
||||
goto read_failure;
|
||||
b = 1;
|
||||
|
||||
bytes = msblk->devblksize - offset;
|
||||
compressed = SQUASHFS_COMPRESSED(length);
|
||||
length = SQUASHFS_COMPRESSED_SIZE(length);
|
||||
if (next_index)
|
||||
*next_index = index + length + 2;
|
||||
|
||||
TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
|
||||
compressed ? "" : "un", length);
|
||||
|
||||
if (length < 0 || length > srclength ||
|
||||
(index + length) > msblk->bytes_used)
|
||||
goto block_release;
|
||||
|
||||
for (; bytes < length; b++) {
|
||||
bh[b] = sb_getblk(sb, ++cur_index);
|
||||
if (bh[b] == NULL)
|
||||
goto block_release;
|
||||
bytes += msblk->devblksize;
|
||||
}
|
||||
ll_rw_block(READ, b - 1, bh + 1);
|
||||
}
|
||||
|
||||
if (compressed) {
|
||||
int zlib_err = 0, zlib_init = 0;
|
||||
|
||||
/*
|
||||
* Uncompress block.
|
||||
*/
|
||||
|
||||
mutex_lock(&msblk->read_data_mutex);
|
||||
|
||||
msblk->stream.avail_out = 0;
|
||||
msblk->stream.avail_in = 0;
|
||||
|
||||
bytes = length;
|
||||
do {
|
||||
if (msblk->stream.avail_in == 0 && k < b) {
|
||||
avail = min(bytes, msblk->devblksize - offset);
|
||||
bytes -= avail;
|
||||
wait_on_buffer(bh[k]);
|
||||
if (!buffer_uptodate(bh[k]))
|
||||
goto release_mutex;
|
||||
|
||||
if (avail == 0) {
|
||||
offset = 0;
|
||||
put_bh(bh[k++]);
|
||||
continue;
|
||||
}
|
||||
|
||||
msblk->stream.next_in = bh[k]->b_data + offset;
|
||||
msblk->stream.avail_in = avail;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (msblk->stream.avail_out == 0) {
|
||||
msblk->stream.next_out = buffer[page++];
|
||||
msblk->stream.avail_out = PAGE_CACHE_SIZE;
|
||||
}
|
||||
|
||||
if (!zlib_init) {
|
||||
zlib_err = zlib_inflateInit(&msblk->stream);
|
||||
if (zlib_err != Z_OK) {
|
||||
ERROR("zlib_inflateInit returned"
|
||||
" unexpected result 0x%x,"
|
||||
" srclength %d\n", zlib_err,
|
||||
srclength);
|
||||
goto release_mutex;
|
||||
}
|
||||
zlib_init = 1;
|
||||
}
|
||||
|
||||
zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
|
||||
|
||||
if (msblk->stream.avail_in == 0 && k < b)
|
||||
put_bh(bh[k++]);
|
||||
} while (zlib_err == Z_OK);
|
||||
|
||||
if (zlib_err != Z_STREAM_END) {
|
||||
ERROR("zlib_inflate returned unexpected result"
|
||||
" 0x%x, srclength %d, avail_in %d,"
|
||||
" avail_out %d\n", zlib_err, srclength,
|
||||
msblk->stream.avail_in,
|
||||
msblk->stream.avail_out);
|
||||
goto release_mutex;
|
||||
}
|
||||
|
||||
zlib_err = zlib_inflateEnd(&msblk->stream);
|
||||
if (zlib_err != Z_OK) {
|
||||
ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
|
||||
" srclength %d\n", zlib_err, srclength);
|
||||
goto release_mutex;
|
||||
}
|
||||
length = msblk->stream.total_out;
|
||||
mutex_unlock(&msblk->read_data_mutex);
|
||||
} else {
|
||||
/*
|
||||
* Block is uncompressed.
|
||||
*/
|
||||
int i, in, pg_offset = 0;
|
||||
|
||||
for (i = 0; i < b; i++) {
|
||||
wait_on_buffer(bh[i]);
|
||||
if (!buffer_uptodate(bh[i]))
|
||||
goto block_release;
|
||||
}
|
||||
|
||||
for (bytes = length; k < b; k++) {
|
||||
in = min(bytes, msblk->devblksize - offset);
|
||||
bytes -= in;
|
||||
while (in) {
|
||||
if (pg_offset == PAGE_CACHE_SIZE) {
|
||||
page++;
|
||||
pg_offset = 0;
|
||||
}
|
||||
avail = min_t(int, in, PAGE_CACHE_SIZE -
|
||||
pg_offset);
|
||||
memcpy(buffer[page] + pg_offset,
|
||||
bh[k]->b_data + offset, avail);
|
||||
in -= avail;
|
||||
pg_offset += avail;
|
||||
offset += avail;
|
||||
}
|
||||
offset = 0;
|
||||
put_bh(bh[k]);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(bh);
|
||||
return length;
|
||||
|
||||
release_mutex:
|
||||
mutex_unlock(&msblk->read_data_mutex);
|
||||
|
||||
block_release:
|
||||
for (; k < b; k++)
|
||||
put_bh(bh[k]);
|
||||
|
||||
read_failure:
|
||||
ERROR("sb_bread failed reading block 0x%llx\n", cur_index);
|
||||
kfree(bh);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* cache.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Blocks in Squashfs are compressed. To avoid repeatedly decompressing
|
||||
* recently accessed data Squashfs uses two small metadata and fragment caches.
|
||||
*
|
||||
* This file implements a generic cache implementation used for both caches,
|
||||
* plus functions layered ontop of the generic cache implementation to
|
||||
* access the metadata and fragment caches.
|
||||
*
|
||||
* To avoid out of memory and fragmentation isssues with vmalloc the cache
|
||||
* uses sequences of kmalloced PAGE_CACHE_SIZE buffers.
|
||||
*
|
||||
* It should be noted that the cache is not used for file datablocks, these
|
||||
* are decompressed and cached in the page-cache in the normal way. The
|
||||
* cache is only used to temporarily cache fragment and metadata blocks
|
||||
* which have been read as as a result of a metadata (i.e. inode or
|
||||
* directory) or fragment access. Because metadata and fragments are packed
|
||||
* together into blocks (to gain greater compression) the read of a particular
|
||||
* piece of metadata or fragment will retrieve other metadata/fragments which
|
||||
* have been packed with it, these because of locality-of-reference may be read
|
||||
* in the near future. Temporarily caching them ensures they are available for
|
||||
* near future access without requiring an additional read and decompress.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/zlib.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Look-up block in cache, and increment usage count. If not in cache, read
|
||||
* and decompress it from disk.
|
||||
*/
|
||||
struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
|
||||
struct squashfs_cache *cache, u64 block, int length)
|
||||
{
|
||||
int i, n;
|
||||
struct squashfs_cache_entry *entry;
|
||||
|
||||
spin_lock(&cache->lock);
|
||||
|
||||
while (1) {
|
||||
for (i = 0; i < cache->entries; i++)
|
||||
if (cache->entry[i].block == block)
|
||||
break;
|
||||
|
||||
if (i == cache->entries) {
|
||||
/*
|
||||
* Block not in cache, if all cache entries are used
|
||||
* go to sleep waiting for one to become available.
|
||||
*/
|
||||
if (cache->unused == 0) {
|
||||
cache->num_waiters++;
|
||||
spin_unlock(&cache->lock);
|
||||
wait_event(cache->wait_queue, cache->unused);
|
||||
spin_lock(&cache->lock);
|
||||
cache->num_waiters--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* At least one unused cache entry. A simple
|
||||
* round-robin strategy is used to choose the entry to
|
||||
* be evicted from the cache.
|
||||
*/
|
||||
i = cache->next_blk;
|
||||
for (n = 0; n < cache->entries; n++) {
|
||||
if (cache->entry[i].refcount == 0)
|
||||
break;
|
||||
i = (i + 1) % cache->entries;
|
||||
}
|
||||
|
||||
cache->next_blk = (i + 1) % cache->entries;
|
||||
entry = &cache->entry[i];
|
||||
|
||||
/*
|
||||
* Initialise choosen cache entry, and fill it in from
|
||||
* disk.
|
||||
*/
|
||||
cache->unused--;
|
||||
entry->block = block;
|
||||
entry->refcount = 1;
|
||||
entry->pending = 1;
|
||||
entry->num_waiters = 0;
|
||||
entry->error = 0;
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
entry->length = squashfs_read_data(sb, entry->data,
|
||||
block, length, &entry->next_index,
|
||||
cache->block_size);
|
||||
|
||||
spin_lock(&cache->lock);
|
||||
|
||||
if (entry->length < 0)
|
||||
entry->error = entry->length;
|
||||
|
||||
entry->pending = 0;
|
||||
|
||||
/*
|
||||
* While filling this entry one or more other processes
|
||||
* have looked it up in the cache, and have slept
|
||||
* waiting for it to become available.
|
||||
*/
|
||||
if (entry->num_waiters) {
|
||||
spin_unlock(&cache->lock);
|
||||
wake_up_all(&entry->wait_queue);
|
||||
} else
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Block already in cache. Increment refcount so it doesn't
|
||||
* get reused until we're finished with it, if it was
|
||||
* previously unused there's one less cache entry available
|
||||
* for reuse.
|
||||
*/
|
||||
entry = &cache->entry[i];
|
||||
if (entry->refcount == 0)
|
||||
cache->unused--;
|
||||
entry->refcount++;
|
||||
|
||||
/*
|
||||
* If the entry is currently being filled in by another process
|
||||
* go to sleep waiting for it to become available.
|
||||
*/
|
||||
if (entry->pending) {
|
||||
entry->num_waiters++;
|
||||
spin_unlock(&cache->lock);
|
||||
wait_event(entry->wait_queue, !entry->pending);
|
||||
} else
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE("Got %s %d, start block %lld, refcount %d, error %d\n",
|
||||
cache->name, i, entry->block, entry->refcount, entry->error);
|
||||
|
||||
if (entry->error)
|
||||
ERROR("Unable to read %s cache entry [%llx]\n", cache->name,
|
||||
block);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release cache entry, once usage count is zero it can be reused.
|
||||
*/
|
||||
void squashfs_cache_put(struct squashfs_cache_entry *entry)
|
||||
{
|
||||
struct squashfs_cache *cache = entry->cache;
|
||||
|
||||
spin_lock(&cache->lock);
|
||||
entry->refcount--;
|
||||
if (entry->refcount == 0) {
|
||||
cache->unused++;
|
||||
/*
|
||||
* If there's any processes waiting for a block to become
|
||||
* available, wake one up.
|
||||
*/
|
||||
if (cache->num_waiters) {
|
||||
spin_unlock(&cache->lock);
|
||||
wake_up(&cache->wait_queue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
spin_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete cache reclaiming all kmalloced buffers.
|
||||
*/
|
||||
void squashfs_cache_delete(struct squashfs_cache *cache)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (cache == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cache->entries; i++) {
|
||||
if (cache->entry[i].data) {
|
||||
for (j = 0; j < cache->pages; j++)
|
||||
kfree(cache->entry[i].data[j]);
|
||||
kfree(cache->entry[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(cache->entry);
|
||||
kfree(cache);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise cache allocating the specified number of entries, each of
|
||||
* size block_size. To avoid vmalloc fragmentation issues each entry
|
||||
* is allocated as a sequence of kmalloced PAGE_CACHE_SIZE buffers.
|
||||
*/
|
||||
struct squashfs_cache *squashfs_cache_init(char *name, int entries,
|
||||
int block_size)
|
||||
{
|
||||
int i, j;
|
||||
struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL);
|
||||
|
||||
if (cache == NULL) {
|
||||
ERROR("Failed to allocate %s cache\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL);
|
||||
if (cache->entry == NULL) {
|
||||
ERROR("Failed to allocate %s cache\n", name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cache->next_blk = 0;
|
||||
cache->unused = entries;
|
||||
cache->entries = entries;
|
||||
cache->block_size = block_size;
|
||||
cache->pages = block_size >> PAGE_CACHE_SHIFT;
|
||||
cache->name = name;
|
||||
cache->num_waiters = 0;
|
||||
spin_lock_init(&cache->lock);
|
||||
init_waitqueue_head(&cache->wait_queue);
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
struct squashfs_cache_entry *entry = &cache->entry[i];
|
||||
|
||||
init_waitqueue_head(&cache->entry[i].wait_queue);
|
||||
entry->cache = cache;
|
||||
entry->block = SQUASHFS_INVALID_BLK;
|
||||
entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL);
|
||||
if (entry->data == NULL) {
|
||||
ERROR("Failed to allocate %s cache entry\n", name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (j = 0; j < cache->pages; j++) {
|
||||
entry->data[j] = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
|
||||
if (entry->data[j] == NULL) {
|
||||
ERROR("Failed to allocate %s buffer\n", name);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
|
||||
cleanup:
|
||||
squashfs_cache_delete(cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copy upto length bytes from cache entry to buffer starting at offset bytes
|
||||
* into the cache entry. If there's not length bytes then copy the number of
|
||||
* bytes available. In all cases return the number of bytes copied.
|
||||
*/
|
||||
int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry,
|
||||
int offset, int length)
|
||||
{
|
||||
int remaining = length;
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
else if (buffer == NULL)
|
||||
return min(length, entry->length - offset);
|
||||
|
||||
while (offset < entry->length) {
|
||||
void *buff = entry->data[offset / PAGE_CACHE_SIZE]
|
||||
+ (offset % PAGE_CACHE_SIZE);
|
||||
int bytes = min_t(int, entry->length - offset,
|
||||
PAGE_CACHE_SIZE - (offset % PAGE_CACHE_SIZE));
|
||||
|
||||
if (bytes >= remaining) {
|
||||
memcpy(buffer, buff, remaining);
|
||||
remaining = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buffer, buff, bytes);
|
||||
buffer += bytes;
|
||||
remaining -= bytes;
|
||||
offset += bytes;
|
||||
}
|
||||
|
||||
return length - remaining;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read length bytes from metadata position <block, offset> (block is the
|
||||
* start of the compressed block on disk, and offset is the offset into
|
||||
* the block once decompressed). Data is packed into consecutive blocks,
|
||||
* and length bytes may require reading more than one block.
|
||||
*/
|
||||
int squashfs_read_metadata(struct super_block *sb, void *buffer,
|
||||
u64 *block, int *offset, int length)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int bytes, copied = length;
|
||||
struct squashfs_cache_entry *entry;
|
||||
|
||||
TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
|
||||
|
||||
while (length) {
|
||||
entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
|
||||
if (entry->error)
|
||||
return entry->error;
|
||||
else if (*offset >= entry->length)
|
||||
return -EIO;
|
||||
|
||||
bytes = squashfs_copy_data(buffer, entry, *offset, length);
|
||||
if (buffer)
|
||||
buffer += bytes;
|
||||
length -= bytes;
|
||||
*offset += bytes;
|
||||
|
||||
if (*offset == entry->length) {
|
||||
*block = entry->next_index;
|
||||
*offset = 0;
|
||||
}
|
||||
|
||||
squashfs_cache_put(entry);
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Look-up in the fragmment cache the fragment located at <start_block> in the
|
||||
* filesystem. If necessary read and decompress it from disk.
|
||||
*/
|
||||
struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *sb,
|
||||
u64 start_block, int length)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
|
||||
return squashfs_cache_get(sb, msblk->fragment_cache, start_block,
|
||||
length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read and decompress the datablock located at <start_block> in the
|
||||
* filesystem. The cache is used here to avoid duplicating locking and
|
||||
* read/decompress code.
|
||||
*/
|
||||
struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb,
|
||||
u64 start_block, int length)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
|
||||
return squashfs_cache_get(sb, msblk->read_page, start_block, length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read a filesystem table (uncompressed sequence of bytes) from disk
|
||||
*/
|
||||
int squashfs_read_table(struct super_block *sb, void *buffer, u64 block,
|
||||
int length)
|
||||
{
|
||||
int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
int i, res;
|
||||
void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE)
|
||||
data[i] = buffer;
|
||||
res = squashfs_read_data(sb, data, block, length |
|
||||
SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length);
|
||||
kfree(data);
|
||||
return res;
|
||||
}
|
||||
235
SQUASHFS/squashfs-tools-4.4/kernel/kernel-2.6/fs/squashfs/dir.c
Normal file
235
SQUASHFS/squashfs-tools-4.4/kernel/kernel-2.6/fs/squashfs/dir.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* dir.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to read directories from disk.
|
||||
*
|
||||
* See namei.c for a description of directory organisation on disk.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
static const unsigned char squashfs_filetype_table[] = {
|
||||
DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
|
||||
};
|
||||
|
||||
/*
|
||||
* Lookup offset (f_pos) in the directory index, returning the
|
||||
* metadata block containing it.
|
||||
*
|
||||
* If we get an error reading the index then return the part of the index
|
||||
* (if any) we have managed to read - the index isn't essential, just
|
||||
* quicker.
|
||||
*/
|
||||
static int get_dir_index_using_offset(struct super_block *sb,
|
||||
u64 *next_block, int *next_offset, u64 index_start, int index_offset,
|
||||
int i_count, u64 f_pos)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int err, i, index, length = 0;
|
||||
struct squashfs_dir_index dir_index;
|
||||
|
||||
TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
|
||||
i_count, f_pos);
|
||||
|
||||
/*
|
||||
* Translate from external f_pos to the internal f_pos. This
|
||||
* is offset by 3 because we invent "." and ".." entries which are
|
||||
* not actually stored in the directory.
|
||||
*/
|
||||
if (f_pos < 3)
|
||||
return f_pos;
|
||||
f_pos -= 3;
|
||||
|
||||
for (i = 0; i < i_count; i++) {
|
||||
err = squashfs_read_metadata(sb, &dir_index, &index_start,
|
||||
&index_offset, sizeof(dir_index));
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
index = le32_to_cpu(dir_index.index);
|
||||
if (index > f_pos)
|
||||
/*
|
||||
* Found the index we're looking for.
|
||||
*/
|
||||
break;
|
||||
|
||||
err = squashfs_read_metadata(sb, NULL, &index_start,
|
||||
&index_offset, le32_to_cpu(dir_index.size) + 1);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
length = index;
|
||||
*next_block = le32_to_cpu(dir_index.start_block) +
|
||||
msblk->directory_table;
|
||||
}
|
||||
|
||||
*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
|
||||
|
||||
/*
|
||||
* Translate back from internal f_pos to external f_pos.
|
||||
*/
|
||||
return length + 3;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
u64 block = squashfs_i(inode)->start + msblk->directory_table;
|
||||
int offset = squashfs_i(inode)->offset, length = 0, dir_count, size,
|
||||
type, err;
|
||||
unsigned int inode_number;
|
||||
struct squashfs_dir_header dirh;
|
||||
struct squashfs_dir_entry *dire;
|
||||
|
||||
TRACE("Entered squashfs_readdir [%llx:%x]\n", block, offset);
|
||||
|
||||
dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
|
||||
if (dire == NULL) {
|
||||
ERROR("Failed to allocate squashfs_dir_entry\n");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return "." and ".." entries as the first two filenames in the
|
||||
* directory. To maximise compression these two entries are not
|
||||
* stored in the directory, and so we invent them here.
|
||||
*
|
||||
* It also means that the external f_pos is offset by 3 from the
|
||||
* on-disk directory f_pos.
|
||||
*/
|
||||
while (file->f_pos < 3) {
|
||||
char *name;
|
||||
int i_ino;
|
||||
|
||||
if (file->f_pos == 0) {
|
||||
name = ".";
|
||||
size = 1;
|
||||
i_ino = inode->i_ino;
|
||||
} else {
|
||||
name = "..";
|
||||
size = 2;
|
||||
i_ino = squashfs_i(inode)->parent;
|
||||
}
|
||||
|
||||
TRACE("Calling filldir(%p, %s, %d, %lld, %d, %d)\n",
|
||||
dirent, name, size, file->f_pos, i_ino,
|
||||
squashfs_filetype_table[1]);
|
||||
|
||||
if (filldir(dirent, name, size, file->f_pos, i_ino,
|
||||
squashfs_filetype_table[1]) < 0) {
|
||||
TRACE("Filldir returned less than 0\n");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
file->f_pos += size;
|
||||
}
|
||||
|
||||
length = get_dir_index_using_offset(inode->i_sb, &block, &offset,
|
||||
squashfs_i(inode)->dir_idx_start,
|
||||
squashfs_i(inode)->dir_idx_offset,
|
||||
squashfs_i(inode)->dir_idx_cnt,
|
||||
file->f_pos);
|
||||
|
||||
while (length < i_size_read(inode)) {
|
||||
/*
|
||||
* Read directory header
|
||||
*/
|
||||
err = squashfs_read_metadata(inode->i_sb, &dirh, &block,
|
||||
&offset, sizeof(dirh));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(dirh);
|
||||
|
||||
dir_count = le32_to_cpu(dirh.count) + 1;
|
||||
while (dir_count--) {
|
||||
/*
|
||||
* Read directory entry.
|
||||
*/
|
||||
err = squashfs_read_metadata(inode->i_sb, dire, &block,
|
||||
&offset, sizeof(*dire));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
size = le16_to_cpu(dire->size) + 1;
|
||||
|
||||
err = squashfs_read_metadata(inode->i_sb, dire->name,
|
||||
&block, &offset, size);
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
length += sizeof(*dire) + size;
|
||||
|
||||
if (file->f_pos >= length)
|
||||
continue;
|
||||
|
||||
dire->name[size] = '\0';
|
||||
inode_number = le32_to_cpu(dirh.inode_number) +
|
||||
((short) le16_to_cpu(dire->inode_number));
|
||||
type = le16_to_cpu(dire->type);
|
||||
|
||||
TRACE("Calling filldir(%p, %s, %d, %lld, %x:%x, %d, %d)"
|
||||
"\n", dirent, dire->name, size,
|
||||
file->f_pos,
|
||||
le32_to_cpu(dirh.start_block),
|
||||
le16_to_cpu(dire->offset),
|
||||
inode_number,
|
||||
squashfs_filetype_table[type]);
|
||||
|
||||
if (filldir(dirent, dire->name, size, file->f_pos,
|
||||
inode_number,
|
||||
squashfs_filetype_table[type]) < 0) {
|
||||
TRACE("Filldir returned less than 0\n");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
file->f_pos = length;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
kfree(dire);
|
||||
return 0;
|
||||
|
||||
failed_read:
|
||||
ERROR("Unable to read directory block [%llx:%x]\n", block, offset);
|
||||
kfree(dire);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const struct file_operations squashfs_dir_ops = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = squashfs_readdir
|
||||
};
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* export.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to make Squashfs filesystems exportable (NFS etc.)
|
||||
*
|
||||
* The export code uses an inode lookup table to map inode numbers passed in
|
||||
* filehandles to an inode location on disk. This table is stored compressed
|
||||
* into metadata blocks. A second index table is used to locate these. This
|
||||
* second index table for speed of access (and because it is small) is read at
|
||||
* mount time and cached in memory.
|
||||
*
|
||||
* The inode lookup table is used only by the export code, inode disk
|
||||
* locations are directly encoded in directories, enabling direct access
|
||||
* without an intermediate lookup for all operations except the export ops.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Look-up inode number (ino) in table, returning the inode location.
|
||||
*/
|
||||
static long long squashfs_inode_lookup(struct super_block *sb, int ino_num)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1);
|
||||
int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1);
|
||||
u64 start = le64_to_cpu(msblk->inode_lookup_table[blk]);
|
||||
__le64 ino;
|
||||
int err;
|
||||
|
||||
TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num);
|
||||
|
||||
err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
TRACE("squashfs_inode_lookup, inode = 0x%llx\n",
|
||||
(u64) le64_to_cpu(ino));
|
||||
|
||||
return le64_to_cpu(ino);
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *squashfs_export_iget(struct super_block *sb,
|
||||
unsigned int ino_num)
|
||||
{
|
||||
long long ino;
|
||||
struct dentry *dentry = ERR_PTR(-ENOENT);
|
||||
|
||||
TRACE("Entered squashfs_export_iget\n");
|
||||
|
||||
ino = squashfs_inode_lookup(sb, ino_num);
|
||||
if (ino >= 0)
|
||||
dentry = d_obtain_alias(squashfs_iget(sb, ino, ino_num));
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *squashfs_fh_to_dentry(struct super_block *sb,
|
||||
struct fid *fid, int fh_len, int fh_type)
|
||||
{
|
||||
if ((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT)
|
||||
|| fh_len < 2)
|
||||
return NULL;
|
||||
|
||||
return squashfs_export_iget(sb, fid->i32.ino);
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *squashfs_fh_to_parent(struct super_block *sb,
|
||||
struct fid *fid, int fh_len, int fh_type)
|
||||
{
|
||||
if (fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4)
|
||||
return NULL;
|
||||
|
||||
return squashfs_export_iget(sb, fid->i32.parent_ino);
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *squashfs_get_parent(struct dentry *child)
|
||||
{
|
||||
struct inode *inode = child->d_inode;
|
||||
unsigned int parent_ino = squashfs_i(inode)->parent;
|
||||
|
||||
return squashfs_export_iget(inode->i_sb, parent_ino);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read uncompressed inode lookup table indexes off disk into memory
|
||||
*/
|
||||
__le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
|
||||
u64 lookup_table_start, unsigned int inodes)
|
||||
{
|
||||
unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
|
||||
__le64 *inode_lookup_table;
|
||||
int err;
|
||||
|
||||
TRACE("In read_inode_lookup_table, length %d\n", length);
|
||||
|
||||
/* Allocate inode lookup table indexes */
|
||||
inode_lookup_table = kmalloc(length, GFP_KERNEL);
|
||||
if (inode_lookup_table == NULL) {
|
||||
ERROR("Failed to allocate inode lookup table\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start,
|
||||
length);
|
||||
if (err < 0) {
|
||||
ERROR("unable to read inode lookup table\n");
|
||||
kfree(inode_lookup_table);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return inode_lookup_table;
|
||||
}
|
||||
|
||||
|
||||
const struct export_operations squashfs_export_ops = {
|
||||
.fh_to_dentry = squashfs_fh_to_dentry,
|
||||
.fh_to_parent = squashfs_fh_to_parent,
|
||||
.get_parent = squashfs_get_parent
|
||||
};
|
||||
502
SQUASHFS/squashfs-tools-4.4/kernel/kernel-2.6/fs/squashfs/file.c
Normal file
502
SQUASHFS/squashfs-tools-4.4/kernel/kernel-2.6/fs/squashfs/file.c
Normal file
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* file.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains code for handling regular files. A regular file
|
||||
* consists of a sequence of contiguous compressed blocks, and/or a
|
||||
* compressed fragment block (tail-end packed block). The compressed size
|
||||
* of each datablock is stored in a block list contained within the
|
||||
* file inode (itself stored in one or more compressed metadata blocks).
|
||||
*
|
||||
* To speed up access to datablocks when reading 'large' files (256 Mbytes or
|
||||
* larger), the code implements an index cache that caches the mapping from
|
||||
* block index to datablock location on disk.
|
||||
*
|
||||
* The index cache allows Squashfs to handle large files (up to 1.75 TiB) while
|
||||
* retaining a simple and space-efficient block list on disk. The cache
|
||||
* is split into slots, caching up to eight 224 GiB files (128 KiB blocks).
|
||||
* Larger files use multiple slots, with 1.75 TiB files using all 8 slots.
|
||||
* The index cache is designed to be memory efficient, and by default uses
|
||||
* 16 KiB.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Locate cache slot in range [offset, index] for specified inode. If
|
||||
* there's more than one return the slot closest to index.
|
||||
*/
|
||||
static struct meta_index *locate_meta_index(struct inode *inode, int offset,
|
||||
int index)
|
||||
{
|
||||
struct meta_index *meta = NULL;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
int i;
|
||||
|
||||
mutex_lock(&msblk->meta_index_mutex);
|
||||
|
||||
TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
|
||||
|
||||
if (msblk->meta_index == NULL)
|
||||
goto not_allocated;
|
||||
|
||||
for (i = 0; i < SQUASHFS_META_SLOTS; i++) {
|
||||
if (msblk->meta_index[i].inode_number == inode->i_ino &&
|
||||
msblk->meta_index[i].offset >= offset &&
|
||||
msblk->meta_index[i].offset <= index &&
|
||||
msblk->meta_index[i].locked == 0) {
|
||||
TRACE("locate_meta_index: entry %d, offset %d\n", i,
|
||||
msblk->meta_index[i].offset);
|
||||
meta = &msblk->meta_index[i];
|
||||
offset = meta->offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (meta)
|
||||
meta->locked = 1;
|
||||
|
||||
not_allocated:
|
||||
mutex_unlock(&msblk->meta_index_mutex);
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find and initialise an empty cache slot for index offset.
|
||||
*/
|
||||
static struct meta_index *empty_meta_index(struct inode *inode, int offset,
|
||||
int skip)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
struct meta_index *meta = NULL;
|
||||
int i;
|
||||
|
||||
mutex_lock(&msblk->meta_index_mutex);
|
||||
|
||||
TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
|
||||
|
||||
if (msblk->meta_index == NULL) {
|
||||
/*
|
||||
* First time cache index has been used, allocate and
|
||||
* initialise. The cache index could be allocated at
|
||||
* mount time but doing it here means it is allocated only
|
||||
* if a 'large' file is read.
|
||||
*/
|
||||
msblk->meta_index = kcalloc(SQUASHFS_META_SLOTS,
|
||||
sizeof(*(msblk->meta_index)), GFP_KERNEL);
|
||||
if (msblk->meta_index == NULL) {
|
||||
ERROR("Failed to allocate meta_index\n");
|
||||
goto failed;
|
||||
}
|
||||
for (i = 0; i < SQUASHFS_META_SLOTS; i++) {
|
||||
msblk->meta_index[i].inode_number = 0;
|
||||
msblk->meta_index[i].locked = 0;
|
||||
}
|
||||
msblk->next_meta_index = 0;
|
||||
}
|
||||
|
||||
for (i = SQUASHFS_META_SLOTS; i &&
|
||||
msblk->meta_index[msblk->next_meta_index].locked; i--)
|
||||
msblk->next_meta_index = (msblk->next_meta_index + 1) %
|
||||
SQUASHFS_META_SLOTS;
|
||||
|
||||
if (i == 0) {
|
||||
TRACE("empty_meta_index: failed!\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
TRACE("empty_meta_index: returned meta entry %d, %p\n",
|
||||
msblk->next_meta_index,
|
||||
&msblk->meta_index[msblk->next_meta_index]);
|
||||
|
||||
meta = &msblk->meta_index[msblk->next_meta_index];
|
||||
msblk->next_meta_index = (msblk->next_meta_index + 1) %
|
||||
SQUASHFS_META_SLOTS;
|
||||
|
||||
meta->inode_number = inode->i_ino;
|
||||
meta->offset = offset;
|
||||
meta->skip = skip;
|
||||
meta->entries = 0;
|
||||
meta->locked = 1;
|
||||
|
||||
failed:
|
||||
mutex_unlock(&msblk->meta_index_mutex);
|
||||
return meta;
|
||||
}
|
||||
|
||||
|
||||
static void release_meta_index(struct inode *inode, struct meta_index *meta)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
mutex_lock(&msblk->meta_index_mutex);
|
||||
meta->locked = 0;
|
||||
mutex_unlock(&msblk->meta_index_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the next n blocks from the block list, starting from
|
||||
* metadata block <start_block, offset>.
|
||||
*/
|
||||
static long long read_indexes(struct super_block *sb, int n,
|
||||
u64 *start_block, int *offset)
|
||||
{
|
||||
int err, i;
|
||||
long long block = 0;
|
||||
__le32 *blist = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
|
||||
|
||||
if (blist == NULL) {
|
||||
ERROR("read_indexes: Failed to allocate block_list\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (n) {
|
||||
int blocks = min_t(int, n, PAGE_CACHE_SIZE >> 2);
|
||||
|
||||
err = squashfs_read_metadata(sb, blist, start_block,
|
||||
offset, blocks << 2);
|
||||
if (err < 0) {
|
||||
ERROR("read_indexes: reading block [%llx:%x]\n",
|
||||
*start_block, *offset);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
for (i = 0; i < blocks; i++) {
|
||||
int size = le32_to_cpu(blist[i]);
|
||||
block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
|
||||
}
|
||||
n -= blocks;
|
||||
}
|
||||
|
||||
kfree(blist);
|
||||
return block;
|
||||
|
||||
failure:
|
||||
kfree(blist);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Each cache index slot has SQUASHFS_META_ENTRIES, each of which
|
||||
* can cache one index -> datablock/blocklist-block mapping. We wish
|
||||
* to distribute these over the length of the file, entry[0] maps index x,
|
||||
* entry[1] maps index x + skip, entry[2] maps index x + 2 * skip, and so on.
|
||||
* The larger the file, the greater the skip factor. The skip factor is
|
||||
* limited to the size of the metadata cache (SQUASHFS_CACHED_BLKS) to ensure
|
||||
* the number of metadata blocks that need to be read fits into the cache.
|
||||
* If the skip factor is limited in this way then the file will use multiple
|
||||
* slots.
|
||||
*/
|
||||
static inline int calculate_skip(int blocks)
|
||||
{
|
||||
int skip = blocks / ((SQUASHFS_META_ENTRIES + 1)
|
||||
* SQUASHFS_META_INDEXES);
|
||||
return min(SQUASHFS_CACHED_BLKS - 1, skip + 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search and grow the index cache for the specified inode, returning the
|
||||
* on-disk locations of the datablock and block list metadata block
|
||||
* <index_block, index_offset> for index (scaled to nearest cache index).
|
||||
*/
|
||||
static int fill_meta_index(struct inode *inode, int index,
|
||||
u64 *index_block, int *index_offset, u64 *data_block)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
int skip = calculate_skip(i_size_read(inode) >> msblk->block_log);
|
||||
int offset = 0;
|
||||
struct meta_index *meta;
|
||||
struct meta_entry *meta_entry;
|
||||
u64 cur_index_block = squashfs_i(inode)->block_list_start;
|
||||
int cur_offset = squashfs_i(inode)->offset;
|
||||
u64 cur_data_block = squashfs_i(inode)->start;
|
||||
int err, i;
|
||||
|
||||
/*
|
||||
* Scale index to cache index (cache slot entry)
|
||||
*/
|
||||
index /= SQUASHFS_META_INDEXES * skip;
|
||||
|
||||
while (offset < index) {
|
||||
meta = locate_meta_index(inode, offset + 1, index);
|
||||
|
||||
if (meta == NULL) {
|
||||
meta = empty_meta_index(inode, offset + 1, skip);
|
||||
if (meta == NULL)
|
||||
goto all_done;
|
||||
} else {
|
||||
offset = index < meta->offset + meta->entries ? index :
|
||||
meta->offset + meta->entries - 1;
|
||||
meta_entry = &meta->meta_entry[offset - meta->offset];
|
||||
cur_index_block = meta_entry->index_block +
|
||||
msblk->inode_table;
|
||||
cur_offset = meta_entry->offset;
|
||||
cur_data_block = meta_entry->data_block;
|
||||
TRACE("get_meta_index: offset %d, meta->offset %d, "
|
||||
"meta->entries %d\n", offset, meta->offset,
|
||||
meta->entries);
|
||||
TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
|
||||
" data_block 0x%llx\n", cur_index_block,
|
||||
cur_offset, cur_data_block);
|
||||
}
|
||||
|
||||
/*
|
||||
* If necessary grow cache slot by reading block list. Cache
|
||||
* slot is extended up to index or to the end of the slot, in
|
||||
* which case further slots will be used.
|
||||
*/
|
||||
for (i = meta->offset + meta->entries; i <= index &&
|
||||
i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
|
||||
int blocks = skip * SQUASHFS_META_INDEXES;
|
||||
long long res = read_indexes(inode->i_sb, blocks,
|
||||
&cur_index_block, &cur_offset);
|
||||
|
||||
if (res < 0) {
|
||||
if (meta->entries == 0)
|
||||
/*
|
||||
* Don't leave an empty slot on read
|
||||
* error allocated to this inode...
|
||||
*/
|
||||
meta->inode_number = 0;
|
||||
err = res;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cur_data_block += res;
|
||||
meta_entry = &meta->meta_entry[i - meta->offset];
|
||||
meta_entry->index_block = cur_index_block -
|
||||
msblk->inode_table;
|
||||
meta_entry->offset = cur_offset;
|
||||
meta_entry->data_block = cur_data_block;
|
||||
meta->entries++;
|
||||
offset++;
|
||||
}
|
||||
|
||||
TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
|
||||
meta->offset, meta->entries);
|
||||
|
||||
release_meta_index(inode, meta);
|
||||
}
|
||||
|
||||
all_done:
|
||||
*index_block = cur_index_block;
|
||||
*index_offset = cur_offset;
|
||||
*data_block = cur_data_block;
|
||||
|
||||
/*
|
||||
* Scale cache index (cache slot entry) to index
|
||||
*/
|
||||
return offset * SQUASHFS_META_INDEXES * skip;
|
||||
|
||||
failed:
|
||||
release_meta_index(inode, meta);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the on-disk location and compressed size of the datablock
|
||||
* specified by index. Fill_meta_index() does most of the work.
|
||||
*/
|
||||
static int read_blocklist(struct inode *inode, int index, u64 *block)
|
||||
{
|
||||
u64 start;
|
||||
long long blks;
|
||||
int offset;
|
||||
__le32 size;
|
||||
int res = fill_meta_index(inode, index, &start, &offset, block);
|
||||
|
||||
TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset"
|
||||
" 0x%x, block 0x%llx\n", res, index, start, offset,
|
||||
*block);
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
/*
|
||||
* res contains the index of the mapping returned by fill_meta_index(),
|
||||
* this will likely be less than the desired index (because the
|
||||
* meta_index cache works at a higher granularity). Read any
|
||||
* extra block indexes needed.
|
||||
*/
|
||||
if (res < index) {
|
||||
blks = read_indexes(inode->i_sb, index - res, &start, &offset);
|
||||
if (blks < 0)
|
||||
return (int) blks;
|
||||
*block += blks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read length of block specified by index.
|
||||
*/
|
||||
res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset,
|
||||
sizeof(size));
|
||||
if (res < 0)
|
||||
return res;
|
||||
return le32_to_cpu(size);
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
|
||||
int bytes, i, offset = 0, sparse = 0;
|
||||
struct squashfs_cache_entry *buffer = NULL;
|
||||
void *pageaddr;
|
||||
|
||||
int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1;
|
||||
int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT);
|
||||
int start_index = page->index & ~mask;
|
||||
int end_index = start_index | mask;
|
||||
int file_end = i_size_read(inode) >> msblk->block_log;
|
||||
|
||||
TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
|
||||
page->index, squashfs_i(inode)->start);
|
||||
|
||||
if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
|
||||
PAGE_CACHE_SHIFT))
|
||||
goto out;
|
||||
|
||||
if (index < file_end || squashfs_i(inode)->fragment_block ==
|
||||
SQUASHFS_INVALID_BLK) {
|
||||
/*
|
||||
* Reading a datablock from disk. Need to read block list
|
||||
* to get location and block size.
|
||||
*/
|
||||
u64 block = 0;
|
||||
int bsize = read_blocklist(inode, index, &block);
|
||||
if (bsize < 0)
|
||||
goto error_out;
|
||||
|
||||
if (bsize == 0) { /* hole */
|
||||
bytes = index == file_end ?
|
||||
(i_size_read(inode) & (msblk->block_size - 1)) :
|
||||
msblk->block_size;
|
||||
sparse = 1;
|
||||
} else {
|
||||
/*
|
||||
* Read and decompress datablock.
|
||||
*/
|
||||
buffer = squashfs_get_datablock(inode->i_sb,
|
||||
block, bsize);
|
||||
if (buffer->error) {
|
||||
ERROR("Unable to read page, block %llx, size %x"
|
||||
"\n", block, bsize);
|
||||
squashfs_cache_put(buffer);
|
||||
goto error_out;
|
||||
}
|
||||
bytes = buffer->length;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Datablock is stored inside a fragment (tail-end packed
|
||||
* block).
|
||||
*/
|
||||
buffer = squashfs_get_fragment(inode->i_sb,
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
|
||||
if (buffer->error) {
|
||||
ERROR("Unable to read page, block %llx, size %x\n",
|
||||
squashfs_i(inode)->fragment_block,
|
||||
squashfs_i(inode)->fragment_size);
|
||||
squashfs_cache_put(buffer);
|
||||
goto error_out;
|
||||
}
|
||||
bytes = i_size_read(inode) & (msblk->block_size - 1);
|
||||
offset = squashfs_i(inode)->fragment_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop copying datablock into pages. As the datablock likely covers
|
||||
* many PAGE_CACHE_SIZE pages (default block size is 128 KiB) explicitly
|
||||
* grab the pages from the page cache, except for the page that we've
|
||||
* been called to fill.
|
||||
*/
|
||||
for (i = start_index; i <= end_index && bytes > 0; i++,
|
||||
bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) {
|
||||
struct page *push_page;
|
||||
int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE);
|
||||
|
||||
TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
|
||||
|
||||
push_page = (i == page->index) ? page :
|
||||
grab_cache_page_nowait(page->mapping, i);
|
||||
|
||||
if (!push_page)
|
||||
continue;
|
||||
|
||||
if (PageUptodate(push_page))
|
||||
goto skip_page;
|
||||
|
||||
pageaddr = kmap_atomic(push_page, KM_USER0);
|
||||
squashfs_copy_data(pageaddr, buffer, offset, avail);
|
||||
memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
|
||||
kunmap_atomic(pageaddr, KM_USER0);
|
||||
flush_dcache_page(push_page);
|
||||
SetPageUptodate(push_page);
|
||||
skip_page:
|
||||
unlock_page(push_page);
|
||||
if (i != page->index)
|
||||
page_cache_release(push_page);
|
||||
}
|
||||
|
||||
if (!sparse)
|
||||
squashfs_cache_put(buffer);
|
||||
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
SetPageError(page);
|
||||
out:
|
||||
pageaddr = kmap_atomic(page, KM_USER0);
|
||||
memset(pageaddr, 0, PAGE_CACHE_SIZE);
|
||||
kunmap_atomic(pageaddr, KM_USER0);
|
||||
flush_dcache_page(page);
|
||||
if (!PageError(page))
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const struct address_space_operations squashfs_aops = {
|
||||
.readpage = squashfs_readpage
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* fragment.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to handle compressed fragments (tail-end packed
|
||||
* datablocks).
|
||||
*
|
||||
* Regular files contain a fragment index which is mapped to a fragment
|
||||
* location on disk and compressed size using a fragment lookup table.
|
||||
* Like everything in Squashfs this fragment lookup table is itself stored
|
||||
* compressed into metadata blocks. A second index table is used to locate
|
||||
* these. This second index table for speed of access (and because it
|
||||
* is small) is read at mount time and cached in memory.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Look-up fragment using the fragment index table. Return the on disk
|
||||
* location of the fragment and its compressed size
|
||||
*/
|
||||
int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
|
||||
u64 *fragment_block)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int block = SQUASHFS_FRAGMENT_INDEX(fragment);
|
||||
int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
|
||||
u64 start_block = le64_to_cpu(msblk->fragment_index[block]);
|
||||
struct squashfs_fragment_entry fragment_entry;
|
||||
int size;
|
||||
|
||||
size = squashfs_read_metadata(sb, &fragment_entry, &start_block,
|
||||
&offset, sizeof(fragment_entry));
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
*fragment_block = le64_to_cpu(fragment_entry.start_block);
|
||||
size = le32_to_cpu(fragment_entry.size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the uncompressed fragment lookup table indexes off disk into memory
|
||||
*/
|
||||
__le64 *squashfs_read_fragment_index_table(struct super_block *sb,
|
||||
u64 fragment_table_start, unsigned int fragments)
|
||||
{
|
||||
unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments);
|
||||
__le64 *fragment_index;
|
||||
int err;
|
||||
|
||||
/* Allocate fragment lookup table indexes */
|
||||
fragment_index = kmalloc(length, GFP_KERNEL);
|
||||
if (fragment_index == NULL) {
|
||||
ERROR("Failed to allocate fragment index table\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = squashfs_read_table(sb, fragment_index, fragment_table_start,
|
||||
length);
|
||||
if (err < 0) {
|
||||
ERROR("unable to read fragment index table\n");
|
||||
kfree(fragment_index);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return fragment_index;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* id.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to handle uids and gids.
|
||||
*
|
||||
* For space efficiency regular files store uid and gid indexes, which are
|
||||
* converted to 32-bit uids/gids using an id look up table. This table is
|
||||
* stored compressed into metadata blocks. A second index table is used to
|
||||
* locate these. This second index table for speed of access (and because it
|
||||
* is small) is read at mount time and cached in memory.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Map uid/gid index into real 32-bit uid/gid using the id look up table
|
||||
*/
|
||||
int squashfs_get_id(struct super_block *sb, unsigned int index,
|
||||
unsigned int *id)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int block = SQUASHFS_ID_BLOCK(index);
|
||||
int offset = SQUASHFS_ID_BLOCK_OFFSET(index);
|
||||
u64 start_block = le64_to_cpu(msblk->id_table[block]);
|
||||
__le32 disk_id;
|
||||
int err;
|
||||
|
||||
err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset,
|
||||
sizeof(disk_id));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*id = le32_to_cpu(disk_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read uncompressed id lookup table indexes from disk into memory
|
||||
*/
|
||||
__le64 *squashfs_read_id_index_table(struct super_block *sb,
|
||||
u64 id_table_start, unsigned short no_ids)
|
||||
{
|
||||
unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids);
|
||||
__le64 *id_table;
|
||||
int err;
|
||||
|
||||
TRACE("In read_id_index_table, length %d\n", length);
|
||||
|
||||
/* Allocate id lookup table indexes */
|
||||
id_table = kmalloc(length, GFP_KERNEL);
|
||||
if (id_table == NULL) {
|
||||
ERROR("Failed to allocate id index table\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = squashfs_read_table(sb, id_table, id_table_start, length);
|
||||
if (err < 0) {
|
||||
ERROR("unable to read id index table\n");
|
||||
kfree(id_table);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return id_table;
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* inode.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to create and read inodes from disk.
|
||||
*
|
||||
* Inodes in Squashfs are identified by a 48-bit inode which encodes the
|
||||
* location of the compressed metadata block containing the inode, and the byte
|
||||
* offset into that block where the inode is placed (<block, offset>).
|
||||
*
|
||||
* To maximise compression there are different inodes for each file type
|
||||
* (regular file, directory, device, etc.), the inode contents and length
|
||||
* varying with the type.
|
||||
*
|
||||
* To further maximise compression, two types of regular file inode and
|
||||
* directory inode are defined: inodes optimised for frequently occurring
|
||||
* regular files and directories, and extended types where extra
|
||||
* information has to be stored.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Initialise VFS inode with the base inode information common to all
|
||||
* Squashfs inode types. Sqsh_ino contains the unswapped base inode
|
||||
* off disk.
|
||||
*/
|
||||
static int squashfs_new_inode(struct super_block *sb, struct inode *inode,
|
||||
struct squashfs_base_inode *sqsh_ino)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->uid), &inode->i_uid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &inode->i_gid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode->i_ino = le32_to_cpu(sqsh_ino->inode_number);
|
||||
inode->i_mtime.tv_sec = le32_to_cpu(sqsh_ino->mtime);
|
||||
inode->i_atime.tv_sec = inode->i_mtime.tv_sec;
|
||||
inode->i_ctime.tv_sec = inode->i_mtime.tv_sec;
|
||||
inode->i_mode = le16_to_cpu(sqsh_ino->mode);
|
||||
inode->i_size = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
struct inode *squashfs_iget(struct super_block *sb, long long ino,
|
||||
unsigned int ino_number)
|
||||
{
|
||||
struct inode *inode = iget_locked(sb, ino_number);
|
||||
int err;
|
||||
|
||||
TRACE("Entered squashfs_iget\n");
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!(inode->i_state & I_NEW))
|
||||
return inode;
|
||||
|
||||
err = squashfs_read_inode(inode, ino);
|
||||
if (err) {
|
||||
iget_failed(inode);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
unlock_new_inode(inode);
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise VFS inode by reading inode from inode table (compressed
|
||||
* metadata). The format and amount of data read depends on type.
|
||||
*/
|
||||
int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
|
||||
int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
|
||||
union squashfs_inode squashfs_ino;
|
||||
struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
|
||||
|
||||
TRACE("Entered squashfs_read_inode\n");
|
||||
|
||||
/*
|
||||
* Read inode base common to all inode types.
|
||||
*/
|
||||
err = squashfs_read_metadata(sb, sqshb_ino, &block,
|
||||
&offset, sizeof(*sqshb_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
err = squashfs_new_inode(sb, inode, sqshb_ino);
|
||||
if (err)
|
||||
goto failed_read;
|
||||
|
||||
block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
|
||||
offset = SQUASHFS_INODE_OFFSET(ino);
|
||||
|
||||
type = le16_to_cpu(sqshb_ino->inode_type);
|
||||
switch (type) {
|
||||
case SQUASHFS_REG_TYPE: {
|
||||
unsigned int frag_offset, frag_size, frag;
|
||||
u64 frag_blk;
|
||||
struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
frag = le32_to_cpu(sqsh_ino->fragment);
|
||||
if (frag != SQUASHFS_INVALID_FRAG) {
|
||||
frag_offset = le32_to_cpu(sqsh_ino->offset);
|
||||
frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
|
||||
if (frag_size < 0) {
|
||||
err = frag_size;
|
||||
goto failed_read;
|
||||
}
|
||||
} else {
|
||||
frag_blk = SQUASHFS_INVALID_BLK;
|
||||
frag_size = 0;
|
||||
frag_offset = 0;
|
||||
}
|
||||
|
||||
inode->i_nlink = 1;
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
|
||||
squashfs_i(inode)->fragment_block = frag_blk;
|
||||
squashfs_i(inode)->fragment_size = frag_size;
|
||||
squashfs_i(inode)->fragment_offset = frag_offset;
|
||||
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
|
||||
squashfs_i(inode)->block_list_start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
inode->i_data.a_ops = &squashfs_aops;
|
||||
|
||||
TRACE("File inode %x:%x, start_block %llx, block_list_start "
|
||||
"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
|
||||
offset, squashfs_i(inode)->start, block, offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LREG_TYPE: {
|
||||
unsigned int frag_offset, frag_size, frag;
|
||||
u64 frag_blk;
|
||||
struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
frag = le32_to_cpu(sqsh_ino->fragment);
|
||||
if (frag != SQUASHFS_INVALID_FRAG) {
|
||||
frag_offset = le32_to_cpu(sqsh_ino->offset);
|
||||
frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
|
||||
if (frag_size < 0) {
|
||||
err = frag_size;
|
||||
goto failed_read;
|
||||
}
|
||||
} else {
|
||||
frag_blk = SQUASHFS_INVALID_BLK;
|
||||
frag_size = 0;
|
||||
frag_offset = 0;
|
||||
}
|
||||
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le64_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_blocks = ((inode->i_size -
|
||||
le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
|
||||
|
||||
squashfs_i(inode)->fragment_block = frag_blk;
|
||||
squashfs_i(inode)->fragment_size = frag_size;
|
||||
squashfs_i(inode)->fragment_offset = frag_offset;
|
||||
squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
|
||||
squashfs_i(inode)->block_list_start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
inode->i_data.a_ops = &squashfs_aops;
|
||||
|
||||
TRACE("File inode %x:%x, start_block %llx, block_list_start "
|
||||
"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
|
||||
offset, squashfs_i(inode)->start, block, offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le16_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_op = &squashfs_dir_inode_ops;
|
||||
inode->i_fop = &squashfs_dir_ops;
|
||||
inode->i_mode |= S_IFDIR;
|
||||
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
|
||||
squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
|
||||
squashfs_i(inode)->dir_idx_cnt = 0;
|
||||
squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
|
||||
|
||||
TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
|
||||
SQUASHFS_INODE_BLK(ino), offset,
|
||||
squashfs_i(inode)->start,
|
||||
le16_to_cpu(sqsh_ino->offset));
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_op = &squashfs_dir_inode_ops;
|
||||
inode->i_fop = &squashfs_dir_ops;
|
||||
inode->i_mode |= S_IFDIR;
|
||||
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
|
||||
squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
|
||||
squashfs_i(inode)->dir_idx_start = block;
|
||||
squashfs_i(inode)->dir_idx_offset = offset;
|
||||
squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);
|
||||
squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
|
||||
|
||||
TRACE("Long directory inode %x:%x, start_block %llx, offset "
|
||||
"%x\n", SQUASHFS_INODE_BLK(ino), offset,
|
||||
squashfs_i(inode)->start,
|
||||
le16_to_cpu(sqsh_ino->offset));
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE:
|
||||
case SQUASHFS_LSYMLINK_TYPE: {
|
||||
struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_data.a_ops = &squashfs_symlink_aops;
|
||||
inode->i_mode |= S_IFLNK;
|
||||
squashfs_i(inode)->start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
|
||||
TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
|
||||
"%x\n", SQUASHFS_INODE_BLK(ino), offset,
|
||||
block, offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE:
|
||||
case SQUASHFS_LBLKDEV_TYPE:
|
||||
case SQUASHFS_LCHRDEV_TYPE: {
|
||||
struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
|
||||
unsigned int rdev;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
if (type == SQUASHFS_CHRDEV_TYPE)
|
||||
inode->i_mode |= S_IFCHR;
|
||||
else
|
||||
inode->i_mode |= S_IFBLK;
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
rdev = le32_to_cpu(sqsh_ino->rdev);
|
||||
init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
|
||||
|
||||
TRACE("Device inode %x:%x, rdev %x\n",
|
||||
SQUASHFS_INODE_BLK(ino), offset, rdev);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
case SQUASHFS_LSOCKET_TYPE: {
|
||||
struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
if (type == SQUASHFS_FIFO_TYPE)
|
||||
inode->i_mode |= S_IFIFO;
|
||||
else
|
||||
inode->i_mode |= S_IFSOCK;
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
init_special_inode(inode, inode->i_mode, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ERROR("Unknown inode type %d in squashfs_iget!\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed_read:
|
||||
ERROR("Unable to read inode 0x%llx\n", ino);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* namei.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to do filename lookup in directories.
|
||||
*
|
||||
* Like inodes, directories are packed into compressed metadata blocks, stored
|
||||
* in a directory table. Directories are accessed using the start address of
|
||||
* the metablock containing the directory and the offset into the
|
||||
* decompressed block (<block, offset>).
|
||||
*
|
||||
* Directories are organised in a slightly complex way, and are not simply
|
||||
* a list of file names. The organisation takes advantage of the
|
||||
* fact that (in most cases) the inodes of the files will be in the same
|
||||
* compressed metadata block, and therefore, can share the start block.
|
||||
* Directories are therefore organised in a two level list, a directory
|
||||
* header containing the shared start block value, and a sequence of directory
|
||||
* entries, each of which share the shared start block. A new directory header
|
||||
* is written once/if the inode start block changes. The directory
|
||||
* header/directory entry list is repeated as many times as necessary.
|
||||
*
|
||||
* Directories are sorted, and can contain a directory index to speed up
|
||||
* file lookup. Directory indexes store one entry per metablock, each entry
|
||||
* storing the index/filename mapping to the first directory header
|
||||
* in each metadata block. Directories are sorted in alphabetical order,
|
||||
* and at lookup the index is scanned linearly looking for the first filename
|
||||
* alphabetically larger than the filename being looked up. At this point the
|
||||
* location of the metadata block the filename is in has been found.
|
||||
* The general idea of the index is ensure only one metadata block needs to be
|
||||
* decompressed to do a lookup irrespective of the length of the directory.
|
||||
* This scheme has the advantage that it doesn't require extra memory overhead
|
||||
* and doesn't require much extra storage on disk.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Lookup name in the directory index, returning the location of the metadata
|
||||
* block containing it, and the directory index this represents.
|
||||
*
|
||||
* If we get an error reading the index then return the part of the index
|
||||
* (if any) we have managed to read - the index isn't essential, just
|
||||
* quicker.
|
||||
*/
|
||||
static int get_dir_index_using_name(struct super_block *sb,
|
||||
u64 *next_block, int *next_offset, u64 index_start,
|
||||
int index_offset, int i_count, const char *name,
|
||||
int len)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int i, size, length = 0, err;
|
||||
struct squashfs_dir_index *index;
|
||||
char *str;
|
||||
|
||||
TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
|
||||
|
||||
index = kmalloc(sizeof(*index) + SQUASHFS_NAME_LEN * 2 + 2, GFP_KERNEL);
|
||||
if (index == NULL) {
|
||||
ERROR("Failed to allocate squashfs_dir_index\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
str = &index->name[SQUASHFS_NAME_LEN + 1];
|
||||
strncpy(str, name, len);
|
||||
str[len] = '\0';
|
||||
|
||||
for (i = 0; i < i_count; i++) {
|
||||
err = squashfs_read_metadata(sb, index, &index_start,
|
||||
&index_offset, sizeof(*index));
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
|
||||
size = le32_to_cpu(index->size) + 1;
|
||||
|
||||
err = squashfs_read_metadata(sb, index->name, &index_start,
|
||||
&index_offset, size);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
index->name[size] = '\0';
|
||||
|
||||
if (strcmp(index->name, str) > 0)
|
||||
break;
|
||||
|
||||
length = le32_to_cpu(index->index);
|
||||
*next_block = le32_to_cpu(index->start_block) +
|
||||
msblk->directory_table;
|
||||
}
|
||||
|
||||
*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
|
||||
kfree(index);
|
||||
|
||||
out:
|
||||
/*
|
||||
* Return index (f_pos) of the looked up metadata block. Translate
|
||||
* from internal f_pos to external f_pos which is offset by 3 because
|
||||
* we invent "." and ".." entries which are not actually stored in the
|
||||
* directory.
|
||||
*/
|
||||
return length + 3;
|
||||
}
|
||||
|
||||
|
||||
static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
{
|
||||
const unsigned char *name = dentry->d_name.name;
|
||||
int len = dentry->d_name.len;
|
||||
struct inode *inode = NULL;
|
||||
struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
|
||||
struct squashfs_dir_header dirh;
|
||||
struct squashfs_dir_entry *dire;
|
||||
u64 block = squashfs_i(dir)->start + msblk->directory_table;
|
||||
int offset = squashfs_i(dir)->offset;
|
||||
int err, length = 0, dir_count, size;
|
||||
|
||||
TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);
|
||||
|
||||
dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
|
||||
if (dire == NULL) {
|
||||
ERROR("Failed to allocate squashfs_dir_entry\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
if (len > SQUASHFS_NAME_LEN) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
length = get_dir_index_using_name(dir->i_sb, &block, &offset,
|
||||
squashfs_i(dir)->dir_idx_start,
|
||||
squashfs_i(dir)->dir_idx_offset,
|
||||
squashfs_i(dir)->dir_idx_cnt, name, len);
|
||||
|
||||
while (length < i_size_read(dir)) {
|
||||
/*
|
||||
* Read directory header.
|
||||
*/
|
||||
err = squashfs_read_metadata(dir->i_sb, &dirh, &block,
|
||||
&offset, sizeof(dirh));
|
||||
if (err < 0)
|
||||
goto read_failure;
|
||||
|
||||
length += sizeof(dirh);
|
||||
|
||||
dir_count = le32_to_cpu(dirh.count) + 1;
|
||||
while (dir_count--) {
|
||||
/*
|
||||
* Read directory entry.
|
||||
*/
|
||||
err = squashfs_read_metadata(dir->i_sb, dire, &block,
|
||||
&offset, sizeof(*dire));
|
||||
if (err < 0)
|
||||
goto read_failure;
|
||||
|
||||
size = le16_to_cpu(dire->size) + 1;
|
||||
|
||||
err = squashfs_read_metadata(dir->i_sb, dire->name,
|
||||
&block, &offset, size);
|
||||
if (err < 0)
|
||||
goto read_failure;
|
||||
|
||||
length += sizeof(*dire) + size;
|
||||
|
||||
if (name[0] < dire->name[0])
|
||||
goto exit_lookup;
|
||||
|
||||
if (len == size && !strncmp(name, dire->name, len)) {
|
||||
unsigned int blk, off, ino_num;
|
||||
long long ino;
|
||||
blk = le32_to_cpu(dirh.start_block);
|
||||
off = le16_to_cpu(dire->offset);
|
||||
ino_num = le32_to_cpu(dirh.inode_number) +
|
||||
(short) le16_to_cpu(dire->inode_number);
|
||||
ino = SQUASHFS_MKINODE(blk, off);
|
||||
|
||||
TRACE("calling squashfs_iget for directory "
|
||||
"entry %s, inode %x:%x, %d\n", name,
|
||||
blk, off, ino_num);
|
||||
|
||||
inode = squashfs_iget(dir->i_sb, ino, ino_num);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
goto exit_lookup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit_lookup:
|
||||
kfree(dire);
|
||||
if (inode)
|
||||
return d_splice_alias(inode, dentry);
|
||||
d_add(dentry, inode);
|
||||
return ERR_PTR(0);
|
||||
|
||||
read_failure:
|
||||
ERROR("Unable to read directory block [%llx:%x]\n",
|
||||
squashfs_i(dir)->start + msblk->directory_table,
|
||||
squashfs_i(dir)->offset);
|
||||
failed:
|
||||
kfree(dire);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
||||
const struct inode_operations squashfs_dir_inode_ops = {
|
||||
.lookup = squashfs_lookup
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs.h
|
||||
*/
|
||||
|
||||
#define TRACE(s, args...) pr_debug("SQUASHFS: "s, ## args)
|
||||
|
||||
#define ERROR(s, args...) pr_err("SQUASHFS error: "s, ## args)
|
||||
|
||||
#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args)
|
||||
|
||||
static inline struct squashfs_inode_info *squashfs_i(struct inode *inode)
|
||||
{
|
||||
return list_entry(inode, struct squashfs_inode_info, vfs_inode);
|
||||
}
|
||||
|
||||
/* block.c */
|
||||
extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *,
|
||||
int);
|
||||
|
||||
/* cache.c */
|
||||
extern struct squashfs_cache *squashfs_cache_init(char *, int, int);
|
||||
extern void squashfs_cache_delete(struct squashfs_cache *);
|
||||
extern struct squashfs_cache_entry *squashfs_cache_get(struct super_block *,
|
||||
struct squashfs_cache *, u64, int);
|
||||
extern void squashfs_cache_put(struct squashfs_cache_entry *);
|
||||
extern int squashfs_copy_data(void *, struct squashfs_cache_entry *, int, int);
|
||||
extern int squashfs_read_metadata(struct super_block *, void *, u64 *,
|
||||
int *, int);
|
||||
extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *,
|
||||
u64, int);
|
||||
extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *,
|
||||
u64, int);
|
||||
extern int squashfs_read_table(struct super_block *, void *, u64, int);
|
||||
|
||||
/* export.c */
|
||||
extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
|
||||
unsigned int);
|
||||
|
||||
/* fragment.c */
|
||||
extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *);
|
||||
extern __le64 *squashfs_read_fragment_index_table(struct super_block *,
|
||||
u64, unsigned int);
|
||||
|
||||
/* id.c */
|
||||
extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
|
||||
extern __le64 *squashfs_read_id_index_table(struct super_block *, u64,
|
||||
unsigned short);
|
||||
|
||||
/* inode.c */
|
||||
extern struct inode *squashfs_iget(struct super_block *, long long,
|
||||
unsigned int);
|
||||
extern int squashfs_read_inode(struct inode *, long long);
|
||||
|
||||
/*
|
||||
* Inodes and files operations
|
||||
*/
|
||||
|
||||
/* dir.c */
|
||||
extern const struct file_operations squashfs_dir_ops;
|
||||
|
||||
/* export.c */
|
||||
extern const struct export_operations squashfs_export_ops;
|
||||
|
||||
/* file.c */
|
||||
extern const struct address_space_operations squashfs_aops;
|
||||
|
||||
/* namei.c */
|
||||
extern const struct inode_operations squashfs_dir_inode_ops;
|
||||
|
||||
/* symlink.c */
|
||||
extern const struct address_space_operations squashfs_symlink_aops;
|
||||
@@ -0,0 +1,381 @@
|
||||
#ifndef SQUASHFS_FS
|
||||
#define SQUASHFS_FS
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs_fs.h
|
||||
*/
|
||||
|
||||
#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
|
||||
#define SQUASHFS_MAJOR 4
|
||||
#define SQUASHFS_MINOR 0
|
||||
#define SQUASHFS_MAGIC 0x73717368
|
||||
#define SQUASHFS_START 0
|
||||
|
||||
/* size of metadata (inode and directory) blocks */
|
||||
#define SQUASHFS_METADATA_SIZE 8192
|
||||
#define SQUASHFS_METADATA_LOG 13
|
||||
|
||||
/* default size of data blocks */
|
||||
#define SQUASHFS_FILE_SIZE 131072
|
||||
#define SQUASHFS_FILE_LOG 17
|
||||
|
||||
#define SQUASHFS_FILE_MAX_SIZE 1048576
|
||||
#define SQUASHFS_FILE_MAX_LOG 20
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_IDS 65536
|
||||
|
||||
/* Max length of filename (not 255) */
|
||||
#define SQUASHFS_NAME_LEN 256
|
||||
|
||||
#define SQUASHFS_INVALID_FRAG (0xffffffffU)
|
||||
#define SQUASHFS_INVALID_BLK (-1LL)
|
||||
|
||||
/* Filesystem flags */
|
||||
#define SQUASHFS_NOI 0
|
||||
#define SQUASHFS_NOD 1
|
||||
#define SQUASHFS_NOF 3
|
||||
#define SQUASHFS_NO_FRAG 4
|
||||
#define SQUASHFS_ALWAYS_FRAG 5
|
||||
#define SQUASHFS_DUPLICATE 6
|
||||
#define SQUASHFS_EXPORT 7
|
||||
|
||||
#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOI)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOD)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOF)
|
||||
|
||||
#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_FRAG)
|
||||
|
||||
#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_ALWAYS_FRAG)
|
||||
|
||||
#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_DUPLICATE)
|
||||
|
||||
#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_EXPORT)
|
||||
|
||||
/* Max number of types and file types */
|
||||
#define SQUASHFS_DIR_TYPE 1
|
||||
#define SQUASHFS_REG_TYPE 2
|
||||
#define SQUASHFS_SYMLINK_TYPE 3
|
||||
#define SQUASHFS_BLKDEV_TYPE 4
|
||||
#define SQUASHFS_CHRDEV_TYPE 5
|
||||
#define SQUASHFS_FIFO_TYPE 6
|
||||
#define SQUASHFS_SOCKET_TYPE 7
|
||||
#define SQUASHFS_LDIR_TYPE 8
|
||||
#define SQUASHFS_LREG_TYPE 9
|
||||
#define SQUASHFS_LSYMLINK_TYPE 10
|
||||
#define SQUASHFS_LBLKDEV_TYPE 11
|
||||
#define SQUASHFS_LCHRDEV_TYPE 12
|
||||
#define SQUASHFS_LFIFO_TYPE 13
|
||||
#define SQUASHFS_LSOCKET_TYPE 14
|
||||
|
||||
/* Flag whether block is compressed or uncompressed, bit is set if block is
|
||||
* uncompressed */
|
||||
#define SQUASHFS_COMPRESSED_BIT (1 << 15)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
|
||||
(B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
|
||||
|
||||
#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
|
||||
~SQUASHFS_COMPRESSED_BIT_BLOCK)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
|
||||
|
||||
/*
|
||||
* Inode number ops. Inodes consist of a compressed block number, and an
|
||||
* uncompressed offset within that block
|
||||
*/
|
||||
#define SQUASHFS_INODE_BLK(A) ((unsigned int) ((A) >> 16))
|
||||
|
||||
#define SQUASHFS_INODE_OFFSET(A) ((unsigned int) ((A) & 0xffff))
|
||||
|
||||
#define SQUASHFS_MKINODE(A, B) ((long long)(((long long) (A)\
|
||||
<< 16) + (B)))
|
||||
|
||||
/* Translate between VFS mode and squashfs mode */
|
||||
#define SQUASHFS_MODE(A) ((A) & 0xfff)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES(A) \
|
||||
((A) * sizeof(struct squashfs_fragment_entry))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
|
||||
sizeof(u64))
|
||||
|
||||
/* inode lookup table defines */
|
||||
#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(u64))
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
|
||||
sizeof(u64))
|
||||
|
||||
/* uid/gid lookup table defines */
|
||||
#define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int))
|
||||
|
||||
#define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\
|
||||
sizeof(u64))
|
||||
|
||||
/* cached data constants for filesystem */
|
||||
#define SQUASHFS_CACHED_BLKS 8
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE_LOG 64
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE (1LL << \
|
||||
(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
|
||||
|
||||
#define SQUASHFS_MARKER_BYTE 0xff
|
||||
|
||||
/* meta index cache */
|
||||
#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
|
||||
#define SQUASHFS_META_ENTRIES 127
|
||||
#define SQUASHFS_META_SLOTS 8
|
||||
|
||||
struct meta_entry {
|
||||
u64 data_block;
|
||||
unsigned int index_block;
|
||||
unsigned short offset;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct meta_index {
|
||||
unsigned int inode_number;
|
||||
unsigned int offset;
|
||||
unsigned short entries;
|
||||
unsigned short skip;
|
||||
unsigned short locked;
|
||||
unsigned short pad;
|
||||
struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* definitions for structures on disk
|
||||
*/
|
||||
#define ZLIB_COMPRESSION 1
|
||||
|
||||
struct squashfs_super_block {
|
||||
__le32 s_magic;
|
||||
__le32 inodes;
|
||||
__le32 mkfs_time;
|
||||
__le32 block_size;
|
||||
__le32 fragments;
|
||||
__le16 compression;
|
||||
__le16 block_log;
|
||||
__le16 flags;
|
||||
__le16 no_ids;
|
||||
__le16 s_major;
|
||||
__le16 s_minor;
|
||||
__le64 root_inode;
|
||||
__le64 bytes_used;
|
||||
__le64 id_table_start;
|
||||
__le64 xattr_table_start;
|
||||
__le64 inode_table_start;
|
||||
__le64 directory_table_start;
|
||||
__le64 fragment_table_start;
|
||||
__le64 lookup_table_start;
|
||||
};
|
||||
|
||||
struct squashfs_dir_index {
|
||||
__le32 index;
|
||||
__le32 start_block;
|
||||
__le32 size;
|
||||
unsigned char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_base_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_ipc_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
};
|
||||
|
||||
struct squashfs_dev_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 rdev;
|
||||
};
|
||||
|
||||
struct squashfs_symlink_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 symlink_size;
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
struct squashfs_reg_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 start_block;
|
||||
__le32 fragment;
|
||||
__le32 offset;
|
||||
__le32 file_size;
|
||||
__le16 block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_lreg_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le64 start_block;
|
||||
__le64 file_size;
|
||||
__le64 sparse;
|
||||
__le32 nlink;
|
||||
__le32 fragment;
|
||||
__le32 offset;
|
||||
__le32 xattr;
|
||||
__le16 block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 start_block;
|
||||
__le32 nlink;
|
||||
__le16 file_size;
|
||||
__le16 offset;
|
||||
__le32 parent_inode;
|
||||
};
|
||||
|
||||
struct squashfs_ldir_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 file_size;
|
||||
__le32 start_block;
|
||||
__le32 parent_inode;
|
||||
__le16 i_count;
|
||||
__le16 offset;
|
||||
__le32 xattr;
|
||||
struct squashfs_dir_index index[0];
|
||||
};
|
||||
|
||||
union squashfs_inode {
|
||||
struct squashfs_base_inode base;
|
||||
struct squashfs_dev_inode dev;
|
||||
struct squashfs_symlink_inode symlink;
|
||||
struct squashfs_reg_inode reg;
|
||||
struct squashfs_lreg_inode lreg;
|
||||
struct squashfs_dir_inode dir;
|
||||
struct squashfs_ldir_inode ldir;
|
||||
struct squashfs_ipc_inode ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry {
|
||||
__le16 offset;
|
||||
__le16 inode_number;
|
||||
__le16 type;
|
||||
__le16 size;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_header {
|
||||
__le32 count;
|
||||
__le32 start_block;
|
||||
__le32 inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_fragment_entry {
|
||||
__le64 start_block;
|
||||
__le32 size;
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef SQUASHFS_FS_I
|
||||
#define SQUASHFS_FS_I
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs_fs_i.h
|
||||
*/
|
||||
|
||||
struct squashfs_inode_info {
|
||||
u64 start;
|
||||
int offset;
|
||||
union {
|
||||
struct {
|
||||
u64 fragment_block;
|
||||
int fragment_size;
|
||||
int fragment_offset;
|
||||
u64 block_list_start;
|
||||
};
|
||||
struct {
|
||||
u64 dir_idx_start;
|
||||
int dir_idx_offset;
|
||||
int dir_idx_cnt;
|
||||
int parent;
|
||||
};
|
||||
};
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef SQUASHFS_FS_SB
|
||||
#define SQUASHFS_FS_SB
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs_fs_sb.h
|
||||
*/
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
|
||||
struct squashfs_cache {
|
||||
char *name;
|
||||
int entries;
|
||||
int next_blk;
|
||||
int num_waiters;
|
||||
int unused;
|
||||
int block_size;
|
||||
int pages;
|
||||
spinlock_t lock;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct squashfs_cache_entry *entry;
|
||||
};
|
||||
|
||||
struct squashfs_cache_entry {
|
||||
u64 block;
|
||||
int length;
|
||||
int refcount;
|
||||
u64 next_index;
|
||||
int pending;
|
||||
int error;
|
||||
int num_waiters;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct squashfs_cache *cache;
|
||||
void **data;
|
||||
};
|
||||
|
||||
struct squashfs_sb_info {
|
||||
int devblksize;
|
||||
int devblksize_log2;
|
||||
struct squashfs_cache *block_cache;
|
||||
struct squashfs_cache *fragment_cache;
|
||||
struct squashfs_cache *read_page;
|
||||
int next_meta_index;
|
||||
__le64 *id_table;
|
||||
__le64 *fragment_index;
|
||||
unsigned int *fragment_index_2;
|
||||
struct mutex read_data_mutex;
|
||||
struct mutex meta_index_mutex;
|
||||
struct meta_index *meta_index;
|
||||
z_stream stream;
|
||||
__le64 *inode_lookup_table;
|
||||
u64 inode_table;
|
||||
u64 directory_table;
|
||||
unsigned int block_size;
|
||||
unsigned short block_log;
|
||||
long long bytes_used;
|
||||
unsigned int inodes;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* super.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to read the superblock, read and initialise
|
||||
* in-memory structures at mount time, and all the VFS glue code to register
|
||||
* the filesystem.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
static struct file_system_type squashfs_fs_type;
|
||||
static struct super_operations squashfs_super_ops;
|
||||
|
||||
static int supported_squashfs_filesystem(short major, short minor, short comp)
|
||||
{
|
||||
if (major < SQUASHFS_MAJOR) {
|
||||
ERROR("Major/Minor mismatch, older Squashfs %d.%d "
|
||||
"filesystems are unsupported\n", major, minor);
|
||||
return -EINVAL;
|
||||
} else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
|
||||
ERROR("Major/Minor mismatch, trying to mount newer "
|
||||
"%d.%d filesystem\n", major, minor);
|
||||
ERROR("Please update your kernel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (comp != ZLIB_COMPRESSION)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
struct squashfs_sb_info *msblk;
|
||||
struct squashfs_super_block *sblk = NULL;
|
||||
char b[BDEVNAME_SIZE];
|
||||
struct inode *root;
|
||||
long long root_inode;
|
||||
unsigned short flags;
|
||||
unsigned int fragments;
|
||||
u64 lookup_table_start;
|
||||
int err;
|
||||
|
||||
TRACE("Entered squashfs_fill_superblock\n");
|
||||
|
||||
sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL);
|
||||
if (sb->s_fs_info == NULL) {
|
||||
ERROR("Failed to allocate squashfs_sb_info\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msblk = sb->s_fs_info;
|
||||
|
||||
msblk->stream.workspace = kmalloc(zlib_inflate_workspacesize(),
|
||||
GFP_KERNEL);
|
||||
if (msblk->stream.workspace == NULL) {
|
||||
ERROR("Failed to allocate zlib workspace\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
|
||||
if (sblk == NULL) {
|
||||
ERROR("Failed to allocate squashfs_super_block\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
|
||||
msblk->devblksize_log2 = ffz(~msblk->devblksize);
|
||||
|
||||
mutex_init(&msblk->read_data_mutex);
|
||||
mutex_init(&msblk->meta_index_mutex);
|
||||
|
||||
/*
|
||||
* msblk->bytes_used is checked in squashfs_read_table to ensure reads
|
||||
* are not beyond filesystem end. But as we're using
|
||||
* squashfs_read_table here to read the superblock (including the value
|
||||
* of bytes_used) we need to set it to an initial sensible dummy value
|
||||
*/
|
||||
msblk->bytes_used = sizeof(*sblk);
|
||||
err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk));
|
||||
|
||||
if (err < 0) {
|
||||
ERROR("unable to read squashfs_super_block\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Check it is a SQUASHFS superblock */
|
||||
sb->s_magic = le32_to_cpu(sblk->s_magic);
|
||||
if (sb->s_magic != SQUASHFS_MAGIC) {
|
||||
if (!silent)
|
||||
ERROR("Can't find a SQUASHFS superblock on %s\n",
|
||||
bdevname(sb->s_bdev, b));
|
||||
err = -EINVAL;
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Check the MAJOR & MINOR versions and compression type */
|
||||
err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
|
||||
le16_to_cpu(sblk->s_minor),
|
||||
le16_to_cpu(sblk->compression));
|
||||
if (err < 0)
|
||||
goto failed_mount;
|
||||
|
||||
err = -EINVAL;
|
||||
|
||||
/*
|
||||
* Check if there's xattrs in the filesystem. These are not
|
||||
* supported in this version, so warn that they will be ignored.
|
||||
*/
|
||||
if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK)
|
||||
ERROR("Xattrs in filesystem, these will be ignored\n");
|
||||
|
||||
/* Check the filesystem does not extend beyond the end of the
|
||||
block device */
|
||||
msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
|
||||
if (msblk->bytes_used < 0 || msblk->bytes_used >
|
||||
i_size_read(sb->s_bdev->bd_inode))
|
||||
goto failed_mount;
|
||||
|
||||
/* Check block size for sanity */
|
||||
msblk->block_size = le32_to_cpu(sblk->block_size);
|
||||
if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)
|
||||
goto failed_mount;
|
||||
|
||||
msblk->block_log = le16_to_cpu(sblk->block_log);
|
||||
if (msblk->block_log > SQUASHFS_FILE_MAX_LOG)
|
||||
goto failed_mount;
|
||||
|
||||
/* Check the root inode for sanity */
|
||||
root_inode = le64_to_cpu(sblk->root_inode);
|
||||
if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE)
|
||||
goto failed_mount;
|
||||
|
||||
msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
|
||||
msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
|
||||
msblk->inodes = le32_to_cpu(sblk->inodes);
|
||||
flags = le16_to_cpu(sblk->flags);
|
||||
|
||||
TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
|
||||
TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags)
|
||||
? "un" : "");
|
||||
TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags)
|
||||
? "un" : "");
|
||||
TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);
|
||||
TRACE("Block size %d\n", msblk->block_size);
|
||||
TRACE("Number of inodes %d\n", msblk->inodes);
|
||||
TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments));
|
||||
TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids));
|
||||
TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);
|
||||
TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);
|
||||
TRACE("sblk->fragment_table_start %llx\n",
|
||||
(u64) le64_to_cpu(sblk->fragment_table_start));
|
||||
TRACE("sblk->id_table_start %llx\n",
|
||||
(u64) le64_to_cpu(sblk->id_table_start));
|
||||
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
sb->s_op = &squashfs_super_ops;
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
msblk->block_cache = squashfs_cache_init("metadata",
|
||||
SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
|
||||
if (msblk->block_cache == NULL)
|
||||
goto failed_mount;
|
||||
|
||||
/* Allocate read_page block */
|
||||
msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size);
|
||||
if (msblk->read_page == NULL) {
|
||||
ERROR("Failed to allocate read_page block\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Allocate and read id index table */
|
||||
msblk->id_table = squashfs_read_id_index_table(sb,
|
||||
le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids));
|
||||
if (IS_ERR(msblk->id_table)) {
|
||||
err = PTR_ERR(msblk->id_table);
|
||||
msblk->id_table = NULL;
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
fragments = le32_to_cpu(sblk->fragments);
|
||||
if (fragments == 0)
|
||||
goto allocate_lookup_table;
|
||||
|
||||
msblk->fragment_cache = squashfs_cache_init("fragment",
|
||||
SQUASHFS_CACHED_FRAGMENTS, msblk->block_size);
|
||||
if (msblk->fragment_cache == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Allocate and read fragment index table */
|
||||
msblk->fragment_index = squashfs_read_fragment_index_table(sb,
|
||||
le64_to_cpu(sblk->fragment_table_start), fragments);
|
||||
if (IS_ERR(msblk->fragment_index)) {
|
||||
err = PTR_ERR(msblk->fragment_index);
|
||||
msblk->fragment_index = NULL;
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
allocate_lookup_table:
|
||||
lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
|
||||
if (lookup_table_start == SQUASHFS_INVALID_BLK)
|
||||
goto allocate_root;
|
||||
|
||||
/* Allocate and read inode lookup table */
|
||||
msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
|
||||
lookup_table_start, msblk->inodes);
|
||||
if (IS_ERR(msblk->inode_lookup_table)) {
|
||||
err = PTR_ERR(msblk->inode_lookup_table);
|
||||
msblk->inode_lookup_table = NULL;
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
sb->s_export_op = &squashfs_export_ops;
|
||||
|
||||
allocate_root:
|
||||
root = new_inode(sb);
|
||||
if (!root) {
|
||||
err = -ENOMEM;
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
err = squashfs_read_inode(root, root_inode);
|
||||
if (err) {
|
||||
iget_failed(root);
|
||||
goto failed_mount;
|
||||
}
|
||||
insert_inode_hash(root);
|
||||
|
||||
sb->s_root = d_alloc_root(root);
|
||||
if (sb->s_root == NULL) {
|
||||
ERROR("Root inode create failed\n");
|
||||
err = -ENOMEM;
|
||||
iput(root);
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
TRACE("Leaving squashfs_fill_super\n");
|
||||
kfree(sblk);
|
||||
return 0;
|
||||
|
||||
failed_mount:
|
||||
squashfs_cache_delete(msblk->block_cache);
|
||||
squashfs_cache_delete(msblk->fragment_cache);
|
||||
squashfs_cache_delete(msblk->read_page);
|
||||
kfree(msblk->inode_lookup_table);
|
||||
kfree(msblk->fragment_index);
|
||||
kfree(msblk->id_table);
|
||||
kfree(msblk->stream.workspace);
|
||||
kfree(sb->s_fs_info);
|
||||
sb->s_fs_info = NULL;
|
||||
kfree(sblk);
|
||||
return err;
|
||||
|
||||
failure:
|
||||
kfree(msblk->stream.workspace);
|
||||
kfree(sb->s_fs_info);
|
||||
sb->s_fs_info = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
|
||||
|
||||
TRACE("Entered squashfs_statfs\n");
|
||||
|
||||
buf->f_type = SQUASHFS_MAGIC;
|
||||
buf->f_bsize = msblk->block_size;
|
||||
buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1;
|
||||
buf->f_bfree = buf->f_bavail = 0;
|
||||
buf->f_files = msblk->inodes;
|
||||
buf->f_ffree = 0;
|
||||
buf->f_namelen = SQUASHFS_NAME_LEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
*flags |= MS_RDONLY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void squashfs_put_super(struct super_block *sb)
|
||||
{
|
||||
if (sb->s_fs_info) {
|
||||
struct squashfs_sb_info *sbi = sb->s_fs_info;
|
||||
squashfs_cache_delete(sbi->block_cache);
|
||||
squashfs_cache_delete(sbi->fragment_cache);
|
||||
squashfs_cache_delete(sbi->read_page);
|
||||
kfree(sbi->id_table);
|
||||
kfree(sbi->fragment_index);
|
||||
kfree(sbi->meta_index);
|
||||
kfree(sbi->stream.workspace);
|
||||
kfree(sb->s_fs_info);
|
||||
sb->s_fs_info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
const char *dev_name, void *data,
|
||||
struct vfsmount *mnt)
|
||||
{
|
||||
return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
|
||||
mnt);
|
||||
}
|
||||
|
||||
|
||||
static struct kmem_cache *squashfs_inode_cachep;
|
||||
|
||||
|
||||
static void init_once(void *foo)
|
||||
{
|
||||
struct squashfs_inode_info *ei = foo;
|
||||
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
}
|
||||
|
||||
|
||||
static int __init init_inodecache(void)
|
||||
{
|
||||
squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
|
||||
sizeof(struct squashfs_inode_info), 0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
|
||||
|
||||
return squashfs_inode_cachep ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
static void destroy_inodecache(void)
|
||||
{
|
||||
kmem_cache_destroy(squashfs_inode_cachep);
|
||||
}
|
||||
|
||||
|
||||
static int __init init_squashfs_fs(void)
|
||||
{
|
||||
int err = init_inodecache();
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = register_filesystem(&squashfs_fs_type);
|
||||
if (err) {
|
||||
destroy_inodecache();
|
||||
return err;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "squashfs: version 4.0 (2009/01/03) "
|
||||
"Phillip Lougher\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit exit_squashfs_fs(void)
|
||||
{
|
||||
unregister_filesystem(&squashfs_fs_type);
|
||||
destroy_inodecache();
|
||||
}
|
||||
|
||||
|
||||
static struct inode *squashfs_alloc_inode(struct super_block *sb)
|
||||
{
|
||||
struct squashfs_inode_info *ei =
|
||||
kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
|
||||
|
||||
return ei ? &ei->vfs_inode : NULL;
|
||||
}
|
||||
|
||||
|
||||
static void squashfs_destroy_inode(struct inode *inode)
|
||||
{
|
||||
kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode));
|
||||
}
|
||||
|
||||
|
||||
static struct file_system_type squashfs_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "squashfs",
|
||||
.get_sb = squashfs_get_sb,
|
||||
.kill_sb = kill_block_super,
|
||||
.fs_flags = FS_REQUIRES_DEV
|
||||
};
|
||||
|
||||
static struct super_operations squashfs_super_ops = {
|
||||
.alloc_inode = squashfs_alloc_inode,
|
||||
.destroy_inode = squashfs_destroy_inode,
|
||||
.statfs = squashfs_statfs,
|
||||
.put_super = squashfs_put_super,
|
||||
.remount_fs = squashfs_remount
|
||||
};
|
||||
|
||||
module_init(init_squashfs_fs);
|
||||
module_exit(exit_squashfs_fs);
|
||||
MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem");
|
||||
MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* symlink.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to handle symbolic links.
|
||||
*
|
||||
* The data contents of symbolic links are stored inside the symbolic
|
||||
* link inode within the inode table. This allows the normally small symbolic
|
||||
* link to be compressed as part of the inode table, achieving much greater
|
||||
* compression than if the symbolic link was compressed individually.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
static int squashfs_symlink_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int index = page->index << PAGE_CACHE_SHIFT;
|
||||
u64 block = squashfs_i(inode)->start;
|
||||
int offset = squashfs_i(inode)->offset;
|
||||
int length = min_t(int, i_size_read(inode) - index, PAGE_CACHE_SIZE);
|
||||
int bytes, copied;
|
||||
void *pageaddr;
|
||||
struct squashfs_cache_entry *entry;
|
||||
|
||||
TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
|
||||
"%llx, offset %x\n", page->index, block, offset);
|
||||
|
||||
/*
|
||||
* Skip index bytes into symlink metadata.
|
||||
*/
|
||||
if (index) {
|
||||
bytes = squashfs_read_metadata(sb, NULL, &block, &offset,
|
||||
index);
|
||||
if (bytes < 0) {
|
||||
ERROR("Unable to read symlink [%llx:%x]\n",
|
||||
squashfs_i(inode)->start,
|
||||
squashfs_i(inode)->offset);
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read length bytes from symlink metadata. Squashfs_read_metadata
|
||||
* is not used here because it can sleep and we want to use
|
||||
* kmap_atomic to map the page. Instead call the underlying
|
||||
* squashfs_cache_get routine. As length bytes may overlap metadata
|
||||
* blocks, we may need to call squashfs_cache_get multiple times.
|
||||
*/
|
||||
for (bytes = 0; bytes < length; offset = 0, bytes += copied) {
|
||||
entry = squashfs_cache_get(sb, msblk->block_cache, block, 0);
|
||||
if (entry->error) {
|
||||
ERROR("Unable to read symlink [%llx:%x]\n",
|
||||
squashfs_i(inode)->start,
|
||||
squashfs_i(inode)->offset);
|
||||
squashfs_cache_put(entry);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
pageaddr = kmap_atomic(page, KM_USER0);
|
||||
copied = squashfs_copy_data(pageaddr + bytes, entry, offset,
|
||||
length - bytes);
|
||||
if (copied == length - bytes)
|
||||
memset(pageaddr + length, 0, PAGE_CACHE_SIZE - length);
|
||||
else
|
||||
block = entry->next_index;
|
||||
kunmap_atomic(pageaddr, KM_USER0);
|
||||
squashfs_cache_put(entry);
|
||||
}
|
||||
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
SetPageError(page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const struct address_space_operations squashfs_symlink_aops = {
|
||||
.readpage = squashfs_symlink_readpage
|
||||
};
|
||||
@@ -0,0 +1,380 @@
|
||||
#ifndef SQUASHFS_FS
|
||||
#define SQUASHFS_FS
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs_fs.h
|
||||
*/
|
||||
|
||||
#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
|
||||
#define SQUASHFS_MAJOR 4
|
||||
#define SQUASHFS_MINOR 0
|
||||
#define SQUASHFS_MAGIC 0x73717368
|
||||
#define SQUASHFS_START 0
|
||||
|
||||
/* size of metadata (inode and directory) blocks */
|
||||
#define SQUASHFS_METADATA_SIZE 8192
|
||||
#define SQUASHFS_METADATA_LOG 13
|
||||
|
||||
/* default size of data blocks */
|
||||
#define SQUASHFS_FILE_SIZE 131072
|
||||
#define SQUASHFS_FILE_LOG 17
|
||||
|
||||
#define SQUASHFS_FILE_MAX_SIZE 1048576
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_IDS 65536
|
||||
|
||||
/* Max length of filename (not 255) */
|
||||
#define SQUASHFS_NAME_LEN 256
|
||||
|
||||
#define SQUASHFS_INVALID_FRAG (0xffffffffU)
|
||||
#define SQUASHFS_INVALID_BLK (-1LL)
|
||||
|
||||
/* Filesystem flags */
|
||||
#define SQUASHFS_NOI 0
|
||||
#define SQUASHFS_NOD 1
|
||||
#define SQUASHFS_NOF 3
|
||||
#define SQUASHFS_NO_FRAG 4
|
||||
#define SQUASHFS_ALWAYS_FRAG 5
|
||||
#define SQUASHFS_DUPLICATE 6
|
||||
#define SQUASHFS_EXPORT 7
|
||||
|
||||
#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOI)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOD)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOF)
|
||||
|
||||
#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_FRAG)
|
||||
|
||||
#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_ALWAYS_FRAG)
|
||||
|
||||
#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_DUPLICATE)
|
||||
|
||||
#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_EXPORT)
|
||||
|
||||
/* Max number of types and file types */
|
||||
#define SQUASHFS_DIR_TYPE 1
|
||||
#define SQUASHFS_REG_TYPE 2
|
||||
#define SQUASHFS_SYMLINK_TYPE 3
|
||||
#define SQUASHFS_BLKDEV_TYPE 4
|
||||
#define SQUASHFS_CHRDEV_TYPE 5
|
||||
#define SQUASHFS_FIFO_TYPE 6
|
||||
#define SQUASHFS_SOCKET_TYPE 7
|
||||
#define SQUASHFS_LDIR_TYPE 8
|
||||
#define SQUASHFS_LREG_TYPE 9
|
||||
#define SQUASHFS_LSYMLINK_TYPE 10
|
||||
#define SQUASHFS_LBLKDEV_TYPE 11
|
||||
#define SQUASHFS_LCHRDEV_TYPE 12
|
||||
#define SQUASHFS_LFIFO_TYPE 13
|
||||
#define SQUASHFS_LSOCKET_TYPE 14
|
||||
|
||||
/* Flag whether block is compressed or uncompressed, bit is set if block is
|
||||
* uncompressed */
|
||||
#define SQUASHFS_COMPRESSED_BIT (1 << 15)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
|
||||
(B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
|
||||
|
||||
#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
|
||||
~SQUASHFS_COMPRESSED_BIT_BLOCK)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
|
||||
|
||||
/*
|
||||
* Inode number ops. Inodes consist of a compressed block number, and an
|
||||
* uncompressed offset within that block
|
||||
*/
|
||||
#define SQUASHFS_INODE_BLK(A) ((unsigned int) ((A) >> 16))
|
||||
|
||||
#define SQUASHFS_INODE_OFFSET(A) ((unsigned int) ((A) & 0xffff))
|
||||
|
||||
#define SQUASHFS_MKINODE(A, B) ((long long)(((long long) (A)\
|
||||
<< 16) + (B)))
|
||||
|
||||
/* Translate between VFS mode and squashfs mode */
|
||||
#define SQUASHFS_MODE(A) ((A) & 0xfff)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES(A) \
|
||||
((A) * sizeof(struct squashfs_fragment_entry))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* inode lookup table defines */
|
||||
#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(long long))
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* uid/gid lookup table defines */
|
||||
#define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int))
|
||||
|
||||
#define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* cached data constants for filesystem */
|
||||
#define SQUASHFS_CACHED_BLKS 8
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE_LOG 64
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE (1LL << \
|
||||
(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
|
||||
|
||||
#define SQUASHFS_MARKER_BYTE 0xff
|
||||
|
||||
/* meta index cache */
|
||||
#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
|
||||
#define SQUASHFS_META_ENTRIES 127
|
||||
#define SQUASHFS_META_SLOTS 8
|
||||
|
||||
struct meta_entry {
|
||||
long long data_block;
|
||||
unsigned int index_block;
|
||||
unsigned short offset;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct meta_index {
|
||||
unsigned int inode_number;
|
||||
unsigned int offset;
|
||||
unsigned short entries;
|
||||
unsigned short skip;
|
||||
unsigned short locked;
|
||||
unsigned short pad;
|
||||
struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* definitions for structures on disk
|
||||
*/
|
||||
#define ZLIB_COMPRESSION 1
|
||||
|
||||
struct squashfs_super_block {
|
||||
__le32 s_magic;
|
||||
__le32 inodes;
|
||||
__le32 mkfs_time;
|
||||
__le32 block_size;
|
||||
__le32 fragments;
|
||||
__le16 compression;
|
||||
__le16 block_log;
|
||||
__le16 flags;
|
||||
__le16 no_ids;
|
||||
__le16 s_major;
|
||||
__le16 s_minor;
|
||||
__le64 root_inode;
|
||||
__le64 bytes_used;
|
||||
__le64 id_table_start;
|
||||
__le64 xattr_table_start;
|
||||
__le64 inode_table_start;
|
||||
__le64 directory_table_start;
|
||||
__le64 fragment_table_start;
|
||||
__le64 lookup_table_start;
|
||||
};
|
||||
|
||||
struct squashfs_dir_index {
|
||||
__le32 index;
|
||||
__le32 start_block;
|
||||
__le32 size;
|
||||
unsigned char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_base_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_ipc_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
};
|
||||
|
||||
struct squashfs_dev_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 rdev;
|
||||
};
|
||||
|
||||
struct squashfs_symlink_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 symlink_size;
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
struct squashfs_reg_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 start_block;
|
||||
__le32 fragment;
|
||||
__le32 offset;
|
||||
__le32 file_size;
|
||||
__le16 block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_lreg_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le64 start_block;
|
||||
__le64 file_size;
|
||||
__le64 sparse;
|
||||
__le32 nlink;
|
||||
__le32 fragment;
|
||||
__le32 offset;
|
||||
__le32 xattr;
|
||||
__le16 block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 start_block;
|
||||
__le32 nlink;
|
||||
__le16 file_size;
|
||||
__le16 offset;
|
||||
__le32 parent_inode;
|
||||
};
|
||||
|
||||
struct squashfs_ldir_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 file_size;
|
||||
__le32 start_block;
|
||||
__le32 parent_inode;
|
||||
__le16 i_count;
|
||||
__le16 offset;
|
||||
__le32 xattr;
|
||||
struct squashfs_dir_index index[0];
|
||||
};
|
||||
|
||||
union squashfs_inode {
|
||||
struct squashfs_base_inode base;
|
||||
struct squashfs_dev_inode dev;
|
||||
struct squashfs_symlink_inode symlink;
|
||||
struct squashfs_reg_inode reg;
|
||||
struct squashfs_lreg_inode lreg;
|
||||
struct squashfs_dir_inode dir;
|
||||
struct squashfs_ldir_inode ldir;
|
||||
struct squashfs_ipc_inode ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry {
|
||||
__le16 offset;
|
||||
__le16 inode_number;
|
||||
__le16 type;
|
||||
__le16 size;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_header {
|
||||
__le32 count;
|
||||
__le32 start_block;
|
||||
__le32 inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_fragment_entry {
|
||||
__le64 start_block;
|
||||
__le32 size;
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef SQUASHFS_FS_I
|
||||
#define SQUASHFS_FS_I
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs_fs_i.h
|
||||
*/
|
||||
|
||||
struct squashfs_inode_info {
|
||||
long long start;
|
||||
int offset;
|
||||
union {
|
||||
struct {
|
||||
long long fragment_block;
|
||||
int fragment_size;
|
||||
int fragment_offset;
|
||||
long long block_list_start;
|
||||
};
|
||||
struct {
|
||||
long long dir_idx_start;
|
||||
int dir_idx_offset;
|
||||
int dir_idx_cnt;
|
||||
int parent;
|
||||
};
|
||||
};
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef SQUASHFS_FS_SB
|
||||
#define SQUASHFS_FS_SB
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* squashfs_fs_sb.h
|
||||
*/
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
|
||||
struct squashfs_cache_entry {
|
||||
long long block;
|
||||
int length;
|
||||
int locked;
|
||||
long long next_index;
|
||||
char pending;
|
||||
char error;
|
||||
int waiting;
|
||||
wait_queue_head_t wait_queue;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct squashfs_cache {
|
||||
char *name;
|
||||
int entries;
|
||||
int block_size;
|
||||
int next_blk;
|
||||
int waiting;
|
||||
int unused;
|
||||
int use_vmalloc;
|
||||
spinlock_t lock;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct squashfs_cache_entry entry[0];
|
||||
};
|
||||
|
||||
struct squashfs_sb_info {
|
||||
int devblksize;
|
||||
int devblksize_log2;
|
||||
struct squashfs_cache *block_cache;
|
||||
struct squashfs_cache *fragment_cache;
|
||||
int next_meta_index;
|
||||
__le64 *id_table;
|
||||
__le64 *fragment_index;
|
||||
unsigned int *fragment_index_2;
|
||||
char *read_page;
|
||||
struct mutex read_data_mutex;
|
||||
struct mutex read_page_mutex;
|
||||
struct mutex meta_index_mutex;
|
||||
struct meta_index *meta_index;
|
||||
z_stream stream;
|
||||
__le64 *inode_lookup_table;
|
||||
long long inode_table;
|
||||
long long directory_table;
|
||||
unsigned int block_size;
|
||||
unsigned short block_log;
|
||||
long long bytes_used;
|
||||
unsigned int inodes;
|
||||
};
|
||||
#endif
|
||||
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/Makefile
Normal file
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/Makefile
Normal file
@@ -0,0 +1,365 @@
|
||||
###############################################
|
||||
# Compression build options #
|
||||
###############################################
|
||||
#
|
||||
#
|
||||
############# Building gzip support ###########
|
||||
#
|
||||
# Gzip support is by default enabled, and the compression type default
|
||||
# (COMP_DEFAULT) is gzip.
|
||||
#
|
||||
# If you don't want/need gzip support then comment out the GZIP SUPPORT line
|
||||
# below, and change COMP_DEFAULT to one of the compression types you have
|
||||
# selected.
|
||||
#
|
||||
# Obviously, you must select at least one of the available gzip, lzma, lzo
|
||||
# compression types.
|
||||
#
|
||||
GZIP_SUPPORT = 1
|
||||
|
||||
########### Building XZ support #############
|
||||
#
|
||||
# LZMA2 compression.
|
||||
#
|
||||
# XZ Utils liblzma (http://tukaani.org/xz/) is supported
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install the library and uncomment
|
||||
# the XZ_SUPPORT line below.
|
||||
#
|
||||
XZ_SUPPORT = 1
|
||||
|
||||
|
||||
############ Building LZO support ##############
|
||||
#
|
||||
# The LZO library (http://www.oberhumer.com/opensource/lzo/) is supported.
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install the library and uncomment
|
||||
# the XZ_SUPPORT line below.
|
||||
#
|
||||
LZO_SUPPORT = 1
|
||||
|
||||
|
||||
########### Building LZ4 support #############
|
||||
#
|
||||
# Yann Collet's LZ4 tools are supported
|
||||
# LZ4 homepage: http://fastcompression.blogspot.com/p/lz4.html
|
||||
# LZ4 source repository: http://code.google.com/p/lz4
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install and uncomment
|
||||
# the LZ4_SUPPORT line below.
|
||||
#
|
||||
LZ4_SUPPORT = 1
|
||||
|
||||
|
||||
########### Building ZSTD support ############
|
||||
#
|
||||
# The ZSTD library is supported
|
||||
# ZSTD homepage: http://zstd.net
|
||||
# ZSTD source repository: https://github.com/facebook/zstd
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install the library and uncomment
|
||||
# the XZ_SUPPORT line below.
|
||||
#
|
||||
ZSTD_SUPPORT = 1
|
||||
|
||||
|
||||
######## Specifying default compression ########
|
||||
#
|
||||
# The next line specifies which compression algorithm is used by default
|
||||
# in Mksquashfs. Obviously the compression algorithm must have been
|
||||
# selected to be built
|
||||
#
|
||||
COMP_DEFAULT = gzip
|
||||
|
||||
|
||||
###############################################
|
||||
# Extended attribute (XATTRs) build options #
|
||||
###############################################
|
||||
#
|
||||
# Building XATTR support for Mksquashfs and Unsquashfs
|
||||
#
|
||||
# If your C library or build/target environment doesn't support XATTRs then
|
||||
# comment out the next line to build Mksquashfs and Unsquashfs without XATTR
|
||||
# support
|
||||
XATTR_SUPPORT = 1
|
||||
|
||||
# Select whether you wish xattrs to be stored by Mksquashfs and extracted
|
||||
# by Unsquashfs by default. If selected users can disable xattr support by
|
||||
# using the -no-xattrs option
|
||||
#
|
||||
# If unselected, Mksquashfs/Unsquashfs won't store and extract xattrs by
|
||||
# default. Users can enable xattrs by using the -xattrs option.
|
||||
XATTR_DEFAULT = 1
|
||||
|
||||
|
||||
###############################################
|
||||
# Reproducible Image options #
|
||||
###############################################
|
||||
#
|
||||
# Select whether you wish reproducible builds by default. If selected users
|
||||
# can disable reproducible builds using the not-reproducible option.
|
||||
# If not selected, users can enable reproducible builds using the
|
||||
# -reproducible option
|
||||
REPRODUCIBLE_DEFAULT = 1
|
||||
|
||||
|
||||
###############################################
|
||||
# Obsolete options #
|
||||
###############################################
|
||||
|
||||
########### Building LZMA support #############
|
||||
#
|
||||
# LZMA1 compression.
|
||||
#
|
||||
# LZMA1 compression is obsolete, and the newer and better XZ (LZMA2)
|
||||
# compression should be used in preference.
|
||||
#
|
||||
# Both XZ Utils liblzma (http://tukaani.org/xz/) and LZMA SDK
|
||||
# (http://www.7-zip.org/sdk.html) are supported
|
||||
#
|
||||
# To build using XZ Utils liblzma - install the library and uncomment
|
||||
# the LZMA_XZ_SUPPORT line below.
|
||||
#
|
||||
# To build using the LZMA SDK (4.65 used in development, other versions may
|
||||
# work) - download and unpack it, uncomment and set LZMA_DIR to unpacked source,
|
||||
# and uncomment the LZMA_SUPPORT line below.
|
||||
#
|
||||
LZMA_XZ_SUPPORT = 1
|
||||
#LZMA_SUPPORT = 1
|
||||
#LZMA_DIR = ../../../../LZMA/lzma465
|
||||
|
||||
###############################################
|
||||
# End of BUILD options section #
|
||||
###############################################
|
||||
|
||||
INCLUDEDIR = -I.
|
||||
INSTALL_DIR = /usr/local/bin
|
||||
|
||||
MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
|
||||
sort.o progressbar.o read_file.o info.o restore.o process_fragments.o \
|
||||
caches-queues-lists.o
|
||||
|
||||
UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
|
||||
unsquash-4.o unsquash-123.o unsquash-34.o swap.o compressor.o unsquashfs_info.o
|
||||
|
||||
CFLAGS ?= -Os
|
||||
CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
|
||||
-D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"$(COMP_DEFAULT)\" \
|
||||
-Wall
|
||||
|
||||
LIBS = -lpthread
|
||||
ifeq ($(GZIP_SUPPORT),1)
|
||||
CFLAGS += -DGZIP_SUPPORT
|
||||
MKSQUASHFS_OBJS += gzip_wrapper.o
|
||||
UNSQUASHFS_OBJS += gzip_wrapper.o
|
||||
LIBS += $(VTZLIB)
|
||||
COMPRESSORS += gzip
|
||||
endif
|
||||
|
||||
ifeq ($(LZMA_SUPPORT),1)
|
||||
LZMA_OBJS = $(LZMA_DIR)/C/Alloc.o $(LZMA_DIR)/C/LzFind.o \
|
||||
$(LZMA_DIR)/C/LzmaDec.o $(LZMA_DIR)/C/LzmaEnc.o $(LZMA_DIR)/C/LzmaLib.o
|
||||
INCLUDEDIR += -I$(LZMA_DIR)/C
|
||||
CFLAGS += -DLZMA_SUPPORT
|
||||
MKSQUASHFS_OBJS += lzma_wrapper.o $(LZMA_OBJS)
|
||||
UNSQUASHFS_OBJS += lzma_wrapper.o $(LZMA_OBJS)
|
||||
COMPRESSORS += lzma
|
||||
endif
|
||||
|
||||
ifeq ($(LZMA_XZ_SUPPORT),1)
|
||||
CFLAGS += -DLZMA_SUPPORT
|
||||
MKSQUASHFS_OBJS += lzma_xz_wrapper.o
|
||||
UNSQUASHFS_OBJS += lzma_xz_wrapper.o
|
||||
LIBS +=
|
||||
COMPRESSORS += lzma
|
||||
endif
|
||||
|
||||
ifeq ($(XZ_SUPPORT),1)
|
||||
CFLAGS += -DXZ_SUPPORT -I$(LZMA_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += xz_wrapper.o
|
||||
UNSQUASHFS_OBJS += xz_wrapper.o
|
||||
LIBS += $(LZMA_LIBDIR)/lib/liblzma.a
|
||||
COMPRESSORS += xz
|
||||
endif
|
||||
|
||||
ifeq ($(LZO_SUPPORT),1)
|
||||
CFLAGS += -DLZO_SUPPORT -I $(LZO_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += lzo_wrapper.o
|
||||
UNSQUASHFS_OBJS += lzo_wrapper.o
|
||||
LIBS += $(LZO_LIBDIR)/lib/liblzo2.a
|
||||
COMPRESSORS += lzo
|
||||
endif
|
||||
|
||||
ifeq ($(LZ4_SUPPORT),1)
|
||||
CFLAGS += -DLZ4_SUPPORT -I $(LZ4_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += lz4_wrapper.o
|
||||
UNSQUASHFS_OBJS += lz4_wrapper.o
|
||||
LIBS += $(LZ4_LIBDIR)/lib/liblz4.a
|
||||
COMPRESSORS += lz4
|
||||
endif
|
||||
|
||||
ifeq ($(ZSTD_SUPPORT),1)
|
||||
CFLAGS += -DZSTD_SUPPORT -I $(ZSTD_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += zstd_wrapper.o
|
||||
UNSQUASHFS_OBJS += zstd_wrapper.o
|
||||
LIBS += $(ZSTD_LIBDIR)/lib/libzstd.a
|
||||
COMPRESSORS += zstd
|
||||
endif
|
||||
|
||||
ifeq ($(XATTR_SUPPORT),1)
|
||||
ifeq ($(XATTR_DEFAULT),1)
|
||||
CFLAGS += -DXATTR_SUPPORT -DXATTR_DEFAULT
|
||||
else
|
||||
CFLAGS += -DXATTR_SUPPORT
|
||||
endif
|
||||
MKSQUASHFS_OBJS += xattr.o read_xattrs.o
|
||||
UNSQUASHFS_OBJS += read_xattrs.o unsquashfs_xattr.o
|
||||
endif
|
||||
|
||||
ifeq ($(REPRODUCIBLE_DEFAULT),1)
|
||||
CFLAGS += -DREPRODUCIBLE_DEFAULT
|
||||
endif
|
||||
|
||||
#
|
||||
# If LZMA_SUPPORT is specified then LZMA_DIR must be specified too
|
||||
#
|
||||
ifeq ($(LZMA_SUPPORT),1)
|
||||
ifndef LZMA_DIR
|
||||
$(error "LZMA_SUPPORT requires LZMA_DIR to be also defined")
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Both LZMA_XZ_SUPPORT and LZMA_SUPPORT cannot be specified
|
||||
#
|
||||
ifeq ($(LZMA_XZ_SUPPORT),1)
|
||||
ifeq ($(LZMA_SUPPORT),1)
|
||||
$(error "Both LZMA_XZ_SUPPORT and LZMA_SUPPORT cannot be specified")
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# At least one compressor must have been selected
|
||||
#
|
||||
ifndef COMPRESSORS
|
||||
$(error "No compressor selected! Select one or more of GZIP, LZMA, XZ, LZO, \
|
||||
LZ4 or ZSTD!")
|
||||
endif
|
||||
|
||||
#
|
||||
# COMP_DEFAULT should be defined
|
||||
#
|
||||
ifndef COMP_DEFAULT
|
||||
$(error "COMP_DEFAULT must be set to a compressor!")
|
||||
endif
|
||||
|
||||
#
|
||||
# COMP_DEFAULT must be a selected compressor
|
||||
#
|
||||
ifeq (, $(findstring $(COMP_DEFAULT), $(COMPRESSORS)))
|
||||
$(error "COMP_DEFAULT is set to ${COMP_DEFAULT}, which isn't selected to be \
|
||||
built!")
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: mksquashfs unsquashfs
|
||||
|
||||
mksquashfs: $(MKSQUASHFS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(MKSQUASHFS_OBJS) $(LIBS) -o $@
|
||||
|
||||
mksquashfs.o: Makefile mksquashfs.c squashfs_fs.h squashfs_swap.h mksquashfs.h \
|
||||
sort.h pseudo.h compressor.h xattr.h action.h error.h progressbar.h \
|
||||
info.h caches-queues-lists.h read_fs.h restore.h process_fragments.h
|
||||
|
||||
read_fs.o: read_fs.c squashfs_fs.h squashfs_swap.h compressor.h xattr.h \
|
||||
error.h mksquashfs.h
|
||||
|
||||
sort.o: sort.c squashfs_fs.h mksquashfs.h sort.h error.h progressbar.h
|
||||
|
||||
swap.o: swap.c
|
||||
|
||||
pseudo.o: pseudo.c pseudo.h error.h progressbar.h
|
||||
|
||||
compressor.o: Makefile compressor.c compressor.h squashfs_fs.h
|
||||
|
||||
xattr.o: xattr.c squashfs_fs.h squashfs_swap.h mksquashfs.h xattr.h error.h \
|
||||
progressbar.h
|
||||
|
||||
read_xattrs.o: read_xattrs.c squashfs_fs.h squashfs_swap.h xattr.h error.h
|
||||
|
||||
action.o: action.c squashfs_fs.h mksquashfs.h action.h error.h
|
||||
|
||||
progressbar.o: progressbar.c error.h
|
||||
|
||||
read_file.o: read_file.c error.h
|
||||
|
||||
info.o: info.c squashfs_fs.h mksquashfs.h error.h progressbar.h \
|
||||
caches-queues-lists.h
|
||||
|
||||
restore.o: restore.c caches-queues-lists.h squashfs_fs.h mksquashfs.h error.h \
|
||||
progressbar.h info.h
|
||||
|
||||
process_fragments.o: process_fragments.c process_fragments.h
|
||||
|
||||
caches-queues-lists.o: caches-queues-lists.c error.h caches-queues-lists.h
|
||||
|
||||
gzip_wrapper.o: gzip_wrapper.c squashfs_fs.h gzip_wrapper.h compressor.h
|
||||
|
||||
lzma_wrapper.o: lzma_wrapper.c compressor.h squashfs_fs.h
|
||||
|
||||
lzma_xz_wrapper.o: lzma_xz_wrapper.c compressor.h squashfs_fs.h
|
||||
|
||||
lzo_wrapper.o: lzo_wrapper.c squashfs_fs.h lzo_wrapper.h compressor.h
|
||||
|
||||
lz4_wrapper.o: lz4_wrapper.c squashfs_fs.h lz4_wrapper.h compressor.h
|
||||
|
||||
xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
|
||||
|
||||
unsquashfs: $(UNSQUASHFS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
|
||||
|
||||
unsquashfs.o: unsquashfs.h unsquashfs.c squashfs_fs.h squashfs_swap.h \
|
||||
squashfs_compat.h xattr.h read_fs.h compressor.h
|
||||
|
||||
unsquash-1.o: unsquashfs.h unsquash-1.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-2.o: unsquashfs.h unsquash-2.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-3.o: unsquashfs.h unsquash-3.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-4.o: unsquashfs.h unsquash-4.c squashfs_fs.h squashfs_swap.h \
|
||||
read_fs.h
|
||||
|
||||
unsquash-123.o: unsquashfs.h unsquash-123.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-34.o: unsquashfs.h unsquash-34.c
|
||||
|
||||
unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h
|
||||
|
||||
unsquashfs_info.o: unsquashfs.h squashfs_fs.h
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -f *.o mksquashfs unsquashfs
|
||||
|
||||
.PHONY: install
|
||||
install: mksquashfs unsquashfs
|
||||
mkdir -p $(INSTALL_DIR)
|
||||
cp mksquashfs $(INSTALL_DIR)
|
||||
cp unsquashfs $(INSTALL_DIR)
|
||||
3266
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.c
Normal file
3266
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.c
Normal file
File diff suppressed because it is too large
Load Diff
328
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.h
Normal file
328
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.h
Normal file
@@ -0,0 +1,328 @@
|
||||
#ifndef ACTION_H
|
||||
#define ACTION_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* action.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lexical analyser definitions
|
||||
*/
|
||||
#define TOK_OPEN_BRACKET 0
|
||||
#define TOK_CLOSE_BRACKET 1
|
||||
#define TOK_AND 2
|
||||
#define TOK_OR 3
|
||||
#define TOK_NOT 4
|
||||
#define TOK_COMMA 5
|
||||
#define TOK_AT 6
|
||||
#define TOK_WHITE_SPACE 7
|
||||
#define TOK_STRING 8
|
||||
#define TOK_EOF 9
|
||||
|
||||
#define TOK_TO_STR(OP, S) ({ \
|
||||
char *s; \
|
||||
switch(OP) { \
|
||||
case TOK_EOF: \
|
||||
s = "EOF"; \
|
||||
break; \
|
||||
case TOK_STRING: \
|
||||
s = S; \
|
||||
break; \
|
||||
default: \
|
||||
s = token_table[OP].string; \
|
||||
break; \
|
||||
} \
|
||||
s; \
|
||||
})
|
||||
|
||||
|
||||
struct token_entry {
|
||||
char *string;
|
||||
int token;
|
||||
int size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Expression parser definitions
|
||||
*/
|
||||
#define OP_TYPE 0
|
||||
#define ATOM_TYPE 1
|
||||
#define UNARY_TYPE 2
|
||||
|
||||
#define SYNTAX_ERROR(S, ARGS...) { \
|
||||
char *src = strdup(source); \
|
||||
src[cur_ptr - source] = '\0'; \
|
||||
fprintf(stderr, "Failed to parse action \"%s\"\n", source); \
|
||||
fprintf(stderr, "Syntax error: "S, ##ARGS); \
|
||||
fprintf(stderr, "Got here \"%s\"\n", src); \
|
||||
free(src); \
|
||||
}
|
||||
|
||||
#define TEST_SYNTAX_ERROR(TEST, ARG, S, ARGS...) { \
|
||||
char *src = strdup(source); \
|
||||
src[cur_ptr - source] = '\0'; \
|
||||
fprintf(stderr, "Failed to parse action \"%s\"\n", source); \
|
||||
fprintf(stderr, "Syntax error in \"%s()\", arg %d: "S, TEST->name, \
|
||||
ARG, ##ARGS); \
|
||||
fprintf(stderr, "Got here \"%s\"\n", src); \
|
||||
free(src); \
|
||||
}
|
||||
|
||||
struct expr;
|
||||
|
||||
struct expr_op {
|
||||
struct expr *lhs;
|
||||
struct expr *rhs;
|
||||
int op;
|
||||
};
|
||||
|
||||
|
||||
struct atom {
|
||||
struct test_entry *test;
|
||||
int args;
|
||||
char **argv;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
struct unary_op {
|
||||
struct expr *expr;
|
||||
int op;
|
||||
};
|
||||
|
||||
|
||||
struct expr {
|
||||
int type;
|
||||
union {
|
||||
struct atom atom;
|
||||
struct expr_op expr_op;
|
||||
struct unary_op unary_op;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Test operation definitions
|
||||
*/
|
||||
#define NUM_EQ 1
|
||||
#define NUM_LESS 2
|
||||
#define NUM_GREATER 3
|
||||
|
||||
struct test_number_arg {
|
||||
long long size;
|
||||
int range;
|
||||
};
|
||||
|
||||
struct test_range_args {
|
||||
long long start;
|
||||
long long end;
|
||||
};
|
||||
|
||||
struct action;
|
||||
struct action_data;
|
||||
|
||||
struct test_entry {
|
||||
char *name;
|
||||
int args;
|
||||
int (*fn)(struct atom *, struct action_data *);
|
||||
int (*parse_args)(struct test_entry *, struct atom *);
|
||||
int exclude_ok;
|
||||
int handle_logging;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Type test specific definitions
|
||||
*/
|
||||
struct type_entry {
|
||||
int value;
|
||||
char type;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Action definitions
|
||||
*/
|
||||
#define FRAGMENT_ACTION 0
|
||||
#define EXCLUDE_ACTION 1
|
||||
#define FRAGMENTS_ACTION 2
|
||||
#define NO_FRAGMENTS_ACTION 3
|
||||
#define ALWAYS_FRAGS_ACTION 4
|
||||
#define NO_ALWAYS_FRAGS_ACTION 5
|
||||
#define COMPRESSED_ACTION 6
|
||||
#define UNCOMPRESSED_ACTION 7
|
||||
#define UID_ACTION 8
|
||||
#define GID_ACTION 9
|
||||
#define GUID_ACTION 10
|
||||
#define MODE_ACTION 11
|
||||
#define EMPTY_ACTION 12
|
||||
#define MOVE_ACTION 13
|
||||
#define PRUNE_ACTION 14
|
||||
#define NOOP_ACTION 15
|
||||
|
||||
/*
|
||||
* Define what file types each action operates over
|
||||
*/
|
||||
#define ACTION_DIR 1
|
||||
#define ACTION_REG 2
|
||||
#define ACTION_ALL_LNK 3
|
||||
#define ACTION_ALL 4
|
||||
#define ACTION_LNK 5
|
||||
|
||||
|
||||
/*
|
||||
* Action logging requested, specified by the various
|
||||
* -action, -true-action, -false-action and -verbose-action
|
||||
* options
|
||||
*/
|
||||
#define ACTION_LOG_NONE 0
|
||||
#define ACTION_LOG_TRUE 1
|
||||
#define ACTION_LOG_FALSE 2
|
||||
#define ACTION_LOG_VERBOSE ACTION_LOG_TRUE | ACTION_LOG_FALSE
|
||||
|
||||
struct action_entry {
|
||||
char *name;
|
||||
int type;
|
||||
int args;
|
||||
int file_types;
|
||||
int (*parse_args)(struct action_entry *, int, char **, void **);
|
||||
void (*run_action)(struct action *, struct dir_ent *);
|
||||
};
|
||||
|
||||
|
||||
struct action_data {
|
||||
int depth;
|
||||
char *name;
|
||||
char *pathname;
|
||||
char *subpath;
|
||||
struct stat *buf;
|
||||
struct dir_ent *dir_ent;
|
||||
struct dir_info *root;
|
||||
};
|
||||
|
||||
|
||||
struct action {
|
||||
int type;
|
||||
struct action_entry *action;
|
||||
int args;
|
||||
char **argv;
|
||||
struct expr *expr;
|
||||
void *data;
|
||||
int verbose;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Uid/gid action specific definitions
|
||||
*/
|
||||
struct uid_info {
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
struct gid_info {
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
struct guid_info {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Mode action specific definitions
|
||||
*/
|
||||
#define ACTION_MODE_SET 0
|
||||
#define ACTION_MODE_ADD 1
|
||||
#define ACTION_MODE_REM 2
|
||||
#define ACTION_MODE_OCT 3
|
||||
|
||||
struct mode_data {
|
||||
struct mode_data *next;
|
||||
int operation;
|
||||
int mode;
|
||||
unsigned int mask;
|
||||
char X;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Empty action specific definitions
|
||||
*/
|
||||
#define EMPTY_ALL 0
|
||||
#define EMPTY_SOURCE 1
|
||||
#define EMPTY_EXCLUDED 2
|
||||
|
||||
struct empty_data {
|
||||
int val;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Move action specific definitions
|
||||
*/
|
||||
#define ACTION_MOVE_RENAME 1
|
||||
#define ACTION_MOVE_MOVE 2
|
||||
|
||||
struct move_ent {
|
||||
int ops;
|
||||
struct dir_ent *dir_ent;
|
||||
char *name;
|
||||
struct dir_info *dest;
|
||||
struct move_ent *next;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Perm test function specific definitions
|
||||
*/
|
||||
#define PERM_ALL 1
|
||||
#define PERM_ANY 2
|
||||
#define PERM_EXACT 3
|
||||
|
||||
struct perm_data {
|
||||
int op;
|
||||
int mode;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* External function definitions
|
||||
*/
|
||||
extern int parse_action(char *, int verbose);
|
||||
extern void dump_actions();
|
||||
extern void *eval_frag_actions(struct dir_info *, struct dir_ent *);
|
||||
extern void *get_frag_action(void *);
|
||||
extern int eval_exclude_actions(char *, char *, char *, struct stat *, int,
|
||||
struct dir_ent *);
|
||||
extern void eval_actions(struct dir_info *, struct dir_ent *);
|
||||
extern int eval_empty_actions(struct dir_info *, struct dir_ent *dir_ent);
|
||||
extern void eval_move_actions(struct dir_info *, struct dir_ent *);
|
||||
extern int eval_prune_actions(struct dir_info *, struct dir_ent *);
|
||||
extern void do_move_actions();
|
||||
extern int read_bytes(int, void *, int);
|
||||
extern int actions();
|
||||
extern int move_actions();
|
||||
extern int empty_actions();
|
||||
extern int read_action_file(char *, int);
|
||||
extern int exclude_actions();
|
||||
extern int prune_actions();
|
||||
#endif
|
||||
35
SQUASHFS/squashfs-tools-4.4/squashfs-tools/build.sh
Normal file
35
SQUASHFS/squashfs-tools-4.4/squashfs-tools/build.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LZMA_LIBDIR=$PWD/../../LIB/LZMA
|
||||
export LZ4_LIBDIR=$PWD/../../LIB/LZ4
|
||||
export ZSTD_LIBDIR=$PWD/../../LIB/ZSTD
|
||||
export LZO_LIBDIR=$PWD/../../LIB/LZO
|
||||
|
||||
if [ -e /lib64/libz.a ]; then
|
||||
export VTZLIB=/lib64/libz.a
|
||||
elif [ -e /lib/libz.a ]; then
|
||||
export VTZLIB=/lib/libz.a
|
||||
elif [ -e /usr/lib/libz.a ]; then
|
||||
export VTZLIB=/usr/lib/libz.a
|
||||
fi
|
||||
|
||||
rm -f unsquashfs
|
||||
make clean
|
||||
make -e unsquashfs
|
||||
|
||||
if [ -e unsquashfs ]; then
|
||||
strip --strip-all unsquashfs
|
||||
echo -e "\n========== SUCCESS ============\n"
|
||||
else
|
||||
echo -e "\n========== FAILED ============\n"
|
||||
fi
|
||||
|
||||
if uname -a | egrep -q 'x86_64|amd64'; then
|
||||
name=unsquashfs_64
|
||||
else
|
||||
name=unsquashfs_32
|
||||
fi
|
||||
|
||||
rm -f ../../$name
|
||||
cp -a unsquashfs ../../$name
|
||||
|
||||
642
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.c
Normal file
642
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.c
Normal file
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* caches-queues-lists.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "caches-queues-lists.h"
|
||||
|
||||
extern int add_overflow(int, int);
|
||||
extern int multiply_overflow(int, int);
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
struct queue *queue_init(int size)
|
||||
{
|
||||
struct queue *queue = malloc(sizeof(struct queue));
|
||||
|
||||
if(queue == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
if(add_overflow(size, 1) ||
|
||||
multiply_overflow(size + 1, sizeof(void *)))
|
||||
BAD_ERROR("Size too large in queue_init\n");
|
||||
|
||||
queue->data = malloc(sizeof(void *) * (size + 1));
|
||||
if(queue->data == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
queue->size = size + 1;
|
||||
queue->readp = queue->writep = 0;
|
||||
pthread_mutex_init(&queue->mutex, NULL);
|
||||
pthread_cond_init(&queue->empty, NULL);
|
||||
pthread_cond_init(&queue->full, NULL);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
||||
void queue_put(struct queue *queue, void *data)
|
||||
{
|
||||
int nextp;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
|
||||
pthread_cond_wait(&queue->full, &queue->mutex);
|
||||
|
||||
queue->data[queue->writep] = data;
|
||||
queue->writep = nextp;
|
||||
pthread_cond_signal(&queue->empty);
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void *queue_get(struct queue *queue)
|
||||
{
|
||||
void *data;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
while(queue->readp == queue->writep)
|
||||
pthread_cond_wait(&queue->empty, &queue->mutex);
|
||||
|
||||
data = queue->data[queue->readp];
|
||||
queue->readp = (queue->readp + 1) % queue->size;
|
||||
pthread_cond_signal(&queue->full);
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
int queue_empty(struct queue *queue)
|
||||
{
|
||||
int empty;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
empty = queue->readp == queue->writep;
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
void queue_flush(struct queue *queue)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
queue->readp = queue->writep;
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void dump_queue(struct queue *queue)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
printf("\tMax size %d, size %d%s\n", queue->size - 1,
|
||||
queue->readp <= queue->writep ? queue->writep - queue->readp :
|
||||
queue->size - queue->readp + queue->writep,
|
||||
queue->readp == queue->writep ? " (EMPTY)" :
|
||||
((queue->writep + 1) % queue->size) == queue->readp ?
|
||||
" (FULL)" : "");
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
/* define seq queue hash tables */
|
||||
#define CALCULATE_SEQ_HASH(N) CALCULATE_HASH(N)
|
||||
|
||||
/* Called with the seq queue mutex held */
|
||||
INSERT_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq)
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
REMOVE_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq);
|
||||
|
||||
|
||||
struct seq_queue *seq_queue_init()
|
||||
{
|
||||
struct seq_queue *queue = malloc(sizeof(struct seq_queue));
|
||||
if(queue == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memset(queue, 0, sizeof(struct seq_queue));
|
||||
|
||||
pthread_mutex_init(&queue->mutex, NULL);
|
||||
pthread_cond_init(&queue->wait, NULL);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
||||
void seq_queue_put(struct seq_queue *queue, struct file_buffer *entry)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
insert_seq_hash_table(queue, entry);
|
||||
|
||||
if(entry->fragment)
|
||||
queue->fragment_count ++;
|
||||
else
|
||||
queue->block_count ++;
|
||||
|
||||
if(entry->sequence == queue->sequence)
|
||||
pthread_cond_signal(&queue->wait);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *seq_queue_get(struct seq_queue *queue)
|
||||
{
|
||||
/*
|
||||
* Return next buffer from queue in sequence order (queue->sequence). If
|
||||
* found return it, otherwise wait for it to arrive.
|
||||
*/
|
||||
int hash = CALCULATE_SEQ_HASH(queue->sequence);
|
||||
struct file_buffer *entry;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
while(1) {
|
||||
for(entry = queue->hash_table[hash]; entry;
|
||||
entry = entry->seq_next)
|
||||
if(entry->sequence == queue->sequence)
|
||||
break;
|
||||
|
||||
if(entry) {
|
||||
/*
|
||||
* found the buffer in the queue, decrement the
|
||||
* appropriate count, and remove from hash list
|
||||
*/
|
||||
if(entry->fragment)
|
||||
queue->fragment_count --;
|
||||
else
|
||||
queue->block_count --;
|
||||
|
||||
remove_seq_hash_table(queue, entry);
|
||||
|
||||
queue->sequence ++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* entry not found, wait for it to arrive */
|
||||
pthread_cond_wait(&queue->wait, &queue->mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
void seq_queue_flush(struct seq_queue *queue)
|
||||
{
|
||||
int i;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
for(i = 0; i < HASH_SIZE; i++)
|
||||
queue->hash_table[i] = NULL;
|
||||
|
||||
queue->fragment_count = queue->block_count = 0;
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void dump_seq_queue(struct seq_queue *queue, int fragment_queue)
|
||||
{
|
||||
int size;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
size = fragment_queue ? queue->fragment_count : queue->block_count;
|
||||
|
||||
printf("\tMax size unlimited, size %d%s\n", size,
|
||||
size == 0 ? " (EMPTY)" : "");
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
/* define cache hash tables */
|
||||
#define CALCULATE_CACHE_HASH(N) CALCULATE_HASH(llabs(N))
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
INSERT_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash)
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
REMOVE_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash);
|
||||
|
||||
/* define cache free list */
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
INSERT_LIST(free, struct file_buffer)
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
REMOVE_LIST(free, struct file_buffer)
|
||||
|
||||
|
||||
struct cache *cache_init(int buffer_size, int max_buffers, int noshrink_lookup,
|
||||
int first_freelist)
|
||||
{
|
||||
struct cache *cache = malloc(sizeof(struct cache));
|
||||
|
||||
if(cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
cache->max_buffers = max_buffers;
|
||||
cache->buffer_size = buffer_size;
|
||||
cache->count = 0;
|
||||
cache->used = 0;
|
||||
cache->free_list = NULL;
|
||||
|
||||
/*
|
||||
* The cache will grow up to max_buffers in size in response to
|
||||
* an increase in readhead/number of buffers in flight. But
|
||||
* once the outstanding buffers gets returned, we can either elect
|
||||
* to shrink the cache, or to put the freed blocks onto a free list.
|
||||
*
|
||||
* For the caches where we want to do lookup (fragment/writer),
|
||||
* a don't shrink policy is best, for the reader cache it
|
||||
* makes no sense to keep buffers around longer than necessary as
|
||||
* we don't do any lookup on those blocks.
|
||||
*/
|
||||
cache->noshrink_lookup = noshrink_lookup;
|
||||
|
||||
/*
|
||||
* The default use freelist before growing cache policy behaves
|
||||
* poorly with appending - with many duplicates the caches
|
||||
* do not grow due to the fact that large queues of outstanding
|
||||
* fragments/writer blocks do not occur, leading to small caches
|
||||
* and un-uncessary performance loss to frequent cache
|
||||
* replacement in the small caches. Therefore with appending
|
||||
* change the policy to grow the caches before reusing blocks
|
||||
* from the freelist
|
||||
*/
|
||||
cache->first_freelist = first_freelist;
|
||||
|
||||
memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
|
||||
pthread_mutex_init(&cache->mutex, NULL);
|
||||
pthread_cond_init(&cache->wait_for_free, NULL);
|
||||
pthread_cond_init(&cache->wait_for_unlock, NULL);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_lookup(struct cache *cache, long long index)
|
||||
{
|
||||
/* Lookup block in the cache, if found return with usage count
|
||||
* incremented, if not found return NULL */
|
||||
int hash = CALCULATE_CACHE_HASH(index);
|
||||
struct file_buffer *entry;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
|
||||
if(entry->index == index)
|
||||
break;
|
||||
|
||||
if(entry) {
|
||||
/* found the block in the cache, increment used count and
|
||||
* if necessary remove from free list so it won't disappear
|
||||
*/
|
||||
if(entry->used == 0) {
|
||||
remove_free_list(&cache->free_list, entry);
|
||||
cache->used ++;
|
||||
}
|
||||
entry->used ++;
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *cache_freelist(struct cache *cache)
|
||||
{
|
||||
struct file_buffer *entry = cache->free_list;
|
||||
|
||||
remove_free_list(&cache->free_list, entry);
|
||||
|
||||
/* a block on the free_list is hashed */
|
||||
remove_cache_hash_table(cache, entry);
|
||||
|
||||
cache->used ++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *cache_alloc(struct cache *cache)
|
||||
{
|
||||
struct file_buffer *entry = malloc(sizeof(struct file_buffer) +
|
||||
cache->buffer_size);
|
||||
if(entry == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
entry->cache = cache;
|
||||
entry->free_prev = entry->free_next = NULL;
|
||||
cache->count ++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *_cache_get(struct cache *cache, long long index,
|
||||
int hash)
|
||||
{
|
||||
/* Get a free block out of the cache indexed on index. */
|
||||
struct file_buffer *entry = NULL;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
while(1) {
|
||||
if(cache->noshrink_lookup) {
|
||||
/* first try to get a block from the free list */
|
||||
if(cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
else if(cache->count < cache->max_buffers) {
|
||||
entry = cache_alloc(cache);
|
||||
cache->used ++;
|
||||
} else if(!cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
} else { /* shrinking non-lookup cache */
|
||||
if(cache->count < cache->max_buffers) {
|
||||
entry = cache_alloc(cache);
|
||||
if(cache->count > cache->max_count)
|
||||
cache->max_count = cache->count;
|
||||
}
|
||||
}
|
||||
|
||||
if(entry)
|
||||
break;
|
||||
|
||||
/* wait for a block */
|
||||
pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
|
||||
}
|
||||
|
||||
/* initialise block and if hash is set insert into the hash table */
|
||||
entry->used = 1;
|
||||
entry->locked = FALSE;
|
||||
entry->wait_on_unlock = FALSE;
|
||||
entry->error = FALSE;
|
||||
if(hash) {
|
||||
entry->index = index;
|
||||
insert_cache_hash_table(cache, entry);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_get(struct cache *cache, long long index)
|
||||
{
|
||||
return _cache_get(cache, index, 1);
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_get_nohash(struct cache *cache)
|
||||
{
|
||||
return _cache_get(cache, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void cache_hash(struct file_buffer *entry, long long index)
|
||||
{
|
||||
struct cache *cache = entry->cache;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
entry->index = index;
|
||||
insert_cache_hash_table(cache, entry);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void cache_block_put(struct file_buffer *entry)
|
||||
{
|
||||
struct cache *cache;
|
||||
|
||||
/*
|
||||
* Finished with this cache entry, once the usage count reaches zero it
|
||||
* can be reused.
|
||||
*
|
||||
* If noshrink_lookup is set, put the block onto the free list.
|
||||
* As blocks remain accessible via the hash table they can be found
|
||||
* getting a new lease of life before they are reused.
|
||||
*
|
||||
* if noshrink_lookup is not set then shrink the cache.
|
||||
*/
|
||||
|
||||
if(entry == NULL)
|
||||
return;
|
||||
|
||||
cache = entry->cache;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
entry->used --;
|
||||
if(entry->used == 0) {
|
||||
if(cache->noshrink_lookup) {
|
||||
insert_free_list(&cache->free_list, entry);
|
||||
cache->used --;
|
||||
} else {
|
||||
free(entry);
|
||||
cache->count --;
|
||||
}
|
||||
|
||||
/* One or more threads may be waiting on this block */
|
||||
pthread_cond_signal(&cache->wait_for_free);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void dump_cache(struct cache *cache)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
if(cache->noshrink_lookup)
|
||||
printf("\tMax buffers %d, Current size %d, Used %d, %s\n",
|
||||
cache->max_buffers, cache->count, cache->used,
|
||||
cache->free_list ? "Free buffers" : "No free buffers");
|
||||
else
|
||||
printf("\tMax buffers %d, Current size %d, Maximum historical "
|
||||
"size %d\n", cache->max_buffers, cache->count,
|
||||
cache->max_count);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_get_nowait(struct cache *cache, long long index)
|
||||
{
|
||||
struct file_buffer *entry = NULL;
|
||||
/*
|
||||
* block doesn't exist, create it, but return it with the
|
||||
* locked flag set, so nothing tries to use it while it doesn't
|
||||
* contain data.
|
||||
*
|
||||
* If there's no space in the cache then return NULL.
|
||||
*/
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
/* first try to get a block from the free list */
|
||||
if(cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
else if(cache->count < cache->max_buffers) {
|
||||
entry = cache_alloc(cache);
|
||||
cache->used ++;
|
||||
} else if(!cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
|
||||
if(entry) {
|
||||
/* initialise block and insert into the hash table */
|
||||
entry->used = 1;
|
||||
entry->locked = TRUE;
|
||||
entry->wait_on_unlock = FALSE;
|
||||
entry->error = FALSE;
|
||||
entry->index = index;
|
||||
insert_cache_hash_table(cache, entry);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_lookup_nowait(struct cache *cache, long long index,
|
||||
char *locked)
|
||||
{
|
||||
/*
|
||||
* Lookup block in the cache, if found return it with the locked flag
|
||||
* indicating whether it is currently locked. In both cases increment
|
||||
* the used count.
|
||||
*
|
||||
* If it doesn't exist in the cache return NULL;
|
||||
*/
|
||||
int hash = CALCULATE_CACHE_HASH(index);
|
||||
struct file_buffer *entry;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
/* first check if the entry already exists */
|
||||
for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
|
||||
if(entry->index == index)
|
||||
break;
|
||||
|
||||
if(entry) {
|
||||
if(entry->used == 0) {
|
||||
remove_free_list(&cache->free_list, entry);
|
||||
cache->used ++;
|
||||
}
|
||||
entry->used ++;
|
||||
*locked = entry->locked;
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
void cache_wait_unlock(struct file_buffer *buffer)
|
||||
{
|
||||
struct cache *cache = buffer->cache;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
while(buffer->locked) {
|
||||
/*
|
||||
* another thread is filling this in, wait until it
|
||||
* becomes unlocked. Used has been incremented to ensure it
|
||||
* doesn't get reused. By definition a block can't be
|
||||
* locked and unused, and so we don't need to worry
|
||||
* about it being on the freelist now, but, it may
|
||||
* become unused when unlocked unless used is
|
||||
* incremented
|
||||
*/
|
||||
buffer->wait_on_unlock = TRUE;
|
||||
pthread_cond_wait(&cache->wait_for_unlock, &cache->mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void cache_unlock(struct file_buffer *entry)
|
||||
{
|
||||
struct cache *cache = entry->cache;
|
||||
|
||||
/*
|
||||
* Unlock this locked cache entry. If anything is waiting for this
|
||||
* to become unlocked, wake it up.
|
||||
*/
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
entry->locked = FALSE;
|
||||
|
||||
if(entry->wait_on_unlock) {
|
||||
entry->wait_on_unlock = FALSE;
|
||||
pthread_cond_broadcast(&cache->wait_for_unlock);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
199
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.h
Normal file
199
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.h
Normal file
@@ -0,0 +1,199 @@
|
||||
#ifndef CACHES_QUEUES_LISTS_H
|
||||
#define CACHES_QUEUES_LISTS_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* caches-queues-lists.h
|
||||
*/
|
||||
|
||||
#define INSERT_LIST(NAME, TYPE) \
|
||||
void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
|
||||
if(*list) { \
|
||||
entry->NAME##_next = *list; \
|
||||
entry->NAME##_prev = (*list)->NAME##_prev; \
|
||||
(*list)->NAME##_prev->NAME##_next = entry; \
|
||||
(*list)->NAME##_prev = entry; \
|
||||
} else { \
|
||||
*list = entry; \
|
||||
entry->NAME##_prev = entry->NAME##_next = entry; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define REMOVE_LIST(NAME, TYPE) \
|
||||
void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
|
||||
if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
|
||||
/* only this entry in the list */ \
|
||||
*list = NULL; \
|
||||
} else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
|
||||
/* more than one entry in the list */ \
|
||||
entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
|
||||
entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
|
||||
if(*list == entry) \
|
||||
*list = entry->NAME##_next; \
|
||||
} \
|
||||
entry->NAME##_prev = entry->NAME##_next = NULL; \
|
||||
}
|
||||
|
||||
|
||||
#define INSERT_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
|
||||
void insert_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
|
||||
{ \
|
||||
int hash = HASH_FUNCTION(entry->FIELD); \
|
||||
\
|
||||
entry->LINK##_next = container->hash_table[hash]; \
|
||||
container->hash_table[hash] = entry; \
|
||||
entry->LINK##_prev = NULL; \
|
||||
if(entry->LINK##_next) \
|
||||
entry->LINK##_next->LINK##_prev = entry; \
|
||||
}
|
||||
|
||||
|
||||
#define REMOVE_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
|
||||
void remove_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
|
||||
{ \
|
||||
if(entry->LINK##_prev) \
|
||||
entry->LINK##_prev->LINK##_next = entry->LINK##_next; \
|
||||
else \
|
||||
container->hash_table[HASH_FUNCTION(entry->FIELD)] = \
|
||||
entry->LINK##_next; \
|
||||
if(entry->LINK##_next) \
|
||||
entry->LINK##_next->LINK##_prev = entry->LINK##_prev; \
|
||||
\
|
||||
entry->LINK##_prev = entry->LINK##_next = NULL; \
|
||||
}
|
||||
|
||||
#define HASH_SIZE 65536
|
||||
#define CALCULATE_HASH(n) ((n) & 0xffff)
|
||||
|
||||
|
||||
/* struct describing a cache entry passed between threads */
|
||||
struct file_buffer {
|
||||
long long index;
|
||||
long long sequence;
|
||||
long long file_size;
|
||||
union {
|
||||
long long block;
|
||||
unsigned short checksum;
|
||||
};
|
||||
struct cache *cache;
|
||||
union {
|
||||
struct file_info *dupl_start;
|
||||
struct file_buffer *hash_next;
|
||||
};
|
||||
union {
|
||||
int duplicate;
|
||||
struct file_buffer *hash_prev;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
struct file_buffer *free_next;
|
||||
struct file_buffer *free_prev;
|
||||
};
|
||||
struct {
|
||||
struct file_buffer *seq_next;
|
||||
struct file_buffer *seq_prev;
|
||||
};
|
||||
};
|
||||
int size;
|
||||
int c_byte;
|
||||
char used;
|
||||
char fragment;
|
||||
char error;
|
||||
char locked;
|
||||
char wait_on_unlock;
|
||||
char noD;
|
||||
char data[0] __attribute__((aligned));
|
||||
};
|
||||
|
||||
|
||||
/* struct describing queues used to pass data between threads */
|
||||
struct queue {
|
||||
int size;
|
||||
int readp;
|
||||
int writep;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t empty;
|
||||
pthread_cond_t full;
|
||||
void **data;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* struct describing seq_queues used to pass data between the read
|
||||
* thread and the deflate and main threads
|
||||
*/
|
||||
struct seq_queue {
|
||||
int fragment_count;
|
||||
int block_count;
|
||||
long long sequence;
|
||||
struct file_buffer *hash_table[HASH_SIZE];
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t wait;
|
||||
};
|
||||
|
||||
|
||||
/* Cache status struct. Caches are used to keep
|
||||
track of memory buffers passed between different threads */
|
||||
struct cache {
|
||||
int max_buffers;
|
||||
int count;
|
||||
int buffer_size;
|
||||
int noshrink_lookup;
|
||||
int first_freelist;
|
||||
union {
|
||||
int used;
|
||||
int max_count;
|
||||
};
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t wait_for_free;
|
||||
pthread_cond_t wait_for_unlock;
|
||||
struct file_buffer *free_list;
|
||||
struct file_buffer *hash_table[HASH_SIZE];
|
||||
};
|
||||
|
||||
|
||||
extern struct queue *queue_init(int);
|
||||
extern void queue_put(struct queue *, void *);
|
||||
extern void *queue_get(struct queue *);
|
||||
extern int queue_empty(struct queue *);
|
||||
extern void queue_flush(struct queue *);
|
||||
extern void dump_queue(struct queue *);
|
||||
extern struct seq_queue *seq_queue_init();
|
||||
extern void seq_queue_put(struct seq_queue *, struct file_buffer *);
|
||||
extern void dump_seq_queue(struct seq_queue *, int);
|
||||
extern struct file_buffer *seq_queue_get(struct seq_queue *);
|
||||
extern void seq_queue_flush(struct seq_queue *);
|
||||
extern struct cache *cache_init(int, int, int, int);
|
||||
extern struct file_buffer *cache_lookup(struct cache *, long long);
|
||||
extern struct file_buffer *cache_get(struct cache *, long long);
|
||||
extern struct file_buffer *cache_get_nohash(struct cache *);
|
||||
extern void cache_hash(struct file_buffer *, long long);
|
||||
extern void cache_block_put(struct file_buffer *);
|
||||
extern void dump_cache(struct cache *);
|
||||
extern struct file_buffer *cache_get_nowait(struct cache *, long long);
|
||||
extern struct file_buffer *cache_lookup_nowait(struct cache *, long long,
|
||||
char *);
|
||||
extern void cache_wait_unlock(struct file_buffer *);
|
||||
extern void cache_unlock(struct file_buffer *);
|
||||
|
||||
extern int first_freelist;
|
||||
#endif
|
||||
145
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.c
Normal file
145
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* compressor.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "compressor.h"
|
||||
#include "squashfs_fs.h"
|
||||
|
||||
#ifndef GZIP_SUPPORT
|
||||
static struct compressor gzip_comp_ops = {
|
||||
ZLIB_COMPRESSION, "gzip"
|
||||
};
|
||||
#else
|
||||
extern struct compressor gzip_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef LZMA_SUPPORT
|
||||
static struct compressor lzma_comp_ops = {
|
||||
LZMA_COMPRESSION, "lzma"
|
||||
};
|
||||
#else
|
||||
extern struct compressor lzma_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef LZO_SUPPORT
|
||||
static struct compressor lzo_comp_ops = {
|
||||
LZO_COMPRESSION, "lzo"
|
||||
};
|
||||
#else
|
||||
extern struct compressor lzo_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef LZ4_SUPPORT
|
||||
static struct compressor lz4_comp_ops = {
|
||||
LZ4_COMPRESSION, "lz4"
|
||||
};
|
||||
#else
|
||||
extern struct compressor lz4_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef XZ_SUPPORT
|
||||
static struct compressor xz_comp_ops = {
|
||||
XZ_COMPRESSION, "xz"
|
||||
};
|
||||
#else
|
||||
extern struct compressor xz_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_SUPPORT
|
||||
static struct compressor zstd_comp_ops = {
|
||||
ZSTD_COMPRESSION, "zstd"
|
||||
};
|
||||
#else
|
||||
extern struct compressor zstd_comp_ops;
|
||||
#endif
|
||||
|
||||
static struct compressor unknown_comp_ops = {
|
||||
0, "unknown"
|
||||
};
|
||||
|
||||
|
||||
struct compressor *compressor[] = {
|
||||
&gzip_comp_ops,
|
||||
&lzma_comp_ops,
|
||||
&lzo_comp_ops,
|
||||
&lz4_comp_ops,
|
||||
&xz_comp_ops,
|
||||
&zstd_comp_ops,
|
||||
&unknown_comp_ops
|
||||
};
|
||||
|
||||
|
||||
struct compressor *lookup_compressor(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(strcmp(compressor[i]->name, name) == 0)
|
||||
break;
|
||||
|
||||
return compressor[i];
|
||||
}
|
||||
|
||||
|
||||
struct compressor *lookup_compressor_id(int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(id == compressor[i]->id)
|
||||
break;
|
||||
|
||||
return compressor[i];
|
||||
}
|
||||
|
||||
|
||||
void display_compressors(char *indent, char *def_comp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(compressor[i]->supported)
|
||||
fprintf(stderr, "%s\t%s%s\n", indent,
|
||||
compressor[i]->name,
|
||||
strcmp(compressor[i]->name, def_comp) == 0 ?
|
||||
" (default)" : "");
|
||||
}
|
||||
|
||||
|
||||
void display_compressor_usage(char *def_comp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(compressor[i]->supported) {
|
||||
char *str = strcmp(compressor[i]->name, def_comp) == 0 ?
|
||||
" (default)" : "";
|
||||
if(compressor[i]->usage) {
|
||||
fprintf(stderr, "\t%s%s\n",
|
||||
compressor[i]->name, str);
|
||||
compressor[i]->usage();
|
||||
} else
|
||||
fprintf(stderr, "\t%s (no options)%s\n",
|
||||
compressor[i]->name, str);
|
||||
}
|
||||
}
|
||||
124
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.h
Normal file
124
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#ifndef COMPRESSOR_H
|
||||
#define COMPRESSOR_H
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* compressor.h
|
||||
*/
|
||||
|
||||
struct compressor {
|
||||
int id;
|
||||
char *name;
|
||||
int supported;
|
||||
int (*init)(void **, int, int);
|
||||
int (*compress)(void *, void *, void *, int, int, int *);
|
||||
int (*uncompress)(void *, void *, int, int, int *);
|
||||
int (*options)(char **, int);
|
||||
int (*options_post)(int);
|
||||
void *(*dump_options)(int, int *);
|
||||
int (*extract_options)(int, void *, int);
|
||||
int (*check_options)(int, void *, int);
|
||||
void (*display_options)(void *, int);
|
||||
void (*usage)();
|
||||
};
|
||||
|
||||
extern struct compressor *lookup_compressor(char *);
|
||||
extern struct compressor *lookup_compressor_id(int);
|
||||
extern void display_compressors(char *, char *);
|
||||
extern void display_compressor_usage(char *);
|
||||
|
||||
static inline int compressor_init(struct compressor *comp, void **stream,
|
||||
int block_size, int datablock)
|
||||
{
|
||||
if(comp->init == NULL)
|
||||
return 0;
|
||||
return comp->init(stream, block_size, datablock);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_compress(struct compressor *comp, void *strm,
|
||||
void *dest, void *src, int size, int block_size, int *error)
|
||||
{
|
||||
return comp->compress(strm, dest, src, size, block_size, error);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_uncompress(struct compressor *comp, void *dest,
|
||||
void *src, int size, int block_size, int *error)
|
||||
{
|
||||
return comp->uncompress(dest, src, size, block_size, error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For the following functions please see the lzo, lz4 or xz
|
||||
* compressors for commented examples of how they are used.
|
||||
*/
|
||||
static inline int compressor_options(struct compressor *comp, char *argv[],
|
||||
int argc)
|
||||
{
|
||||
if(comp->options == NULL)
|
||||
return -1;
|
||||
|
||||
return comp->options(argv, argc);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_options_post(struct compressor *comp, int block_size)
|
||||
{
|
||||
if(comp->options_post == NULL)
|
||||
return 0;
|
||||
return comp->options_post(block_size);
|
||||
}
|
||||
|
||||
|
||||
static inline void *compressor_dump_options(struct compressor *comp,
|
||||
int block_size, int *size)
|
||||
{
|
||||
if(comp->dump_options == NULL)
|
||||
return NULL;
|
||||
return comp->dump_options(block_size, size);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_extract_options(struct compressor *comp,
|
||||
int block_size, void *buffer, int size)
|
||||
{
|
||||
if(comp->extract_options == NULL)
|
||||
return size ? -1 : 0;
|
||||
return comp->extract_options(block_size, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_check_options(struct compressor *comp,
|
||||
int block_size, void *buffer, int size)
|
||||
{
|
||||
if(comp->check_options == NULL)
|
||||
return 0;
|
||||
return comp->check_options(block_size, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
static inline void compressor_display_options(struct compressor *comp,
|
||||
void *buffer, int size)
|
||||
{
|
||||
if(comp->display_options != NULL)
|
||||
comp->display_options(buffer, size);
|
||||
}
|
||||
#endif
|
||||
106
SQUASHFS/squashfs-tools-4.4/squashfs-tools/error.h
Normal file
106
SQUASHFS/squashfs-tools-4.4/squashfs-tools/error.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* error.h
|
||||
*/
|
||||
|
||||
extern int exit_on_error;
|
||||
|
||||
extern void prep_exit();
|
||||
extern void progressbar_error(char *fmt, ...);
|
||||
extern void progressbar_info(char *fmt, ...);
|
||||
|
||||
#ifdef SQUASHFS_TRACE
|
||||
#define TRACE(s, args...) \
|
||||
do { \
|
||||
progressbar_info("squashfs: "s, ## args);\
|
||||
} while(0)
|
||||
#else
|
||||
#define TRACE(s, args...)
|
||||
#endif
|
||||
|
||||
#define INFO(s, args...) \
|
||||
do {\
|
||||
if(!silent)\
|
||||
progressbar_info(s, ## args);\
|
||||
} while(0)
|
||||
|
||||
#define ERROR(s, args...) \
|
||||
do {\
|
||||
progressbar_error(s, ## args); \
|
||||
} while(0)
|
||||
|
||||
#define ERROR_START(s, args...) \
|
||||
do { \
|
||||
disable_progress_bar(); \
|
||||
fprintf(stderr, s, ## args); \
|
||||
} while(0)
|
||||
|
||||
#define ERROR_EXIT(s, args...) \
|
||||
do {\
|
||||
if (exit_on_error) { \
|
||||
fprintf(stderr, "\n"); \
|
||||
EXIT_MKSQUASHFS(); \
|
||||
} else { \
|
||||
fprintf(stderr, s, ## args); \
|
||||
enable_progress_bar(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define EXIT_MKSQUASHFS() \
|
||||
do {\
|
||||
prep_exit();\
|
||||
exit(1);\
|
||||
} while(0)
|
||||
|
||||
#define BAD_ERROR(s, args...) \
|
||||
do {\
|
||||
progressbar_error("FATAL ERROR:" s, ##args); \
|
||||
EXIT_MKSQUASHFS();\
|
||||
} while(0)
|
||||
|
||||
#define EXIT_UNSQUASH(s, args...) BAD_ERROR(s, ##args)
|
||||
|
||||
#define EXIT_UNSQUASH_IGNORE(s, args...) \
|
||||
do {\
|
||||
if(ignore_errors) \
|
||||
ERROR(s, ##args); \
|
||||
else \
|
||||
BAD_ERROR(s, ##args); \
|
||||
} while(0)
|
||||
|
||||
#define EXIT_UNSQUASH_STRICT(s, args...) \
|
||||
do {\
|
||||
if(!strict_errors) \
|
||||
ERROR(s, ##args); \
|
||||
else \
|
||||
BAD_ERROR(s, ##args); \
|
||||
} while(0)
|
||||
|
||||
#define MEM_ERROR() \
|
||||
do {\
|
||||
progressbar_error("FATAL ERROR: Out of memory (%s)\n", \
|
||||
__func__); \
|
||||
EXIT_MKSQUASHFS();\
|
||||
} while(0)
|
||||
#endif
|
||||
32
SQUASHFS/squashfs-tools-4.4/squashfs-tools/fnmatch_compat.h
Normal file
32
SQUASHFS/squashfs-tools-4.4/squashfs-tools/fnmatch_compat.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef FNMATCH_COMPAT
|
||||
#define FNMATCH_COMPAT
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2015
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* fnmatch_compat.h
|
||||
*/
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
#ifndef FNM_EXTMATCH
|
||||
#define FNM_EXTMATCH 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
500
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.c
Normal file
500
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* gzip_wrapper.c
|
||||
*
|
||||
* Support for ZLIB compression http://www.zlib.net
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "gzip_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
static struct strategy strategy[] = {
|
||||
{ "default", Z_DEFAULT_STRATEGY, 0 },
|
||||
{ "filtered", Z_FILTERED, 0 },
|
||||
{ "huffman_only", Z_HUFFMAN_ONLY, 0 },
|
||||
{ "run_length_encoded", Z_RLE, 0 },
|
||||
{ "fixed", Z_FIXED, 0 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static int strategy_count = 0;
|
||||
|
||||
/* default compression level */
|
||||
static int compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
|
||||
|
||||
/* default window size */
|
||||
static int window_size = GZIP_DEFAULT_WINDOW_SIZE;
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The gzip_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int gzip_options(char *argv[], int argc)
|
||||
{
|
||||
if(strcmp(argv[0], "-Xcompression-level") == 0) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "gzip: -Xcompression-level missing "
|
||||
"compression level\n");
|
||||
fprintf(stderr, "gzip: -Xcompression-level it "
|
||||
"should be 1 >= n <= 9\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
compression_level = atoi(argv[1]);
|
||||
if(compression_level < 1 || compression_level > 9) {
|
||||
fprintf(stderr, "gzip: -Xcompression-level invalid, it "
|
||||
"should be 1 >= n <= 9\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if(strcmp(argv[0], "-Xwindow-size") == 0) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "gzip: -Xwindow-size missing window "
|
||||
" size\n");
|
||||
fprintf(stderr, "gzip: -Xwindow-size <window-size>\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
window_size = atoi(argv[1]);
|
||||
if(window_size < 8 || window_size > 15) {
|
||||
fprintf(stderr, "gzip: -Xwindow-size invalid, it "
|
||||
"should be 8 >= n <= 15\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if(strcmp(argv[0], "-Xstrategy") == 0) {
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "gzip: -Xstrategy missing "
|
||||
"strategies\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
name = argv[1];
|
||||
while(name[0] != '\0') {
|
||||
for(i = 0; strategy[i].name; i++) {
|
||||
int n = strlen(strategy[i].name);
|
||||
if((strncmp(name, strategy[i].name, n) == 0) &&
|
||||
(name[n] == '\0' ||
|
||||
name[n] == ',')) {
|
||||
if(strategy[i].selected == 0) {
|
||||
strategy[i].selected = 1;
|
||||
strategy_count++;
|
||||
}
|
||||
name += name[n] == ',' ? n + 1 : n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(strategy[i].name == NULL) {
|
||||
fprintf(stderr, "gzip: -Xstrategy unrecognised "
|
||||
"strategy\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
failed:
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after all options have been parsed.
|
||||
* It is used to do post-processing on the compressor options using
|
||||
* values that were not expected to be known at option parse time.
|
||||
*
|
||||
* This function returns 0 on successful post processing, or
|
||||
* -1 on error
|
||||
*/
|
||||
static int gzip_options_post(int block_size)
|
||||
{
|
||||
if(strategy_count == 1 && strategy[0].selected) {
|
||||
strategy_count = 0;
|
||||
strategy[0].selected = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*
|
||||
*/
|
||||
static void *gzip_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct gzip_comp_opts comp_opts;
|
||||
int i, strategies = 0;
|
||||
|
||||
/*
|
||||
* If default compression options of:
|
||||
* compression-level: 8 and
|
||||
* window-size: 15 and
|
||||
* strategy_count == 0 then
|
||||
* don't store a compression options structure (this is compatible
|
||||
* with the legacy implementation of GZIP for Squashfs)
|
||||
*/
|
||||
if(compression_level == GZIP_DEFAULT_COMPRESSION_LEVEL &&
|
||||
window_size == GZIP_DEFAULT_WINDOW_SIZE &&
|
||||
strategy_count == 0)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; strategy[i].name; i++)
|
||||
strategies |= strategy[i].selected << i;
|
||||
|
||||
comp_opts.compression_level = compression_level;
|
||||
comp_opts.window_size = window_size;
|
||||
comp_opts.strategy = strategies;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int gzip_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct gzip_comp_opts *comp_opts = buffer;
|
||||
int i;
|
||||
|
||||
if(size == 0) {
|
||||
/* Set default values */
|
||||
compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
|
||||
window_size = GZIP_DEFAULT_WINDOW_SIZE;
|
||||
strategy_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "gzip: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
compression_level = comp_opts->compression_level;
|
||||
|
||||
if(comp_opts->window_size < 8 ||
|
||||
comp_opts->window_size > 15) {
|
||||
fprintf(stderr, "gzip: bad window size in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
window_size = comp_opts->window_size;
|
||||
|
||||
strategy_count = 0;
|
||||
for(i = 0; strategy[i].name; i++) {
|
||||
if((comp_opts->strategy >> i) & 1) {
|
||||
strategy[i].selected = 1;
|
||||
strategy_count ++;
|
||||
} else
|
||||
strategy[i].selected = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "gzip: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void gzip_display_options(void *buffer, int size)
|
||||
{
|
||||
struct gzip_comp_opts *comp_opts = buffer;
|
||||
int i, printed;
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "gzip: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
printf("\tcompression-level %d\n", comp_opts->compression_level);
|
||||
|
||||
if(comp_opts->window_size < 8 ||
|
||||
comp_opts->window_size > 15) {
|
||||
fprintf(stderr, "gzip: bad window size in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
printf("\twindow-size %d\n", comp_opts->window_size);
|
||||
|
||||
for(i = 0, printed = 0; strategy[i].name; i++) {
|
||||
if((comp_opts->strategy >> i) & 1) {
|
||||
if(printed)
|
||||
printf(", ");
|
||||
else
|
||||
printf("\tStrategies selected: ");
|
||||
printf("%s", strategy[i].name);
|
||||
printed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!printed)
|
||||
printf("\tStrategies selected: default\n");
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "gzip: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to initialise the
|
||||
* compressor, before compress() is called.
|
||||
*
|
||||
* This function returns 0 on success, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int gzip_init(void **strm, int block_size, int datablock)
|
||||
{
|
||||
int i, j, res;
|
||||
struct gzip_stream *stream;
|
||||
|
||||
if(!datablock || !strategy_count) {
|
||||
stream = malloc(sizeof(*stream) + sizeof(struct gzip_strategy));
|
||||
if(stream == NULL)
|
||||
goto failed;
|
||||
|
||||
stream->strategies = 1;
|
||||
stream->strategy[0].strategy = Z_DEFAULT_STRATEGY;
|
||||
} else {
|
||||
stream = malloc(sizeof(*stream) +
|
||||
sizeof(struct gzip_strategy) * strategy_count);
|
||||
if(stream == NULL)
|
||||
goto failed;
|
||||
|
||||
memset(stream->strategy, 0, sizeof(struct gzip_strategy) *
|
||||
strategy_count);
|
||||
|
||||
stream->strategies = strategy_count;
|
||||
|
||||
for(i = 0, j = 0; strategy[i].name; i++) {
|
||||
if(!strategy[i].selected)
|
||||
continue;
|
||||
|
||||
stream->strategy[j].strategy = strategy[i].strategy;
|
||||
if(j) {
|
||||
stream->strategy[j].buffer = malloc(block_size);
|
||||
if(stream->strategy[j].buffer == NULL)
|
||||
goto failed2;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
stream->stream.zalloc = Z_NULL;
|
||||
stream->stream.zfree = Z_NULL;
|
||||
stream->stream.opaque = 0;
|
||||
|
||||
res = deflateInit2(&stream->stream, compression_level, Z_DEFLATED,
|
||||
window_size, 8, stream->strategy[0].strategy);
|
||||
if(res != Z_OK)
|
||||
goto failed2;
|
||||
|
||||
*strm = stream;
|
||||
return 0;
|
||||
|
||||
failed2:
|
||||
for(i = 1; i < stream->strategies; i++)
|
||||
free(stream->strategy[i].buffer);
|
||||
free(stream);
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int gzip_compress(void *strm, void *d, void *s, int size, int block_size,
|
||||
int *error)
|
||||
{
|
||||
int i, res;
|
||||
struct gzip_stream *stream = strm;
|
||||
struct gzip_strategy *selected = NULL;
|
||||
|
||||
stream->strategy[0].buffer = d;
|
||||
|
||||
for(i = 0; i < stream->strategies; i++) {
|
||||
struct gzip_strategy *strategy = &stream->strategy[i];
|
||||
|
||||
res = deflateReset(&stream->stream);
|
||||
if(res != Z_OK)
|
||||
goto failed;
|
||||
|
||||
stream->stream.next_in = s;
|
||||
stream->stream.avail_in = size;
|
||||
stream->stream.next_out = strategy->buffer;
|
||||
stream->stream.avail_out = block_size;
|
||||
|
||||
if(stream->strategies > 1) {
|
||||
res = deflateParams(&stream->stream,
|
||||
compression_level, strategy->strategy);
|
||||
if(res != Z_OK)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
res = deflate(&stream->stream, Z_FINISH);
|
||||
strategy->length = stream->stream.total_out;
|
||||
if(res == Z_STREAM_END) {
|
||||
if(!selected || selected->length > strategy->length)
|
||||
selected = strategy;
|
||||
} else if(res != Z_OK)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(!selected)
|
||||
/*
|
||||
* Output buffer overflow. Return out of buffer space
|
||||
*/
|
||||
return 0;
|
||||
|
||||
if(selected->buffer != d)
|
||||
memcpy(d, selected->buffer, selected->length);
|
||||
|
||||
return (int) selected->length;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* All other errors return failure, with the compressor
|
||||
* specific error code in *error
|
||||
*/
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int gzip_uncompress(void *d, void *s, int size, int outsize, int *error)
|
||||
{
|
||||
int res;
|
||||
unsigned long bytes = outsize;
|
||||
|
||||
res = uncompress(d, &bytes, s, size);
|
||||
|
||||
if(res == Z_OK)
|
||||
return (int) bytes;
|
||||
else {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gzip_usage()
|
||||
{
|
||||
fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
|
||||
fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
|
||||
"%d)\n", GZIP_DEFAULT_COMPRESSION_LEVEL);
|
||||
fprintf(stderr, "\t -Xwindow-size <window-size>\n");
|
||||
fprintf(stderr, "\t\t<window-size> should be 8 .. 15 (default "
|
||||
"%d)\n", GZIP_DEFAULT_WINDOW_SIZE);
|
||||
fprintf(stderr, "\t -Xstrategy strategy1,strategy2,...,strategyN\n");
|
||||
fprintf(stderr, "\t\tCompress using strategy1,strategy2,...,strategyN"
|
||||
" in turn\n");
|
||||
fprintf(stderr, "\t\tand choose the best compression.\n");
|
||||
fprintf(stderr, "\t\tAvailable strategies: default, filtered, "
|
||||
"huffman_only,\n\t\trun_length_encoded and fixed\n");
|
||||
}
|
||||
|
||||
|
||||
struct compressor gzip_comp_ops = {
|
||||
.init = gzip_init,
|
||||
.compress = gzip_compress,
|
||||
.uncompress = gzip_uncompress,
|
||||
.options = gzip_options,
|
||||
.options_post = gzip_options_post,
|
||||
.dump_options = gzip_dump_options,
|
||||
.extract_options = gzip_extract_options,
|
||||
.display_options = gzip_display_options,
|
||||
.usage = gzip_usage,
|
||||
.id = ZLIB_COMPRESSION,
|
||||
.name = "gzip",
|
||||
.supported = 1
|
||||
};
|
||||
75
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.h
Normal file
75
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef GZIP_WRAPPER_H
|
||||
#define GZIP_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* gzip_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le16(unsigned short);
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->compression_level = inswap_le32((s)->compression_level); \
|
||||
(s)->window_size = inswap_le16((s)->window_size); \
|
||||
(s)->strategy = inswap_le16((s)->strategy); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/* Default compression */
|
||||
#define GZIP_DEFAULT_COMPRESSION_LEVEL 9
|
||||
#define GZIP_DEFAULT_WINDOW_SIZE 15
|
||||
|
||||
struct gzip_comp_opts {
|
||||
int compression_level;
|
||||
short window_size;
|
||||
short strategy;
|
||||
};
|
||||
|
||||
struct strategy {
|
||||
char *name;
|
||||
int strategy;
|
||||
int selected;
|
||||
};
|
||||
|
||||
struct gzip_strategy {
|
||||
int strategy;
|
||||
int length;
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
struct gzip_stream {
|
||||
z_stream stream;
|
||||
int strategies;
|
||||
struct gzip_strategy strategy[0];
|
||||
};
|
||||
#endif
|
||||
191
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.c
Normal file
191
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* info.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
#include "caches-queues-lists.h"
|
||||
|
||||
static int silent = 0;
|
||||
static struct dir_ent *ent = NULL;
|
||||
|
||||
pthread_t info_thread;
|
||||
|
||||
|
||||
void disable_info()
|
||||
{
|
||||
ent = NULL;
|
||||
}
|
||||
|
||||
|
||||
void update_info(struct dir_ent *dir_ent)
|
||||
{
|
||||
ent = dir_ent;
|
||||
}
|
||||
|
||||
|
||||
void print_filename()
|
||||
{
|
||||
struct dir_ent *dir_ent = ent;
|
||||
|
||||
if(dir_ent == NULL)
|
||||
return;
|
||||
|
||||
if(dir_ent->our_dir->subpath[0] != '\0')
|
||||
INFO("%s/%s\n", dir_ent->our_dir->subpath, dir_ent->name);
|
||||
else
|
||||
INFO("/%s\n", dir_ent->name);
|
||||
}
|
||||
|
||||
|
||||
void dump_state()
|
||||
{
|
||||
disable_progress_bar();
|
||||
|
||||
printf("Queue and Cache status dump\n");
|
||||
printf("===========================\n");
|
||||
|
||||
printf("file buffer queue (reader thread -> deflate thread(s))\n");
|
||||
dump_queue(to_deflate);
|
||||
|
||||
printf("uncompressed fragment queue (reader thread -> fragment"
|
||||
" thread(s))\n");
|
||||
dump_queue(to_process_frag);
|
||||
|
||||
printf("processed fragment queue (fragment thread(s) -> main"
|
||||
" thread)\n");
|
||||
dump_seq_queue(to_main, 1);
|
||||
|
||||
printf("compressed block queue (deflate thread(s) -> main thread)\n");
|
||||
dump_seq_queue(to_main, 0);
|
||||
|
||||
printf("uncompressed packed fragment queue (main thread -> fragment"
|
||||
" deflate thread(s))\n");
|
||||
dump_queue(to_frag);
|
||||
|
||||
if(!reproducible) {
|
||||
printf("locked frag queue (compressed frags waiting while multi-block"
|
||||
" file is written)\n");
|
||||
dump_queue(locked_fragment);
|
||||
|
||||
printf("compressed block queue (main & fragment deflate threads(s) ->"
|
||||
" writer thread)\n");
|
||||
dump_queue(to_writer);
|
||||
} else {
|
||||
printf("compressed fragment queue (fragment deflate threads(s) ->"
|
||||
"fragment order thread)\n");
|
||||
|
||||
dump_seq_queue(to_order, 0);
|
||||
|
||||
printf("compressed block queue (main & fragment order threads ->"
|
||||
" writer thread)\n");
|
||||
dump_queue(to_writer);
|
||||
}
|
||||
|
||||
printf("read cache (uncompressed blocks read by reader thread)\n");
|
||||
dump_cache(reader_buffer);
|
||||
|
||||
printf("block write cache (compressed blocks waiting for the writer"
|
||||
" thread)\n");
|
||||
dump_cache(bwriter_buffer);
|
||||
printf("fragment write cache (compressed fragments waiting for the"
|
||||
" writer thread)\n");
|
||||
dump_cache(fwriter_buffer);
|
||||
|
||||
printf("fragment cache (frags waiting to be compressed by fragment"
|
||||
" deflate thread(s))\n");
|
||||
dump_cache(fragment_buffer);
|
||||
|
||||
printf("fragment reserve cache (avoids pipeline stall if frag cache"
|
||||
" full in dup check)\n");
|
||||
dump_cache(reserve_cache);
|
||||
|
||||
enable_progress_bar();
|
||||
}
|
||||
|
||||
|
||||
void *info_thrd(void *arg)
|
||||
{
|
||||
sigset_t sigmask;
|
||||
struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
|
||||
int sig, waiting = 0;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGQUIT);
|
||||
sigaddset(&sigmask, SIGHUP);
|
||||
|
||||
while(1) {
|
||||
if(waiting)
|
||||
sig = sigtimedwait(&sigmask, NULL, ×pec);
|
||||
else
|
||||
sig = sigwaitinfo(&sigmask, NULL);
|
||||
|
||||
if(sig == -1) {
|
||||
switch(errno) {
|
||||
case EAGAIN:
|
||||
/* interval timed out */
|
||||
waiting = 0;
|
||||
/* FALLTHROUGH */
|
||||
case EINTR:
|
||||
/* if waiting, the wait will be longer, but
|
||||
that's OK */
|
||||
continue;
|
||||
default:
|
||||
BAD_ERROR("sigtimedwait/sigwaitinfo failed "
|
||||
"because %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if(sig == SIGQUIT && !waiting) {
|
||||
print_filename();
|
||||
|
||||
/* set one second interval period, if ^\ received
|
||||
within then, dump queue and cache status */
|
||||
waiting = 1;
|
||||
} else
|
||||
dump_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_info()
|
||||
{
|
||||
pthread_create(&info_thread, NULL, info_thrd, NULL);
|
||||
}
|
||||
30
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.h
Normal file
30
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef INFO_H
|
||||
#define INFO_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* info.h
|
||||
*/
|
||||
|
||||
extern void disable_info();
|
||||
extern void update_info(struct dir_ent *);
|
||||
extern void init_info();
|
||||
#endif
|
||||
286
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.c
Normal file
286
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lz4_wrapper.c
|
||||
*
|
||||
* Support for LZ4 compression http://fastcompression.blogspot.com/p/lz4.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <lz4.h>
|
||||
#include <lz4hc.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "lz4_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
/* LZ4 1.7.0 introduced new functions, and since r131,
|
||||
* the older functions produce deprecated warnings.
|
||||
*
|
||||
* There are still too many distros using older versions
|
||||
* to switch to the newer functions, but, the deprecated
|
||||
* functions may completely disappear. This is a mess.
|
||||
*
|
||||
* Support both by checking the library version and
|
||||
* using shadow definitions
|
||||
*/
|
||||
|
||||
/* Earlier (but > 1.7.0) versions don't define this */
|
||||
#ifndef LZ4HC_CLEVEL_MAX
|
||||
#define LZ4HC_CLEVEL_MAX 12
|
||||
#endif
|
||||
|
||||
#if LZ4_VERSION_NUMBER >= 10700
|
||||
#define COMPRESS(src, dest, size, max) LZ4_compress_default(src, dest, size, max)
|
||||
#define COMPRESS_HC(src, dest, size, max) LZ4_compress_HC(src, dest, size, max, LZ4HC_CLEVEL_MAX)
|
||||
#else
|
||||
#define COMPRESS(src, dest, size, max) LZ4_compress_limitedOutput(src, dest, size, max)
|
||||
#define COMPRESS_HC(src, dest, size, max) LZ4_compressHC_limitedOutput(src, dest, size, max)
|
||||
#endif
|
||||
|
||||
static int hc = 0;
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The lz4_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int lz4_options(char *argv[], int argc)
|
||||
{
|
||||
if(strcmp(argv[0], "-Xhc") == 0) {
|
||||
hc = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*
|
||||
* Currently LZ4 always returns a comp_opts structure, with
|
||||
* the version indicating LZ4_LEGACY stream fomat. This is to
|
||||
* easily accomodate changes in the kernel code to different
|
||||
* stream formats
|
||||
*/
|
||||
static void *lz4_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct lz4_comp_opts comp_opts;
|
||||
|
||||
comp_opts.version = LZ4_LEGACY;
|
||||
comp_opts.flags = hc ? LZ4_HC : 0;
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int lz4_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct lz4_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* we expect the stream format to be LZ4_LEGACY */
|
||||
if(comp_opts->version != LZ4_LEGACY) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 version\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check compression flags, currently only LZ4_HC ("high compression")
|
||||
* can be set.
|
||||
*/
|
||||
if(comp_opts->flags == LZ4_HC)
|
||||
hc = 1;
|
||||
else if(comp_opts->flags != 0) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 flags\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lz4: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for unsquashfs.
|
||||
* Its purpose is to check that the compression options are
|
||||
* understood by this version of LZ4.
|
||||
*
|
||||
* This is important for LZ4 because the format understood by the
|
||||
* Linux kernel may change from the already obsolete legacy format
|
||||
* currently supported.
|
||||
*
|
||||
* If this does happen, then this version of LZ4 will not be able to decode
|
||||
* the newer format. So we need to check for this.
|
||||
*
|
||||
* This function returns 0 on sucessful checking of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int lz4_check_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct lz4_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* we expect the stream format to be LZ4_LEGACY */
|
||||
if(comp_opts->version != LZ4_LEGACY) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 version\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lz4: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void lz4_display_options(void *buffer, int size)
|
||||
{
|
||||
struct lz4_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* check passed comp opts struct is of the correct length */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* we expect the stream format to be LZ4_LEGACY */
|
||||
if(comp_opts->version != LZ4_LEGACY) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 version\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check compression flags, currently only LZ4_HC ("high compression")
|
||||
* can be set.
|
||||
*/
|
||||
if(comp_opts->flags & ~LZ4_FLAGS_MASK) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 flags\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(comp_opts->flags & LZ4_HC)
|
||||
printf("\tHigh Compression option specified (-Xhc)\n");
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lz4: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
static int lz4_compress(void *strm, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lz4_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
int res = LZ4_decompress_safe(src, dest, size, outsize);
|
||||
if(res < 0) {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void lz4_usage()
|
||||
{
|
||||
fprintf(stderr, "\t -Xhc\n");
|
||||
fprintf(stderr, "\t\tCompress using LZ4 High Compression\n");
|
||||
}
|
||||
|
||||
|
||||
struct compressor lz4_comp_ops = {
|
||||
.compress = lz4_compress,
|
||||
.uncompress = lz4_uncompress,
|
||||
.options = lz4_options,
|
||||
.dump_options = lz4_dump_options,
|
||||
.extract_options = lz4_extract_options,
|
||||
.check_options = lz4_check_options,
|
||||
.display_options = lz4_display_options,
|
||||
.usage = lz4_usage,
|
||||
.id = LZ4_COMPRESSION,
|
||||
.name = "lz4",
|
||||
.supported = 1
|
||||
};
|
||||
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.h
Normal file
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef LZ4_WRAPPER_H
|
||||
#define LZ4_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lz4_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->version = inswap_le32((s)->version); \
|
||||
(s)->flags = inswap_le32((s)->flags); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the various stream formats recognised.
|
||||
* Currently omly legacy stream format is supported by the
|
||||
* kernel
|
||||
*/
|
||||
#define LZ4_LEGACY 1
|
||||
#define LZ4_FLAGS_MASK 1
|
||||
|
||||
/* Define the compression flags recognised. */
|
||||
#define LZ4_HC 1
|
||||
|
||||
struct lz4_comp_opts {
|
||||
int version;
|
||||
int flags;
|
||||
};
|
||||
#endif
|
||||
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_wrapper.c
Normal file
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_wrapper.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzma_wrapper.c
|
||||
*
|
||||
* Support for LZMA1 compression using LZMA SDK (4.65 used in
|
||||
* development, other versions may work) http://www.7-zip.org/sdk.html
|
||||
*/
|
||||
|
||||
#include <LzmaLib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "compressor.h"
|
||||
|
||||
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
|
||||
|
||||
static int lzma_compress(void *strm, void *dest, void *src, int size, int block_size,
|
||||
int *error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lzma_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
size_t outlen, inlen = size - LZMA_HEADER_SIZE;
|
||||
int res;
|
||||
|
||||
outlen = s[LZMA_PROPS_SIZE] |
|
||||
(s[LZMA_PROPS_SIZE + 1] << 8) |
|
||||
(s[LZMA_PROPS_SIZE + 2] << 16) |
|
||||
(s[LZMA_PROPS_SIZE + 3] << 24);
|
||||
|
||||
if(outlen > outsize) {
|
||||
*error = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = LzmaUncompress(dest, &outlen, src + LZMA_HEADER_SIZE, &inlen, src,
|
||||
LZMA_PROPS_SIZE);
|
||||
|
||||
if(res == SZ_OK)
|
||||
return outlen;
|
||||
else {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct compressor lzma_comp_ops = {
|
||||
.init = NULL,
|
||||
.compress = lzma_compress,
|
||||
.uncompress = lzma_uncompress,
|
||||
.options = NULL,
|
||||
.usage = NULL,
|
||||
.id = LZMA_COMPRESSION,
|
||||
.name = "lzma",
|
||||
.supported = 1
|
||||
};
|
||||
|
||||
163
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_xz_wrapper.c
Normal file
163
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_xz_wrapper.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzma_xz_wrapper.c
|
||||
*
|
||||
* Support for LZMA1 compression using XZ Utils liblzma http://tukaani.org/xz/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lzma.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "compressor.h"
|
||||
|
||||
#define LZMA_PROPS_SIZE 5
|
||||
#define LZMA_UNCOMP_SIZE 8
|
||||
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNCOMP_SIZE)
|
||||
|
||||
#define LZMA_OPTIONS 5
|
||||
#define MEMLIMIT (32 * 1024 * 1024)
|
||||
|
||||
static int lzma_compress(void *dummy, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
unsigned char *d = (unsigned char *) dest;
|
||||
lzma_options_lzma opt;
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
int res;
|
||||
|
||||
lzma_lzma_preset(&opt, LZMA_OPTIONS);
|
||||
opt.dict_size = block_size;
|
||||
|
||||
res = lzma_alone_encoder(&strm, &opt);
|
||||
if(res != LZMA_OK) {
|
||||
lzma_end(&strm);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
strm.next_out = dest;
|
||||
strm.avail_out = block_size;
|
||||
strm.next_in = src;
|
||||
strm.avail_in = size;
|
||||
|
||||
res = lzma_code(&strm, LZMA_FINISH);
|
||||
lzma_end(&strm);
|
||||
|
||||
if(res == LZMA_STREAM_END) {
|
||||
/*
|
||||
* Fill in the 8 byte little endian uncompressed size field in
|
||||
* the LZMA header. 8 bytes is excessively large for squashfs
|
||||
* but this is the standard LZMA header and which is expected by
|
||||
* the kernel code
|
||||
*/
|
||||
|
||||
d[LZMA_PROPS_SIZE] = size & 255;
|
||||
d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255;
|
||||
d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255;
|
||||
d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255;
|
||||
d[LZMA_PROPS_SIZE + 4] = 0;
|
||||
d[LZMA_PROPS_SIZE + 5] = 0;
|
||||
d[LZMA_PROPS_SIZE + 6] = 0;
|
||||
d[LZMA_PROPS_SIZE + 7] = 0;
|
||||
|
||||
return (int) strm.total_out;
|
||||
}
|
||||
|
||||
if(res == LZMA_OK)
|
||||
/*
|
||||
* Output buffer overflow. Return out of buffer space
|
||||
*/
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* All other errors return failure, with the compressor
|
||||
* specific error code in *error
|
||||
*/
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int lzma_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
int uncompressed_size = 0, res;
|
||||
unsigned char lzma_header[LZMA_HEADER_SIZE];
|
||||
|
||||
res = lzma_alone_decoder(&strm, MEMLIMIT);
|
||||
if(res != LZMA_OK) {
|
||||
lzma_end(&strm);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memcpy(lzma_header, src, LZMA_HEADER_SIZE);
|
||||
uncompressed_size = lzma_header[LZMA_PROPS_SIZE] |
|
||||
(lzma_header[LZMA_PROPS_SIZE + 1] << 8) |
|
||||
(lzma_header[LZMA_PROPS_SIZE + 2] << 16) |
|
||||
(lzma_header[LZMA_PROPS_SIZE + 3] << 24);
|
||||
|
||||
if(uncompressed_size > outsize) {
|
||||
res = 0;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memset(lzma_header + LZMA_PROPS_SIZE, 255, LZMA_UNCOMP_SIZE);
|
||||
|
||||
strm.next_out = dest;
|
||||
strm.avail_out = outsize;
|
||||
strm.next_in = lzma_header;
|
||||
strm.avail_in = LZMA_HEADER_SIZE;
|
||||
|
||||
res = lzma_code(&strm, LZMA_RUN);
|
||||
|
||||
if(res != LZMA_OK || strm.avail_in != 0) {
|
||||
lzma_end(&strm);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
strm.next_in = src + LZMA_HEADER_SIZE;
|
||||
strm.avail_in = size - LZMA_HEADER_SIZE;
|
||||
|
||||
res = lzma_code(&strm, LZMA_FINISH);
|
||||
lzma_end(&strm);
|
||||
|
||||
if(res == LZMA_STREAM_END || (res == LZMA_OK &&
|
||||
strm.total_out >= uncompressed_size && strm.avail_in == 0))
|
||||
return uncompressed_size;
|
||||
|
||||
failed:
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct compressor lzma_comp_ops = {
|
||||
.init = NULL,
|
||||
.compress = lzma_compress,
|
||||
.uncompress = lzma_uncompress,
|
||||
.options = NULL,
|
||||
.usage = NULL,
|
||||
.id = LZMA_COMPRESSION,
|
||||
.name = "lzma",
|
||||
.supported = 1
|
||||
};
|
||||
|
||||
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.c
Normal file
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzo_wrapper.c
|
||||
*
|
||||
* Support for LZO compression http://www.oberhumer.com/opensource/lzo
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <lzo/lzoconf.h>
|
||||
#include <lzo/lzo1x.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "lzo_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
static struct lzo_algorithm lzo[] = {
|
||||
{ "lzo1x_1", LZO1X_1_MEM_COMPRESS, lzo1x_1_compress },
|
||||
{ "lzo1x_1_11", LZO1X_1_11_MEM_COMPRESS, lzo1x_1_11_compress },
|
||||
{ "lzo1x_1_12", LZO1X_1_12_MEM_COMPRESS, lzo1x_1_12_compress },
|
||||
{ "lzo1x_1_15", LZO1X_1_15_MEM_COMPRESS, lzo1x_1_15_compress },
|
||||
{ "lzo1x_999", LZO1X_999_MEM_COMPRESS, lzo1x_999_wrapper },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
/* default LZO compression algorithm and compression level */
|
||||
static int algorithm = SQUASHFS_LZO1X_999;
|
||||
static int compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
|
||||
|
||||
/* user specified compression level */
|
||||
static int user_comp_level = -1;
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The lzo_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int lzo_options(char *argv[], int argc)
|
||||
{
|
||||
(void)argv;
|
||||
(void)argc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after all options have been parsed.
|
||||
* It is used to do post-processing on the compressor options using
|
||||
* values that were not expected to be known at option parse time.
|
||||
*
|
||||
* In this case the LZO algorithm may not be known until after the
|
||||
* compression level has been set (-Xalgorithm used after -Xcompression-level)
|
||||
*
|
||||
* This function returns 0 on successful post processing, or
|
||||
* -1 on error
|
||||
*/
|
||||
static int lzo_options_post(int block_size)
|
||||
{
|
||||
/*
|
||||
* Use of compression level only makes sense for
|
||||
* LZO1X_999 algorithm
|
||||
*/
|
||||
if(user_comp_level != -1) {
|
||||
if(algorithm != SQUASHFS_LZO1X_999) {
|
||||
fprintf(stderr, "lzo: -Xcompression-level not "
|
||||
"supported by selected %s algorithm\n",
|
||||
lzo[algorithm].name);
|
||||
fprintf(stderr, "lzo: -Xcompression-level is only "
|
||||
"applicable for the lzo1x_999 algorithm\n");
|
||||
goto failed;
|
||||
}
|
||||
compression_level = user_comp_level;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*
|
||||
*/
|
||||
static void *lzo_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct lzo_comp_opts comp_opts;
|
||||
|
||||
/*
|
||||
* If default compression options of SQUASHFS_LZO1X_999 and
|
||||
* compression level of SQUASHFS_LZO1X_999_COMP_DEFAULT then
|
||||
* don't store a compression options structure (this is compatible
|
||||
* with the legacy implementation of LZO for Squashfs)
|
||||
*/
|
||||
if(algorithm == SQUASHFS_LZO1X_999 &&
|
||||
compression_level == SQUASHFS_LZO1X_999_COMP_DEFAULT)
|
||||
return NULL;
|
||||
|
||||
comp_opts.algorithm = algorithm;
|
||||
comp_opts.compression_level = algorithm == SQUASHFS_LZO1X_999 ?
|
||||
compression_level : 0;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int lzo_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct lzo_comp_opts *comp_opts = buffer;
|
||||
|
||||
if(size == 0) {
|
||||
/* Set default values */
|
||||
algorithm = SQUASHFS_LZO1X_999;
|
||||
compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
switch(comp_opts->algorithm) {
|
||||
case SQUASHFS_LZO1X_1:
|
||||
case SQUASHFS_LZO1X_1_11:
|
||||
case SQUASHFS_LZO1X_1_12:
|
||||
case SQUASHFS_LZO1X_1_15:
|
||||
if(comp_opts->compression_level != 0) {
|
||||
fprintf(stderr, "lzo: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
case SQUASHFS_LZO1X_999:
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "lzo: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
compression_level = comp_opts->compression_level;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "lzo: bad algorithm in compression options "
|
||||
"structure\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
algorithm = comp_opts->algorithm;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lzo: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void lzo_display_options(void *buffer, int size)
|
||||
{
|
||||
struct lzo_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
switch(comp_opts->algorithm) {
|
||||
case SQUASHFS_LZO1X_1:
|
||||
case SQUASHFS_LZO1X_1_11:
|
||||
case SQUASHFS_LZO1X_1_12:
|
||||
case SQUASHFS_LZO1X_1_15:
|
||||
printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
|
||||
break;
|
||||
case SQUASHFS_LZO1X_999:
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "lzo: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
|
||||
printf("\tcompression level %d\n",
|
||||
comp_opts->compression_level);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "lzo: bad algorithm in compression options "
|
||||
"structure\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lzo: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to initialise the
|
||||
* compressor, before compress() is called.
|
||||
*
|
||||
* This function returns 0 on success, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int squashfs_lzo_init(void **strm, int block_size, int datablock)
|
||||
{
|
||||
struct lzo_stream *stream;
|
||||
|
||||
stream = *strm = malloc(sizeof(struct lzo_stream));
|
||||
if(stream == NULL)
|
||||
goto failed;
|
||||
|
||||
stream->workspace = malloc(lzo[algorithm].size);
|
||||
if(stream->workspace == NULL)
|
||||
goto failed2;
|
||||
|
||||
stream->buffer = malloc(LZO_MAX_EXPANSION(block_size));
|
||||
if(stream->buffer != NULL)
|
||||
return 0;
|
||||
|
||||
free(stream->workspace);
|
||||
failed2:
|
||||
free(stream);
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int lzo_compress(void *strm, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lzo_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
int res;
|
||||
lzo_uint outlen = outsize;
|
||||
|
||||
res = lzo1x_decompress_safe(src, size, dest, &outlen, NULL);
|
||||
if(res != LZO_E_OK) {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
|
||||
static void lzo_usage()
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "\t -Xalgorithm <algorithm>\n");
|
||||
fprintf(stderr, "\t\tWhere <algorithm> is one of:\n");
|
||||
|
||||
for(i = 0; lzo[i].name; i++)
|
||||
fprintf(stderr, "\t\t\t%s%s\n", lzo[i].name,
|
||||
i == SQUASHFS_LZO1X_999 ? " (default)" : "");
|
||||
|
||||
fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
|
||||
fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
|
||||
"%d)\n", SQUASHFS_LZO1X_999_COMP_DEFAULT);
|
||||
fprintf(stderr, "\t\tOnly applies to lzo1x_999 algorithm\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function for lzo1x_999 compression algorithm.
|
||||
* All other lzo1x_xxx compressors do not take a compression level,
|
||||
* so we need to wrap lzo1x_999 to pass the compression level which
|
||||
* is applicable to it
|
||||
*/
|
||||
int lzo1x_999_wrapper(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst,
|
||||
lzo_uintp compsize, lzo_voidp workspace)
|
||||
{
|
||||
return lzo1x_999_compress_level(src, src_len, dst, compsize,
|
||||
workspace, NULL, 0, 0, compression_level);
|
||||
}
|
||||
|
||||
|
||||
struct compressor lzo_comp_ops = {
|
||||
.init = squashfs_lzo_init,
|
||||
.compress = lzo_compress,
|
||||
.uncompress = lzo_uncompress,
|
||||
.options = lzo_options,
|
||||
.options_post = lzo_options_post,
|
||||
.dump_options = lzo_dump_options,
|
||||
.extract_options = lzo_extract_options,
|
||||
.display_options = lzo_display_options,
|
||||
.usage = lzo_usage,
|
||||
.id = LZO_COMPRESSION,
|
||||
.name = "lzo",
|
||||
.supported = 1
|
||||
};
|
||||
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.h
Normal file
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef LZO_WRAPPER_H
|
||||
#define LZO_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzo_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->algorithm = inswap_le32((s)->algorithm); \
|
||||
(s)->compression_level = inswap_le32((s)->compression_level); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/* Define the compression flags recognised. */
|
||||
#define SQUASHFS_LZO1X_1 0
|
||||
#define SQUASHFS_LZO1X_1_11 1
|
||||
#define SQUASHFS_LZO1X_1_12 2
|
||||
#define SQUASHFS_LZO1X_1_15 3
|
||||
#define SQUASHFS_LZO1X_999 4
|
||||
|
||||
/* Default compression level used by SQUASHFS_LZO1X_999 */
|
||||
#define SQUASHFS_LZO1X_999_COMP_DEFAULT 8
|
||||
|
||||
struct lzo_comp_opts {
|
||||
int algorithm;
|
||||
int compression_level;
|
||||
};
|
||||
|
||||
struct lzo_algorithm {
|
||||
char *name;
|
||||
int size;
|
||||
int (*compress) (const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
|
||||
lzo_voidp);
|
||||
};
|
||||
|
||||
struct lzo_stream {
|
||||
void *workspace;
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
#define LZO_MAX_EXPANSION(size) (size + (size / 16) + 64 + 3)
|
||||
|
||||
int lzo1x_999_wrapper(const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
|
||||
lzo_voidp);
|
||||
|
||||
#endif
|
||||
6372
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.c
Normal file
6372
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.c
Normal file
File diff suppressed because it is too large
Load Diff
165
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.h
Normal file
165
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef MKSQUASHFS_H
|
||||
#define MKSQUASHFS_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
||||
* 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* mksquashfs.h
|
||||
*
|
||||
*/
|
||||
|
||||
struct dir_info {
|
||||
char *pathname;
|
||||
char *subpath;
|
||||
unsigned int count;
|
||||
unsigned int directory_count;
|
||||
int depth;
|
||||
unsigned int excluded;
|
||||
char dir_is_ldir;
|
||||
struct dir_ent *dir_ent;
|
||||
struct dir_ent *list;
|
||||
DIR *linuxdir;
|
||||
};
|
||||
|
||||
struct dir_ent {
|
||||
char *name;
|
||||
char *source_name;
|
||||
char *nonstandard_pathname;
|
||||
struct inode_info *inode;
|
||||
struct dir_info *dir;
|
||||
struct dir_info *our_dir;
|
||||
struct dir_ent *next;
|
||||
};
|
||||
|
||||
struct inode_info {
|
||||
struct stat buf;
|
||||
struct inode_info *next;
|
||||
squashfs_inode inode;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
int pseudo_id;
|
||||
char type;
|
||||
char read;
|
||||
char root_entry;
|
||||
char pseudo_file;
|
||||
char no_fragments;
|
||||
char always_use_fragments;
|
||||
char noD;
|
||||
char noF;
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
/* in memory file info */
|
||||
struct file_info {
|
||||
long long file_size;
|
||||
long long bytes;
|
||||
long long start;
|
||||
unsigned int *block_list;
|
||||
struct file_info *next;
|
||||
struct fragment *fragment;
|
||||
unsigned short checksum;
|
||||
unsigned short fragment_checksum;
|
||||
char have_frag_checksum;
|
||||
char have_checksum;
|
||||
};
|
||||
|
||||
/* fragment block data structures */
|
||||
struct fragment {
|
||||
unsigned int index;
|
||||
int offset;
|
||||
int size;
|
||||
};
|
||||
|
||||
/* in memory uid tables */
|
||||
#define ID_ENTRIES 256
|
||||
#define ID_HASH(id) (id & (ID_ENTRIES - 1))
|
||||
#define ISA_UID 1
|
||||
#define ISA_GID 2
|
||||
|
||||
struct id {
|
||||
unsigned int id;
|
||||
int index;
|
||||
char flags;
|
||||
struct id *next;
|
||||
};
|
||||
|
||||
/* fragment to file mapping used when appending */
|
||||
struct append_file {
|
||||
struct file_info *file;
|
||||
struct append_file *next;
|
||||
};
|
||||
|
||||
#define PSEUDO_FILE_OTHER 1
|
||||
#define PSEUDO_FILE_PROCESS 2
|
||||
|
||||
#define IS_PSEUDO(a) ((a)->pseudo_file)
|
||||
#define IS_PSEUDO_PROCESS(a) ((a)->pseudo_file & PSEUDO_FILE_PROCESS)
|
||||
#define IS_PSEUDO_OTHER(a) ((a)->pseudo_file & PSEUDO_FILE_OTHER)
|
||||
|
||||
/*
|
||||
* Amount of physical memory to use by default, and the default queue
|
||||
* ratios
|
||||
*/
|
||||
#define SQUASHFS_TAKE 4
|
||||
#define SQUASHFS_READQ_MEM 4
|
||||
#define SQUASHFS_BWRITEQ_MEM 4
|
||||
#define SQUASHFS_FWRITEQ_MEM 4
|
||||
|
||||
/*
|
||||
* Lowest amount of physical memory considered viable for Mksquashfs
|
||||
* to run in Mbytes
|
||||
*/
|
||||
#define SQUASHFS_LOWMEM 64
|
||||
|
||||
/* offset of data in compressed metadata blocks (allowing room for
|
||||
* compressed size */
|
||||
#define BLOCK_OFFSET 2
|
||||
|
||||
#ifdef REPRODUCIBLE_DEFAULT
|
||||
#define NOREP_STR
|
||||
#define REP_STR " (default)"
|
||||
#define REP_DEF 1
|
||||
#else
|
||||
#define NOREP_STR " (default)"
|
||||
#define REP_STR
|
||||
#define REP_DEF 0
|
||||
#endif
|
||||
|
||||
extern struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
|
||||
struct cache *bwriter_buffer, *fwriter_buffer;
|
||||
extern struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
|
||||
*to_frag, *locked_fragment, *to_process_frag;
|
||||
extern struct append_file **file_mapping;
|
||||
extern struct seq_queue *to_main, *to_order;
|
||||
extern pthread_mutex_t fragment_mutex, dup_mutex;
|
||||
extern struct squashfs_fragment_entry *fragment_table;
|
||||
extern struct compressor *comp;
|
||||
extern int block_size;
|
||||
extern struct file_info *dupl[];
|
||||
extern int read_fs_bytes(int, long long, int, void *);
|
||||
extern void add_file(long long, long long, long long, unsigned int *, int,
|
||||
unsigned int, int, int);
|
||||
extern struct id *create_id(unsigned int);
|
||||
extern unsigned int get_uid(unsigned int);
|
||||
extern unsigned int get_guid(unsigned int);
|
||||
extern int read_bytes(int, void *, int);
|
||||
extern unsigned short get_checksum_mem(char *, int);
|
||||
extern int reproducible;
|
||||
#endif
|
||||
371
SQUASHFS/squashfs-tools-4.4/squashfs-tools/process_fragments.c
Normal file
371
SQUASHFS/squashfs-tools-4.4/squashfs-tools/process_fragments.c
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* process_fragments.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "caches-queues-lists.h"
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
#include "info.h"
|
||||
#include "compressor.h"
|
||||
#include "process_fragments.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
extern struct queue *to_process_frag;
|
||||
extern struct seq_queue *to_main;
|
||||
extern int sparse_files;
|
||||
extern long long start_offset;
|
||||
|
||||
/*
|
||||
* Compute 16 bit BSD checksum over the data, and check for sparseness
|
||||
*/
|
||||
static int checksum_sparse(struct file_buffer *file_buffer)
|
||||
{
|
||||
unsigned char *b = (unsigned char *) file_buffer->data;
|
||||
unsigned short chksum = 0;
|
||||
int bytes = file_buffer->size, sparse = TRUE, value;
|
||||
|
||||
while(bytes --) {
|
||||
chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
|
||||
value = *b++;
|
||||
if(value) {
|
||||
sparse = FALSE;
|
||||
chksum += value;
|
||||
}
|
||||
}
|
||||
|
||||
file_buffer->checksum = chksum;
|
||||
return sparse;
|
||||
}
|
||||
|
||||
|
||||
static int read_filesystem(int fd, long long byte, int bytes, void *buff)
|
||||
{
|
||||
off_t off = byte;
|
||||
|
||||
TRACE("read_filesystem: reading from position 0x%llx, bytes %d\n",
|
||||
byte, bytes);
|
||||
|
||||
if(lseek(fd, start_offset + off, SEEK_SET) == -1) {
|
||||
ERROR("read_filesystem: Lseek on destination failed because %s, "
|
||||
"offset=0x%llx\n", strerror(errno), start_offset + off);
|
||||
return 0;
|
||||
} else if(read_bytes(fd, buff, bytes) < bytes) {
|
||||
ERROR("Read on destination failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *get_fragment(struct fragment *fragment,
|
||||
char *data_buffer, int fd)
|
||||
{
|
||||
struct squashfs_fragment_entry *disk_fragment;
|
||||
struct file_buffer *buffer, *compressed_buffer;
|
||||
long long start_block;
|
||||
int res, size, index = fragment->index;
|
||||
char locked;
|
||||
|
||||
/*
|
||||
* Lookup fragment block in cache.
|
||||
* If the fragment block doesn't exist, then get the compressed version
|
||||
* from the writer cache or off disk, and decompress it.
|
||||
*
|
||||
* This routine has two things which complicate the code:
|
||||
*
|
||||
* 1. Multiple threads can simultaneously lookup/create the
|
||||
* same buffer. This means a buffer needs to be "locked"
|
||||
* when it is being filled in, to prevent other threads from
|
||||
* using it when it is not ready. This is because we now do
|
||||
* fragment duplicate checking in parallel.
|
||||
* 2. We have two caches which need to be checked for the
|
||||
* presence of fragment blocks: the normal fragment cache
|
||||
* and a "reserve" cache. The reserve cache is used to
|
||||
* prevent an unnecessary pipeline stall when the fragment cache
|
||||
* is full of fragments waiting to be compressed.
|
||||
*/
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
|
||||
again:
|
||||
buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
|
||||
if(buffer) {
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
if(locked)
|
||||
/* got a buffer being filled in. Wait for it */
|
||||
cache_wait_unlock(buffer);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* not in fragment cache, is it in the reserve cache? */
|
||||
buffer = cache_lookup_nowait(reserve_cache, index, &locked);
|
||||
if(buffer) {
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
if(locked)
|
||||
/* got a buffer being filled in. Wait for it */
|
||||
cache_wait_unlock(buffer);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* in neither cache, try to get it from the fragment cache */
|
||||
buffer = cache_get_nowait(fragment_buffer, index);
|
||||
if(!buffer) {
|
||||
/*
|
||||
* no room, get it from the reserve cache, this is
|
||||
* dimensioned so it will always have space (no more than
|
||||
* processors + 1 can have an outstanding reserve buffer)
|
||||
*/
|
||||
buffer = cache_get_nowait(reserve_cache, index);
|
||||
if(!buffer) {
|
||||
/* failsafe */
|
||||
ERROR("no space in reserve cache\n");
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
|
||||
compressed_buffer = cache_lookup(fwriter_buffer, index);
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
|
||||
pthread_mutex_lock(&fragment_mutex);
|
||||
disk_fragment = &fragment_table[index];
|
||||
size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
|
||||
start_block = disk_fragment->start_block;
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
|
||||
int error;
|
||||
char *data;
|
||||
|
||||
if(compressed_buffer)
|
||||
data = compressed_buffer->data;
|
||||
else {
|
||||
res = read_filesystem(fd, start_block, size, data_buffer);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read fragment from output"
|
||||
" filesystem\n");
|
||||
BAD_ERROR("Output filesystem corrupted?\n");
|
||||
}
|
||||
data = data_buffer;
|
||||
}
|
||||
|
||||
res = compressor_uncompress(comp, buffer->data, data, size,
|
||||
block_size, &error);
|
||||
if(res == -1)
|
||||
BAD_ERROR("%s uncompress failed with error code %d\n",
|
||||
comp->name, error);
|
||||
} else if(compressed_buffer)
|
||||
memcpy(buffer->data, compressed_buffer->data, size);
|
||||
else {
|
||||
res = read_filesystem(fd, start_block, size, buffer->data);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read fragment from output "
|
||||
"filesystem\n");
|
||||
BAD_ERROR("Output filesystem corrupted?\n");
|
||||
}
|
||||
}
|
||||
|
||||
cache_unlock(buffer);
|
||||
cache_block_put(compressed_buffer);
|
||||
|
||||
finished:
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *get_fragment_cksum(struct file_info *file,
|
||||
char *data_buffer, int fd, unsigned short *checksum)
|
||||
{
|
||||
struct file_buffer *frag_buffer;
|
||||
struct append_file *append;
|
||||
int index = file->fragment->index;
|
||||
|
||||
frag_buffer = get_fragment(file->fragment, data_buffer, fd);
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
|
||||
|
||||
for(append = file_mapping[index]; append; append = append->next) {
|
||||
int offset = append->file->fragment->offset;
|
||||
int size = append->file->fragment->size;
|
||||
char *data = frag_buffer->data + offset;
|
||||
unsigned short cksum = get_checksum_mem(data, size);
|
||||
|
||||
if(file == append->file)
|
||||
*checksum = cksum;
|
||||
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
append->file->fragment_checksum = cksum;
|
||||
append->file->have_frag_checksum = TRUE;
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
return frag_buffer;
|
||||
}
|
||||
|
||||
|
||||
void *frag_thrd(void *destination_file)
|
||||
{
|
||||
sigset_t sigmask, old_mask;
|
||||
char *data_buffer;
|
||||
int fd;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGINT);
|
||||
sigaddset(&sigmask, SIGTERM);
|
||||
sigaddset(&sigmask, SIGUSR1);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask);
|
||||
|
||||
fd = open(destination_file, O_RDONLY);
|
||||
if(fd == -1)
|
||||
BAD_ERROR("frag_thrd: can't open destination for reading\n");
|
||||
|
||||
data_buffer = malloc(SQUASHFS_FILE_MAX_SIZE);
|
||||
if(data_buffer == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
|
||||
|
||||
while(1) {
|
||||
struct file_buffer *file_buffer = queue_get(to_process_frag);
|
||||
struct file_buffer *buffer;
|
||||
int sparse = checksum_sparse(file_buffer);
|
||||
struct file_info *dupl_ptr;
|
||||
long long file_size;
|
||||
unsigned short checksum;
|
||||
char flag;
|
||||
int res;
|
||||
|
||||
if(sparse_files && sparse) {
|
||||
file_buffer->c_byte = 0;
|
||||
file_buffer->fragment = FALSE;
|
||||
} else
|
||||
file_buffer->c_byte = file_buffer->size;
|
||||
|
||||
/*
|
||||
* Specutively pull into the fragment cache any fragment blocks
|
||||
* which contain fragments which *this* fragment may be
|
||||
* be a duplicate.
|
||||
*
|
||||
* By ensuring the fragment block is in cache ahead of time
|
||||
* should eliminate the parallelisation stall when the
|
||||
* main thread needs to read the fragment block to do a
|
||||
* duplicate check on it.
|
||||
*
|
||||
* If this is a fragment belonging to a larger file
|
||||
* (with additional blocks) then ignore it. Here we're
|
||||
* interested in the "low hanging fruit" of files which
|
||||
* consist of only a fragment
|
||||
*/
|
||||
if(file_buffer->file_size != file_buffer->size) {
|
||||
seq_queue_put(to_main, file_buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
file_size = file_buffer->file_size;
|
||||
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
dupl_ptr = dupl[DUP_HASH(file_size)];
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
|
||||
file_buffer->dupl_start = dupl_ptr;
|
||||
file_buffer->duplicate = FALSE;
|
||||
|
||||
for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
|
||||
if(file_size != dupl_ptr->file_size ||
|
||||
file_size != dupl_ptr->fragment->size)
|
||||
continue;
|
||||
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
flag = dupl_ptr->have_frag_checksum;
|
||||
checksum = dupl_ptr->fragment_checksum;
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
|
||||
/*
|
||||
* If we have the checksum and it matches then
|
||||
* read in the fragment block.
|
||||
*
|
||||
* If we *don't* have the checksum, then we are
|
||||
* appending, and the fragment block is on the
|
||||
* "old" filesystem. Read it in and checksum
|
||||
* the entire fragment buffer
|
||||
*/
|
||||
if(!flag) {
|
||||
buffer = get_fragment_cksum(dupl_ptr,
|
||||
data_buffer, fd, &checksum);
|
||||
if(checksum != file_buffer->checksum) {
|
||||
cache_block_put(buffer);
|
||||
continue;
|
||||
}
|
||||
} else if(checksum == file_buffer->checksum)
|
||||
buffer = get_fragment(dupl_ptr->fragment,
|
||||
data_buffer, fd);
|
||||
else
|
||||
continue;
|
||||
|
||||
res = memcmp(file_buffer->data, buffer->data +
|
||||
dupl_ptr->fragment->offset, file_size);
|
||||
cache_block_put(buffer);
|
||||
if(res == 0) {
|
||||
struct file_buffer *dup = malloc(sizeof(*dup));
|
||||
if(dup == NULL)
|
||||
MEM_ERROR();
|
||||
memcpy(dup, file_buffer, sizeof(*dup));
|
||||
cache_block_put(file_buffer);
|
||||
dup->dupl_start = dupl_ptr;
|
||||
dup->duplicate = TRUE;
|
||||
file_buffer = dup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
seq_queue_put(to_main, file_buffer);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef PROCESS_FRAGMENTS_H
|
||||
#define PROCESS_FRAGMENTS_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* process_fragments.h
|
||||
*/
|
||||
|
||||
#define DUP_HASH(a) (a & 0xffff)
|
||||
|
||||
extern void *frag_thrd(void *);
|
||||
#endif
|
||||
259
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.c
Normal file
259
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* progressbar.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/* flag whether progressbar display is enabled or not */
|
||||
int display_progress_bar = FALSE;
|
||||
|
||||
/* flag whether the progress bar is temporarily disbled */
|
||||
int temp_disabled = FALSE;
|
||||
|
||||
int rotate = 0;
|
||||
int cur_uncompressed = 0, estimated_uncompressed = 0;
|
||||
int columns;
|
||||
|
||||
pthread_t progress_thread;
|
||||
pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
static void sigwinch_handler()
|
||||
{
|
||||
struct winsize winsize;
|
||||
|
||||
if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
|
||||
if(isatty(STDOUT_FILENO))
|
||||
ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
|
||||
"columns\n");
|
||||
columns = 80;
|
||||
} else
|
||||
columns = winsize.ws_col;
|
||||
}
|
||||
|
||||
|
||||
static void sigalrm_handler()
|
||||
{
|
||||
rotate = (rotate + 1) % 4;
|
||||
}
|
||||
|
||||
|
||||
void inc_progress_bar()
|
||||
{
|
||||
cur_uncompressed ++;
|
||||
}
|
||||
|
||||
|
||||
void dec_progress_bar(int count)
|
||||
{
|
||||
cur_uncompressed -= count;
|
||||
}
|
||||
|
||||
|
||||
void progress_bar_size(int count)
|
||||
{
|
||||
estimated_uncompressed += count;
|
||||
}
|
||||
|
||||
|
||||
static void progress_bar(long long current, long long max, int columns)
|
||||
{
|
||||
char rotate_list[] = { '|', '/', '-', '\\' };
|
||||
int max_digits, used, hashes, spaces;
|
||||
static int tty = -1;
|
||||
|
||||
if(max == 0)
|
||||
return;
|
||||
|
||||
max_digits = floor(log10(max)) + 1;
|
||||
used = max_digits * 2 + 11;
|
||||
hashes = (current * (columns - used)) / max;
|
||||
spaces = columns - used - hashes;
|
||||
|
||||
if((current > max) || (columns - used < 0))
|
||||
return;
|
||||
|
||||
if(tty == -1)
|
||||
tty = isatty(STDOUT_FILENO);
|
||||
if(!tty) {
|
||||
static long long previous = -1;
|
||||
|
||||
/* Updating much more frequently than this results in huge
|
||||
* log files. */
|
||||
if((current % 100) != 0 && current != max)
|
||||
return;
|
||||
/* Don't update just to rotate the spinner. */
|
||||
if(current == previous)
|
||||
return;
|
||||
previous = current;
|
||||
}
|
||||
|
||||
printf("\r[");
|
||||
|
||||
while (hashes --)
|
||||
putchar('=');
|
||||
|
||||
putchar(rotate_list[rotate]);
|
||||
|
||||
while(spaces --)
|
||||
putchar(' ');
|
||||
|
||||
printf("] %*lld/%*lld", max_digits, current, max_digits, max);
|
||||
printf(" %3lld%%", current * 100 / max);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
void enable_progress_bar()
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar)
|
||||
progress_bar(cur_uncompressed, estimated_uncompressed, columns);
|
||||
temp_disabled = FALSE;
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void disable_progress_bar()
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar)
|
||||
printf("\n");
|
||||
temp_disabled = TRUE;
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void set_progressbar_state(int state)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar != state) {
|
||||
if(display_progress_bar && !temp_disabled) {
|
||||
progress_bar(cur_uncompressed, estimated_uncompressed,
|
||||
columns);
|
||||
printf("\n");
|
||||
}
|
||||
display_progress_bar = state;
|
||||
}
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void *progress_thrd(void *arg)
|
||||
{
|
||||
struct timespec requested_time, remaining;
|
||||
struct itimerval itimerval;
|
||||
struct winsize winsize;
|
||||
|
||||
if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
|
||||
if(isatty(STDOUT_FILENO))
|
||||
ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
|
||||
"columns\n");
|
||||
columns = 80;
|
||||
} else
|
||||
columns = winsize.ws_col;
|
||||
signal(SIGWINCH, sigwinch_handler);
|
||||
signal(SIGALRM, sigalrm_handler);
|
||||
|
||||
itimerval.it_value.tv_sec = 0;
|
||||
itimerval.it_value.tv_usec = 250000;
|
||||
itimerval.it_interval.tv_sec = 0;
|
||||
itimerval.it_interval.tv_usec = 250000;
|
||||
setitimer(ITIMER_REAL, &itimerval, NULL);
|
||||
|
||||
requested_time.tv_sec = 0;
|
||||
requested_time.tv_nsec = 250000000;
|
||||
|
||||
while(1) {
|
||||
int res = nanosleep(&requested_time, &remaining);
|
||||
|
||||
if(res == -1 && errno != EINTR)
|
||||
BAD_ERROR("nanosleep failed in progress thread\n");
|
||||
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar && !temp_disabled)
|
||||
progress_bar(cur_uncompressed, estimated_uncompressed,
|
||||
columns);
|
||||
pthread_mutex_unlock(&progress_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_progress_bar()
|
||||
{
|
||||
pthread_create(&progress_thread, NULL, progress_thrd, NULL);
|
||||
}
|
||||
|
||||
|
||||
void progressbar_error(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
|
||||
if(display_progress_bar && !temp_disabled)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void progressbar_info(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
|
||||
if(display_progress_bar && !temp_disabled)
|
||||
printf("\n");
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.h
Normal file
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef PROGRESSBAR_H
|
||||
#define PROGRESSBAR_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* progressbar.h
|
||||
*/
|
||||
|
||||
extern void inc_progress_bar();
|
||||
extern void dec_progress_bar(int count);
|
||||
extern void progress_bar_size(int count);
|
||||
extern void enable_progress_bar();
|
||||
extern void disable_progress_bar();
|
||||
extern void init_progress_bar();
|
||||
extern void set_progressbar_state(int);
|
||||
#endif
|
||||
559
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.c
Normal file
559
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.c
Normal file
@@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2012, 2014, 2017, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* pseudo.c
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "pseudo.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
extern int read_file(char *filename, char *type, int (parse_line)(char *));
|
||||
|
||||
struct pseudo_dev **pseudo_file = NULL;
|
||||
struct pseudo *pseudo = NULL;
|
||||
int pseudo_count = 0;
|
||||
|
||||
static char *get_component(char *target, char **targname)
|
||||
{
|
||||
char *start;
|
||||
|
||||
start = target;
|
||||
while(*target != '/' && *target != '\0')
|
||||
target ++;
|
||||
|
||||
*targname = strndup(start, target - start);
|
||||
|
||||
while(*target == '/')
|
||||
target ++;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add pseudo device target to the set of pseudo devices. Pseudo_dev
|
||||
* describes the pseudo device attributes.
|
||||
*/
|
||||
struct pseudo *add_pseudo(struct pseudo *pseudo, struct pseudo_dev *pseudo_dev,
|
||||
char *target, char *alltarget)
|
||||
{
|
||||
char *targname;
|
||||
int i;
|
||||
|
||||
target = get_component(target, &targname);
|
||||
|
||||
if(pseudo == NULL) {
|
||||
pseudo = malloc(sizeof(struct pseudo));
|
||||
if(pseudo == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
pseudo->names = 0;
|
||||
pseudo->count = 0;
|
||||
pseudo->name = NULL;
|
||||
}
|
||||
|
||||
for(i = 0; i < pseudo->names; i++)
|
||||
if(strcmp(pseudo->name[i].name, targname) == 0)
|
||||
break;
|
||||
|
||||
if(i == pseudo->names) {
|
||||
/* allocate new name entry */
|
||||
pseudo->names ++;
|
||||
pseudo->name = realloc(pseudo->name, (i + 1) *
|
||||
sizeof(struct pseudo_entry));
|
||||
if(pseudo->name == NULL)
|
||||
MEM_ERROR();
|
||||
pseudo->name[i].name = targname;
|
||||
|
||||
if(target[0] == '\0') {
|
||||
/* at leaf pathname component */
|
||||
pseudo->name[i].pseudo = NULL;
|
||||
pseudo->name[i].pathname = strdup(alltarget);
|
||||
pseudo->name[i].dev = pseudo_dev;
|
||||
} else {
|
||||
/* recurse adding child components */
|
||||
pseudo->name[i].dev = NULL;
|
||||
pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev,
|
||||
target, alltarget);
|
||||
}
|
||||
} else {
|
||||
/* existing matching entry */
|
||||
free(targname);
|
||||
|
||||
if(pseudo->name[i].pseudo == NULL) {
|
||||
/* No sub-directory which means this is the leaf
|
||||
* component of a pre-existing pseudo file.
|
||||
*/
|
||||
if(target[0] != '\0') {
|
||||
/*
|
||||
* entry must exist as either a 'd' type or
|
||||
* 'm' type pseudo file
|
||||
*/
|
||||
if(pseudo->name[i].dev->type == 'd' ||
|
||||
pseudo->name[i].dev->type == 'm')
|
||||
/* recurse adding child components */
|
||||
pseudo->name[i].pseudo =
|
||||
add_pseudo(NULL, pseudo_dev,
|
||||
target, alltarget);
|
||||
else {
|
||||
ERROR_START("%s already exists as a "
|
||||
"non directory.",
|
||||
pseudo->name[i].name);
|
||||
ERROR_EXIT(". Ignoring %s!\n",
|
||||
alltarget);
|
||||
}
|
||||
} else if(memcmp(pseudo_dev, pseudo->name[i].dev,
|
||||
sizeof(struct pseudo_dev)) != 0) {
|
||||
ERROR_START("%s already exists as a different "
|
||||
"pseudo definition.", alltarget);
|
||||
ERROR_EXIT(" Ignoring!\n");
|
||||
} else {
|
||||
ERROR_START("%s already exists as an identical "
|
||||
"pseudo definition!", alltarget);
|
||||
ERROR_EXIT(" Ignoring!\n");
|
||||
}
|
||||
} else {
|
||||
if(target[0] == '\0') {
|
||||
/*
|
||||
* sub-directory exists, which means we can only
|
||||
* add a pseudo file of type 'd' or type 'm'
|
||||
*/
|
||||
if(pseudo->name[i].dev == NULL &&
|
||||
(pseudo_dev->type == 'd' ||
|
||||
pseudo_dev->type == 'm')) {
|
||||
pseudo->name[i].pathname =
|
||||
strdup(alltarget);
|
||||
pseudo->name[i].dev = pseudo_dev;
|
||||
} else {
|
||||
ERROR_START("%s already exists as a "
|
||||
"different pseudo definition.",
|
||||
pseudo->name[i].name);
|
||||
ERROR_EXIT(" Ignoring %s!\n",
|
||||
alltarget);
|
||||
}
|
||||
} else
|
||||
/* recurse adding child components */
|
||||
add_pseudo(pseudo->name[i].pseudo, pseudo_dev,
|
||||
target, alltarget);
|
||||
}
|
||||
}
|
||||
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find subdirectory in pseudo directory referenced by pseudo, matching
|
||||
* filename. If filename doesn't exist or if filename is a leaf file
|
||||
* return NULL
|
||||
*/
|
||||
struct pseudo *pseudo_subdir(char *filename, struct pseudo *pseudo)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(pseudo == NULL)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; i < pseudo->names; i++)
|
||||
if(strcmp(filename, pseudo->name[i].name) == 0)
|
||||
return pseudo->name[i].pseudo;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct pseudo_entry *pseudo_readdir(struct pseudo *pseudo)
|
||||
{
|
||||
if(pseudo == NULL)
|
||||
return NULL;
|
||||
|
||||
while(pseudo->count < pseudo->names) {
|
||||
if(pseudo->name[pseudo->count].dev != NULL)
|
||||
return &pseudo->name[pseudo->count++];
|
||||
else
|
||||
pseudo->count++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int pseudo_exec_file(struct pseudo_dev *dev, int *child)
|
||||
{
|
||||
int res, pipefd[2];
|
||||
|
||||
res = pipe(pipefd);
|
||||
if(res == -1) {
|
||||
ERROR("Executing dynamic pseudo file, pipe failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*child = fork();
|
||||
if(*child == -1) {
|
||||
ERROR("Executing dynamic pseudo file, fork failed\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(*child == 0) {
|
||||
close(pipefd[0]);
|
||||
close(STDOUT_FILENO);
|
||||
res = dup(pipefd[1]);
|
||||
if(res == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
execl("/bin/sh", "sh", "-c", dev->command, (char *) NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
close(pipefd[1]);
|
||||
return pipefd[0];
|
||||
|
||||
failed:
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void add_pseudo_file(struct pseudo_dev *dev)
|
||||
{
|
||||
pseudo_file = realloc(pseudo_file, (pseudo_count + 1) *
|
||||
sizeof(struct pseudo_dev *));
|
||||
if(pseudo_file == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
dev->pseudo_id = pseudo_count;
|
||||
pseudo_file[pseudo_count ++] = dev;
|
||||
}
|
||||
|
||||
|
||||
struct pseudo_dev *get_pseudo_file(int pseudo_id)
|
||||
{
|
||||
return pseudo_file[pseudo_id];
|
||||
}
|
||||
|
||||
|
||||
int read_pseudo_def(char *def)
|
||||
{
|
||||
int n, bytes;
|
||||
int quoted = 0;
|
||||
unsigned int major = 0, minor = 0, mode;
|
||||
char type, *ptr;
|
||||
char suid[100], sgid[100]; /* overflow safe */
|
||||
char *filename, *name;
|
||||
char *orig_def = def;
|
||||
long long uid, gid;
|
||||
struct pseudo_dev *dev;
|
||||
|
||||
/*
|
||||
* Scan for filename, don't use sscanf() and "%s" because
|
||||
* that can't handle filenames with spaces.
|
||||
*
|
||||
* Filenames with spaces should either escape (backslash) the
|
||||
* space or use double quotes.
|
||||
*/
|
||||
filename = malloc(strlen(def) + 1);
|
||||
if(filename == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
for(name = filename; (quoted || !isspace(*def)) && *def != '\0';) {
|
||||
if(*def == '"') {
|
||||
quoted = !quoted;
|
||||
def ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(*def == '\\') {
|
||||
def ++;
|
||||
if (*def == '\0')
|
||||
break;
|
||||
}
|
||||
*name ++ = *def ++;
|
||||
}
|
||||
*name = '\0';
|
||||
|
||||
/* Skip any leading slashes (/) */
|
||||
for(name = filename; *name == '/'; name ++);
|
||||
|
||||
if(*name == '\0') {
|
||||
ERROR("Not enough or invalid arguments in pseudo file "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
goto error;
|
||||
}
|
||||
|
||||
n = sscanf(def, " %c %o %99s %99s %n", &type, &mode, suid, sgid,
|
||||
&bytes);
|
||||
def += bytes;
|
||||
|
||||
if(n < 4) {
|
||||
ERROR("Not enough or invalid arguments in pseudo file "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
switch(n) {
|
||||
case -1:
|
||||
/* FALLTHROUGH */
|
||||
case 0:
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
ERROR("Couldn't parse filename, type or octal mode\n");
|
||||
ERROR("If the filename has spaces, either quote it, or "
|
||||
"backslash the spaces\n");
|
||||
break;
|
||||
case 2:
|
||||
ERROR("Read filename, type and mode, but failed to "
|
||||
"read or match uid\n");
|
||||
break;
|
||||
default:
|
||||
ERROR("Read filename, type, mode and uid, but failed "
|
||||
"to read or match gid\n");
|
||||
break;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case 'b':
|
||||
/* FALLTHROUGH */
|
||||
case 'c':
|
||||
n = sscanf(def, "%u %u %n", &major, &minor, &bytes);
|
||||
def += bytes;
|
||||
|
||||
if(n < 2) {
|
||||
ERROR("Not enough or invalid arguments in %s device "
|
||||
"pseudo file definition \"%s\"\n", type == 'b' ?
|
||||
"block" : "character", orig_def);
|
||||
if(n < 1)
|
||||
ERROR("Read filename, type, mode, uid and gid, "
|
||||
"but failed to read or match major\n");
|
||||
else
|
||||
ERROR("Read filename, type, mode, uid, gid "
|
||||
"and major, but failed to read or "
|
||||
"match minor\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(major > 0xfff) {
|
||||
ERROR("Major %d out of range\n", major);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(minor > 0xfffff) {
|
||||
ERROR("Minor %d out of range\n", minor);
|
||||
goto error;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 'd':
|
||||
/* FALLTHROUGH */
|
||||
case 'm':
|
||||
/*
|
||||
* Check for trailing junk after expected arguments
|
||||
*/
|
||||
if(def[0] != '\0') {
|
||||
ERROR("Unexpected tailing characters in pseudo file "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if(def[0] == '\0') {
|
||||
ERROR("Not enough arguments in dynamic file pseudo "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
ERROR("Expected command, which can be an executable "
|
||||
"or a piece of shell script\n");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if(def[0] == '\0') {
|
||||
ERROR("Not enough arguments in symlink pseudo "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
ERROR("Expected symlink\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(strlen(def) > 65535) {
|
||||
ERROR("Symlink pseudo definition %s is greater than 65535"
|
||||
" bytes!\n", def);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Unsupported type %c\n", type);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
if(mode > 07777) {
|
||||
ERROR("Mode %o out of range\n", mode);
|
||||
goto error;
|
||||
}
|
||||
|
||||
uid = strtoll(suid, &ptr, 10);
|
||||
if(*ptr == '\0') {
|
||||
if(uid < 0 || uid > ((1LL << 32) - 1)) {
|
||||
ERROR("Uid %s out of range\n", suid);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
struct passwd *pwuid = getpwnam(suid);
|
||||
if(pwuid)
|
||||
uid = pwuid->pw_uid;
|
||||
else {
|
||||
ERROR("Uid %s invalid uid or unknown user\n", suid);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
gid = strtoll(sgid, &ptr, 10);
|
||||
if(*ptr == '\0') {
|
||||
if(gid < 0 || gid > ((1LL << 32) - 1)) {
|
||||
ERROR("Gid %s out of range\n", sgid);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
struct group *grgid = getgrnam(sgid);
|
||||
if(grgid)
|
||||
gid = grgid->gr_gid;
|
||||
else {
|
||||
ERROR("Gid %s invalid uid or unknown user\n", sgid);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case 'b':
|
||||
mode |= S_IFBLK;
|
||||
break;
|
||||
case 'c':
|
||||
mode |= S_IFCHR;
|
||||
break;
|
||||
case 'd':
|
||||
mode |= S_IFDIR;
|
||||
break;
|
||||
case 'f':
|
||||
mode |= S_IFREG;
|
||||
break;
|
||||
case 's':
|
||||
/* permissions on symlinks are always rwxrwxrwx */
|
||||
mode = 0777 | S_IFLNK;
|
||||
break;
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(struct pseudo_dev));
|
||||
if(dev == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
dev->type = type;
|
||||
dev->mode = mode;
|
||||
dev->uid = uid;
|
||||
dev->gid = gid;
|
||||
dev->major = major;
|
||||
dev->minor = minor;
|
||||
if(type == 'f') {
|
||||
dev->command = strdup(def);
|
||||
add_pseudo_file(dev);
|
||||
}
|
||||
if(type == 's')
|
||||
dev->symlink = strdup(def);
|
||||
|
||||
pseudo = add_pseudo(pseudo, dev, name, name);
|
||||
|
||||
free(filename);
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
ERROR("Pseudo definitions should be of the format\n");
|
||||
ERROR("\tfilename d mode uid gid\n");
|
||||
ERROR("\tfilename m mode uid gid\n");
|
||||
ERROR("\tfilename b mode uid gid major minor\n");
|
||||
ERROR("\tfilename c mode uid gid major minor\n");
|
||||
ERROR("\tfilename f mode uid gid command\n");
|
||||
ERROR("\tfilename s mode uid gid symlink\n");
|
||||
free(filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int read_pseudo_file(char *filename)
|
||||
{
|
||||
return read_file(filename, "pseudo", read_pseudo_def);
|
||||
}
|
||||
|
||||
|
||||
struct pseudo *get_pseudo()
|
||||
{
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SQUASHFS_TRACE
|
||||
static void dump_pseudo(struct pseudo *pseudo, char *string)
|
||||
{
|
||||
int i, res;
|
||||
char *path;
|
||||
|
||||
for(i = 0; i < pseudo->names; i++) {
|
||||
struct pseudo_entry *entry = &pseudo->name[i];
|
||||
if(string) {
|
||||
res = asprintf(&path, "%s/%s", string, entry->name);
|
||||
if(res == -1)
|
||||
BAD_ERROR("asprintf failed in dump_pseudo\n");
|
||||
} else
|
||||
path = entry->name;
|
||||
if(entry->dev)
|
||||
ERROR("%s %c 0%o %d %d %d %d\n", path, entry->dev->type,
|
||||
entry->dev->mode & ~S_IFMT, entry->dev->uid,
|
||||
entry->dev->gid, entry->dev->major,
|
||||
entry->dev->minor);
|
||||
if(entry->pseudo)
|
||||
dump_pseudo(entry->pseudo, path);
|
||||
if(string)
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_pseudos()
|
||||
{
|
||||
if (pseudo)
|
||||
dump_pseudo(pseudo, NULL);
|
||||
}
|
||||
#else
|
||||
void dump_pseudos()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.h
Normal file
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef PSEUDO_H
|
||||
#define PSEUDO_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* pseudo.h
|
||||
*/
|
||||
struct pseudo_dev {
|
||||
char type;
|
||||
unsigned int mode;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int major;
|
||||
unsigned int minor;
|
||||
int pseudo_id;
|
||||
union {
|
||||
char *command;
|
||||
char *symlink;
|
||||
};
|
||||
};
|
||||
|
||||
struct pseudo_entry {
|
||||
char *name;
|
||||
char *pathname;
|
||||
struct pseudo *pseudo;
|
||||
struct pseudo_dev *dev;
|
||||
};
|
||||
|
||||
struct pseudo {
|
||||
int names;
|
||||
int count;
|
||||
struct pseudo_entry *name;
|
||||
};
|
||||
|
||||
extern int read_pseudo_def(char *);
|
||||
extern int read_pseudo_file(char *);
|
||||
extern struct pseudo *pseudo_subdir(char *, struct pseudo *);
|
||||
extern struct pseudo_entry *pseudo_readdir(struct pseudo *);
|
||||
extern struct pseudo_dev *get_pseudo_file(int);
|
||||
extern int pseudo_exec_file(struct pseudo_dev *, int *);
|
||||
extern struct pseudo *get_pseudo();
|
||||
extern void dump_pseudos();
|
||||
#endif
|
||||
150
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_file.c
Normal file
150
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_file.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_file.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define MAX_LINE 16384
|
||||
|
||||
/*
|
||||
* Read file, passing each line to parse_line() for
|
||||
* parsing.
|
||||
*
|
||||
* Lines can be split across multiple lines using "\".
|
||||
*
|
||||
* Blank lines and comment lines indicated by # are supported.
|
||||
*/
|
||||
int read_file(char *filename, char *type, int (parse_line)(char *))
|
||||
{
|
||||
FILE *fd;
|
||||
char *def, *err, *line = NULL;
|
||||
int res, size = 0;
|
||||
|
||||
fd = fopen(filename, "r");
|
||||
if(fd == NULL) {
|
||||
ERROR("Could not open %s device file \"%s\" because %s\n",
|
||||
type, filename, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
int total = 0;
|
||||
|
||||
while(1) {
|
||||
int len;
|
||||
|
||||
if(total + (MAX_LINE + 1) > size) {
|
||||
line = realloc(line, size += (MAX_LINE + 1));
|
||||
if(line == NULL)
|
||||
MEM_ERROR();
|
||||
}
|
||||
|
||||
err = fgets(line + total, MAX_LINE + 1, fd);
|
||||
if(err == NULL)
|
||||
break;
|
||||
|
||||
len = strlen(line + total);
|
||||
total += len;
|
||||
|
||||
if(len == MAX_LINE && line[total - 1] != '\n') {
|
||||
/* line too large */
|
||||
ERROR("Line too long when reading "
|
||||
"%s file \"%s\", larger than "
|
||||
"%d bytes\n", type, filename, MAX_LINE);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove '\n' terminator if it exists (the last line
|
||||
* in the file may not be '\n' terminated)
|
||||
*/
|
||||
if(len && line[total - 1] == '\n') {
|
||||
line[-- total] = '\0';
|
||||
len --;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no line continuation then jump out to
|
||||
* process line. Note, we have to be careful to
|
||||
* check for "\\" (backslashed backslash) and to
|
||||
* ensure we don't look at the previous line
|
||||
*/
|
||||
if(len == 0 || line[total - 1] != '\\' || (len >= 2 &&
|
||||
strcmp(line + total - 2, "\\\\") == 0))
|
||||
break;
|
||||
else
|
||||
total --;
|
||||
}
|
||||
|
||||
if(err == NULL) {
|
||||
if(ferror(fd)) {
|
||||
ERROR("Reading %s file \"%s\" failed "
|
||||
"because %s\n", type, filename,
|
||||
strerror(errno));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* At EOF, normally we'll be finished, but, have to
|
||||
* check for special case where we had "\" line
|
||||
* continuation and then hit EOF immediately afterwards
|
||||
*/
|
||||
if(total == 0)
|
||||
break;
|
||||
else
|
||||
line[total] = '\0';
|
||||
}
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
for(def = line; isspace(*def); def ++);
|
||||
|
||||
/* if line is now empty after skipping characters, skip it */
|
||||
if(*def == '\0')
|
||||
continue;
|
||||
|
||||
/* if comment line, skip */
|
||||
if(*def == '#')
|
||||
continue;
|
||||
|
||||
res = parse_line(def);
|
||||
if(res == FALSE)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
free(line);
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
fclose(fd);
|
||||
free(line);
|
||||
return FALSE;
|
||||
}
|
||||
996
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.c
Normal file
996
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.c
Normal file
@@ -0,0 +1,996 @@
|
||||
/*
|
||||
* Read a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
* 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_fs.c
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_swap.h"
|
||||
#include "compressor.h"
|
||||
#include "xattr.h"
|
||||
#include "error.h"
|
||||
#include "mksquashfs.h"
|
||||
|
||||
int read_block(int fd, long long start, long long *next, int expected,
|
||||
void *block)
|
||||
{
|
||||
unsigned short c_byte;
|
||||
int res, compressed;
|
||||
int outlen = expected ? expected : SQUASHFS_METADATA_SIZE;
|
||||
|
||||
/* Read block size */
|
||||
res = read_fs_bytes(fd, start, 2, &c_byte);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
|
||||
SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
|
||||
compressed = SQUASHFS_COMPRESSED(c_byte);
|
||||
c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
|
||||
|
||||
/*
|
||||
* The block size should not be larger than
|
||||
* the uncompressed size (or max uncompressed size if
|
||||
* expected is 0)
|
||||
*/
|
||||
if (c_byte > outlen)
|
||||
return 0;
|
||||
|
||||
if(compressed) {
|
||||
char buffer[c_byte];
|
||||
int error;
|
||||
|
||||
res = read_fs_bytes(fd, start + 2, c_byte, buffer);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
|
||||
res = compressor_uncompress(comp, block, buffer, c_byte,
|
||||
outlen, &error);
|
||||
if(res == -1) {
|
||||
ERROR("%s uncompress failed with error code %d\n",
|
||||
comp->name, error);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
res = read_fs_bytes(fd, start + 2, c_byte, block);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
res = c_byte;
|
||||
}
|
||||
|
||||
if(next)
|
||||
*next = start + 2 + c_byte;
|
||||
|
||||
/*
|
||||
* if expected, then check the (uncompressed) return data
|
||||
* is of the expected size
|
||||
*/
|
||||
if(expected && expected != res)
|
||||
return 0;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#define NO_BYTES(SIZE) \
|
||||
(bytes - (cur_ptr - inode_table) < (SIZE))
|
||||
|
||||
#define NO_INODE_BYTES(INODE) NO_BYTES(sizeof(struct INODE))
|
||||
|
||||
unsigned char *scan_inode_table(int fd, long long start, long long end,
|
||||
long long root_inode_start, int root_inode_offset,
|
||||
struct squashfs_super_block *sBlk, union squashfs_inode_header
|
||||
*dir_inode, unsigned int *root_inode_block, unsigned int
|
||||
*root_inode_size, long long *uncompressed_file, unsigned int
|
||||
*uncompressed_directory, int *file_count, int *sym_count, int
|
||||
*dev_count, int *dir_count, int *fifo_count, int *sock_count,
|
||||
unsigned int *id_table)
|
||||
{
|
||||
unsigned char *cur_ptr;
|
||||
unsigned char *inode_table = NULL;
|
||||
int byte, files = 0;
|
||||
unsigned int directory_start_block, bytes = 0, size = 0;
|
||||
struct squashfs_base_inode_header base;
|
||||
|
||||
TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start "
|
||||
"0x%llx\n", start, end, root_inode_start);
|
||||
|
||||
*root_inode_block = UINT_MAX;
|
||||
while(start < end) {
|
||||
if(start == root_inode_start) {
|
||||
TRACE("scan_inode_table: read compressed block 0x%llx "
|
||||
"containing root inode\n", start);
|
||||
*root_inode_block = bytes;
|
||||
}
|
||||
if(size - bytes < SQUASHFS_METADATA_SIZE) {
|
||||
inode_table = realloc(inode_table, size
|
||||
+= SQUASHFS_METADATA_SIZE);
|
||||
if(inode_table == NULL)
|
||||
MEM_ERROR();
|
||||
}
|
||||
TRACE("scan_inode_table: reading block 0x%llx\n", start);
|
||||
byte = read_block(fd, start, &start, 0, inode_table + bytes);
|
||||
if(byte == 0)
|
||||
goto corrupted;
|
||||
|
||||
bytes += byte;
|
||||
|
||||
/* If this is not the last metadata block in the inode table
|
||||
* then it should be SQUASHFS_METADATA_SIZE in size.
|
||||
* Note, we can't use expected in read_block() above for this
|
||||
* because we don't know if this is the last block until
|
||||
* after reading.
|
||||
*/
|
||||
if(start != end && byte != SQUASHFS_METADATA_SIZE)
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/*
|
||||
* We expect to have found the metadata block containing the
|
||||
* root inode in the above inode_table metadata block scan. If it
|
||||
* hasn't been found then the filesystem is corrupted
|
||||
*/
|
||||
if(*root_inode_block == UINT_MAX)
|
||||
goto corrupted;
|
||||
|
||||
/*
|
||||
* The number of bytes available after the root inode medata block
|
||||
* should be at least the root inode offset + the size of a
|
||||
* regular directory inode, if not the filesystem is corrupted
|
||||
*
|
||||
* +-----------------------+-----------------------+
|
||||
* | | directory |
|
||||
* | | inode |
|
||||
* +-----------------------+-----------------------+
|
||||
* ^ ^ ^
|
||||
* *root_inode_block root_inode_offset bytes
|
||||
*/
|
||||
if((bytes - *root_inode_block) < (root_inode_offset +
|
||||
sizeof(struct squashfs_dir_inode_header)))
|
||||
goto corrupted;
|
||||
|
||||
/*
|
||||
* Read last inode entry which is the root directory inode, and obtain
|
||||
* the last directory start block index. This is used when calculating
|
||||
* the total uncompressed directory size. The directory bytes in the
|
||||
* last * block will be counted as normal.
|
||||
*
|
||||
* Note, the previous check ensures the following calculation won't
|
||||
* underflow, and we won't access beyond the buffer
|
||||
*/
|
||||
*root_inode_size = bytes - (*root_inode_block + root_inode_offset);
|
||||
bytes = *root_inode_block + root_inode_offset;
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER(inode_table + bytes, &dir_inode->dir);
|
||||
|
||||
if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE)
|
||||
directory_start_block = dir_inode->dir.start_block;
|
||||
else if(dir_inode->base.inode_type == SQUASHFS_LDIR_TYPE) {
|
||||
if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER(inode_table + bytes,
|
||||
&dir_inode->ldir);
|
||||
directory_start_block = dir_inode->ldir.start_block;
|
||||
} else
|
||||
/* bad type, corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
get_uid(id_table[dir_inode->base.uid]);
|
||||
get_guid(id_table[dir_inode->base.guid]);
|
||||
|
||||
/* allocate fragment to file mapping table */
|
||||
file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
|
||||
if(file_mapping == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
for(cur_ptr = inode_table; cur_ptr < inode_table + bytes; files ++) {
|
||||
if(NO_INODE_BYTES(squashfs_base_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
|
||||
|
||||
TRACE("scan_inode_table: processing inode @ byte position "
|
||||
"0x%x, type 0x%x\n",
|
||||
(unsigned int) (cur_ptr - inode_table),
|
||||
base.inode_type);
|
||||
|
||||
get_uid(id_table[base.uid]);
|
||||
get_guid(id_table[base.guid]);
|
||||
|
||||
switch(base.inode_type) {
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
struct squashfs_reg_inode_header inode;
|
||||
int frag_bytes, blocks, i;
|
||||
long long start, file_bytes = 0;
|
||||
unsigned int *block_list;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_reg_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
|
||||
|
||||
frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
0 : inode.file_size % sBlk->block_size;
|
||||
blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(inode.file_size + sBlk->block_size - 1) >>
|
||||
sBlk->block_log : inode.file_size >>
|
||||
sBlk->block_log;
|
||||
start = inode.start_block;
|
||||
|
||||
TRACE("scan_inode_table: regular file, file_size %d, "
|
||||
"blocks %d\n", inode.file_size, blocks);
|
||||
|
||||
if(NO_BYTES(blocks * sizeof(unsigned int)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
block_list = malloc(blocks * sizeof(unsigned int));
|
||||
if(block_list == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
cur_ptr += sizeof(inode);
|
||||
SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
|
||||
|
||||
*uncompressed_file += inode.file_size;
|
||||
(*file_count) ++;
|
||||
|
||||
for(i = 0; i < blocks; i++)
|
||||
file_bytes +=
|
||||
SQUASHFS_COMPRESSED_SIZE_BLOCK
|
||||
(block_list[i]);
|
||||
|
||||
if(inode.fragment != SQUASHFS_INVALID_FRAG &&
|
||||
inode.fragment >= sBlk->fragments) {
|
||||
free(block_list);
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
add_file(start, inode.file_size, file_bytes,
|
||||
block_list, blocks, inode.fragment,
|
||||
inode.offset, frag_bytes);
|
||||
|
||||
cur_ptr += blocks * sizeof(unsigned int);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LREG_TYPE: {
|
||||
struct squashfs_lreg_inode_header inode;
|
||||
int frag_bytes, blocks, i;
|
||||
long long start, file_bytes = 0;
|
||||
unsigned int *block_list;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_lreg_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
|
||||
|
||||
frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
0 : inode.file_size % sBlk->block_size;
|
||||
blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(inode.file_size + sBlk->block_size - 1) >>
|
||||
sBlk->block_log : inode.file_size >>
|
||||
sBlk->block_log;
|
||||
start = inode.start_block;
|
||||
|
||||
TRACE("scan_inode_table: extended regular "
|
||||
"file, file_size %lld, blocks %d\n",
|
||||
inode.file_size, blocks);
|
||||
|
||||
if(NO_BYTES(blocks * sizeof(unsigned int)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
block_list = malloc(blocks * sizeof(unsigned int));
|
||||
if(block_list == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
cur_ptr += sizeof(inode);
|
||||
SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
|
||||
|
||||
*uncompressed_file += inode.file_size;
|
||||
(*file_count) ++;
|
||||
|
||||
for(i = 0; i < blocks; i++)
|
||||
file_bytes +=
|
||||
SQUASHFS_COMPRESSED_SIZE_BLOCK
|
||||
(block_list[i]);
|
||||
|
||||
if(inode.fragment != SQUASHFS_INVALID_FRAG &&
|
||||
inode.fragment >= sBlk->fragments) {
|
||||
free(block_list);
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
add_file(start, inode.file_size, file_bytes,
|
||||
block_list, blocks, inode.fragment,
|
||||
inode.offset, frag_bytes);
|
||||
|
||||
cur_ptr += blocks * sizeof(unsigned int);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE:
|
||||
case SQUASHFS_LSYMLINK_TYPE: {
|
||||
struct squashfs_symlink_inode_header inode;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_symlink_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
|
||||
|
||||
(*sym_count) ++;
|
||||
|
||||
if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) {
|
||||
if(NO_BYTES(inode.symlink_size +
|
||||
sizeof(unsigned int)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
cur_ptr += sizeof(inode) + inode.symlink_size +
|
||||
sizeof(unsigned int);
|
||||
} else {
|
||||
if(NO_BYTES(inode.symlink_size))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
cur_ptr += sizeof(inode) + inode.symlink_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
struct squashfs_dir_inode_header dir_inode;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_dir_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
|
||||
|
||||
if(dir_inode.start_block < directory_start_block)
|
||||
*uncompressed_directory += dir_inode.file_size;
|
||||
|
||||
(*dir_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_dir_inode_header);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
struct squashfs_ldir_inode_header dir_inode;
|
||||
int i;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_ldir_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
|
||||
|
||||
if(dir_inode.start_block < directory_start_block)
|
||||
*uncompressed_directory += dir_inode.file_size;
|
||||
|
||||
(*dir_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ldir_inode_header);
|
||||
|
||||
for(i = 0; i < dir_inode.i_count; i++) {
|
||||
struct squashfs_dir_index index;
|
||||
|
||||
if(NO_BYTES(sizeof(index)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
|
||||
|
||||
if(NO_BYTES(index.size + 1))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
cur_ptr += sizeof(index) + index.size + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_dev_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*dev_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_dev_inode_header);
|
||||
break;
|
||||
case SQUASHFS_LBLKDEV_TYPE:
|
||||
case SQUASHFS_LCHRDEV_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_ldev_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*dev_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ldev_inode_header);
|
||||
break;
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_ipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*fifo_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ipc_inode_header);
|
||||
break;
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_lipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*fifo_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_lipc_inode_header);
|
||||
break;
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_ipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*sock_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ipc_inode_header);
|
||||
break;
|
||||
case SQUASHFS_LSOCKET_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_lipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*sock_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_lipc_inode_header);
|
||||
break;
|
||||
default:
|
||||
ERROR("Unknown inode type %d in scan_inode_table!\n",
|
||||
base.inode_type);
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Read existing filesystem, %d inodes scanned\n", files);
|
||||
return inode_table;
|
||||
|
||||
corrupted:
|
||||
ERROR("scan_inode_table: filesystem corruption detected in "
|
||||
"scanning metadata\n");
|
||||
free(inode_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source)
|
||||
{
|
||||
int res, bytes = 0;
|
||||
char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
|
||||
|
||||
res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
|
||||
sBlk);
|
||||
if(res == 0) {
|
||||
ERROR("Can't find a SQUASHFS superblock on %s\n",
|
||||
source);
|
||||
ERROR("Wrong filesystem or filesystem is corrupted!\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
|
||||
|
||||
if(sBlk->s_magic != SQUASHFS_MAGIC) {
|
||||
if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP)
|
||||
ERROR("Pre 4.0 big-endian filesystem on %s, appending"
|
||||
" to this is unsupported\n", source);
|
||||
else {
|
||||
ERROR("Can't find a SQUASHFS superblock on %s\n",
|
||||
source);
|
||||
ERROR("Wrong filesystem or filesystem is corrupted!\n");
|
||||
}
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Check the MAJOR & MINOR versions */
|
||||
if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
|
||||
if(sBlk->s_major < 4)
|
||||
ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem."
|
||||
" Appending\nto SQUASHFS %d.%d filesystems is "
|
||||
"not supported. Please convert it to a "
|
||||
"SQUASHFS 4 filesystem\n", source,
|
||||
sBlk->s_major,
|
||||
sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
|
||||
else
|
||||
ERROR("Filesystem on %s is %d.%d, which is a later "
|
||||
"filesystem version than I support\n",
|
||||
source, sBlk->s_major, sBlk->s_minor);
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Check the compression type */
|
||||
comp = lookup_compressor_id(sBlk->compression);
|
||||
if(!comp->supported) {
|
||||
ERROR("Filesystem on %s uses %s compression, this is "
|
||||
"unsupported by this version\n", source, comp->name);
|
||||
ERROR("Compressors available:\n");
|
||||
display_compressors("", "");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read extended superblock information from disk.
|
||||
*
|
||||
* Read compressor specific options from disk if present, and pass
|
||||
* to compressor to set compressor options.
|
||||
*
|
||||
* Note, if there's no compressor options present, the compressor
|
||||
* is still called to set the default options (the defaults may have
|
||||
* been changed by the user specifying options on the command
|
||||
* line which need to be over-ridden).
|
||||
*
|
||||
* Compressor_extract_options is also used to ensure that
|
||||
* we know how decompress a filesystem compressed with these
|
||||
* compression options.
|
||||
*/
|
||||
if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
|
||||
bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
|
||||
|
||||
if(bytes == 0) {
|
||||
ERROR("Failed to read compressor options from append "
|
||||
"filesystem\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
}
|
||||
|
||||
res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes);
|
||||
if(res == -1) {
|
||||
ERROR("Compressor failed to set compressor options\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
printf("Found a valid %sSQUASHFS superblock on %s.\n",
|
||||
SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source);
|
||||
printf("\tCompression used %s\n", comp->name);
|
||||
printf("\tInodes are %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
|
||||
printf("\tData is %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
|
||||
printf("\tFragments are %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
|
||||
printf("\tXattrs are %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : "");
|
||||
printf("\tFragments are %spresent in the filesystem\n",
|
||||
SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
|
||||
printf("\tAlways-use-fragments option is %sspecified\n",
|
||||
SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
|
||||
printf("\tDuplicates are %sremoved\n",
|
||||
SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
|
||||
printf("\tXattrs are %sstored\n",
|
||||
SQUASHFS_NO_XATTRS(sBlk->flags) ? "not " : "");
|
||||
printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n",
|
||||
sBlk->bytes_used / 1024.0, sBlk->bytes_used
|
||||
/ (1024.0 * 1024.0));
|
||||
printf("\tBlock size %d\n", sBlk->block_size);
|
||||
printf("\tNumber of fragments %d\n", sBlk->fragments);
|
||||
printf("\tNumber of inodes %d\n", sBlk->inodes);
|
||||
printf("\tNumber of ids %d\n", sBlk->no_ids);
|
||||
TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start);
|
||||
TRACE("sBlk->directory_table_start %llx\n",
|
||||
sBlk->directory_table_start);
|
||||
TRACE("sBlk->id_table_start %llx\n", sBlk->id_table_start);
|
||||
TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start);
|
||||
TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start);
|
||||
TRACE("sBlk->xattr_id_table_start %llx\n", sBlk->xattr_id_table_start);
|
||||
printf("\n");
|
||||
|
||||
return comp;
|
||||
|
||||
failed_mount:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
unsigned char *squashfs_readdir(int fd, int root_entries,
|
||||
unsigned int directory_start_block, int offset, int size,
|
||||
unsigned int *last_directory_block, struct squashfs_super_block *sBlk,
|
||||
void (push_directory_entry)(char *, squashfs_inode, int, int))
|
||||
{
|
||||
struct squashfs_dir_header dirh;
|
||||
char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__ ((aligned));
|
||||
struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
|
||||
unsigned char *directory_table = NULL;
|
||||
int byte, bytes = 0, dir_count;
|
||||
long long start = sBlk->directory_table_start + directory_start_block,
|
||||
last_start_block = start;
|
||||
|
||||
size += offset;
|
||||
directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) &
|
||||
~(SQUASHFS_METADATA_SIZE - 1));
|
||||
if(directory_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
while(bytes < size) {
|
||||
int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ?
|
||||
SQUASHFS_METADATA_SIZE : 0;
|
||||
|
||||
TRACE("squashfs_readdir: reading block 0x%llx, bytes read so "
|
||||
"far %d\n", start, bytes);
|
||||
|
||||
last_start_block = start;
|
||||
byte = read_block(fd, start, &start, expected, directory_table + bytes);
|
||||
if(byte == 0) {
|
||||
ERROR("Failed to read directory\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(directory_table);
|
||||
return NULL;
|
||||
}
|
||||
bytes += byte;
|
||||
}
|
||||
|
||||
if(!root_entries)
|
||||
goto all_done;
|
||||
|
||||
bytes = offset;
|
||||
while(bytes < size) {
|
||||
SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
free(directory_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE("squashfs_readdir: Read directory header @ byte position "
|
||||
"0x%x, 0x%x directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
while(dir_count--) {
|
||||
SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
free(directory_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_readdir: pushing directory entry %s, "
|
||||
"inode %x:%x, type 0x%x\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
push_directory_entry(dire->name,
|
||||
SQUASHFS_MKINODE(dirh.start_block,
|
||||
dire->offset), dirh.inode_number +
|
||||
dire->inode_number, dire->type);
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
all_done:
|
||||
*last_directory_block = (unsigned int) last_start_block -
|
||||
sBlk->directory_table_start;
|
||||
return directory_table;
|
||||
}
|
||||
|
||||
|
||||
unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int indexes = SQUASHFS_ID_BLOCKS(sBlk->no_ids);
|
||||
long long index[indexes];
|
||||
int bytes = SQUASHFS_ID_BYTES(sBlk->no_ids);
|
||||
unsigned int *id_table;
|
||||
int res, i;
|
||||
|
||||
id_table = malloc(bytes);
|
||||
if(id_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->id_table_start,
|
||||
SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read id table index\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(id_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_ID_BLOCKS(index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, index[i], NULL, expected,
|
||||
((unsigned char *) id_table) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read id table block %d, from 0x%llx, length %d\n", i,
|
||||
index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read id table block %d, from 0x%llx, "
|
||||
"length %d\n", i, index[i], length);
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(id_table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids);
|
||||
|
||||
for(i = 0; i < sBlk->no_ids; i++) {
|
||||
TRACE("Adding id %d to id tables\n", id_table[i]);
|
||||
create_id(id_table[i]);
|
||||
}
|
||||
|
||||
return id_table;
|
||||
}
|
||||
|
||||
|
||||
struct squashfs_fragment_entry *read_fragment_table(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int res, i;
|
||||
int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk->fragments);
|
||||
int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
|
||||
long long fragment_table_index[indexes];
|
||||
struct squashfs_fragment_entry *fragment_table;
|
||||
|
||||
TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
|
||||
"from 0x%llx\n", sBlk->fragments, indexes,
|
||||
sBlk->fragment_table_start);
|
||||
|
||||
fragment_table = malloc(bytes);
|
||||
if(fragment_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->fragment_table_start,
|
||||
SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments),
|
||||
fragment_table_index);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read fragment table index\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(fragment_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, fragment_table_index[i], NULL,
|
||||
expected, ((unsigned char *) fragment_table) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
|
||||
i, fragment_table_index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read fragment table block %d, from "
|
||||
"0x%llx, length %d\n", i,
|
||||
fragment_table_index[i], length);
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(fragment_table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < sBlk->fragments; i++)
|
||||
SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
|
||||
|
||||
return fragment_table;
|
||||
}
|
||||
|
||||
|
||||
squashfs_inode *read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes);
|
||||
int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes);
|
||||
long long index[indexes];
|
||||
int res, i;
|
||||
squashfs_inode *inode_lookup_table;
|
||||
|
||||
inode_lookup_table = malloc(lookup_bytes);
|
||||
if(inode_lookup_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->lookup_table_start,
|
||||
SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read inode lookup table index\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(inode_lookup_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
lookup_bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, index[i], NULL, expected,
|
||||
((unsigned char *) inode_lookup_table) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read inode lookup table block %d, from 0x%llx, length "
|
||||
"%d\n", i, index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read inode lookup table block %d, "
|
||||
"from 0x%llx, length %d\n", i, index[i],
|
||||
length);
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(inode_lookup_table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_LONG_LONGS(inode_lookup_table, sBlk->inodes);
|
||||
|
||||
return inode_lookup_table;
|
||||
}
|
||||
|
||||
|
||||
long long read_filesystem(char *root_name, int fd, struct squashfs_super_block *sBlk,
|
||||
char **cinode_table, char **data_cache, char **cdirectory_table,
|
||||
char **directory_data_cache, unsigned int *last_directory_block,
|
||||
unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
|
||||
unsigned int *root_inode_size, unsigned int *inode_dir_start_block,
|
||||
int *file_count, int *sym_count, int *dev_count, int *dir_count,
|
||||
int *fifo_count, int *sock_count, long long *uncompressed_file,
|
||||
unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
|
||||
unsigned int *inode_dir_inode_number,
|
||||
unsigned int *inode_dir_parent_inode,
|
||||
void (push_directory_entry)(char *, squashfs_inode, int, int),
|
||||
struct squashfs_fragment_entry **fragment_table,
|
||||
squashfs_inode **inode_lookup_table)
|
||||
{
|
||||
unsigned char *inode_table = NULL, *directory_table = NULL;
|
||||
long long start = sBlk->inode_table_start;
|
||||
long long end = sBlk->directory_table_start;
|
||||
long long root_inode_start = start +
|
||||
SQUASHFS_INODE_BLK(sBlk->root_inode);
|
||||
unsigned int root_inode_offset =
|
||||
SQUASHFS_INODE_OFFSET(sBlk->root_inode);
|
||||
unsigned int root_inode_block;
|
||||
union squashfs_inode_header inode;
|
||||
unsigned int *id_table = NULL;
|
||||
int res;
|
||||
|
||||
printf("Scanning existing filesystem...\n");
|
||||
|
||||
if(get_xattrs(fd, sBlk) == 0)
|
||||
goto error;
|
||||
|
||||
if(sBlk->fragments > 0) {
|
||||
*fragment_table = read_fragment_table(fd, sBlk);
|
||||
if(*fragment_table == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(sBlk->lookup_table_start != SQUASHFS_INVALID_BLK) {
|
||||
*inode_lookup_table = read_inode_lookup_table(fd, sBlk);
|
||||
if(*inode_lookup_table == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
id_table = read_id_table(fd, sBlk);
|
||||
if(id_table == NULL)
|
||||
goto error;
|
||||
|
||||
inode_table = scan_inode_table(fd, start, end, root_inode_start,
|
||||
root_inode_offset, sBlk, &inode, &root_inode_block,
|
||||
root_inode_size, uncompressed_file, uncompressed_directory,
|
||||
file_count, sym_count, dev_count, dir_count, fifo_count,
|
||||
sock_count, id_table);
|
||||
if(inode_table == NULL)
|
||||
goto error;
|
||||
|
||||
*uncompressed_inode = root_inode_block;
|
||||
|
||||
if(inode.base.inode_type == SQUASHFS_DIR_TYPE ||
|
||||
inode.base.inode_type == SQUASHFS_LDIR_TYPE) {
|
||||
if(inode.base.inode_type == SQUASHFS_DIR_TYPE) {
|
||||
*inode_dir_start_block = inode.dir.start_block;
|
||||
*inode_dir_offset = inode.dir.offset;
|
||||
*inode_dir_file_size = inode.dir.file_size - 3;
|
||||
*inode_dir_inode_number = inode.dir.inode_number;
|
||||
*inode_dir_parent_inode = inode.dir.parent_inode;
|
||||
} else {
|
||||
*inode_dir_start_block = inode.ldir.start_block;
|
||||
*inode_dir_offset = inode.ldir.offset;
|
||||
*inode_dir_file_size = inode.ldir.file_size - 3;
|
||||
*inode_dir_inode_number = inode.ldir.inode_number;
|
||||
*inode_dir_parent_inode = inode.ldir.parent_inode;
|
||||
}
|
||||
|
||||
directory_table = squashfs_readdir(fd, !root_name,
|
||||
*inode_dir_start_block, *inode_dir_offset,
|
||||
*inode_dir_file_size, last_directory_block, sBlk,
|
||||
push_directory_entry);
|
||||
if(directory_table == NULL)
|
||||
goto error;
|
||||
|
||||
root_inode_start -= start;
|
||||
*cinode_table = malloc(root_inode_start);
|
||||
if(*cinode_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, start, root_inode_start, *cinode_table);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read inode table\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*cdirectory_table = malloc(*last_directory_block);
|
||||
if(*cdirectory_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->directory_table_start,
|
||||
*last_directory_block, *cdirectory_table);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read directory table\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*data_cache = malloc(root_inode_offset + *root_inode_size);
|
||||
if(*data_cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(*data_cache, inode_table + root_inode_block,
|
||||
root_inode_offset + *root_inode_size);
|
||||
|
||||
*directory_data_cache = malloc(*inode_dir_offset +
|
||||
*inode_dir_file_size);
|
||||
if(*directory_data_cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(*directory_data_cache, directory_table,
|
||||
*inode_dir_offset + *inode_dir_file_size);
|
||||
|
||||
free(id_table);
|
||||
free(inode_table);
|
||||
free(directory_table);
|
||||
return sBlk->inode_table_start;
|
||||
}
|
||||
|
||||
error:
|
||||
free(id_table);
|
||||
free(inode_table);
|
||||
free(directory_table);
|
||||
return 0;
|
||||
}
|
||||
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.h
Normal file
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef READ_FS_H
|
||||
#define READ_FS_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_fs.h
|
||||
*
|
||||
*/
|
||||
extern struct compressor *read_super(int, struct squashfs_super_block *,
|
||||
char *);
|
||||
extern long long read_filesystem(char *, int, struct squashfs_super_block *,
|
||||
char **, char **, char **, char **, unsigned int *, unsigned int *,
|
||||
unsigned int *, unsigned int *, unsigned int *, int *, int *, int *, int *,
|
||||
int *, int *, long long *, unsigned int *, unsigned int *, unsigned int *,
|
||||
unsigned int *, void (push_directory_entry)(char *, squashfs_inode, int, int),
|
||||
struct squashfs_fragment_entry **, squashfs_inode **);
|
||||
#endif
|
||||
428
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_xattrs.c
Normal file
428
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_xattrs.c
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Read a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2010, 2012, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_xattrs.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common xattr read code shared between mksquashfs and unsquashfs
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_swap.h"
|
||||
#include "xattr.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int read_fs_bytes(int, long long, int, void *);
|
||||
extern int read_block(int, long long, long long *, int, void *);
|
||||
|
||||
static struct hash_entry {
|
||||
long long start;
|
||||
unsigned int offset;
|
||||
struct hash_entry *next;
|
||||
} *hash_table[65536];
|
||||
|
||||
static struct squashfs_xattr_id *xattr_ids;
|
||||
static void *xattrs = NULL;
|
||||
static long long xattr_table_start;
|
||||
|
||||
/*
|
||||
* Prefix lookup table, storing mapping to/from prefix string and prefix id
|
||||
*/
|
||||
struct prefix prefix_table[] = {
|
||||
{ "user.", SQUASHFS_XATTR_USER },
|
||||
{ "trusted.", SQUASHFS_XATTR_TRUSTED },
|
||||
{ "security.", SQUASHFS_XATTR_SECURITY },
|
||||
{ "", -1 }
|
||||
};
|
||||
|
||||
/*
|
||||
* store mapping from location of compressed block in fs ->
|
||||
* location of uncompressed block in memory
|
||||
*/
|
||||
static void save_xattr_block(long long start, int offset)
|
||||
{
|
||||
struct hash_entry *hash_entry = malloc(sizeof(*hash_entry));
|
||||
int hash = start & 0xffff;
|
||||
|
||||
TRACE("save_xattr_block: start %lld, offset %d\n", start, offset);
|
||||
|
||||
if(hash_entry == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
hash_entry->start = start;
|
||||
hash_entry->offset = offset;
|
||||
hash_entry->next = hash_table[hash];
|
||||
hash_table[hash] = hash_entry;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* map from location of compressed block in fs ->
|
||||
* location of uncompressed block in memory
|
||||
*/
|
||||
static int get_xattr_block(long long start)
|
||||
{
|
||||
int hash = start & 0xffff;
|
||||
struct hash_entry *hash_entry = hash_table[hash];
|
||||
|
||||
for(; hash_entry; hash_entry = hash_entry->next)
|
||||
if(hash_entry->start == start)
|
||||
break;
|
||||
|
||||
TRACE("get_xattr_block: start %lld, offset %d\n", start,
|
||||
hash_entry ? hash_entry->offset : -1);
|
||||
|
||||
return hash_entry ? hash_entry->offset : -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* construct the xattr_list entry from the fs xattr, including
|
||||
* mapping name and prefix into a full name
|
||||
*/
|
||||
static int read_xattr_entry(struct xattr_list *xattr,
|
||||
struct squashfs_xattr_entry *entry, void *name)
|
||||
{
|
||||
int i, len, type = entry->type & XATTR_PREFIX_MASK;
|
||||
|
||||
for(i = 0; prefix_table[i].type != -1; i++)
|
||||
if(prefix_table[i].type == type)
|
||||
break;
|
||||
|
||||
if(prefix_table[i].type == -1) {
|
||||
ERROR("read_xattr_entry: Unrecognised xattr type %d\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(prefix_table[i].prefix);
|
||||
xattr->full_name = malloc(len + entry->size + 1);
|
||||
if(xattr->full_name == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(xattr->full_name, prefix_table[i].prefix, len);
|
||||
memcpy(xattr->full_name + len, name, entry->size);
|
||||
xattr->full_name[len + entry->size] = '\0';
|
||||
xattr->name = xattr->full_name + len;
|
||||
xattr->size = entry->size;
|
||||
xattr->type = type;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read and decompress the xattr id table and the xattr metadata.
|
||||
* This is cached in memory for later use by get_xattr()
|
||||
*/
|
||||
int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk, int flag, long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of ids (id_table.xattr_ids) is 2^32 (unsigned int)
|
||||
* Max size of bytes is 2^32*16 or 2^36
|
||||
* Max indexes is (2^32*16)/8K or 2^23
|
||||
* Max index_bytes is ((2^32*16)/8K)*8 or 2^26 or 64M
|
||||
*/
|
||||
int res, i, indexes, index_bytes;
|
||||
unsigned int ids;
|
||||
long long bytes;
|
||||
long long *index, start, end;
|
||||
struct squashfs_xattr_table id_table;
|
||||
|
||||
TRACE("read_xattrs_from_disk\n");
|
||||
|
||||
if(sBlk->xattr_id_table_start == SQUASHFS_INVALID_BLK)
|
||||
return SQUASHFS_INVALID_BLK;
|
||||
|
||||
/*
|
||||
* Read xattr id table, containing start of xattr metadata and the
|
||||
* number of xattrs in the file system
|
||||
*/
|
||||
res = read_fs_bytes(fd, sBlk->xattr_id_table_start, sizeof(id_table),
|
||||
&id_table);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
|
||||
SQUASHFS_INSWAP_XATTR_TABLE(&id_table);
|
||||
|
||||
/*
|
||||
* Compute index table values
|
||||
*/
|
||||
ids = id_table.xattr_ids;
|
||||
xattr_table_start = id_table.xattr_table_start;
|
||||
index_bytes = SQUASHFS_XATTR_BLOCK_BYTES((long long) ids);
|
||||
indexes = SQUASHFS_XATTR_BLOCKS((long long) ids);
|
||||
|
||||
/*
|
||||
* The size of the index table (index_bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(index_bytes != (sBlk->bytes_used - (sBlk->xattr_id_table_start + sizeof(id_table)))) {
|
||||
ERROR("read_xattrs_from_disk: Bad xattr_ids count in super block\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* id_table.xattr_table_start stores the start of the compressed xattr
|
||||
* metadata blocks. This by definition is also the end of the previous
|
||||
* filesystem table - the id lookup table.
|
||||
*/
|
||||
if(table_start != NULL)
|
||||
*table_start = id_table.xattr_table_start;
|
||||
|
||||
/*
|
||||
* If flag is set then return once we've read the above
|
||||
* table_start. That value is necessary for sanity checking,
|
||||
* but we don't actually want to extract the xattrs, and so
|
||||
* stop here.
|
||||
*/
|
||||
if(flag)
|
||||
return id_table.xattr_ids;
|
||||
|
||||
/*
|
||||
* Allocate and read the index to the xattr id table metadata
|
||||
* blocks
|
||||
*/
|
||||
index = malloc(index_bytes);
|
||||
if(index == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->xattr_id_table_start + sizeof(id_table),
|
||||
index_bytes, index);
|
||||
if(res ==0)
|
||||
goto failed1;
|
||||
|
||||
SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
|
||||
|
||||
/*
|
||||
* Allocate enough space for the uncompressed xattr id table, and
|
||||
* read and decompress it
|
||||
*/
|
||||
bytes = SQUASHFS_XATTR_BYTES((long long) ids);
|
||||
xattr_ids = malloc(bytes);
|
||||
if(xattr_ids == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, index[i], NULL, expected,
|
||||
((unsigned char *) xattr_ids) +
|
||||
((long long) i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read xattr id table block %d, from 0x%llx, length "
|
||||
"%d\n", i, index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read xattr id table block %d, "
|
||||
"from 0x%llx, length %d\n", i, index[i],
|
||||
length);
|
||||
goto failed2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and decompress the xattr metadata
|
||||
*
|
||||
* Note the first xattr id table metadata block is immediately after
|
||||
* the last xattr metadata block, so we can use index[0] to work out
|
||||
* the end of the xattr metadata
|
||||
*/
|
||||
start = xattr_table_start;
|
||||
end = index[0];
|
||||
for(i = 0; start < end; i++) {
|
||||
int length;
|
||||
xattrs = realloc(xattrs, (i + 1) * SQUASHFS_METADATA_SIZE);
|
||||
if(xattrs == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
/* store mapping from location of compressed block in fs ->
|
||||
* location of uncompressed block in memory */
|
||||
save_xattr_block(start, i * SQUASHFS_METADATA_SIZE);
|
||||
|
||||
length = read_block(fd, start, &start, 0,
|
||||
((unsigned char *) xattrs) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read xattr block %d, length %d\n", i, length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read xattr block %d\n", i);
|
||||
goto failed3;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not the last metadata block in the xattr metadata
|
||||
* then it should be SQUASHFS_METADATA_SIZE in size.
|
||||
* Note, we can't use expected in read_block() above for this
|
||||
* because we don't know if this is the last block until
|
||||
* after reading.
|
||||
*/
|
||||
if(start != end && length != SQUASHFS_METADATA_SIZE) {
|
||||
ERROR("Xattr block %d should be %d bytes in length, "
|
||||
"it is %d bytes\n", i, SQUASHFS_METADATA_SIZE,
|
||||
length);
|
||||
goto failed3;
|
||||
}
|
||||
}
|
||||
|
||||
/* swap if necessary the xattr id entries */
|
||||
for(i = 0; i < ids; i++)
|
||||
SQUASHFS_INSWAP_XATTR_ID(&xattr_ids[i]);
|
||||
|
||||
free(index);
|
||||
|
||||
return ids;
|
||||
|
||||
failed3:
|
||||
free(xattrs);
|
||||
failed2:
|
||||
free(xattr_ids);
|
||||
failed1:
|
||||
free(index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void free_xattr(struct xattr_list *xattr_list, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < count; i++)
|
||||
free(xattr_list[i].full_name);
|
||||
|
||||
free(xattr_list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Construct and return the list of xattr name:value pairs for the passed xattr
|
||||
* id
|
||||
*
|
||||
* There are two users for get_xattr(), Mksquashfs uses it to read the
|
||||
* xattrs from the filesystem on appending, and Unsquashfs uses it
|
||||
* to retrieve the xattrs for writing to disk.
|
||||
*
|
||||
* Unfortunately, the two users disagree on what to do with unknown
|
||||
* xattr prefixes, Mksquashfs wants to treat this as fatal otherwise
|
||||
* this will cause xattrs to be be lost on appending. Unsquashfs
|
||||
* on the otherhand wants to retrieve the xattrs which are known and
|
||||
* to ignore the rest, this allows Unsquashfs to cope more gracefully
|
||||
* with future versions which may have unknown xattrs, as long as the
|
||||
* general xattr structure is adhered to, Unsquashfs should be able
|
||||
* to safely ignore unknown xattrs, and to write the ones it knows about,
|
||||
* this is better than completely refusing to retrieve all the xattrs.
|
||||
*
|
||||
* So return an error flag if any unrecognised types were found.
|
||||
*/
|
||||
struct xattr_list *get_xattr(int i, unsigned int *count, int *failed)
|
||||
{
|
||||
long long start;
|
||||
struct xattr_list *xattr_list = NULL;
|
||||
unsigned int offset;
|
||||
void *xptr;
|
||||
int j, n, res = 1;
|
||||
|
||||
TRACE("get_xattr\n");
|
||||
|
||||
if(xattr_ids[i].count == 0) {
|
||||
ERROR("get_xattr: xattr count unexpectedly 0 - corrupt fs?\n");
|
||||
*failed = TRUE;
|
||||
*count = 0;
|
||||
return NULL;
|
||||
} else
|
||||
*failed = FALSE;
|
||||
|
||||
start = SQUASHFS_XATTR_BLK(xattr_ids[i].xattr) + xattr_table_start;
|
||||
offset = SQUASHFS_XATTR_OFFSET(xattr_ids[i].xattr);
|
||||
xptr = xattrs + get_xattr_block(start) + offset;
|
||||
|
||||
TRACE("get_xattr: xattr_id %d, count %d, start %lld, offset %d\n", i,
|
||||
xattr_ids[i].count, start, offset);
|
||||
|
||||
for(j = 0, n = 0; n < xattr_ids[i].count; n++) {
|
||||
struct squashfs_xattr_entry entry;
|
||||
struct squashfs_xattr_val val;
|
||||
|
||||
if(res != 0) {
|
||||
xattr_list = realloc(xattr_list, (j + 1) *
|
||||
sizeof(struct xattr_list));
|
||||
if(xattr_list == NULL)
|
||||
MEM_ERROR();
|
||||
}
|
||||
|
||||
SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry);
|
||||
xptr += sizeof(entry);
|
||||
|
||||
res = read_xattr_entry(&xattr_list[j], &entry, xptr);
|
||||
if(res == 0) {
|
||||
/* unknown type, skip, and set error flag */
|
||||
xptr += entry.size;
|
||||
SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
|
||||
xptr += sizeof(val) + val.vsize;
|
||||
*failed = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
xptr += entry.size;
|
||||
|
||||
TRACE("get_xattr: xattr %d, type %d, size %d, name %s\n", j,
|
||||
entry.type, entry.size, xattr_list[j].full_name);
|
||||
|
||||
if(entry.type & SQUASHFS_XATTR_VALUE_OOL) {
|
||||
long long xattr;
|
||||
void *ool_xptr;
|
||||
|
||||
xptr += sizeof(val);
|
||||
SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1);
|
||||
xptr += sizeof(xattr);
|
||||
start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
|
||||
offset = SQUASHFS_XATTR_OFFSET(xattr);
|
||||
ool_xptr = xattrs + get_xattr_block(start) + offset;
|
||||
SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val);
|
||||
xattr_list[j].value = ool_xptr + sizeof(val);
|
||||
} else {
|
||||
SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
|
||||
xattr_list[j].value = xptr + sizeof(val);
|
||||
xptr += sizeof(val) + val.vsize;
|
||||
}
|
||||
|
||||
TRACE("get_xattr: xattr %d, vsize %d\n", j, val.vsize);
|
||||
|
||||
xattr_list[j++].vsize = val.vsize;
|
||||
}
|
||||
|
||||
*count = j;
|
||||
return xattr_list;
|
||||
}
|
||||
168
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.c
Normal file
168
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* restore.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "caches-queues-lists.h"
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
#include "info.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
extern pthread_t reader_thread, writer_thread, main_thread, order_thread;
|
||||
extern pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
|
||||
extern struct queue *to_deflate, *to_writer, *to_frag, *to_process_frag;
|
||||
extern struct seq_queue *to_main, *to_order;
|
||||
extern void restorefs();
|
||||
extern int processors;
|
||||
extern int reproducible;
|
||||
|
||||
static int interrupted = 0;
|
||||
static pthread_t restore_thread;
|
||||
|
||||
void *restore_thrd(void *arg)
|
||||
{
|
||||
sigset_t sigmask, old_mask;
|
||||
int i, sig;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGINT);
|
||||
sigaddset(&sigmask, SIGTERM);
|
||||
sigaddset(&sigmask, SIGUSR1);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask);
|
||||
|
||||
while(1) {
|
||||
sigwait(&sigmask, &sig);
|
||||
|
||||
if((sig == SIGINT || sig == SIGTERM) && !interrupted) {
|
||||
ERROR("Interrupting will restore original "
|
||||
"filesystem!\n");
|
||||
ERROR("Interrupt again to quit\n");
|
||||
interrupted = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* kill main thread/worker threads and restore */
|
||||
set_progressbar_state(FALSE);
|
||||
disable_info();
|
||||
|
||||
/* first kill the reader thread */
|
||||
pthread_cancel(reader_thread);
|
||||
pthread_join(reader_thread, NULL);
|
||||
|
||||
/*
|
||||
* then flush the reader to deflator thread(s) output queue.
|
||||
* The deflator thread(s) will idle
|
||||
*/
|
||||
queue_flush(to_deflate);
|
||||
|
||||
/* now kill the deflator thread(s) */
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_cancel(deflator_thread[i]);
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_join(deflator_thread[i], NULL);
|
||||
|
||||
/*
|
||||
* then flush the reader to process fragment thread(s) output
|
||||
* queue. The process fragment thread(s) will idle
|
||||
*/
|
||||
queue_flush(to_process_frag);
|
||||
|
||||
/* now kill the process fragment thread(s) */
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_cancel(frag_thread[i]);
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_join(frag_thread[i], NULL);
|
||||
|
||||
/*
|
||||
* then flush the reader/deflator/process fragment to main
|
||||
* thread output queue. The main thread will idle
|
||||
*/
|
||||
seq_queue_flush(to_main);
|
||||
|
||||
/* now kill the main thread */
|
||||
pthread_cancel(main_thread);
|
||||
pthread_join(main_thread, NULL);
|
||||
|
||||
/* then flush the main thread to fragment deflator thread(s)
|
||||
* queue. The fragment deflator thread(s) will idle
|
||||
*/
|
||||
queue_flush(to_frag);
|
||||
|
||||
/* now kill the fragment deflator thread(s) */
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_cancel(frag_deflator_thread[i]);
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_join(frag_deflator_thread[i], NULL);
|
||||
|
||||
if(reproducible) {
|
||||
/* then flush the fragment deflator_threads(s)
|
||||
* to frag orderer thread. The frag orderer
|
||||
* thread will idle
|
||||
*/
|
||||
seq_queue_flush(to_order);
|
||||
|
||||
/* now kill the frag orderer thread */
|
||||
pthread_cancel(order_thread);
|
||||
pthread_join(order_thread, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* then flush the main thread/fragment deflator thread(s)
|
||||
* to writer thread queue. The writer thread will idle
|
||||
*/
|
||||
queue_flush(to_writer);
|
||||
|
||||
/* now kill the writer thread */
|
||||
pthread_cancel(writer_thread);
|
||||
pthread_join(writer_thread, NULL);
|
||||
|
||||
TRACE("All threads cancelled\n");
|
||||
|
||||
restorefs();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pthread_t *init_restore_thread()
|
||||
{
|
||||
pthread_create(&restore_thread, NULL, restore_thrd, NULL);
|
||||
return &restore_thread;
|
||||
}
|
||||
28
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.h
Normal file
28
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef RESTORE_H
|
||||
#define RESTORE_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* restore.h
|
||||
*/
|
||||
|
||||
extern pthread_t *init_restore_thread();
|
||||
#endif
|
||||
363
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.c
Normal file
363
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.c
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
|
||||
* 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* sort.c
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define MAX_LINE 16384
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "sort.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
|
||||
int mkisofs_style = -1;
|
||||
|
||||
struct sort_info {
|
||||
dev_t st_dev;
|
||||
ino_t st_ino;
|
||||
int priority;
|
||||
struct sort_info *next;
|
||||
};
|
||||
|
||||
struct sort_info *sort_info_list[65536];
|
||||
|
||||
struct priority_entry *priority_list[65536];
|
||||
|
||||
extern int silent;
|
||||
extern void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
|
||||
int *c_size);
|
||||
extern char *pathname(struct dir_ent *dir_ent);
|
||||
|
||||
|
||||
void add_priority_list(struct dir_ent *dir, int priority)
|
||||
{
|
||||
struct priority_entry *new_priority_entry;
|
||||
|
||||
priority += 32768;
|
||||
new_priority_entry = malloc(sizeof(struct priority_entry));
|
||||
if(new_priority_entry == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
new_priority_entry->dir = dir;;
|
||||
new_priority_entry->next = priority_list[priority];
|
||||
priority_list[priority] = new_priority_entry;
|
||||
}
|
||||
|
||||
|
||||
int get_priority(char *filename, struct stat *buf, int priority)
|
||||
{
|
||||
int hash = buf->st_ino & 0xffff;
|
||||
struct sort_info *s;
|
||||
|
||||
for(s = sort_info_list[hash]; s; s = s->next)
|
||||
if((s->st_dev == buf->st_dev) && (s->st_ino == buf->st_ino)) {
|
||||
TRACE("returning priority %d (%s)\n", s->priority,
|
||||
filename);
|
||||
return s->priority;
|
||||
}
|
||||
TRACE("returning priority %d (%s)\n", priority, filename);
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
#define ADD_ENTRY(buf, priority) {\
|
||||
int hash = buf.st_ino & 0xffff;\
|
||||
struct sort_info *s;\
|
||||
if((s = malloc(sizeof(struct sort_info))) == NULL) \
|
||||
MEM_ERROR(); \
|
||||
s->st_dev = buf.st_dev;\
|
||||
s->st_ino = buf.st_ino;\
|
||||
s->priority = priority;\
|
||||
s->next = sort_info_list[hash];\
|
||||
sort_info_list[hash] = s;\
|
||||
}
|
||||
int add_sort_list(char *path, int priority, int source, char *source_path[])
|
||||
{
|
||||
int i, n;
|
||||
struct stat buf;
|
||||
|
||||
TRACE("add_sort_list: filename %s, priority %d\n", path, priority);
|
||||
if(strlen(path) > 1 && strcmp(path + strlen(path) - 2, "/*") == 0)
|
||||
path[strlen(path) - 2] = '\0';
|
||||
|
||||
TRACE("add_sort_list: filename %s, priority %d\n", path, priority);
|
||||
re_read:
|
||||
if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
|
||||
strncmp(path, "../", 3) == 0 || mkisofs_style == 1) {
|
||||
if(lstat(path, &buf) == -1)
|
||||
goto error;
|
||||
TRACE("adding filename %s, priority %d, st_dev %d, st_ino "
|
||||
"%lld\n", path, priority, (int) buf.st_dev,
|
||||
(long long) buf.st_ino);
|
||||
ADD_ENTRY(buf, priority);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for(i = 0, n = 0; i < source; i++) {
|
||||
char *filename;
|
||||
int res = asprintf(&filename, "%s/%s", source_path[i], path);
|
||||
if(res == -1)
|
||||
BAD_ERROR("asprintf failed in add_sort_list\n");
|
||||
res = lstat(filename, &buf);
|
||||
free(filename);
|
||||
if(res == -1) {
|
||||
if(!(errno == ENOENT || errno == ENOTDIR))
|
||||
goto error;
|
||||
continue;
|
||||
}
|
||||
ADD_ENTRY(buf, priority);
|
||||
n ++;
|
||||
}
|
||||
|
||||
if(n == 0 && mkisofs_style == -1 && lstat(path, &buf) != -1) {
|
||||
ERROR("WARNING: Mkisofs style sortlist detected! This is "
|
||||
"supported but please\n");
|
||||
ERROR("convert to mksquashfs style sortlist! A sortlist entry");
|
||||
ERROR(" should be\neither absolute (starting with ");
|
||||
ERROR("'/') start with './' or '../' (taken to be\nrelative to "
|
||||
"$PWD), otherwise it ");
|
||||
ERROR("is assumed the entry is relative to one\nof the source "
|
||||
"directories, i.e. with ");
|
||||
ERROR("\"mksquashfs test test.sqsh\",\nthe sortlist ");
|
||||
ERROR("entry \"file\" is assumed to be inside the directory "
|
||||
"test.\n\n");
|
||||
mkisofs_style = 1;
|
||||
goto re_read;
|
||||
}
|
||||
|
||||
mkisofs_style = 0;
|
||||
|
||||
if(n == 1)
|
||||
return TRUE;
|
||||
if(n > 1) {
|
||||
ERROR(" Ambiguous sortlist entry \"%s\"\n\nIt maps to more "
|
||||
"than one source entry! Please use an absolute path."
|
||||
"\n", path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
error:
|
||||
ERROR_START("Cannot stat sortlist entry \"%s\"\n", path);
|
||||
ERROR("This is probably because you're using the wrong file\n");
|
||||
ERROR("path relative to the source directories.");
|
||||
ERROR_EXIT(" Ignoring");
|
||||
/*
|
||||
* Historical note
|
||||
* Failure to stat a sortlist entry is deliberately ignored, even
|
||||
* though it is an error. Squashfs release 2.2 changed the behaviour
|
||||
* to treat it as a fatal error, but it was changed back to
|
||||
* the original behaviour to ignore it in release 2.2-r2 following
|
||||
* feedback from users at the time.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void generate_file_priorities(struct dir_info *dir, int priority,
|
||||
struct stat *buf)
|
||||
{
|
||||
struct dir_ent *dir_ent = dir->list;
|
||||
|
||||
priority = get_priority(dir->pathname, buf, priority);
|
||||
|
||||
for(; dir_ent; dir_ent = dir_ent->next) {
|
||||
struct stat *buf = &dir_ent->inode->buf;
|
||||
if(dir_ent->inode->root_entry)
|
||||
continue;
|
||||
|
||||
switch(buf->st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
add_priority_list(dir_ent,
|
||||
get_priority(pathname(dir_ent), buf,
|
||||
priority));
|
||||
break;
|
||||
case S_IFDIR:
|
||||
generate_file_priorities(dir_ent->dir,
|
||||
priority, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int read_sort_file(char *filename, int source, char *source_path[])
|
||||
{
|
||||
FILE *fd;
|
||||
char line_buffer[MAX_LINE + 1]; /* overflow safe */
|
||||
char sort_filename[MAX_LINE + 1]; /* overflow safe */
|
||||
char *line, *name;
|
||||
int n, priority, res;
|
||||
|
||||
if((fd = fopen(filename, "r")) == NULL) {
|
||||
ERROR("Failed to open sort file \"%s\" because %s\n",
|
||||
filename, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(fgets(line = line_buffer, MAX_LINE + 1, fd) != NULL) {
|
||||
int len = strlen(line);
|
||||
|
||||
if(len == MAX_LINE && line[len - 1] != '\n') {
|
||||
/* line too large */
|
||||
ERROR("Line too long when reading "
|
||||
"sort file \"%s\", larger than %d "
|
||||
"bytes\n", filename, MAX_LINE);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove '\n' terminator if it exists (the last line
|
||||
* in the file may not be '\n' terminated)
|
||||
*/
|
||||
if(len && line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
while(isspace(*line))
|
||||
line ++;
|
||||
|
||||
/* if comment line, skip */
|
||||
if(*line == '#')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Scan for filename, don't use sscanf() and "%s" because
|
||||
* that can't handle filenames with spaces
|
||||
*/
|
||||
for(name = sort_filename; !isspace(*line) && *line != '\0';) {
|
||||
if(*line == '\\') {
|
||||
line ++;
|
||||
if (*line == '\0')
|
||||
break;
|
||||
}
|
||||
*name ++ = *line ++;
|
||||
}
|
||||
*name = '\0';
|
||||
|
||||
/*
|
||||
* if filename empty, then line was empty of anything but
|
||||
* whitespace or a backslash character. Skip empy lines
|
||||
*/
|
||||
if(sort_filename[0] == '\0')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Scan the rest of the line, we expect a decimal number
|
||||
* which is the filename priority
|
||||
*/
|
||||
errno = 0;
|
||||
res = sscanf(line, "%d%n", &priority, &n);
|
||||
|
||||
if((res < 1 || errno) && errno != ERANGE) {
|
||||
if(errno == 0)
|
||||
/* No error, assume EOL or match failure */
|
||||
ERROR("Sort file \"%s\", can't find priority "
|
||||
"in entry \"%s\", EOL or match "
|
||||
"failure\n", filename, line_buffer);
|
||||
else
|
||||
/* Some other failure not ERANGE */
|
||||
ERROR("Sscanf failed reading sort file \"%s\" "
|
||||
"because %s\n", filename,
|
||||
strerror(errno));
|
||||
goto failed;
|
||||
} else if((errno == ERANGE) ||
|
||||
(priority < -32768 || priority > 32767)) {
|
||||
ERROR("Sort file \"%s\", entry \"%s\" has priority "
|
||||
"outside range of -32767:32768.\n", filename,
|
||||
line_buffer);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Skip any trailing whitespace */
|
||||
line += n;
|
||||
while(isspace(*line))
|
||||
line ++;
|
||||
|
||||
if(*line != '\0') {
|
||||
ERROR("Sort file \"%s\", trailing characters after "
|
||||
"priority in entry \"%s\"\n", filename,
|
||||
line_buffer);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
res = add_sort_list(sort_filename, priority, source,
|
||||
source_path);
|
||||
if(res == FALSE)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(ferror(fd)) {
|
||||
ERROR("Reading sort file \"%s\" failed because %s\n", filename,
|
||||
strerror(errno));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
fclose(fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void sort_files_and_write(struct dir_info *dir)
|
||||
{
|
||||
int i;
|
||||
struct priority_entry *entry;
|
||||
squashfs_inode inode;
|
||||
int duplicate_file;
|
||||
|
||||
for(i = 65535; i >= 0; i--)
|
||||
for(entry = priority_list[i]; entry; entry = entry->next) {
|
||||
TRACE("%d: %s\n", i - 32768, pathname(entry->dir));
|
||||
if(entry->dir->inode->inode == SQUASHFS_INVALID_BLK) {
|
||||
write_file(&inode, entry->dir, &duplicate_file);
|
||||
INFO("file %s, uncompressed size %lld bytes %s"
|
||||
"\n", pathname(entry->dir),
|
||||
(long long)
|
||||
entry->dir->inode->buf.st_size,
|
||||
duplicate_file ? "DUPLICATE" : "");
|
||||
entry->dir->inode->inode = inode;
|
||||
entry->dir->inode->type = SQUASHFS_FILE_TYPE;
|
||||
} else
|
||||
INFO("file %s, uncompressed size %lld bytes "
|
||||
"LINK\n", pathname(entry->dir),
|
||||
(long long)
|
||||
entry->dir->inode->buf.st_size);
|
||||
}
|
||||
}
|
||||
37
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.h
Normal file
37
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef SORT_H
|
||||
#define SORT_H
|
||||
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* sort.h
|
||||
*/
|
||||
|
||||
struct priority_entry {
|
||||
struct dir_ent *dir;
|
||||
struct priority_entry *next;
|
||||
};
|
||||
|
||||
extern int read_sort_file(char *, int, char *[]);
|
||||
extern void sort_files_and_write(struct dir_info *);
|
||||
extern void generate_file_priorities(struct dir_info *, int priority,
|
||||
struct stat *);
|
||||
extern struct priority_entry *priority_list[65536];
|
||||
#endif
|
||||
834
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_compat.h
Normal file
834
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_compat.h
Normal file
@@ -0,0 +1,834 @@
|
||||
#ifndef SQUASHFS_COMPAT
|
||||
#define SQUASHFS_COMPAT
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_compat.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* definitions for structures on disk - layout 3.x
|
||||
*/
|
||||
|
||||
#define SQUASHFS_CHECK 2
|
||||
#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_CHECK)
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_UIDS 256
|
||||
#define SQUASHFS_GUIDS 255
|
||||
|
||||
struct squashfs_super_block_3 {
|
||||
unsigned int s_magic;
|
||||
unsigned int inodes;
|
||||
unsigned int bytes_used_2;
|
||||
unsigned int uid_start_2;
|
||||
unsigned int guid_start_2;
|
||||
unsigned int inode_table_start_2;
|
||||
unsigned int directory_table_start_2;
|
||||
unsigned int s_major:16;
|
||||
unsigned int s_minor:16;
|
||||
unsigned int block_size_1:16;
|
||||
unsigned int block_log:16;
|
||||
unsigned int flags:8;
|
||||
unsigned int no_uids:8;
|
||||
unsigned int no_guids:8;
|
||||
int mkfs_time /* time of filesystem creation */;
|
||||
squashfs_inode root_inode;
|
||||
unsigned int block_size;
|
||||
unsigned int fragments;
|
||||
unsigned int fragment_table_start_2;
|
||||
long long bytes_used;
|
||||
long long uid_start;
|
||||
long long guid_start;
|
||||
long long inode_table_start;
|
||||
long long directory_table_start;
|
||||
long long fragment_table_start;
|
||||
long long lookup_table_start;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_index_3 {
|
||||
unsigned int index;
|
||||
unsigned int start_block;
|
||||
unsigned char size;
|
||||
unsigned char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_base_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
squashfs_block start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_lreg_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
squashfs_block start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
long long file_size;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
unsigned int start_block;
|
||||
unsigned int parent_inode;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ldir_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size:27;
|
||||
unsigned int offset:13;
|
||||
unsigned int start_block;
|
||||
unsigned int i_count:16;
|
||||
unsigned int parent_inode;
|
||||
struct squashfs_dir_index_3 index[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_3 {
|
||||
struct squashfs_base_inode_header_3 base;
|
||||
struct squashfs_dev_inode_header_3 dev;
|
||||
struct squashfs_symlink_inode_header_3 symlink;
|
||||
struct squashfs_reg_inode_header_3 reg;
|
||||
struct squashfs_lreg_inode_header_3 lreg;
|
||||
struct squashfs_dir_inode_header_3 dir;
|
||||
struct squashfs_ldir_inode_header_3 ldir;
|
||||
struct squashfs_ipc_inode_header_3 ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry_3 {
|
||||
unsigned int offset:13;
|
||||
unsigned int type:3;
|
||||
unsigned int size:8;
|
||||
int inode_number:16;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_header_3 {
|
||||
unsigned int count:8;
|
||||
unsigned int start_block;
|
||||
unsigned int inode_number;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_fragment_entry_3 {
|
||||
long long start_block;
|
||||
unsigned int size;
|
||||
unsigned int pending;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
typedef struct squashfs_super_block_3 squashfs_super_block_3;
|
||||
typedef struct squashfs_dir_index_3 squashfs_dir_index_3;
|
||||
typedef struct squashfs_base_inode_header_3 squashfs_base_inode_header_3;
|
||||
typedef struct squashfs_ipc_inode_header_3 squashfs_ipc_inode_header_3;
|
||||
typedef struct squashfs_dev_inode_header_3 squashfs_dev_inode_header_3;
|
||||
typedef struct squashfs_symlink_inode_header_3 squashfs_symlink_inode_header_3;
|
||||
typedef struct squashfs_reg_inode_header_3 squashfs_reg_inode_header_3;
|
||||
typedef struct squashfs_lreg_inode_header_3 squashfs_lreg_inode_header_3;
|
||||
typedef struct squashfs_dir_inode_header_3 squashfs_dir_inode_header_3;
|
||||
typedef struct squashfs_ldir_inode_header_3 squashfs_ldir_inode_header_3;
|
||||
typedef struct squashfs_dir_entry_3 squashfs_dir_entry_3;
|
||||
typedef struct squashfs_dir_header_3 squashfs_dir_header_3;
|
||||
typedef struct squashfs_fragment_entry_3 squashfs_fragment_entry_3;
|
||||
|
||||
/*
|
||||
* macros to convert each packed bitfield structure from little endian to big
|
||||
* endian and vice versa. These are needed when creating or using a filesystem
|
||||
* on a machine with different byte ordering to the target architecture.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SQUASHFS_SWAP_START \
|
||||
int bits;\
|
||||
int b_pos;\
|
||||
unsigned long long val;\
|
||||
unsigned char *s;\
|
||||
unsigned char *d;
|
||||
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block_3));\
|
||||
SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
|
||||
SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
|
||||
SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
|
||||
SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
|
||||
SQUASHFS_SWAP((s)->flags, d, 288, 8);\
|
||||
SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
|
||||
SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
|
||||
SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
|
||||
SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
|
||||
SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
|
||||
SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
|
||||
SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
|
||||
SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
|
||||
SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
|
||||
SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
|
||||
SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
|
||||
SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
|
||||
SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, n)\
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 24, 8);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_3(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_ipc_inode_header_3))\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_3)); \
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_lreg_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 224, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 147, 13);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_ldir_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 155, 13);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
|
||||
SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
|
||||
SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INDEX_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_3));\
|
||||
SQUASHFS_SWAP((s)->index, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->size, d, 64, 8);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_3));\
|
||||
SQUASHFS_SWAP((s)->count, d, 0, 8);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_3));\
|
||||
SQUASHFS_SWAP((s)->offset, d, 0, 13);\
|
||||
SQUASHFS_SWAP((s)->type, d, 13, 3);\
|
||||
SQUASHFS_SWAP((s)->size, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_INODE_T_3(s, d) SQUASHFS_SWAP_LONG_LONGS_3(s, d, 1)
|
||||
|
||||
#define SQUASHFS_SWAP_SHORTS_3(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 2);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
16)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_INTS_3(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 4);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
32)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LONG_LONGS_3(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 8);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
64)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * bits / 8);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
bits)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES_3(s, d, n) SQUASHFS_SWAP_LONG_LONGS_3(s, d, n)
|
||||
#define SQUASHFS_SWAP_LOOKUP_BLOCKS_3(s, d, n) SQUASHFS_SWAP_LONG_LONGS_3(s, d, n)
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_3));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
|
||||
SQUASHFS_SWAP((s)->size, d, 64, 32);\
|
||||
}
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES_3(A) ((A) * sizeof(struct squashfs_fragment_entry_3))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_3(A) (SQUASHFS_FRAGMENT_BYTES_3(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET_3(A) (SQUASHFS_FRAGMENT_BYTES_3(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES_3(A) ((SQUASHFS_FRAGMENT_BYTES_3(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES_3(A) (SQUASHFS_FRAGMENT_INDEXES_3(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* inode lookup table defines */
|
||||
#define SQUASHFS_LOOKUP_BYTES_3(A) ((A) * sizeof(squashfs_inode))
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_3(A) (SQUASHFS_LOOKUP_BYTES_3(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_OFFSET_3(A) (SQUASHFS_LOOKUP_BYTES_3(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCKS_3(A) ((SQUASHFS_LOOKUP_BYTES_3(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_BYTES_3(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/*
|
||||
* definitions for structures on disk - layout 1.x
|
||||
*/
|
||||
#define SQUASHFS_TYPES 5
|
||||
#define SQUASHFS_IPC_TYPE 0
|
||||
|
||||
struct squashfs_base_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int type:4;
|
||||
unsigned int offset:4;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
int mtime;
|
||||
unsigned int start_block;
|
||||
unsigned int file_size:32;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
int mtime;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_1 {
|
||||
struct squashfs_base_inode_header_1 base;
|
||||
struct squashfs_dev_inode_header_1 dev;
|
||||
struct squashfs_symlink_inode_header_1 symlink;
|
||||
struct squashfs_reg_inode_header_1 reg;
|
||||
struct squashfs_dir_inode_header_1 dir;
|
||||
struct squashfs_ipc_inode_header_1 ipc;
|
||||
};
|
||||
|
||||
typedef struct squashfs_dir_index_1 squashfs_dir_index_1;
|
||||
typedef struct squashfs_base_inode_header_1 squashfs_base_inode_header_1;
|
||||
typedef struct squashfs_ipc_inode_header_1 squashfs_ipc_inode_header_1;
|
||||
typedef struct squashfs_dev_inode_header_1 squashfs_dev_inode_header_1;
|
||||
typedef struct squashfs_symlink_inode_header_1 squashfs_symlink_inode_header_1;
|
||||
typedef struct squashfs_reg_inode_header_1 squashfs_reg_inode_header_1;
|
||||
typedef struct squashfs_dir_inode_header_1 squashfs_dir_inode_header_1;
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 4);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 20, 4);
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_ipc_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->type, d, 24, 4);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 28, 4);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 43, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
|
||||
}
|
||||
|
||||
/*
|
||||
* definitions for structures on disk - layout 2.x
|
||||
*/
|
||||
struct squashfs_dir_index_2 {
|
||||
unsigned int index:27;
|
||||
unsigned int start_block:29;
|
||||
unsigned char size;
|
||||
unsigned char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_base_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
int mtime;
|
||||
unsigned int start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size:32;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
int mtime;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ldir_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int file_size:27;
|
||||
unsigned int offset:13;
|
||||
int mtime;
|
||||
unsigned int start_block:24;
|
||||
unsigned int i_count:16;
|
||||
struct squashfs_dir_index_2 index[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_2 {
|
||||
struct squashfs_base_inode_header_2 base;
|
||||
struct squashfs_dev_inode_header_2 dev;
|
||||
struct squashfs_symlink_inode_header_2 symlink;
|
||||
struct squashfs_reg_inode_header_2 reg;
|
||||
struct squashfs_dir_inode_header_2 dir;
|
||||
struct squashfs_ldir_inode_header_2 ldir;
|
||||
struct squashfs_ipc_inode_header_2 ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_header_2 {
|
||||
unsigned int count:8;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_entry_2 {
|
||||
unsigned int offset:13;
|
||||
unsigned int type:3;
|
||||
unsigned int size:8;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_fragment_entry_2 {
|
||||
unsigned int start_block;
|
||||
unsigned int size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct squashfs_dir_index_2 squashfs_dir_index_2;
|
||||
typedef struct squashfs_base_inode_header_2 squashfs_base_inode_header_2;
|
||||
typedef struct squashfs_ipc_inode_header_2 squashfs_ipc_inode_header_2;
|
||||
typedef struct squashfs_dev_inode_header_2 squashfs_dev_inode_header_2;
|
||||
typedef struct squashfs_symlink_inode_header_2 squashfs_symlink_inode_header_2;
|
||||
typedef struct squashfs_reg_inode_header_2 squashfs_reg_inode_header_2;
|
||||
typedef struct squashfs_lreg_inode_header_2 squashfs_lreg_inode_header_2;
|
||||
typedef struct squashfs_dir_inode_header_2 squashfs_dir_inode_header_2;
|
||||
typedef struct squashfs_ldir_inode_header_2 squashfs_ldir_inode_header_2;
|
||||
typedef struct squashfs_dir_entry_2 squashfs_dir_entry_2;
|
||||
typedef struct squashfs_dir_header_2 squashfs_dir_header_2;
|
||||
typedef struct squashfs_fragment_entry_2 squashfs_fragment_entry_2;
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 24, 8);\
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_2)); \
|
||||
SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 128, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 51, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_ldir_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 59, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
|
||||
SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
|
||||
SQUASHFS_SWAP((s)->index, d, 0, 27);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
|
||||
SQUASHFS_SWAP((s)->size, d, 56, 8);\
|
||||
}
|
||||
#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
|
||||
SQUASHFS_SWAP((s)->count, d, 0, 8);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
|
||||
SQUASHFS_SWAP((s)->offset, d, 0, 13);\
|
||||
SQUASHFS_SWAP((s)->type, d, 13, 3);\
|
||||
SQUASHFS_SWAP((s)->size, d, 16, 8);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->size, d, 32, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS_3(s, d, n)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES_2(A) ((A) * sizeof(struct squashfs_fragment_entry_2))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
|
||||
sizeof(int))
|
||||
/*
|
||||
* macros used to swap each structure entry, taking into account
|
||||
* bitfields and different bitfield placing conventions on differing architectures
|
||||
*/
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* convert from little endian to big endian */
|
||||
#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
|
||||
#else
|
||||
/* convert from big endian to little endian */
|
||||
#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
|
||||
#endif
|
||||
|
||||
#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
|
||||
b_pos = pos % 8;\
|
||||
val = 0;\
|
||||
s = (unsigned char *)p + (pos / 8);\
|
||||
d = ((unsigned char *) &val) + 7;\
|
||||
for(bits = 0; bits < (tbits + b_pos); bits += 8) \
|
||||
*d-- = *s++;\
|
||||
value = (val >> (SHIFT));\
|
||||
}
|
||||
#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
|
||||
#endif
|
||||
499
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_fs.h
Normal file
499
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_fs.h
Normal file
@@ -0,0 +1,499 @@
|
||||
#ifndef SQUASHFS_FS
|
||||
#define SQUASHFS_FS
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
|
||||
* 2013, 2014, 2017, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_fs.h
|
||||
*/
|
||||
|
||||
#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
|
||||
#define SQUASHFS_MAJOR 4
|
||||
#define SQUASHFS_MINOR 0
|
||||
#define SQUASHFS_MAGIC 0x73717368
|
||||
#define SQUASHFS_MAGIC_SWAP 0x68737173
|
||||
#define SQUASHFS_START 0
|
||||
|
||||
/* size of metadata (inode and directory) blocks */
|
||||
#define SQUASHFS_METADATA_SIZE 8192
|
||||
#define SQUASHFS_METADATA_LOG 13
|
||||
|
||||
/* default size of data blocks */
|
||||
#define SQUASHFS_FILE_SIZE 131072
|
||||
|
||||
#define SQUASHFS_FILE_MAX_SIZE 1048576
|
||||
#define SQUASHFS_FILE_MAX_LOG 20
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_IDS 65536
|
||||
|
||||
/* Max length of filename (not 255) */
|
||||
#define SQUASHFS_NAME_LEN 256
|
||||
|
||||
/* Max value for directory header count */
|
||||
#define SQUASHFS_DIR_COUNT 256
|
||||
|
||||
#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
|
||||
#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
|
||||
#define SQUASHFS_INVALID_XATTR ((unsigned int) 0xffffffff)
|
||||
#define SQUASHFS_INVALID_BLK ((long long) -1)
|
||||
#define SQUASHFS_USED_BLK ((long long) -2)
|
||||
|
||||
/* Filesystem flags */
|
||||
#define SQUASHFS_NOI 0
|
||||
#define SQUASHFS_NOD 1
|
||||
#define SQUASHFS_CHECK 2
|
||||
#define SQUASHFS_NOF 3
|
||||
#define SQUASHFS_NO_FRAG 4
|
||||
#define SQUASHFS_ALWAYS_FRAG 5
|
||||
#define SQUASHFS_DUPLICATE 6
|
||||
#define SQUASHFS_EXPORT 7
|
||||
#define SQUASHFS_NOX 8
|
||||
#define SQUASHFS_NO_XATTR 9
|
||||
#define SQUASHFS_COMP_OPT 10
|
||||
#define SQUASHFS_NOID 11
|
||||
|
||||
#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOI)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOD)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOF)
|
||||
|
||||
#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_FRAG)
|
||||
|
||||
#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_ALWAYS_FRAG)
|
||||
|
||||
#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_DUPLICATE)
|
||||
|
||||
#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_EXPORT)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_XATTRS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOX)
|
||||
|
||||
#define SQUASHFS_NO_XATTRS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_XATTR)
|
||||
|
||||
#define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_COMP_OPT)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_IDS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOID)
|
||||
|
||||
#define SQUASHFS_MKFLAGS(noi, nod, nof, nox, noid, no_frag, always_frag, \
|
||||
duplicate_checking, exportable, no_xattr, comp_opt) (noi | \
|
||||
(nod << 1) | (nof << 3) | (no_frag << 4) | \
|
||||
(always_frag << 5) | (duplicate_checking << 6) | \
|
||||
(exportable << 7) | (nox << 8) | (no_xattr << 9) | \
|
||||
(comp_opt << 10) | (noid << 11))
|
||||
|
||||
/* Max number of types and file types */
|
||||
#define SQUASHFS_DIR_TYPE 1
|
||||
#define SQUASHFS_FILE_TYPE 2
|
||||
#define SQUASHFS_SYMLINK_TYPE 3
|
||||
#define SQUASHFS_BLKDEV_TYPE 4
|
||||
#define SQUASHFS_CHRDEV_TYPE 5
|
||||
#define SQUASHFS_FIFO_TYPE 6
|
||||
#define SQUASHFS_SOCKET_TYPE 7
|
||||
#define SQUASHFS_LDIR_TYPE 8
|
||||
#define SQUASHFS_LREG_TYPE 9
|
||||
#define SQUASHFS_LSYMLINK_TYPE 10
|
||||
#define SQUASHFS_LBLKDEV_TYPE 11
|
||||
#define SQUASHFS_LCHRDEV_TYPE 12
|
||||
#define SQUASHFS_LFIFO_TYPE 13
|
||||
#define SQUASHFS_LSOCKET_TYPE 14
|
||||
|
||||
/* Xattr types */
|
||||
#define SQUASHFS_XATTR_USER 0
|
||||
#define SQUASHFS_XATTR_TRUSTED 1
|
||||
#define SQUASHFS_XATTR_SECURITY 2
|
||||
#define SQUASHFS_XATTR_VALUE_OOL 256
|
||||
#define SQUASHFS_XATTR_PREFIX_MASK 0xff
|
||||
|
||||
/* Flag whether block is compressed or uncompressed, bit is set if block is
|
||||
* uncompressed */
|
||||
#define SQUASHFS_COMPRESSED_BIT (1 << 15)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
|
||||
(B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
|
||||
|
||||
#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
|
||||
~SQUASHFS_COMPRESSED_BIT_BLOCK)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
|
||||
|
||||
/*
|
||||
* Inode number ops. Inodes consist of a compressed block number, and an
|
||||
* uncompressed offset within that block
|
||||
*/
|
||||
#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
|
||||
|
||||
#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
|
||||
|
||||
#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A)\
|
||||
<< 16) + (B)))
|
||||
|
||||
/* Compute 32 bit VFS inode number from squashfs inode number */
|
||||
#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
|
||||
((b) >> 2) + 1))
|
||||
|
||||
/* Translate between VFS mode and squashfs mode */
|
||||
#define SQUASHFS_MODE(a) ((a) & 0xfff)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * \
|
||||
sizeof(struct squashfs_fragment_entry))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* inode lookup table defines */
|
||||
#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode))
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* uid lookup table defines */
|
||||
#define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int))
|
||||
|
||||
#define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* xattr id lookup table defines */
|
||||
#define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id))
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
#define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16))
|
||||
|
||||
#define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff))
|
||||
|
||||
/* cached data constants for filesystem */
|
||||
#define SQUASHFS_CACHED_BLKS 8
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE_LOG 64
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
|
||||
(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
|
||||
|
||||
#define SQUASHFS_MARKER_BYTE 0xff
|
||||
|
||||
/* meta index cache */
|
||||
#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
|
||||
#define SQUASHFS_META_ENTRIES 31
|
||||
#define SQUASHFS_META_NUMBER 8
|
||||
#define SQUASHFS_SLOTS 4
|
||||
|
||||
struct meta_entry {
|
||||
long long data_block;
|
||||
unsigned int index_block;
|
||||
unsigned short offset;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct meta_index {
|
||||
unsigned int inode_number;
|
||||
unsigned int offset;
|
||||
unsigned short entries;
|
||||
unsigned short skip;
|
||||
unsigned short locked;
|
||||
unsigned short pad;
|
||||
struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* definitions for structures on disk
|
||||
*/
|
||||
|
||||
typedef long long squashfs_block;
|
||||
typedef long long squashfs_inode;
|
||||
|
||||
#define ZLIB_COMPRESSION 1
|
||||
#define LZMA_COMPRESSION 2
|
||||
#define LZO_COMPRESSION 3
|
||||
#define XZ_COMPRESSION 4
|
||||
#define LZ4_COMPRESSION 5
|
||||
#define ZSTD_COMPRESSION 6
|
||||
|
||||
struct squashfs_super_block {
|
||||
unsigned int s_magic;
|
||||
unsigned int inodes;
|
||||
unsigned int mkfs_time /* time of filesystem creation */;
|
||||
unsigned int block_size;
|
||||
unsigned int fragments;
|
||||
unsigned short compression;
|
||||
unsigned short block_log;
|
||||
unsigned short flags;
|
||||
unsigned short no_ids;
|
||||
unsigned short s_major;
|
||||
unsigned short s_minor;
|
||||
squashfs_inode root_inode;
|
||||
long long bytes_used;
|
||||
long long id_table_start;
|
||||
long long xattr_id_table_start;
|
||||
long long inode_table_start;
|
||||
long long directory_table_start;
|
||||
long long fragment_table_start;
|
||||
long long lookup_table_start;
|
||||
};
|
||||
|
||||
struct squashfs_dir_index {
|
||||
unsigned int index;
|
||||
unsigned int start_block;
|
||||
unsigned int size;
|
||||
unsigned char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_base_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_ipc_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
};
|
||||
|
||||
struct squashfs_lipc_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int xattr;
|
||||
};
|
||||
|
||||
struct squashfs_dev_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int rdev;
|
||||
};
|
||||
|
||||
struct squashfs_ldev_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int rdev;
|
||||
unsigned int xattr;
|
||||
};
|
||||
|
||||
struct squashfs_symlink_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int symlink_size;
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
struct squashfs_reg_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size;
|
||||
unsigned int block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_lreg_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
squashfs_block start_block;
|
||||
long long file_size;
|
||||
long long sparse;
|
||||
unsigned int nlink;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int xattr;
|
||||
unsigned int block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int start_block;
|
||||
unsigned int nlink;
|
||||
unsigned short file_size;
|
||||
unsigned short offset;
|
||||
unsigned int parent_inode;
|
||||
};
|
||||
|
||||
struct squashfs_ldir_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size;
|
||||
unsigned int start_block;
|
||||
unsigned int parent_inode;
|
||||
unsigned short i_count;
|
||||
unsigned short offset;
|
||||
unsigned int xattr;
|
||||
struct squashfs_dir_index index[0];
|
||||
};
|
||||
|
||||
union squashfs_inode_header {
|
||||
struct squashfs_base_inode_header base;
|
||||
struct squashfs_dev_inode_header dev;
|
||||
struct squashfs_ldev_inode_header ldev;
|
||||
struct squashfs_symlink_inode_header symlink;
|
||||
struct squashfs_reg_inode_header reg;
|
||||
struct squashfs_lreg_inode_header lreg;
|
||||
struct squashfs_dir_inode_header dir;
|
||||
struct squashfs_ldir_inode_header ldir;
|
||||
struct squashfs_ipc_inode_header ipc;
|
||||
struct squashfs_lipc_inode_header lipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry {
|
||||
unsigned short offset;
|
||||
short inode_number;
|
||||
unsigned short type;
|
||||
unsigned short size;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_header {
|
||||
unsigned int count;
|
||||
unsigned int start_block;
|
||||
unsigned int inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_fragment_entry {
|
||||
long long start_block;
|
||||
unsigned int size;
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_entry {
|
||||
unsigned short type;
|
||||
unsigned short size;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_val {
|
||||
unsigned int vsize;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_id {
|
||||
long long xattr;
|
||||
unsigned int count;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_table {
|
||||
long long xattr_table_start;
|
||||
unsigned int xattr_ids;
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
#endif
|
||||
423
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_swap.h
Normal file
423
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_swap.h
Normal file
@@ -0,0 +1,423 @@
|
||||
#ifndef SQUASHFS_SWAP_H
|
||||
#define SQUASHFS_SWAP_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2008, 2009, 2010, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_swap.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* macros to convert each stucture from big endian to little endian
|
||||
*/
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#include <stddef.h>
|
||||
extern void swap_le16(void *, void *);
|
||||
extern void swap_le32(void *, void *);
|
||||
extern void swap_le64(void *, void *);
|
||||
extern void swap_le16_num(void *, void *, int);
|
||||
extern void swap_le32_num(void *, void *, int);
|
||||
extern void swap_le64_num(void *, void *, int);
|
||||
extern unsigned short inswap_le16(unsigned short);
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
extern long long inswap_le64(long long);
|
||||
extern void inswap_le16_num(unsigned short *, int);
|
||||
extern void inswap_le32_num(unsigned int *, int);
|
||||
extern void inswap_le64_num(long long *, int);
|
||||
|
||||
#define _SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, s_magic, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, inodes, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, mkfs_time, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, block_size, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, fragments, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, compression, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, block_log, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, flags, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, no_ids, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, s_major, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, s_minor, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, root_inode, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, bytes_used, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, id_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, xattr_id_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, inode_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, directory_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, fragment_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, lookup_table_start, struct squashfs_super_block);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_INDEX(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, index, struct squashfs_dir_index);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_index);\
|
||||
SWAP_FUNC(32, s, d, size, struct squashfs_dir_index);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_base_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_IPC_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_ipc_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_lipc_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DEV_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, rdev, struct squashfs_dev_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, rdev, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_ldev_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, symlink_size, struct squashfs_symlink_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_REG_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, fragment, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, offset, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, file_size, struct squashfs_reg_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LREG_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(64, s, d, start_block, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(64, s, d, file_size, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(64, s, d, sparse, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, fragment, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, offset, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_lreg_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, file_size, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, offset, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, parent_inode, struct squashfs_dir_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, file_size, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, parent_inode, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, i_count, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, offset, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_ldir_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_ENTRY(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, offset, struct squashfs_dir_entry);\
|
||||
SWAP_FUNC##S(16, s, d, inode_number, struct squashfs_dir_entry);\
|
||||
SWAP_FUNC(16, s, d, type, struct squashfs_dir_entry);\
|
||||
SWAP_FUNC(16, s, d, size, struct squashfs_dir_entry);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, count, struct squashfs_dir_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(64, s, d, start_block, struct squashfs_fragment_entry);\
|
||||
SWAP_FUNC(32, s, d, size, struct squashfs_fragment_entry);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_ENTRY(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, type, struct squashfs_xattr_entry);\
|
||||
SWAP_FUNC(16, s, d, size, struct squashfs_xattr_entry);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_VAL(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, vsize, struct squashfs_xattr_val);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_ID(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(64, s, d, xattr, struct squashfs_xattr_id);\
|
||||
SWAP_FUNC(32, s, d, count, struct squashfs_xattr_id);\
|
||||
SWAP_FUNC(32, s, d, size, struct squashfs_xattr_id);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_TABLE(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(64, s, d, xattr_table_start, struct squashfs_xattr_table);\
|
||||
SWAP_FUNC(32, s, d, xattr_ids, struct squashfs_xattr_table);\
|
||||
}
|
||||
|
||||
/* big endian architecture copy and swap macros */
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
|
||||
_SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_INDEX(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_INDEX(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_IPC_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_DEV_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_REG_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LREG_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_ENTRY(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \
|
||||
_SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_ENTRY(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_VAL(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_VAL(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_ID(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_ID(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_TABLE(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_TABLE(s, d, SWAP_LE)
|
||||
#define SWAP_LE(bits, s, d, field, type) \
|
||||
SWAP_LE##bits(((void *)(s)) + offsetof(type, field), \
|
||||
((void *)(d)) + offsetof(type, field))
|
||||
#define SWAP_LES(bits, s, d, field, type) \
|
||||
SWAP_LE(bits, s, d, field, type)
|
||||
#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \
|
||||
SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
|
||||
#define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
|
||||
#define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
|
||||
#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
|
||||
|
||||
#define SWAP_LE16(s, d) swap_le16(s, d)
|
||||
#define SWAP_LE32(s, d) swap_le32(s, d)
|
||||
#define SWAP_LE64(s, d) swap_le64(s, d)
|
||||
|
||||
/* big endian architecture swap in-place macros */
|
||||
#define SQUASHFS_INSWAP_SUPER_BLOCK(s) \
|
||||
_SQUASHFS_SWAP_SUPER_BLOCK(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_INDEX(s) \
|
||||
_SQUASHFS_SWAP_DIR_INDEX(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_BASE_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_BASE_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_IPC_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_IPC_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LIPC_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LIPC_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DEV_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_DEV_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LDEV_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LDEV_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_SYMLINK_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_REG_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_REG_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LREG_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LREG_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_DIR_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LDIR_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LDIR_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_ENTRY(s) \
|
||||
_SQUASHFS_SWAP_DIR_ENTRY(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_HEADER(s) \
|
||||
_SQUASHFS_SWAP_DIR_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_ENTRY(s) \
|
||||
_SQUASHFS_SWAP_FRAGMENT_ENTRY(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_ENTRY(s) \
|
||||
_SQUASHFS_SWAP_XATTR_ENTRY(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_VAL(s) \
|
||||
_SQUASHFS_SWAP_XATTR_VAL(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_ID(s) \
|
||||
_SQUASHFS_SWAP_XATTR_ID(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_TABLE(s) \
|
||||
_SQUASHFS_SWAP_XATTR_TABLE(s, s, INSWAP_LE)
|
||||
#define INSWAP_LE(bits, s, d, field, type) \
|
||||
(s)->field = inswap_le##bits((s)->field)
|
||||
#define INSWAP_LES(bits, s, d, field, type) \
|
||||
(s)->field = (short) inswap_le##bits((unsigned short) \
|
||||
(s)->field)
|
||||
#define SQUASHFS_INSWAP_INODE_T(s) s = inswap_le64(s)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n) inswap_le64_num(s, n)
|
||||
#define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n) inswap_le64_num(s, n)
|
||||
#define SQUASHFS_INSWAP_ID_BLOCKS(s, n) inswap_le64_num(s, n)
|
||||
#define SQUASHFS_INSWAP_SHORTS(s, n) inswap_le16_num(s, n)
|
||||
#define SQUASHFS_INSWAP_INTS(s, n) inswap_le32_num(s, n)
|
||||
#define SQUASHFS_INSWAP_LONG_LONGS(s, n) inswap_le64_num(s, n)
|
||||
#else
|
||||
/* little endian architecture, just copy */
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_super_block))
|
||||
#define SQUASHFS_SWAP_DIR_INDEX(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_index))
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_base_inode_header))
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ipc_inode_header))
|
||||
#define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lipc_inode_header))
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dev_inode_header))
|
||||
#define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldev_inode_header))
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_symlink_inode_header))
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_reg_inode_header))
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lreg_inode_header))
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_inode_header))
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldir_inode_header))
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_entry))
|
||||
#define SQUASHFS_SWAP_DIR_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_header))
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_fragment_entry))
|
||||
#define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_entry))
|
||||
#define SQUASHFS_SWAP_XATTR_VAL(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_val))
|
||||
#define SQUASHFS_SWAP_XATTR_ID(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_id))
|
||||
#define SQUASHFS_SWAP_XATTR_TABLE(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_table))
|
||||
#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \
|
||||
SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
|
||||
#define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
|
||||
#define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
|
||||
#define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
|
||||
#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
|
||||
memcpy(d, s, n * sizeof(long long))
|
||||
|
||||
/* little endian architecture, data already in place so do nothing */
|
||||
#define SQUASHFS_INSWAP_SUPER_BLOCK(s)
|
||||
#define SQUASHFS_INSWAP_DIR_INDEX(s)
|
||||
#define SQUASHFS_INSWAP_BASE_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_IPC_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LIPC_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_DEV_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LDEV_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_SYMLINK_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_REG_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LREG_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_DIR_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LDIR_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_DIR_ENTRY(s)
|
||||
#define SQUASHFS_INSWAP_DIR_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_ENTRY(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_ENTRY(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_VAL(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_ID(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_TABLE(s)
|
||||
#define SQUASHFS_INSWAP_INODE_T(s)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n)
|
||||
#define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n)
|
||||
#define SQUASHFS_INSWAP_ID_BLOCKS(s, n)
|
||||
#define SQUASHFS_INSWAP_SHORTS(s, n)
|
||||
#define SQUASHFS_INSWAP_INTS(s, n)
|
||||
#define SQUASHFS_INSWAP_LONG_LONGS(s, n)
|
||||
#endif
|
||||
#endif
|
||||
123
SQUASHFS/squashfs-tools-4.4/squashfs-tools/swap.c
Normal file
123
SQUASHFS/squashfs-tools-4.4/squashfs-tools/swap.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2010
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* swap.c
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
void swap_le16(void *src, void *dest)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
unsigned char *d = dest;
|
||||
|
||||
d[0] = s[1];
|
||||
d[1] = s[0];
|
||||
}
|
||||
|
||||
|
||||
void swap_le32(void *src, void *dest)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
unsigned char *d = dest;
|
||||
|
||||
d[0] = s[3];
|
||||
d[1] = s[2];
|
||||
d[2] = s[1];
|
||||
d[3] = s[0];
|
||||
}
|
||||
|
||||
|
||||
void swap_le64(void *src, void *dest)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
unsigned char *d = dest;
|
||||
|
||||
d[0] = s[7];
|
||||
d[1] = s[6];
|
||||
d[2] = s[5];
|
||||
d[3] = s[4];
|
||||
d[4] = s[3];
|
||||
d[5] = s[2];
|
||||
d[6] = s[1];
|
||||
d[7] = s[0];
|
||||
}
|
||||
|
||||
|
||||
unsigned short inswap_le16(unsigned short num)
|
||||
{
|
||||
return (num >> 8) |
|
||||
((num & 0xff) << 8);
|
||||
}
|
||||
|
||||
|
||||
unsigned int inswap_le32(unsigned int num)
|
||||
{
|
||||
return (num >> 24) |
|
||||
((num & 0xff0000) >> 8) |
|
||||
((num & 0xff00) << 8) |
|
||||
((num & 0xff) << 24);
|
||||
}
|
||||
|
||||
|
||||
long long inswap_le64(long long n)
|
||||
{
|
||||
unsigned long long num = n;
|
||||
|
||||
return (num >> 56) |
|
||||
((num & 0xff000000000000LL) >> 40) |
|
||||
((num & 0xff0000000000LL) >> 24) |
|
||||
((num & 0xff00000000LL) >> 8) |
|
||||
((num & 0xff000000) << 8) |
|
||||
((num & 0xff0000) << 24) |
|
||||
((num & 0xff00) << 40) |
|
||||
((num & 0xff) << 56);
|
||||
}
|
||||
|
||||
|
||||
#define SWAP_LE_NUM(BITS) \
|
||||
void swap_le##BITS##_num(void *s, void *d, int n) \
|
||||
{\
|
||||
int i;\
|
||||
for(i = 0; i < n; i++, s += BITS / 8, d += BITS / 8)\
|
||||
swap_le##BITS(s, d);\
|
||||
}
|
||||
|
||||
SWAP_LE_NUM(16)
|
||||
SWAP_LE_NUM(32)
|
||||
SWAP_LE_NUM(64)
|
||||
|
||||
#define INSWAP_LE_NUM(BITS, TYPE) \
|
||||
void inswap_le##BITS##_num(TYPE *s, int n) \
|
||||
{\
|
||||
int i;\
|
||||
for(i = 0; i < n; i++)\
|
||||
s[i] = inswap_le##BITS(s[i]);\
|
||||
}
|
||||
|
||||
INSWAP_LE_NUM(16, unsigned short)
|
||||
INSWAP_LE_NUM(32, unsigned int)
|
||||
INSWAP_LE_NUM(64, long long)
|
||||
#endif
|
||||
411
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-1.c
Normal file
411
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-1.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-1.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
static unsigned int *uid_table, *guid_table;
|
||||
static char *inode_table, *directory_table;
|
||||
static squashfs_operations ops;
|
||||
|
||||
static void read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
|
||||
{
|
||||
unsigned short block_size;
|
||||
int i;
|
||||
|
||||
TRACE("read_block_list: blocks %d\n", blocks);
|
||||
|
||||
for(i = 0; i < blocks; i++, block_ptr += 2) {
|
||||
if(swap) {
|
||||
unsigned short sblock_size;
|
||||
memcpy(&sblock_size, block_ptr, sizeof(unsigned short));
|
||||
SQUASHFS_SWAP_SHORTS_3((&block_size), &sblock_size, 1);
|
||||
} else
|
||||
memcpy(&block_size, block_ptr, sizeof(unsigned short));
|
||||
block_list[i] = SQUASHFS_COMPRESSED_SIZE(block_size) |
|
||||
(SQUASHFS_COMPRESSED(block_size) ? 0 :
|
||||
SQUASHFS_COMPRESSED_BIT_BLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct inode *read_inode(unsigned int start_block, unsigned int offset)
|
||||
{
|
||||
static union squashfs_inode_header_1 header;
|
||||
long long start = sBlk.s.inode_table_start + start_block;
|
||||
int bytes = lookup_entry(inode_table_hash, start);
|
||||
char *block_ptr = inode_table + bytes + offset;
|
||||
static struct inode i;
|
||||
|
||||
TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
|
||||
start);
|
||||
|
||||
if(swap) {
|
||||
squashfs_base_inode_header_1 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.base));
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_1(&header.base, &sinode,
|
||||
sizeof(squashfs_base_inode_header_1));
|
||||
} else
|
||||
memcpy(&header.base, block_ptr, sizeof(header.base));
|
||||
|
||||
i.uid = (uid_t) uid_table[(header.base.inode_type - 1) /
|
||||
SQUASHFS_TYPES * 16 + header.base.uid];
|
||||
if(header.base.inode_type == SQUASHFS_IPC_TYPE) {
|
||||
squashfs_ipc_inode_header_1 *inodep = &header.ipc;
|
||||
|
||||
if(swap) {
|
||||
squashfs_ipc_inode_header_1 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_IPC_INODE_HEADER_1(inodep, &sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
if(inodep->type == SQUASHFS_SOCKET_TYPE) {
|
||||
i.mode = S_IFSOCK | header.base.mode;
|
||||
i.type = SQUASHFS_SOCKET_TYPE;
|
||||
} else {
|
||||
i.mode = S_IFIFO | header.base.mode;
|
||||
i.type = SQUASHFS_FIFO_TYPE;
|
||||
}
|
||||
i.uid = (uid_t) uid_table[inodep->offset * 16 + inodep->uid];
|
||||
} else {
|
||||
i.mode = lookup_type[(header.base.inode_type - 1) %
|
||||
SQUASHFS_TYPES + 1] | header.base.mode;
|
||||
i.type = (header.base.inode_type - 1) % SQUASHFS_TYPES + 1;
|
||||
}
|
||||
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
i.gid = header.base.guid == 15 ? i.uid :
|
||||
(uid_t) guid_table[header.base.guid];
|
||||
i.time = sBlk.s.mkfs_time;
|
||||
i.inode_number = inode_number ++;
|
||||
|
||||
switch(i.type) {
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
squashfs_dir_inode_header_1 *inode = &header.dir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dir_inode_header_1 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.dir));
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER_1(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(header.dir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.time = inode->mtime;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
squashfs_reg_inode_header_1 *inode = &header.reg;
|
||||
|
||||
if(swap) {
|
||||
squashfs_reg_inode_header_1 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(sinode));
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER_1(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(*inode));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.time = inode->mtime;
|
||||
i.blocks = (i.data + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
i.fragment = 0;
|
||||
i.frag_bytes = 0;
|
||||
i.offset = 0;
|
||||
i.sparse = 0;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE: {
|
||||
squashfs_symlink_inode_header_1 *inodep =
|
||||
&header.symlink;
|
||||
|
||||
if(swap) {
|
||||
squashfs_symlink_inode_header_1 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.symlink = malloc(inodep->symlink_size + 1);
|
||||
if(i.symlink == NULL)
|
||||
EXIT_UNSQUASH("read_inode: failed to malloc "
|
||||
"symlink data\n");
|
||||
strncpy(i.symlink, block_ptr +
|
||||
sizeof(squashfs_symlink_inode_header_1),
|
||||
inodep->symlink_size);
|
||||
i.symlink[inodep->symlink_size] = '\0';
|
||||
i.data = inodep->symlink_size;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
squashfs_dev_inode_header_1 *inodep = &header.dev;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dev_inode_header_1 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER_1(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.data = inodep->rdev;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE: {
|
||||
i.data = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
EXIT_UNSQUASH("Unknown inode type %d in "
|
||||
" read_inode_header_1!\n",
|
||||
header.base.inode_type);
|
||||
}
|
||||
return &i;
|
||||
}
|
||||
|
||||
|
||||
static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset,
|
||||
struct inode **i)
|
||||
{
|
||||
squashfs_dir_header_2 dirh;
|
||||
char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__((aligned));
|
||||
squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
|
||||
long long start;
|
||||
int bytes;
|
||||
int dir_count, size;
|
||||
struct dir_ent *new_dir;
|
||||
struct dir *dir;
|
||||
|
||||
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
|
||||
block_start, offset);
|
||||
|
||||
*i = read_inode(block_start, offset);
|
||||
|
||||
dir = malloc(sizeof(struct dir));
|
||||
if(dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
|
||||
|
||||
dir->dir_count = 0;
|
||||
dir->cur_entry = 0;
|
||||
dir->mode = (*i)->mode;
|
||||
dir->uid = (*i)->uid;
|
||||
dir->guid = (*i)->gid;
|
||||
dir->mtime = (*i)->time;
|
||||
dir->xattr = (*i)->xattr;
|
||||
dir->dirs = NULL;
|
||||
|
||||
if ((*i)->data == 0)
|
||||
/*
|
||||
* if the directory is empty, skip the unnecessary
|
||||
* lookup_entry, this fixes the corner case with
|
||||
* completely empty filesystems where lookup_entry correctly
|
||||
* returning -1 is incorrectly treated as an error
|
||||
*/
|
||||
return dir;
|
||||
|
||||
start = sBlk.s.directory_table_start + (*i)->start;
|
||||
bytes = lookup_entry(directory_table_hash, start);
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
|
||||
"found!\n", block_start);
|
||||
|
||||
bytes += (*i)->offset;
|
||||
size = (*i)->data + bytes;
|
||||
|
||||
while(bytes < size) {
|
||||
if(swap) {
|
||||
squashfs_dir_header_2 sdirh;
|
||||
memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
|
||||
SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
|
||||
} else
|
||||
memcpy(&dirh, directory_table + bytes, sizeof(dirh));
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
TRACE("squashfs_opendir: Read directory header @ byte position "
|
||||
"%d, %d directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
while(dir_count--) {
|
||||
if(swap) {
|
||||
squashfs_dir_entry_2 sdire;
|
||||
memcpy(&sdire, directory_table + bytes,
|
||||
sizeof(sdire));
|
||||
SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
|
||||
} else
|
||||
memcpy(dire, directory_table + bytes,
|
||||
sizeof(*dire));
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_opendir: directory entry %s, inode "
|
||||
"%d:%d, type %d\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
if((dir->dir_count % DIR_ENT_SIZE) == 0) {
|
||||
new_dir = realloc(dir->dirs, (dir->dir_count +
|
||||
DIR_ENT_SIZE) * sizeof(struct dir_ent));
|
||||
if(new_dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: "
|
||||
"realloc failed!\n");
|
||||
dir->dirs = new_dir;
|
||||
}
|
||||
strcpy(dir->dirs[dir->dir_count].name, dire->name);
|
||||
dir->dirs[dir->dir_count].start_block =
|
||||
dirh.start_block;
|
||||
dir->dirs[dir->dir_count].offset = dire->offset;
|
||||
dir->dirs[dir->dir_count].type = dire->type;
|
||||
dir->dir_count ++;
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
||||
corrupted:
|
||||
free(dir->dirs);
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
squashfs_operations *read_filesystem_tables_1()
|
||||
{
|
||||
long long table_start;
|
||||
|
||||
/* Read uid and gid lookup tables */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.no_guids) {
|
||||
if(sBlk.guid_start >= sBlk.s.bytes_used) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* In 1.x filesystems, there should never be more than 15 gids */
|
||||
if(sBlk.no_guids > 15) {
|
||||
ERROR("read_filesystem_tables: gids too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_guids, sBlk.guid_start, sBlk.s.bytes_used, &guid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.guid_start;
|
||||
} else {
|
||||
/* no guids, guid_start should be 0 */
|
||||
if(sBlk.guid_start != 0) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
table_start = sBlk.s.bytes_used;
|
||||
}
|
||||
|
||||
if(sBlk.uid_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: uid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* There should be at least one uid */
|
||||
if(sBlk.no_uids == 0) {
|
||||
ERROR("read_filesystem_tables: uid count bad in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* In 1.x filesystems, there should never be more than 48 uids */
|
||||
if(sBlk.no_uids > 48) {
|
||||
ERROR("read_filesystem_tables: uids too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_uids, sBlk.uid_start, table_start, &uid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.uid_start;
|
||||
|
||||
/* Read directory table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.directory_table_start > table_start) {
|
||||
ERROR("read_filesystem_tables: directory table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
directory_table = read_directory_table(sBlk.s.directory_table_start,
|
||||
table_start);
|
||||
if(directory_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
/* Read inode table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
|
||||
ERROR("read_filesystem_tables: inode table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
inode_table = read_inode_table(sBlk.s.inode_table_start,
|
||||
sBlk.s.directory_table_start);
|
||||
if(inode_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
return &ops;
|
||||
|
||||
corrupted:
|
||||
ERROR("File system corruption detected\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static squashfs_operations ops = {
|
||||
.opendir = squashfs_opendir,
|
||||
.read_block_list = read_block_list,
|
||||
.read_inode = read_inode
|
||||
};
|
||||
83
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-123.c
Normal file
83
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-123.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-123.c
|
||||
*
|
||||
* Helper functions used by unsquash-1, unsquash-2 and unsquash-3.
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
int read_ids(int ids, long long start, long long end, unsigned int **id_table)
|
||||
{
|
||||
/* Note on overflow limits:
|
||||
* Size of ids is 2^8
|
||||
* Max length is 2^8*4 or 1024
|
||||
*/
|
||||
int res;
|
||||
int length = ids * sizeof(unsigned int);
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (end - start)) {
|
||||
ERROR("read_ids: Bad inode count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_ids: no_ids %d\n", ids);
|
||||
|
||||
*id_table = malloc(length);
|
||||
if(*id_table == NULL) {
|
||||
ERROR("read_ids: failed to allocate uid/gid table\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(swap) {
|
||||
unsigned int *sid_table = malloc(length);
|
||||
|
||||
if(sid_table == NULL) {
|
||||
ERROR("read_ids: failed to allocate uid/gid table\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = read_fs_bytes(fd, start, length, sid_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_ids: failed to read uid/gid table"
|
||||
"\n");
|
||||
free(sid_table);
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_SWAP_INTS_3((*id_table), sid_table, ids);
|
||||
free(sid_table);
|
||||
} else {
|
||||
res = read_fs_bytes(fd, start, length, *id_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_ids: failed to read uid/gid table"
|
||||
"\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
529
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-2.c
Normal file
529
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-2.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-2.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
static squashfs_fragment_entry_2 *fragment_table;
|
||||
static unsigned int *uid_table, *guid_table;
|
||||
static char *inode_table, *directory_table;
|
||||
static squashfs_operations ops;
|
||||
|
||||
static void read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
|
||||
{
|
||||
TRACE("read_block_list: blocks %d\n", blocks);
|
||||
|
||||
if(swap) {
|
||||
SQUASHFS_SWAP_INTS_3(block_list, block_ptr, blocks);
|
||||
} else
|
||||
memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
|
||||
static int read_fragment_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.fragments is 2^32 (unsigned int)
|
||||
* Max size of bytes is 2^32*8 or 2^35
|
||||
* Max indexes is (2^32*8)/8K or 2^22
|
||||
* Max length is ((2^32*8)/8K)*4 or 2^24 or 16M
|
||||
*/
|
||||
int res, i;
|
||||
long long bytes = SQUASHFS_FRAGMENT_BYTES_2((long long) sBlk.s.fragments);
|
||||
int indexes = SQUASHFS_FRAGMENT_INDEXES_2((long long) sBlk.s.fragments);
|
||||
int length = SQUASHFS_FRAGMENT_INDEX_BYTES_2((long long) sBlk.s.fragments);
|
||||
unsigned int *fragment_table_index;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start- sBlk.s.fragment_table_start)) {
|
||||
ERROR("read_ids: Bad inode count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
|
||||
"from 0x%llx\n", sBlk.s.fragments, indexes,
|
||||
sBlk.s.fragment_table_start);
|
||||
|
||||
fragment_table_index = malloc(length);
|
||||
if(fragment_table_index == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table index\n");
|
||||
|
||||
fragment_table = malloc(bytes);
|
||||
if(fragment_table == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table\n");
|
||||
|
||||
if(swap) {
|
||||
unsigned int *sfragment_table_index = malloc(length);
|
||||
|
||||
if(sfragment_table_index == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table index\n");
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start,
|
||||
length, sfragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
free(sfragment_table_index);
|
||||
goto failed;
|
||||
}
|
||||
SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index,
|
||||
sfragment_table_index, indexes);
|
||||
free(sfragment_table_index);
|
||||
} else {
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start,
|
||||
length, fragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, fragment_table_index[i], NULL,
|
||||
expected, ((char *) fragment_table) + ((long long) i *
|
||||
SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read fragment table block %d, from 0x%x, length %d\n", i,
|
||||
fragment_table_index[i], length);
|
||||
if(length == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table block\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if(swap) {
|
||||
squashfs_fragment_entry_2 sfragment;
|
||||
for(i = 0; i < sBlk.s.fragments; i++) {
|
||||
SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment),
|
||||
(&fragment_table[i]));
|
||||
memcpy((char *) &fragment_table[i], (char *) &sfragment,
|
||||
sizeof(squashfs_fragment_entry_2));
|
||||
}
|
||||
}
|
||||
|
||||
*table_start = fragment_table_index[0];
|
||||
free(fragment_table_index);
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
free(fragment_table_index);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void read_fragment(unsigned int fragment, long long *start_block, int *size)
|
||||
{
|
||||
TRACE("read_fragment: reading fragment %d\n", fragment);
|
||||
|
||||
squashfs_fragment_entry_2 *fragment_entry = &fragment_table[fragment];
|
||||
*start_block = fragment_entry->start_block;
|
||||
*size = fragment_entry->size;
|
||||
}
|
||||
|
||||
|
||||
static struct inode *read_inode(unsigned int start_block, unsigned int offset)
|
||||
{
|
||||
static union squashfs_inode_header_2 header;
|
||||
long long start = sBlk.s.inode_table_start + start_block;
|
||||
int bytes = lookup_entry(inode_table_hash, start);
|
||||
char *block_ptr = inode_table + bytes + offset;
|
||||
static struct inode i;
|
||||
|
||||
TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
|
||||
start);
|
||||
|
||||
if(swap) {
|
||||
squashfs_base_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.base));
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode,
|
||||
sizeof(squashfs_base_inode_header_2));
|
||||
} else
|
||||
memcpy(&header.base, block_ptr, sizeof(header.base));
|
||||
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
i.uid = (uid_t) uid_table[header.base.uid];
|
||||
i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid :
|
||||
(uid_t) guid_table[header.base.guid];
|
||||
i.mode = lookup_type[header.base.inode_type] | header.base.mode;
|
||||
i.type = header.base.inode_type;
|
||||
i.time = sBlk.s.mkfs_time;
|
||||
i.inode_number = inode_number++;
|
||||
|
||||
switch(header.base.inode_type) {
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
squashfs_dir_inode_header_2 *inode = &header.dir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dir_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.dir));
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(&header.dir, block_ptr,
|
||||
sizeof(header.dir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.time = inode->mtime;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
squashfs_ldir_inode_header_2 *inode = &header.ldir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_ldir_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.ldir));
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(&header.ldir, block_ptr,
|
||||
sizeof(header.ldir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.time = inode->mtime;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
squashfs_reg_inode_header_2 *inode = &header.reg;
|
||||
|
||||
if(swap) {
|
||||
squashfs_reg_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(sinode));
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER_2(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(*inode));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.time = inode->mtime;
|
||||
i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
|
||||
? 0 : inode->file_size % sBlk.s.block_size;
|
||||
i.fragment = inode->fragment;
|
||||
i.offset = inode->offset;
|
||||
i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(i.data + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log : i.data >>
|
||||
sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.sparse = 0;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE: {
|
||||
squashfs_symlink_inode_header_2 *inodep =
|
||||
&header.symlink;
|
||||
|
||||
if(swap) {
|
||||
squashfs_symlink_inode_header_2 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.symlink = malloc(inodep->symlink_size + 1);
|
||||
if(i.symlink == NULL)
|
||||
EXIT_UNSQUASH("read_inode: failed to malloc "
|
||||
"symlink data\n");
|
||||
strncpy(i.symlink, block_ptr +
|
||||
sizeof(squashfs_symlink_inode_header_2),
|
||||
inodep->symlink_size);
|
||||
i.symlink[inodep->symlink_size] = '\0';
|
||||
i.data = inodep->symlink_size;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
squashfs_dev_inode_header_2 *inodep = &header.dev;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dev_inode_header_2 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.data = inodep->rdev;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
i.data = 0;
|
||||
break;
|
||||
default:
|
||||
EXIT_UNSQUASH("Unknown inode type %d in "
|
||||
"read_inode_header_2!\n",
|
||||
header.base.inode_type);
|
||||
}
|
||||
return &i;
|
||||
}
|
||||
|
||||
|
||||
static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset,
|
||||
struct inode **i)
|
||||
{
|
||||
squashfs_dir_header_2 dirh;
|
||||
char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__((aligned));
|
||||
squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
|
||||
long long start;
|
||||
int bytes;
|
||||
int dir_count, size;
|
||||
struct dir_ent *new_dir;
|
||||
struct dir *dir;
|
||||
|
||||
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
|
||||
block_start, offset);
|
||||
|
||||
*i = read_inode(block_start, offset);
|
||||
|
||||
dir = malloc(sizeof(struct dir));
|
||||
if(dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
|
||||
|
||||
dir->dir_count = 0;
|
||||
dir->cur_entry = 0;
|
||||
dir->mode = (*i)->mode;
|
||||
dir->uid = (*i)->uid;
|
||||
dir->guid = (*i)->gid;
|
||||
dir->mtime = (*i)->time;
|
||||
dir->xattr = (*i)->xattr;
|
||||
dir->dirs = NULL;
|
||||
|
||||
if ((*i)->data == 0)
|
||||
/*
|
||||
* if the directory is empty, skip the unnecessary
|
||||
* lookup_entry, this fixes the corner case with
|
||||
* completely empty filesystems where lookup_entry correctly
|
||||
* returning -1 is incorrectly treated as an error
|
||||
*/
|
||||
return dir;
|
||||
|
||||
start = sBlk.s.directory_table_start + (*i)->start;
|
||||
bytes = lookup_entry(directory_table_hash, start);
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
|
||||
"found!\n", block_start);
|
||||
|
||||
bytes += (*i)->offset;
|
||||
size = (*i)->data + bytes;
|
||||
|
||||
while(bytes < size) {
|
||||
if(swap) {
|
||||
squashfs_dir_header_2 sdirh;
|
||||
memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
|
||||
SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
|
||||
} else
|
||||
memcpy(&dirh, directory_table + bytes, sizeof(dirh));
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
TRACE("squashfs_opendir: Read directory header @ byte position "
|
||||
"%d, %d directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
while(dir_count--) {
|
||||
if(swap) {
|
||||
squashfs_dir_entry_2 sdire;
|
||||
memcpy(&sdire, directory_table + bytes,
|
||||
sizeof(sdire));
|
||||
SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
|
||||
} else
|
||||
memcpy(dire, directory_table + bytes,
|
||||
sizeof(*dire));
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_opendir: directory entry %s, inode "
|
||||
"%d:%d, type %d\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
if((dir->dir_count % DIR_ENT_SIZE) == 0) {
|
||||
new_dir = realloc(dir->dirs, (dir->dir_count +
|
||||
DIR_ENT_SIZE) * sizeof(struct dir_ent));
|
||||
if(new_dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: "
|
||||
"realloc failed!\n");
|
||||
dir->dirs = new_dir;
|
||||
}
|
||||
strcpy(dir->dirs[dir->dir_count].name, dire->name);
|
||||
dir->dirs[dir->dir_count].start_block =
|
||||
dirh.start_block;
|
||||
dir->dirs[dir->dir_count].offset = dire->offset;
|
||||
dir->dirs[dir->dir_count].type = dire->type;
|
||||
dir->dir_count ++;
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
||||
corrupted:
|
||||
free(dir->dirs);
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
squashfs_operations *read_filesystem_tables_2()
|
||||
{
|
||||
long long table_start;
|
||||
|
||||
/* Read uid and gid lookup tables */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.no_guids) {
|
||||
if(sBlk.guid_start >= sBlk.s.bytes_used) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_guids, sBlk.guid_start, sBlk.s.bytes_used, &guid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.guid_start;
|
||||
} else {
|
||||
/* no guids, guid_start should be 0 */
|
||||
if(sBlk.guid_start != 0) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
table_start = sBlk.s.bytes_used;
|
||||
}
|
||||
|
||||
if(sBlk.uid_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: uid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* There should be at least one uid */
|
||||
if(sBlk.no_uids == 0) {
|
||||
ERROR("read_filesystem_tables: uid count bad in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_uids, sBlk.uid_start, table_start, &uid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.uid_start;
|
||||
|
||||
/* Read fragment table */
|
||||
if(sBlk.s.fragments != 0) {
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.fragment_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* The number of fragments should not exceed the number of inodes */
|
||||
if(sBlk.s.fragments > sBlk.s.inodes) {
|
||||
ERROR("read_filesystem_tables: Bad fragment count in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_fragment_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
} else {
|
||||
/*
|
||||
* Sanity check super block contents - with 0 fragments,
|
||||
* the fragment table should be empty
|
||||
*/
|
||||
if(sBlk.s.fragment_table_start != table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start invalid in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read directory table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.directory_table_start > table_start) {
|
||||
ERROR("read_filesystem_tables: directory table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
directory_table = read_directory_table(sBlk.s.directory_table_start,
|
||||
table_start);
|
||||
if(directory_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
/* Read inode table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
|
||||
ERROR("read_filesystem_tables: inode table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
inode_table = read_inode_table(sBlk.s.inode_table_start,
|
||||
sBlk.s.directory_table_start);
|
||||
if(inode_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
return &ops;
|
||||
|
||||
corrupted:
|
||||
ERROR("File system corruption detected\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static squashfs_operations ops = {
|
||||
.opendir = squashfs_opendir,
|
||||
.read_fragment = read_fragment,
|
||||
.read_block_list = read_block_list,
|
||||
.read_inode = read_inode
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user