--- /dev/null +++ squashfs-tools/compression_method.c @@ -0,0 +1,12 @@ +#include "compression_method.h" + +const char* compression_method_str(enum compression_method_t compression_method) { + switch (compression_method) { +#if defined(LZMA1_SUPPORT) + case LZMA1: + return "LZMA1"; +#endif + default: + return "ZLIB"; + } +} --- /dev/null +++ squashfs-tools/compression_method.h @@ -0,0 +1,13 @@ +#ifndef COMPRESSION_METHOD_H +#define COMPRESSION_METHOD_H + +enum compression_method_t { + ZLIB +#if defined(LZMA1_SUPPORT) + , LZMA1 +#endif +}; + +extern const char* compression_method_str(enum compression_method_t compression_method); + +#endif --- squashfs-tools/Makefile +++ squashfs-tools/Makefile @@ -3,26 +3,42 @@ INCLUDEDIR = . CFLAGS := -I$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -O2 +LINKER = $(CC) -all: mksquashfs unsquashfs +LIBS := -lz +ifeq ($(LZMA1_SUPPORT),1) +LZMA_LIBNAME := lzma +SUFFIX := -multi +CPPFLAGS += -DLZMA1_SUPPORT $(if $(strip $(LZMA_DIR)),-I$(strip $(LZMA_DIR))/C) +LINKER = $(if $(findstring ++,$(LZMA_LIBNAME)),$(CXX),$(CC)) +LIBS += $(if $(strip $(LZMA_DIR)),-L$(strip $(LZMA_DIR))) -l$(strip $(LZMA_LIBNAME)) +endif +LIBS += -lpthread -lm -mksquashfs: mksquashfs.o read_fs.o sort.o - $(CC) $^ -lz -lpthread -lm -o $@ +all: mksquashfs$(SUFFIX) unsquashfs$(SUFFIX) -mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h +mksquashfs$(SUFFIX): mksquashfs$(SUFFIX).o read_fs$(SUFFIX).o sort$(SUFFIX).o compression_method$(SUFFIX).o + $(LINKER) $(LDFLAGS) $^ $(LIBS) -o $@ -read_fs.o: read_fs.c squashfs_fs.h read_fs.h global.h +mksquashfs$(SUFFIX).o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h -sort.o: sort.c squashfs_fs.h global.h sort.h +read_fs$(SUFFIX).o: read_fs.c squashfs_fs.h read_fs.h global.h -unsquashfs: unsquashfs.o - $(CC) $^ -lz -lpthread -lm -o $@ +sort$(SUFFIX).o: sort.c squashfs_fs.h global.h sort.h -unsquashfs.o: unsquashfs.c squashfs_fs.h read_fs.h global.h +compression_method$(SUFFIX).o: compression_method.c compression_method.h + +unsquashfs$(SUFFIX): unsquashfs$(SUFFIX).o compression_method$(SUFFIX).o + $(LINKER) $(LDFLAGS) $^ $(LIBS) -o $@ + +unsquashfs$(SUFFIX).o: unsquashfs.c squashfs_fs.h read_fs.h global.h + +%$(SUFFIX).o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< clean: - -rm -f *.o mksquashfs unsquashfs + -rm -f *.o mksquashfs unsquashfs mksquashfs-multi unsquashfs-multi -install: mksquashfs unsquashfs +install: mksquashfs$(SUFFIX) unsquashfs$(SUFFIX) mkdir -p $(INSTALL_DIR) cp $^ $(INSTALL_DIR) --- squashfs-tools/mksquashfs.c +++ squashfs-tools/mksquashfs.c @@ -62,6 +62,11 @@ #include #endif +#if defined(LZMA1_SUPPORT) +#include +#endif +#include "compression_method.h" + #include "squashfs_fs.h" #include "mksquashfs.h" #include "global.h" @@ -104,6 +109,15 @@ EXIT_MKSQUASHFS();\ } while(0) +enum compression_method_t compression_method = ZLIB; // ZLIB by default +#if defined(LZMA1_SUPPORT) +zlib_uncompress_t uncompress_fct = &uncompress; // ZLIB by default +zlib_compress2_t compress2_fct = &compress2; // ZLIB by default +#else +#define uncompress_fct uncompress +#define compress2_fct compress2 +#endif + int delete = FALSE; int fd; int cur_uncompressed = 0, estimated_uncompressed = 0; @@ -809,6 +823,14 @@ if(uncompressed) goto notcompressed; +#if defined(LZMA1_SUPPORT) +if (compression_method == LZMA1) { + c_byte = block_size; + res = compress2_fct(d, &c_byte, s, size, 9); + if (res == 0) + res = Z_STREAM_END; +} else { +#endif if(stream == NULL) { if((stream = *strm = malloc(sizeof(z_stream))) == NULL) BAD_ERROR("mangle::compress failed, not enough memory\n"); @@ -819,19 +841,19 @@ if((res = deflateInit(stream, 9)) != Z_OK) { if(res == Z_MEM_ERROR) - BAD_ERROR("zlib::compress failed, not enough memory\n"); + BAD_ERROR("%s::compress failed, not enough memory\n", compression_method_str(compression_method)); else if(res == Z_STREAM_ERROR) - BAD_ERROR("zlib::compress failed, not a valid compression level\n"); + BAD_ERROR("%s::compress failed, not a valid compression level\n", compression_method_str(compression_method)); else if(res == Z_VERSION_ERROR) - BAD_ERROR("zlib::compress failed, incorrect zlib version\n"); + BAD_ERROR("%s::compress failed, incorrect zlib version\n", compression_method_str(compression_method)); else - BAD_ERROR("zlib::compress failed, unknown error %d\n", res); + BAD_ERROR("%s::compress failed, unknown error %d\n", compression_method_str(compression_method), res); } } else if((res = deflateReset(stream)) != Z_OK) { if(res == Z_STREAM_ERROR) - BAD_ERROR("zlib::compress failed, stream state inconsistent\n"); + BAD_ERROR("%s::compress failed, stream state inconsistent\n", compression_method_str(compression_method)); else - BAD_ERROR("zlib::compress failed, unknown error %d\n", res); + BAD_ERROR("%s::compress failed, unknown error %d\n", compression_method_str(compression_method), res); } stream->next_in = (unsigned char *) s; @@ -842,14 +864,17 @@ res = deflate(stream, Z_FINISH); if(res != Z_STREAM_END && res != Z_OK) { if(res == Z_STREAM_ERROR) - BAD_ERROR("zlib::compress failed, stream state inconsistent\n"); + BAD_ERROR("%s::compress failed, stream state inconsistent\n", compression_method_str(compression_method)); else if(res == Z_BUF_ERROR) - BAD_ERROR("zlib::compress failed, no progress possible\n"); + BAD_ERROR("%s::compress failed, no progress possible\n", compression_method_str(compression_method)); else - BAD_ERROR("zlib::compress failed, unknown error %d\n", res); + BAD_ERROR("%s::compress failed, unknown error %d\n", compression_method_str(compression_method), res); } c_byte = stream->total_out; +#if defined(LZMA1_SUPPORT) +} +#endif if(res != Z_STREAM_END || c_byte >= size) { notcompressed: @@ -1490,13 +1515,13 @@ read_destination(fd, start_block, size, data); } - if((res = uncompress((unsigned char *) buffer->data, &bytes, (const unsigned char *) data, size)) != Z_OK) { + if((res = uncompress_fct((unsigned char *) buffer->data, &bytes, (const unsigned char *) data, size)) != Z_OK) { if(res == Z_MEM_ERROR) - BAD_ERROR("zlib::uncompress failed, not enough memory\n"); + BAD_ERROR("%s::uncompress failed, not enough memory\n", compression_method_str(compression_method)); else if(res == Z_BUF_ERROR) - BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n"); + BAD_ERROR("%s::uncompress failed, not enough room in output buffer\n", compression_method_str(compression_method)); else - BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res); + BAD_ERROR("%s::uncompress failed, unknown error %d\n", compression_method_str(compression_method), res); } } else if(compressed_buffer) memcpy(buffer->data, compressed_buffer->data, size); @@ -3791,6 +3816,12 @@ exit(1); } } +#if defined(LZMA1_SUPPORT) + } else if (strcmp(argv[i], "-lzma1") == 0) { + compression_method = LZMA1; + uncompress_fct = &LZMA_ZLIB_COMPAT(uncompress); + compress2_fct = &LZMA_ZLIB_COMPAT(compress2); +#endif } else if(strcmp(argv[i], "-noI") == 0 || strcmp(argv[i], "-noInodeCompression") == 0) noI = TRUE; @@ -3853,6 +3884,9 @@ ERROR("-read-queue \tSet input queue to Mbytes. Default %d Mbytes\n", READER_BUFFER_DEFAULT); ERROR("-write-queue \tSet output queue to Mbytes. Default %d Mbytes\n", WRITER_BUFFER_DEFAULT); ERROR("-fragment-queue \tSet fagment queue to Mbytes. Default %d Mbytes\n", FRAGMENT_BUFFER_DEFAULT); +#if defined(LZMA1_SUPPORT) + ERROR("-lzma1\t\t\tuse LZMA1 compression instead of default ZLIB\n"); +#endif ERROR("-noI\t\t\tdo not compress inode table\n"); ERROR("-noD\t\t\tdo not compress data blocks\n"); ERROR("-noF\t\t\tdo not compress fragment blocks\n"); @@ -3892,10 +3926,18 @@ writer_buffer_size = writeb_mbytes << (20 - block_log); fragment_buffer_size = fragmentb_mbytes << (20 - block_log); +#if defined(LZMA1_SUPPORT) +if (compression_method == LZMA1) { + s_minor = SQUASHFS_MINOR_LZMA1; +} else { +#endif if(block_size <= 65536 && sparse_files == FALSE) s_minor = 0; else s_minor = SQUASHFS_MINOR; +#if defined(LZMA1_SUPPORT) +} +#endif for(i = 0; i < source; i++) if(lstat(source_path[i], &source_buf) == -1) { @@ -4004,6 +4046,12 @@ always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags); duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags); exportable = SQUASHFS_EXPORTABLE(sBlk.flags); + +#if defined(LZMA1_SUPPORT) + // compression_method is set by read_super + uncompress_fct = (compression_method == LZMA1) ? &LZMA_ZLIB_COMPAT(uncompress) : &uncompress; + compress2_fct = (compression_method == LZMA1) ? &LZMA_ZLIB_COMPAT(compress2) : &compress2; +#endif } initialise_threads(); @@ -4035,7 +4083,7 @@ printf("Appending to existing %s %d.%d filesystem on %s, block size %d\n", be ? "big endian" : "little endian", SQUASHFS_MAJOR, s_minor, argv[source + 1], block_size); - printf("All -be, -le, -b, -noI, -noD, -noF, -check_data, no-duplicates, no-fragments, -always-use-fragments and -exportable options ignored\n"); + printf("All -be, -le, -b, -noI, -noD, -noF, -check_data, no-duplicates, no-fragments, -always-use-fragments, -exportable and -lzma1 options ignored\n"); printf("\nIf appending is not wanted, please re-run with -noappend specified!\n\n"); compressed_data = (inode_dir_offset + inode_dir_file_size) & ~(SQUASHFS_METADATA_SIZE - 1); --- squashfs-tools/read_fs.c +++ squashfs-tools/read_fs.c @@ -43,6 +43,11 @@ #include #endif +#if defined(LZMA1_SUPPORT) +#include +#endif +#include "compression_method.h" + #include "squashfs_fs.h" #include "read_fs.h" #include "global.h" @@ -61,6 +66,13 @@ fprintf(stderr, s, ## args); \ } while(0) +extern enum compression_method_t compression_method; +#if defined(LZMA1_SUPPORT) +extern zlib_uncompress_t uncompress_fct; +#else +#define uncompress_fct uncompress +#endif + int swap; int read_block(int fd, long long start, long long *next, unsigned char *block, squashfs_super_block *sBlk) @@ -85,13 +97,13 @@ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); read_bytes(fd, start + offset, c_byte, buffer); - if((res = uncompress(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { + if((res = uncompress_fct(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { if(res == Z_MEM_ERROR) - ERROR("zlib::uncompress failed, not enough memory\n"); + ERROR("%s::uncompress failed, not enough memory\n", compression_method_str(compression_method)); else if(res == Z_BUF_ERROR) - ERROR("zlib::uncompress failed, not enough room in output buffer\n"); + ERROR("%s::uncompress failed, not enough room in output buffer\n", compression_method_str(compression_method)); else - ERROR("zlib::uncompress failed, unknown error %d\n", res); + ERROR("%s::uncompress failed, unknown error %d\n", compression_method_str(compression_method), res); return 0; } if(next) @@ -365,7 +377,11 @@ } /* Check the MAJOR & MINOR versions */ +#if defined(LZMA1_SUPPORT) + if(sBlk->s_major != SQUASHFS_MAJOR || (sBlk->s_minor > SQUASHFS_MINOR && sBlk->s_minor != SQUASHFS_MINOR_LZMA1)) { +#else if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { +#endif if(sBlk->s_major < 3) 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 3 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor); else @@ -374,6 +390,17 @@ goto failed_mount; } +#if defined(LZMA1_SUPPORT) + if (sBlk->s_minor == SQUASHFS_MINOR_LZMA1) { + compression_method = LZMA1; + } else { + if (compression_method != ZLIB) { + ERROR("Reading a ZLIB compressed SQUASHFS filesystem on %s - ignoring -lzma1 option\n", source); + } + compression_method = ZLIB; + } +#endif + #if __BYTE_ORDER == __BIG_ENDIAN *be = !swap; #else @@ -384,6 +411,7 @@ 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("\tCompression method is %s\n", compression_method_str(compression_method)); printf("\tCheck data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not "); 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 "); --- squashfs-tools/squashfs_fs.h +++ squashfs-tools/squashfs_fs.h @@ -38,6 +38,7 @@ #define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE #define SQUASHFS_MAJOR 3 #define SQUASHFS_MINOR 1 +#define SQUASHFS_MINOR_LZMA1 76 #define SQUASHFS_MAGIC 0x73717368 #define SQUASHFS_MAGIC_SWAP 0x68737173 #define SQUASHFS_START 0 --- squashfs-tools/unsquashfs.c +++ squashfs-tools/unsquashfs.c @@ -61,6 +61,11 @@ #include // get_nprocs() #endif +#if defined(LZMA1_SUPPORT) +#include +#endif +#include "compression_method.h" + #include "squashfs_fs.h" #include "read_fs.h" #include "global.h" @@ -186,6 +191,13 @@ /* default size of data buffer in Mbytes */ #define DATA_BUFFER_DEFAULT 256 +enum compression_method_t compression_method = ZLIB; // ZLIB by default +#if defined(LZMA1_SUPPORT) +zlib_uncompress_t uncompress_fct = &uncompress; // ZLIB by default +#else +#define uncompress_fct uncompress +#endif + squashfs_super_block sBlk; squashfs_operations s_ops; @@ -697,15 +709,15 @@ if(read_bytes(start + offset, c_byte, buffer) == FALSE) goto failed; - res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte); + res = uncompress_fct((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte); if(res != Z_OK) { if(res == Z_MEM_ERROR) - EXIT_UNSQUASH("zlib::uncompress failed, not enough memory\n"); + EXIT_UNSQUASH("%s::uncompress failed, not enough memory\n", compression_method_str(compression_method)); else if(res == Z_BUF_ERROR) - EXIT_UNSQUASH("zlib::uncompress failed, not enough room in output buffer\n"); + EXIT_UNSQUASH("%s::uncompress failed, not enough room in output buffer\n", compression_method_str(compression_method)); else - EXIT_UNSQUASH("zlib::uncompress failed, unknown error %d\n", res); + EXIT_UNSQUASH("%s::uncompress failed, unknown error %d\n", compression_method_str(compression_method), res); goto failed; } if(next) @@ -737,15 +749,15 @@ if(read_bytes(start, c_byte, data) == FALSE) return 0; - res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte); + res = uncompress_fct((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte); if(res != Z_OK) { if(res == Z_MEM_ERROR) - EXIT_UNSQUASH("zlib::uncompress failed, not enough memory\n"); + EXIT_UNSQUASH("%s::uncompress failed, not enough memory\n", compression_method_str(compression_method)); else if(res == Z_BUF_ERROR) - EXIT_UNSQUASH("zlib::uncompress failed, not enough room in output buffer\n"); + EXIT_UNSQUASH("%s::uncompress failed, not enough room in output buffer\n", compression_method_str(compression_method)); else - EXIT_UNSQUASH("zlib::uncompress failed, unknown error %d\n", res); + EXIT_UNSQUASH("%s::uncompress failed, unknown error %d\n", compression_method_str(compression_method), res); return 0; } @@ -2132,6 +2144,7 @@ printf("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags) ? "un" : ""); if(sBlk.s_major > 1 && !SQUASHFS_NO_FRAGMENTS(sBlk.flags)) printf("Fragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags) ? "un" : ""); + printf("Compression method is %s\n", compression_method_str(compression_method)); printf("Check data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk.flags) ? "" : "not "); if(sBlk.s_major > 1) { printf("Fragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk.flags) ? "not " : ""); @@ -2201,7 +2214,11 @@ s_ops.read_block_list = read_block_list; s_ops.read_inode = read_inode_2; } - } else if(sBlk.s_major == 3 && sBlk.s_minor <= 1) { +#if defined(LZMA1_SUPPORT) + } else if(sBlk.s_major == 3 && (sBlk.s_minor <= SQUASHFS_MINOR || sBlk.s_minor == SQUASHFS_MINOR_LZMA1)) { +#else + } else if(sBlk.s_major == 3 && sBlk.s_minor <= SQUASHFS_MINOR) { +#endif s_ops.squashfs_opendir = squashfs_opendir; s_ops.read_fragment = read_fragment; s_ops.read_fragment_table = read_fragment_table; @@ -2213,6 +2230,12 @@ goto failed_mount; } +#if defined(LZMA1_SUPPORT) + compression_method = (sBlk.s_minor == SQUASHFS_MINOR_LZMA1) ? LZMA1 : ZLIB; + uncompress_fct = (compression_method == LZMA1) ? &LZMA_ZLIB_COMPAT(uncompress) : &uncompress; +#endif + ERROR("Filesystem on %s is %s compressed (%d:%d)\n", source, compression_method_str(compression_method), sBlk.s_major, sBlk.s_minor); + return TRUE; failed_mount: @@ -2344,15 +2367,15 @@ int res; unsigned long bytes = block_size; - res = uncompress((unsigned char *) tmp, &bytes, (const unsigned char *) entry->data, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size)); + res = uncompress_fct((unsigned char *) tmp, &bytes, (const unsigned char *) entry->data, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size)); if(res != Z_OK) { if(res == Z_MEM_ERROR) - EXIT_UNSQUASH("zlib::uncompress failed, not enough memory\n"); + EXIT_UNSQUASH("%s::uncompress failed, not enough memory\n", compression_method_str(compression_method)); else if(res == Z_BUF_ERROR) - EXIT_UNSQUASH("zlib::uncompress failed, not enough room in output buffer\n"); + EXIT_UNSQUASH("%s::uncompress failed, not enough room in output buffer\n", compression_method_str(compression_method)); else - EXIT_UNSQUASH("zlib::uncompress failed, unknown error %d\n", res); + EXIT_UNSQUASH("%s::uncompress failed, unknown error %d\n", compression_method_str(compression_method), res); } else memcpy(entry->data, tmp, bytes);