diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c9fdd6..597cd8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ if(NOT TARGET zlib) endif() endif() -file(GLOB_RECURSE SRC "src/*.cpp") +file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c" "src/*.h") file(GLOB_RECURSE HEADERS "include/*.h" "include/*.inl") foreach(_source IN ITEMS ${HEADERS}) @@ -70,6 +70,7 @@ endforeach() add_library(FS STATIC ${SRC} ${HEADERS}) target_include_directories(FS PUBLIC "include") target_include_directories(FS PRIVATE "src") +target_include_directories(FS PRIVATE "src/libzip") target_include_directories(FS PUBLIC "${PROJECT_SOURCE_DIR}/../Logger/include") target_include_directories(FS PUBLIC "${PROJECT_SOURCE_DIR}/../cppcoro/include") target_include_directories(FS PRIVATE "src/fast_io/include") diff --git a/include/fs/StreamSourceToSourceAdapter.h b/include/fs/StreamSourceToMapSourceAdapter.h similarity index 78% rename from include/fs/StreamSourceToSourceAdapter.h rename to include/fs/StreamSourceToMapSourceAdapter.h index 3ce3a54..9f77c3e 100644 --- a/include/fs/StreamSourceToSourceAdapter.h +++ b/include/fs/StreamSourceToMapSourceAdapter.h @@ -8,11 +8,11 @@ namespace fs { -class FS_API StreamSourceToSourceAdapter final : public IMapSource +class FS_API StreamSourceToMapSourceAdapter final : public IMapSource { public: - explicit StreamSourceToSourceAdapter(tl::unique_ref&& i_srcSource); - ~StreamSourceToSourceAdapter() override = default; + explicit StreamSourceToMapSourceAdapter(tl::unique_ref i_srcSource); + ~StreamSourceToMapSourceAdapter() override = default; tl::optional getLastError() const override; diff --git a/include/fs/zip/DeflateFileWriter.h b/include/fs/zip/DeflateFileWriter.h deleted file mode 100644 index dbb3059..0000000 --- a/include/fs/zip/DeflateFileWriter.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "fs/AbsPath.h" -#include "fs/zip/ZipWriter.h" - -#include "tl/ptr.h" - -namespace fs -{ - -class IFilesystem; - -////////////////////////////////////////////////////////////////////////// - -class FS_API DeflateFileWriter -{ -public: - //compression level: 0 to 9 - DeflateFileWriter(AbsPathView filePath, tl::lent_ref filesystem, uint8_t compressionLevel); - - DeflateFileWriter(const DeflateFileWriter&) = delete; - DeflateFileWriter& operator=(const DeflateFileWriter&) = delete; - - DeflateFileWriter(DeflateFileWriter&&) = default; - DeflateFileWriter& operator=(DeflateFileWriter&&) = default; - - ZipWriter::DataWriterResult operator()(IStreamSink& sink); - -private: - AbsPath m_filePath; - tl::lent_ref m_filesystem; - uint8_t m_compressionLevel = 9; -}; - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/include/fs/zip/DeflateSinkWriter.h b/include/fs/zip/DeflateSinkWriter.h deleted file mode 100644 index 2812e22..0000000 --- a/include/fs/zip/DeflateSinkWriter.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "fs/IStreamSource.h" -#include "fs/zip/ZipWriter.h" - -namespace fs -{ - -////////////////////////////////////////////////////////////////////////// - -class ISource; -////////////////////////////////////////////////////////////////////////// - -class FS_API DeflateSinkWriter -{ -public: - //compression level: 0 to 9 - DeflateSinkWriter(IStreamSource& source, uint8_t compressionLevel); - DeflateSinkWriter(tl::span data, uint8_t compressionLevel); - - DeflateSinkWriter(const DeflateSinkWriter&) = delete; - DeflateSinkWriter& operator=(const DeflateSinkWriter&) = delete; - - DeflateSinkWriter(DeflateSinkWriter&&) = default; - DeflateSinkWriter& operator=(DeflateSinkWriter&&) = default; - - ZipWriter::DataWriterResult operator()(IStreamSink& sink); - -private: - IStreamSource* m_source = nullptr; - tl::span m_data; - uint8_t m_compressionLevel = 9; -}; - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/include/fs/zip/StoreFileWriter.h b/include/fs/zip/StoreFileWriter.h deleted file mode 100644 index c2349e9..0000000 --- a/include/fs/zip/StoreFileWriter.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "fs/AbsPath.h" -#include "fs/zip/ZipWriter.h" - -#include "tl/ptr.h" - -namespace fs -{ - -class IFilesystem; - -////////////////////////////////////////////////////////////////////////// - -class FS_API StoreFileWriter -{ -public: - StoreFileWriter(AbsPathView filePath, tl::lent_ref filesystem); - - StoreFileWriter(const StoreFileWriter&) = delete; - StoreFileWriter& operator=(const StoreFileWriter&) = delete; - - StoreFileWriter(StoreFileWriter&&) = default; - StoreFileWriter& operator=(StoreFileWriter&&) = default; - - ZipWriter::DataWriterResult operator()(IStreamSink& sink); - -private: - AbsPath m_filePath; - tl::lent_ref m_filesystem; -}; - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/include/fs/zip/StoreSinkWriter.h b/include/fs/zip/StoreSinkWriter.h deleted file mode 100644 index f4c5c5f..0000000 --- a/include/fs/zip/StoreSinkWriter.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "fs/zip/ZipWriter.h" - -namespace fs -{ - -////////////////////////////////////////////////////////////////////////// - -class ISource; -////////////////////////////////////////////////////////////////////////// - -class FS_API StoreSinkWriter -{ -public: - explicit StoreSinkWriter(ISource& source); - - StoreSinkWriter(const StoreSinkWriter&) = delete; - StoreSinkWriter& operator=(const StoreSinkWriter&) = delete; - - StoreSinkWriter(StoreSinkWriter&&) = default; - StoreSinkWriter& operator=(StoreSinkWriter&&) = default; - - ZipWriter::DataWriterResult operator()(IStreamSink& sink); - -private: - tl::reference_wrapper m_inSource; -}; - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/include/fs/zip/ZipBase.h b/include/fs/zip/ZipBase.h deleted file mode 100644 index 16a23e8..0000000 --- a/include/fs/zip/ZipBase.h +++ /dev/null @@ -1,158 +0,0 @@ -#pragma once -#include "tl/flag_set.h" -#include "fs/Api.h" - -namespace fs -{ - -class FS_API ZipBase -{ -public: - enum class GeneralBitFlag : uint16_t - { - Encrypted = 1 << 0, - CompressionMethodSpecific1 = 1 << 1, - CompressionMethodSpecific2 = 1 << 2, - DataDescriptorNeeded = 1 << 3, - StrongEncryption = 1 << 6, - LanguageEncodingFlag = 1 << 11, - LocalHeaderFieldsMasked = 1 << 13, - }; - typedef tl::flag_set GeneralBitFlags; - - enum class CompressionMethod : uint16_t - { - Store = 0, - Shrunk = 1, - Reduced1 = 2, - Reduced2 = 3, - Reduced3 = 4, - Reduced4 = 5, - Implode = 6, - //Reserved = 7, - Deflate = 8, - Deflate64 = 9, - PKWareImplode = 10, - //Reserved = 11, - BZip2 = 12, - //Reserved = 13, - LZMA = 14, - //Reserved = 15, - //Reserved = 16, - //Reserved = 17, - Terse = 18, - LZ77 = 19, - - LZ4 = 20, // non-standard - ZStd = 21, // non-standard - - WavPack = 97, - PPMd = 98, - }; - -protected: - ////////////////////////////////////////////////////////////////////////// - //These structs follow pretty closely the https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT standard - -#pragma pack(push, 1) - - struct LocalFileHeader - { - static constexpr uint32_t k_signature = 0x04034b50u; - uint32_t signature = k_signature; - uint16_t versionNeededToExtract = 0; - uint16_t generalBitFlag = 0; - uint16_t compressionMethod = 0; - uint16_t lastModFileTime = 0; - uint16_t lastModFileDate = 0; - uint32_t crc32 = 0; - uint32_t compressedSize = 0; - uint32_t uncompressedSize = 0; - uint16_t filenameLength = 0; - uint16_t extraFieldLength = 0; - }; - - struct DataDescriptor - { - uint32_t crc32 = 0; - uint32_t compressedSize = 0; - uint32_t uncompressedSize = 0; - }; - - struct CentralDirectoryFileHeader - { - static constexpr uint32_t k_signature = 0x02014b50u; - uint32_t signature = k_signature; - uint16_t versionMadeBy = 0; - uint16_t versionNeededToExtract = 0; - uint16_t generalBitFlag = 0; - uint16_t compressionMethod = 0; - uint16_t lastModFileTime = 0; - uint16_t lastModFileDate = 0; - uint32_t crc32 = 0; - uint32_t compressedSize = 0; - uint32_t uncompressedSize = 0; - uint16_t filenameLength = 0; - uint16_t extraFieldLength = 0; - uint16_t fileCommentLength = 0; - uint16_t diskNumberStart = 0; - uint16_t internalFileAttributes = 0; - uint32_t externalFileAttributes = 0; - uint32_t localHeaderOffset = 0; - }; - - struct EndOfCentralDirectoryRecord - { - static constexpr uint32_t k_signature = 0x06054b50u; - uint32_t signature = k_signature; - uint16_t diskNumber = 0; - uint16_t centralDirectoryStartDiskNumber = 0; - uint16_t centralDirectoryRecordCountOnThisDisk = 0; - uint16_t centralDirectoryRecordCount = 0; - uint32_t centralDirectorySize = 0; - uint32_t centralDirectoryOffset = 0; - uint16_t zipFileCommentLength = 0; - }; - - struct ExtendedInformationExtraField64 - { - static constexpr uint32_t k_tag = 0x0001; - uint16_t tag = k_tag; - uint16_t size = 0; - uint64_t originalSize = 0; - uint64_t compressedSize = 0; - uint64_t localHeaderOffset = 0; - uint32_t diskNumber = 0; - }; - - struct EndOfCentralDirectoryRecord64 - { - static constexpr uint32_t k_signature = 0x06064b50u; - uint32_t signature = k_signature; - uint64_t endOfCentralDirectorySize = 0; - uint16_t versionMadeBy = 0; - uint16_t versionNeededToExtract = 0; - uint32_t diskNumber = 0; - uint32_t centralDirectoryStartDiskNumber = 0; - uint64_t centralDirectoryRecordCountOnThisDisk = 0; - uint64_t centralDirectoryRecordCount = 0; - uint64_t centralDirectorySize = 0; - uint64_t centralDirectoryOffset = 0; - }; - - struct EndOfCentralDirectoryLocator64 - { - static constexpr uint32_t k_signature = 0x07064b50u; - uint32_t signature = k_signature; - uint32_t centralDirectoryStartDiskNumber = 0; - uint64_t endOfCentralDirectoryRecordOffset = 0; - uint32_t diskCount = 0; - }; - -#pragma pack(pop) - - static void computeMsDosTime(time_t time, uint16_t& o_date, uint16_t& o_time); - static CentralDirectoryFileHeader computeCentralDirectoryFileHeader(const LocalFileHeader& header, bool zip64); -}; - -} diff --git a/include/fs/zip/ZipPack.h b/include/fs/zip/ZipPack.h index 748aadd..a2122dc 100644 --- a/include/fs/zip/ZipPack.h +++ b/include/fs/zip/ZipPack.h @@ -3,18 +3,40 @@ #include "tl/result.h" #include "tl/string.h" #include "tl/vector_map.h" +#include "fs/IStreamSource.h" #include "fs/IPack.h" #include "fs/AbsPath.h" -#include "fs/zip/ZipReader.h" #include "fs/Api.h" +struct zip; +struct zip_source; +struct zip_file; +namespace tl +{ +template<> struct ptr_traits +{ + static constexpr inline bool custom_deleter = true; + static constexpr inline bool requires_virtual_destructor_check = false; +}; +//template<> struct ptr_traits +//{ +// static constexpr inline bool custom_deleter = true; +// static constexpr inline bool requires_virtual_destructor_check = false; +//}; +template<> struct ptr_traits +{ + static constexpr inline bool custom_deleter = true; + static constexpr inline bool requires_virtual_destructor_check = false; +}; +} + namespace fs { class MapSourceView; -class FS_API ZipPack final : virtual public IPack +class FS_API ZipPack final : public IPack { public: ZipPack() = default; @@ -22,10 +44,10 @@ public: typedef tl::result, Error> CreateResult; - static CreateResult create(tl::unique_ref zipFileSource); - static CreateResult create(tl::lent_ref filesystem, AbsPathView zipFileLocation); + static CreateResult create(tl::unique_ref source); + static CreateResult create(tl::lent_ref filesystem, AbsPathView path); - virtual void setEncryptionData(const tl::string& key, uint32_t rounds); + void setEncryptionData(const tl::string& key, uint32_t rounds); OpenSourceResult openSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override; OpenStreamSourceResult openStreamSource(AbsPathView path, SourceFlags flags = SourceFlags()) const override; @@ -42,46 +64,51 @@ public: tl::result convertToNativePath(AbsPathView path) const override; + struct ZipData + { + tl::unique_ptr fsMapSource; + + tl::lent_ptr filesystem; + AbsPath path; + tl::unique_ptr fsSource; + uint64_t cachedSize = uint64_t(-1); + + //tl::unique_ptr zipSource; + tl::unique_ptr zipArchive; + }; + protected: struct File; struct Folder; struct EntryIndex; - ZipPack(tl::unique_ref zipFileSource, ZipReader zipReader); - ZipPack(tl::lent_ref filesystem, AbsPathView zipFileLocation, ZipReader zipReader); + ZipPack(tl::shared_ptr data); - OpenMapSourceResult openRawMapSource(const File& file, MapView mapView) const; - OpenSourceResult openRawSource(const File& file) const; + //OpenMapSourceResult openRawMapSource(const File& file, MapView mapView) const; + //OpenSourceResult openRawSource(const File& file) const; - OpenSourceResult openZipSource(const File& file) const; - OpenMapSourceResult openZipMapSource(const File& file) const; - OpenStreamSourceResult openZipStreamSource(const File& file) const; + OpenSourceResult _openSource(const File& file) const; + OpenMapSourceResult _openMapSource(const File& file) const; + OpenStreamSourceResult _openStreamSource(const File& file) const; uint16_t getOrAddFolder(AbsPathView folderPath, tl::vector>& io_childrenIndices); - void createEntries(ZipReader zipReader); + void createEntries(zip& archive); struct File { + uint16_t zipIndex = 0; //index inside the zip archive tl::string name; - uint8_t isCompressed : 1; - uint8_t uncompressedSizeH = 0; - uint8_t compressedSizeH = 0; - uint8_t dataOffsetH = 0; uint16_t parentIndex = 0; - uint32_t lastModTimePoint = 0; - uint32_t uncompressedSizeL = 0; - uint32_t compressedSizeL = 0; - uint32_t dataOffsetL = 0; }; static_assert(sizeof(File) <= sizeof(tl::string) + 40, "Check your sizes!!!"); struct Folder { + uint16_t zipIndex = 0; //index inside the zip archive tl::string name; uint16_t parentIndex = 0; uint16_t childrenStartIndex = 0; // this is an index inside m_childrenIndices uint16_t childrenCount = 0; - uint32_t lastModTimePoint = 0; }; static_assert(sizeof(Folder) <= sizeof(tl::string) + 20, "Check your sizes!!!"); @@ -99,12 +126,8 @@ protected: static_assert(sizeof(EntryIndex) == 4, "Check your sizes!!!"); private: - tl::lent_ptr m_filesystem; - mutable std::mutex m_zipMapSourceLock; - tl::unique_ptr m_zipMapSource; - - AbsPath m_zipFileLocation; + tl::shared_ptr m_zipData; tl::string m_encryptionKey; uint32_t m_encryptionRounds = 32; diff --git a/include/fs/zip/ZipReader.h b/include/fs/zip/ZipReader.h deleted file mode 100644 index 2e525a9..0000000 --- a/include/fs/zip/ZipReader.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once -#include "ZipBase.h" -#include "tl/memory_buffer.h" -#include "tl/result.h" -#include "tl/vector.h" - -namespace fs -{ - -////////////////////////////////////////////////////////////////////////// - -class ISource; - -////////////////////////////////////////////////////////////////////////// - -class ZipReader : public ZipBase -{ -public: - enum class ErrorCode : uint8_t - { - InvalidStream, - BadSignature, - BadOffset, - CorruptedFile, - }; - typedef tl::error Error; - - typedef tl::result CreateResult; - - static CreateResult create(ISource& source); - - struct Entry - { - tl::string name; - CompressionMethod compressionMethod = CompressionMethod::Store; - GeneralBitFlags generalBitFlags; - uint64_t uncompressedSize = 0; - uint64_t compressedSize = 0; - uint32_t crc32 = 0; - uint64_t localHeaderOffset = 0; - uint64_t dataOffset = 0; - time_t lastModTimePoint = 0; - tl::memory_buffer comment; - }; - - size_t getEntryCount() const; - const Entry& getEntry(size_t index) const; - - typedef tl::result SeekResult; - SeekResult seekSourceToEntryData(const Entry& entry, ISource& o_source) const; - -private: - explicit ZipReader(tl::vector entries); - - typedef tl::result, Error> CentralDirectoryResult; - static CentralDirectoryResult findCentralDirectoryBounds(ISource& source); - - tl::vector m_entries; -}; - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/include/fs/zip/ZipUtils.h b/include/fs/zip/ZipUtils.h index 43a8063..6194b11 100644 --- a/include/fs/zip/ZipUtils.h +++ b/include/fs/zip/ZipUtils.h @@ -13,7 +13,7 @@ FS_API UnzipResult unzipSource(IFilesystem& dstFilesystem, AbsPathView filePath, FS_API UnzipResult unzipFile(IFilesystem& dstFilesystem, AbsPathView filePath, tl::lent_ref filesystem, AbsPathView srcFilePath); typedef tl::result ZipResult; -FS_API ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel, size_t fileDataAlignment = 0); -FS_API ZipResult zipToFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel, size_t fileDataAlignment = 0); +FS_API ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel); +FS_API ZipResult zipToFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel); } diff --git a/include/fs/zip/ZipWriter.h b/include/fs/zip/ZipWriter.h index 4668500..4883d52 100644 --- a/include/fs/zip/ZipWriter.h +++ b/include/fs/zip/ZipWriter.h @@ -1,77 +1,65 @@ #pragma once -#include "ZipBase.h" #include "fs/Api.h" #include #include #include #include #include +#include "fs/zip/ZipPack.h" namespace fs { ////////////////////////////////////////////////////////////////////////// -class IStreamSource; +class ISource; class IStreamSink; class ISink; ////////////////////////////////////////////////////////////////////////// -class FS_API ZipWriter : public ZipBase +class FS_API ZipWriter { public: - struct DataWriterPayload - { - CompressionMethod compressionMethod; - uint32_t uncompressedCRC32 = 0; //mandatory!!! - uint64_t uncompressedSize = 0; //optional, will be set to the written size if == 0 - }; + //0 - no compression (Store) + //9 - max compression (Deflate) + using Compression = uint8_t; - using DataWriterError = tl::generic_error; - using DataWriterResult = tl::result; + ZipWriter(ISink& sink); + ~ZipWriter(); - using DataWriter = tl::function; - - ZipWriter(ISink& sink, size_t fileDataAlignment); - ~ZipWriter() = default; - - tl::result addFile(tl::string name, const DataWriter& dataWriter); - - tl::result addFile(tl::string name, tl::optional lastModificationTime, const DataWriter& dataWriter); + tl::result addBuffer(tl::string name, Compression compression, tl::span buffer); + tl::result addBuffer(tl::string name, time_t lastModificationTime, Compression compression, tl::span buffer); + tl::result addBuffer(tl::string name, + tl::span comment, + tl::span extraField, + time_t lastModificationTime, + Compression compression, + tl::span buffer); + tl::result addFile(tl::string name, Compression compression, ISource& source); + tl::result addFile(tl::string name, time_t lastModificationTime, Compression compression, ISource& source); tl::result addFile(tl::string name, - tl::span comment, - tl::span extraField, - GeneralBitFlags generalBitFlags, - tl::optional lastModificationTime, - const DataWriter& dataWriter); + tl::span comment, + tl::span extraField, + time_t lastModificationTime, + Compression compression, + ISource& source); void finish(); private: - uint64_t computePadding(uint64_t offset, const LocalFileHeader& header) const; + tl::result _addSource(tl::string name, + tl::span comment, + tl::span extraField, + time_t lastModificationTime, + Compression compression, + zip_source* source); ISink& m_sink; - size_t m_fileDataAlignment = 0; - - struct CentralDirectoryRecord - { - uint64_t compressedSize = 0; - uint64_t uncompressedSize = 0; - uint64_t localHeaderOffset = 0; - - CentralDirectoryFileHeader header; - tl::string name; - tl::memory_buffer comment; - tl::memory_buffer extraField; - bool zip64 = false; - }; - - tl::vector m_records; - - tl::memory_buffer m_buffer; + tl::unique_ptr m_zipArchive; }; + ////////////////////////////////////////////////////////////////////////// } diff --git a/src/StreamSourceToSourceAdapter.cpp b/src/StreamSourceToMapSourceAdapter.cpp similarity index 72% rename from src/StreamSourceToSourceAdapter.cpp rename to src/StreamSourceToMapSourceAdapter.cpp index 78592a7..91b6316 100644 --- a/src/StreamSourceToSourceAdapter.cpp +++ b/src/StreamSourceToMapSourceAdapter.cpp @@ -1,9 +1,10 @@ #include "StdAfx.h" -#include "fs/StreamSourceToSourceAdapter.h" +#include "fs/StreamSourceToMapSourceAdapter.h" #include +#include "fs/ReadStream.h" #include "tl/narrow_cast.h" namespace fs @@ -12,21 +13,21 @@ namespace fs static constexpr size_t k_chunkSize = 10 * 1024; -StreamSourceToSourceAdapter::StreamSourceToSourceAdapter(tl::unique_ref&& srcSource) +StreamSourceToMapSourceAdapter::StreamSourceToMapSourceAdapter(tl::unique_ref srcSource) : m_srcSource(std::move(srcSource)) { } ////////////////////////////////////////////////////////////////////////// -tl::optional StreamSourceToSourceAdapter::getLastError() const +tl::optional StreamSourceToMapSourceAdapter::getLastError() const { return m_optLastError; } ////////////////////////////////////////////////////////////////////////// -size_t StreamSourceToSourceAdapter::read(tl::span data) +size_t StreamSourceToMapSourceAdapter::read(tl::span data) { if (m_optLastError.has_value()) { @@ -69,7 +70,7 @@ size_t StreamSourceToSourceAdapter::read(tl::span data) ////////////////////////////////////////////////////////////////////////// -void StreamSourceToSourceAdapter::seekBeg(uint64_t offset) +void StreamSourceToMapSourceAdapter::seekBeg(uint64_t offset) { if (m_optLastError.has_value()) { @@ -88,7 +89,7 @@ void StreamSourceToSourceAdapter::seekBeg(uint64_t offset) ////////////////////////////////////////////////////////////////////////// -void StreamSourceToSourceAdapter::seekRel(int64_t offset) +void StreamSourceToMapSourceAdapter::seekRel(int64_t offset) { if (m_optLastError.has_value()) { @@ -107,7 +108,7 @@ void StreamSourceToSourceAdapter::seekRel(int64_t offset) ////////////////////////////////////////////////////////////////////////// -uint64_t StreamSourceToSourceAdapter::tell() const +uint64_t StreamSourceToMapSourceAdapter::tell() const { if (m_optLastError.has_value()) { @@ -120,7 +121,7 @@ uint64_t StreamSourceToSourceAdapter::tell() const ////////////////////////////////////////////////////////////////////////// -uint64_t StreamSourceToSourceAdapter::getSize() const +uint64_t StreamSourceToMapSourceAdapter::getSize() const { if (m_optLastError.has_value()) { @@ -137,7 +138,7 @@ uint64_t StreamSourceToSourceAdapter::getSize() const ////////////////////////////////////////////////////////////////////////// -bool StreamSourceToSourceAdapter::isEOS() const +bool StreamSourceToMapSourceAdapter::isEOS() const { if (m_optLastError.has_value()) { @@ -156,14 +157,14 @@ bool StreamSourceToSourceAdapter::isEOS() const ////////////////////////////////////////////////////////////////////////// -size_t StreamSourceToSourceAdapter::getPreferredBufferSize() const +size_t StreamSourceToMapSourceAdapter::getPreferredBufferSize() const { return m_srcSource->getPreferredBufferSize(); } ////////////////////////////////////////////////////////////////////////// -tl::span StreamSourceToSourceAdapter::map(size_t size) +tl::span StreamSourceToMapSourceAdapter::map(size_t size) { if (m_optLastError.has_value()) { @@ -189,33 +190,19 @@ tl::span StreamSourceToSourceAdapter::map(size_t size) ////////////////////////////////////////////////////////////////////////// -void StreamSourceToSourceAdapter::readAll() const +void StreamSourceToMapSourceAdapter::readAll() const { - if (m_readAll) - return; - - const size_t chunkSize = m_srcSource->getPreferredBufferSize() > 0 ? m_srcSource->getPreferredBufferSize() : k_chunkSize; - - do + if (!m_readAll) { - const size_t dataSize = m_data.size(); - m_data.resize_uninitialized(dataSize + chunkSize); - const uint64_t read = m_srcSource->read({ m_data.data() + dataSize, chunkSize }); - if (read < chunkSize || m_srcSource->isEOS()) - { - m_data.resize_uninitialized(dataSize + tl::narrow(read)); - break; - } - m_optLastError = m_srcSource->getLastError(); - if (m_optLastError != tl::nullopt) + if (auto readResult = fs::readStream(m_data, *m_srcSource); readResult.has_error()) { + m_optLastError = readResult.error(); m_data.clear(); - break; } - } while (true); - m_data.shrink_to_fit(); - m_readAll = true; + m_data.shrink_to_fit(); + m_readAll = true; + } } ////////////////////////////////////////////////////////////////////////// diff --git a/src/libzip/CMakeLists.txt b/src/libzip/CMakeLists.txt new file mode 100644 index 0000000..7714013 --- /dev/null +++ b/src/libzip/CMakeLists.txt @@ -0,0 +1,196 @@ +include(CheckFunctionExists) + +set(CMAKE_C_VISIBILITY_PRESET hidden) + +add_library(zip + zip_add.c + zip_add_dir.c + zip_add_entry.c + zip_algorithm_deflate.c + zip_buffer.c + zip_close.c + zip_delete.c + zip_dir_add.c + zip_dirent.c + zip_discard.c + zip_entry.c + zip_error.c + zip_error_clear.c + zip_error_get.c + zip_error_get_sys_type.c + zip_error_strerror.c + zip_error_to_str.c + zip_extra_field.c + zip_extra_field_api.c + zip_fclose.c + zip_fdopen.c + zip_file_add.c + zip_file_error_clear.c + zip_file_error_get.c + zip_file_get_comment.c + zip_file_get_external_attributes.c + zip_file_get_offset.c + zip_file_rename.c + zip_file_replace.c + zip_file_set_comment.c + zip_file_set_encryption.c + zip_file_set_external_attributes.c + zip_file_set_mtime.c + zip_file_strerror.c + zip_fopen.c + zip_fopen_encrypted.c + zip_fopen_index.c + zip_fopen_index_encrypted.c + zip_fread.c + zip_fseek.c + zip_ftell.c + zip_get_archive_comment.c + zip_get_archive_flag.c + zip_get_encryption_implementation.c + zip_get_file_comment.c + zip_get_name.c + zip_get_num_entries.c + zip_get_num_files.c + zip_hash.c + zip_io_util.c + zip_libzip_version.c + zip_memdup.c + zip_name_locate.c + zip_new.c + zip_open.c + zip_pkware.c + zip_progress.c + zip_rename.c + zip_replace.c + zip_set_archive_comment.c + zip_set_archive_flag.c + zip_set_default_password.c + zip_set_file_comment.c + zip_set_file_compression.c + zip_set_name.c + zip_source_accept_empty.c + zip_source_begin_write.c + zip_source_begin_write_cloning.c + zip_source_buffer.c + zip_source_call.c + zip_source_close.c + zip_source_commit_write.c + zip_source_compress.c + zip_source_crc.c + zip_source_error.c + zip_source_file_common.c + zip_source_free.c + zip_source_function.c + zip_source_get_file_attributes.c + zip_source_is_deleted.c + zip_source_layered.c + zip_source_open.c + zip_source_pass_to_lower_layer.c + zip_source_pkware_decode.c + zip_source_pkware_encode.c + zip_source_read.c + zip_source_remove.c + zip_source_rollback_write.c + zip_source_seek.c + zip_source_seek_write.c + zip_source_stat.c + zip_source_supports.c + zip_source_tell.c + zip_source_tell_write.c + zip_source_window.c + zip_source_write.c + zip_source_zip.c + zip_source_zip_new.c + zip_stat.c + zip_stat_index.c + zip_stat_init.c + zip_strerror.c + zip_string.c + zip_unchange.c + zip_unchange_all.c + zip_unchange_archive.c + zip_unchange_data.c + zip_utf-8.c + ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c + ) +add_library(libzip::zip ALIAS zip) + +if(WIN32) + if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) + target_sources(zip PRIVATE zip_random_uwp.c) + else() + target_sources(zip PRIVATE zip_random_win32.c) + target_link_libraries(zip PRIVATE advapi32) + endif() +endif(WIN32) + +if(HAVE_LIBBZ2) + target_sources(zip PRIVATE zip_algorithm_bzip2.c) + target_link_libraries(zip PRIVATE BZip2::BZip2) +endif() + +if(HAVE_LIBLZMA) + target_sources(zip PRIVATE zip_algorithm_xz.c) + target_link_libraries(zip PRIVATE LibLZMA::LibLZMA) +endif() + +if(HAVE_LIBZSTD) + target_sources(zip PRIVATE zip_algorithm_zstd.c) + target_link_libraries(zip PRIVATE ${zstd_TARGET}) +endif() + +if(HAVE_COMMONCRYPTO) + target_sources(zip PRIVATE zip_crypto_commoncrypto.c) +elseif(HAVE_WINDOWS_CRYPTO) + target_sources(zip PRIVATE zip_crypto_win.c) + target_link_libraries(zip PRIVATE bcrypt) +elseif(HAVE_GNUTLS) + target_sources(zip PRIVATE zip_crypto_gnutls.c) + target_link_libraries(zip PRIVATE GnuTLS::GnuTLS Nettle::Nettle) +elseif(HAVE_OPENSSL) + target_sources(zip PRIVATE zip_crypto_openssl.c) + target_link_libraries(zip PRIVATE OpenSSL::Crypto) +elseif(HAVE_MBEDTLS) + target_sources(zip PRIVATE zip_crypto_mbedtls.c) + target_link_libraries(zip PRIVATE MbedTLS::MbedTLS) +endif() + +if(HAVE_CRYPTO) + target_sources(zip PRIVATE zip_winzip_aes.c zip_source_winzip_aes_decode.c zip_source_winzip_aes_encode.c) +endif() + +if(SHARED_LIB_VERSIONNING) + set_target_properties(zip PROPERTIES VERSION 5.5 SOVERSION 5) +endif() + +#target_link_libraries(zip PRIVATE ZLIB::ZLIB) +target_include_directories(zip + PUBLIC + $ + $ + $ + ) + +if(LIBZIP_DO_INSTALL) + install(TARGETS zip + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES zip.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() + +# create zip_err_str.c from zip.h and zipint.h +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c + COMMAND "${CMAKE_COMMAND}" + "-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" + "-DCMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "-P" "${PROJECT_SOURCE_DIR}/cmake/GenerateZipErrorStrings.cmake" + DEPENDS + ${PROJECT_SOURCE_DIR}/cmake/GenerateZipErrorStrings.cmake + ${PROJECT_SOURCE_DIR}/lib/zip.h + ${PROJECT_SOURCE_DIR}/lib/zipint.h + COMMENT "Generating zip_err_str.c" +) diff --git a/src/libzip/compat.h b/src/libzip/compat.h new file mode 100644 index 0000000..31f764e --- /dev/null +++ b/src/libzip/compat.h @@ -0,0 +1,239 @@ +#ifndef _HAD_LIBZIP_COMPAT_H +#define _HAD_LIBZIP_COMPAT_H + +/* + compat.h -- compatibility defines. + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipconf.h" + +#include "config.h" + +/* to have *_MAX definitions for all types when compiling with g++ */ +#define __STDC_LIMIT_MACROS + +/* to have ISO C secure library functions */ +#define __STDC_WANT_LIB_EXT1__ 1 + + +#define ZIP_STATIC +#define ZIP_EXTERN extern + +#ifdef _WIN32 +/* for dup(), close(), etc. */ +#include +#endif + +#ifdef HAVE_STDBOOL_H +#include +#elif !defined(__BOOL_DEFINED) +typedef char bool; +#define true 1 +#define false 0 +#endif + +#include + +/* at least MinGW does not provide EOPNOTSUPP, see + * http://sourceforge.net/p/mingw/bugs/263/ + */ +#ifndef EOPNOTSUPP +#define EOPNOTSUPP EINVAL +#endif + +/* at least MinGW does not provide EOVERFLOW, see + * http://sourceforge.net/p/mingw/bugs/242/ + */ +#ifndef EOVERFLOW +#define EOVERFLOW EFBIG +#endif + +/* not supported on at least Windows */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifdef _WIN32 +#if defined(HAVE__CLOSE) +#define close _close +#endif +#if defined(HAVE__DUP) +#define dup _dup +#endif +/* crashes reported when using fdopen instead of _fdopen on Windows/Visual Studio 10/Win64 */ +#if defined(HAVE__FDOPEN) +#define fdopen _fdopen +#endif +#if !defined(HAVE_FILENO) && defined(HAVE__FILENO) +#define fileno _fileno +#endif +#if !defined(HAVE_SNPRINTF) && defined(HAVE__SNPRINTF) +#define snprintf _snprintf +#endif +#if !defined(HAVE__SNWPRINTF_S) +#define _snwprintf_s(buf, bufsz, len, fmt, ...) (_snwprintf((buf), (len), (fmt), __VA_ARGS__)) +#endif +#if defined(HAVE__STRDUP) +#if !defined(HAVE_STRDUP) || defined(_WIN32) +#undef strdup +#define strdup _strdup +#endif +#endif +#if !defined(HAVE__SETMODE) && defined(HAVE_SETMODE) +#define _setmode setmode +#endif +#if !defined(HAVE_STRTOLL) && defined(HAVE__STRTOI64) +#define strtoll _strtoi64 +#endif +#if !defined(HAVE_STRTOULL) && defined(HAVE__STRTOUI64) +#define strtoull _strtoui64 +#endif +#if defined(HAVE__UNLINK) +#define unlink _unlink +#endif +#endif + +#ifndef HAVE_FSEEKO +#define fseeko(s, o, w) (fseek((s), (long int)(o), (w))) +#endif + +#ifndef HAVE_FTELLO +#define ftello(s) ((long)ftell((s))) +#endif + +#ifdef HAVE_LOCALTIME_S +#ifdef _WIN32 +/* Windows is incompatible to the C11 standard, hurray! */ +#define zip_localtime(t, tm) (localtime_s((tm), (t)) == 0 ? tm : NULL) +#else +#define zip_localtime localtime_s +#endif +#else +#ifdef HAVE_LOCALTIME_R +#define zip_localtime localtime_r +#else +#define zip_localtime(t, tm) (localtime(t)) +#endif +#endif + +#ifndef HAVE_MEMCPY_S +#define memcpy_s(dest, destsz, src, count) (memcpy((dest), (src), (count)) == NULL) +#endif + +#ifndef HAVE_SNPRINTF_S +#ifdef HAVE__SNPRINTF_S +#define snprintf_s(buf, bufsz, fmt, ...) (_snprintf_s((buf), (bufsz), (bufsz), (fmt), __VA_ARGS__)) +#else +#define snprintf_s snprintf +#endif +#endif + +#if !defined(HAVE_STRCASECMP) +#if defined(HAVE__STRICMP) +#define strcasecmp _stricmp +#elif defined(HAVE_STRICMP) +#define strcasecmp stricmp +#endif +#endif + +#ifndef HAVE_STRNCPY_S +#define strncpy_s(dest, destsz, src, count) (strncpy((dest), (src), (count)), 0) +#endif + +#ifndef HAVE_STRERROR_S +#define strerrorlen_s(errnum) (strlen(strerror(errnum))) +#define strerror_s(buf, bufsz, errnum) ((void)strncpy_s((buf), (bufsz), strerror(errnum), (bufsz)), (buf)[(bufsz)-1] = '\0', strerrorlen_s(errnum) >= (bufsz)) +#else +#ifndef HAVE_STRERRORLEN_S +#define strerrorlen_s(errnum) 8192 +#endif +#endif + +#if SIZEOF_OFF_T == 8 +#define ZIP_OFF_MAX ZIP_INT64_MAX +#define ZIP_OFF_MIN ZIP_INT64_MIN +#elif SIZEOF_OFF_T == 4 +#define ZIP_OFF_MAX ZIP_INT32_MAX +#define ZIP_OFF_MIN ZIP_INT32_MIN +#elif SIZEOF_OFF_T == 2 +#define ZIP_OFF_MAX ZIP_INT16_MAX +#define ZIP_OFF_MIN ZIP_INT16_MIN +#else +#error unsupported size of off_t +#endif + +#if defined(HAVE_FTELLO) && defined(HAVE_FSEEKO) +#define ZIP_FSEEK_MAX ZIP_OFF_MAX +#define ZIP_FSEEK_MIN ZIP_OFF_MIN +#else +#include +#define ZIP_FSEEK_MAX LONG_MAX +#define ZIP_FSEEK_MIN LONG_MIN +#endif + +#ifndef SIZE_MAX +#if SIZEOF_SIZE_T == 8 +#define SIZE_MAX ZIP_INT64_MAX +#elif SIZEOF_SIZE_T == 4 +#define SIZE_MAX ZIP_INT32_MAX +#elif SIZEOF_SIZE_T == 2 +#define SIZE_MAX ZIP_INT16_MAX +#else +#error unsupported size of size_t +#endif +#endif + +#ifndef PRId64 +#ifdef _MSC_VER +#define PRId64 "I64d" +#else +#define PRId64 "lld" +#endif +#endif + +#ifndef PRIu64 +#ifdef _MSC_VER +#define PRIu64 "I64u" +#else +#define PRIu64 "llu" +#endif +#endif + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#endif + +#endif /* compat.h */ diff --git a/src/libzip/config.h b/src/libzip/config.h new file mode 100644 index 0000000..2976249 --- /dev/null +++ b/src/libzip/config.h @@ -0,0 +1,93 @@ +#ifndef HAD_CONFIG_H +#define HAD_CONFIG_H +#ifndef _HAD_ZIPCONF_H +#include "zipconf.h" +#endif +/* BEGIN DEFINES */ +#define ENABLE_FDOPEN +/* #undef HAVE___PROGNAME */ +#define HAVE__CLOSE +#define HAVE__DUP +#define HAVE__FDOPEN +#define HAVE__FILENO +#define HAVE__SETMODE +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define HAVE__SNPRINTF +#else +/* #undef HAVE__SNPRINTF */ +#endif +#define HAVE__SNPRINTF_S +#define HAVE__SNWPRINTF_S +#define HAVE__STRDUP +#define HAVE__STRICMP +#define HAVE__STRTOI64 +#define HAVE__STRTOUI64 +#define HAVE__UNLINK +/* #undef HAVE_ARC4RANDOM */ +/* #undef HAVE_CLONEFILE */ +/* #undef HAVE_COMMONCRYPTO */ +#define HAVE_CRYPTO +/* #undef HAVE_FICLONERANGE */ +#define HAVE_FILENO +/* #undef HAVE_FCHMOD */ +/* #undef HAVE_FSEEKO */ +/* #undef HAVE_FTELLO */ +/* #undef HAVE_GETPROGNAME */ +/* #undef HAVE_GNUTLS */ +/* #undef HAVE_LIBBZ2 */ +/* #undef HAVE_LIBLZMA */ +/* #undef HAVE_LIBZSTD */ +/* #undef HAVE_LOCALTIME_R */ +#define HAVE_LOCALTIME_S +#define HAVE_MEMCPY_S +/* #undef HAVE_MBEDTLS */ +/* #undef HAVE_MKSTEMP */ +/* #undef HAVE_NULLABLE */ +/* #undef HAVE_OPENSSL */ +#define HAVE_SETMODE +#if defined(_MSC_VER) && _MSC_VER < 1900 +/* #undef HAVE_SNPRINTF */ +#else +#define HAVE_SNPRINTF +#endif +/* #undef HAVE_SNPRINTF_S */ +/* #undef HAVE_STRCASECMP */ +#define HAVE_STRDUP +#define HAVE_STRERROR_S +/* #undef HAVE_STRERRORLEN_S */ +#define HAVE_STRICMP +#define HAVE_STRNCPY_S +#if defined(_MSC_VER) && _MSC_VER < 1800 +/* #undef HAVE_STRTOLL */ +/* #undef HAVE_STRTOULL */ +#else +#define HAVE_STRTOLL +#define HAVE_STRTOULL +#endif +/* #undef HAVE_STRUCT_TM_TM_ZONE */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +/* #undef HAVE_STDBOOL_H */ +#else +#define HAVE_STDBOOL_H +#endif +/* #undef HAVE_STRINGS_H */ +/* #undef HAVE_UNISTD_H */ +#define HAVE_WINDOWS_CRYPTO +#define SIZEOF_OFF_T 4 +#ifdef _WIN64 +#define SIZEOF_SIZE_T 8 +#else +#define SIZEOF_SIZE_T 4 +#endif +/* #undef HAVE_DIRENT_H */ +/* #undef HAVE_FTS_H */ +/* #undef HAVE_NDIR_H */ +/* #undef HAVE_SYS_DIR_H */ +/* #undef HAVE_SYS_NDIR_H */ +/* #undef WORDS_BIGENDIAN */ +#define HAVE_SHARED +/* END DEFINES */ +#define PACKAGE "libzip" +#define VERSION "1.10.1" + +#endif /* HAD_CONFIG_H */ diff --git a/src/libzip/zip.h b/src/libzip/zip.h new file mode 100644 index 0000000..7359ba0 --- /dev/null +++ b/src/libzip/zip.h @@ -0,0 +1,498 @@ +#ifndef _HAD_ZIP_H +#define _HAD_ZIP_H + +/* + zip.h -- exported declarations. + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* fix autoindent */ +#endif +#endif + +#include + +#define ZIP_STATIC +#define ZIP_EXTERN extern + +#ifndef ZIP_DEPRECATED +#if defined(__GNUC__) || defined(__clang__) +#define ZIP_DEPRECATED(x) __attribute__((deprecated(x))) +#elif defined(_MSC_VER) +#define ZIP_DEPRECATED(x) __declspec(deprecated(x)) +#else +#define ZIP_DEPRECATED(x) +#endif +#endif + +#include +#include +#include + +/* flags for fs_zip_open */ + +#define ZIP_CREATE 1 +#define ZIP_EXCL 2 +#define ZIP_CHECKCONS 4 +#define ZIP_TRUNCATE 8 +#define ZIP_RDONLY 16 + + +/* flags for fs_zip_name_locate, fs_zip_fopen, fs_zip_stat, ... */ + +#define ZIP_FL_NOCASE 1u /* ignore case on name lookup */ +#define ZIP_FL_NODIR 2u /* ignore directory component */ +#define ZIP_FL_COMPRESSED 4u /* read compressed data */ +#define ZIP_FL_UNCHANGED 8u /* use original data, ignoring changes */ +/* 16u was ZIP_FL_RECOMPRESS, which is deprecated */ +#define ZIP_FL_ENCRYPTED 32u /* read encrypted data (implies ZIP_FL_COMPRESSED) */ +#define ZIP_FL_ENC_GUESS 0u /* guess string encoding (is default) */ +#define ZIP_FL_ENC_RAW 64u /* get unmodified string */ +#define ZIP_FL_ENC_STRICT 128u /* follow specification strictly */ +#define ZIP_FL_LOCAL 256u /* in local header */ +#define ZIP_FL_CENTRAL 512u /* in central directory */ +/* 1024u reserved for internal use */ +#define ZIP_FL_ENC_UTF_8 2048u /* string is UTF-8 encoded */ +#define ZIP_FL_ENC_CP437 4096u /* string is CP437 encoded */ +#define ZIP_FL_OVERWRITE 8192u /* fs_zip_file_add: if file with name exists, overwrite (replace) it */ + +/* archive global flags flags */ + +#define ZIP_AFL_RDONLY 2u /* read only -- cannot be cleared */ +#define ZIP_AFL_IS_TORRENTZIP 4u /* current archive is torrentzipped */ +#define ZIP_AFL_WANT_TORRENTZIP 8u /* write archive in torrentzip format */ +#define ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE 16u /* don't remove file if archive is empty */ + + +/* create a new extra field */ + +#define ZIP_EXTRA_FIELD_ALL ZIP_UINT16_MAX +#define ZIP_EXTRA_FIELD_NEW ZIP_UINT16_MAX + +/* length parameter to various functions */ + +#define ZIP_LENGTH_TO_END 0 +#define ZIP_LENGTH_UNCHECKED (-2) /* only supported by fs_zip_source_file and its variants */ + +/* libzip error codes */ + +#define ZIP_ER_OK 0 /* N No error */ +#define ZIP_ER_MULTIDISK 1 /* N Multi-disk zip archives not supported */ +#define ZIP_ER_RENAME 2 /* S Renaming temporary file failed */ +#define ZIP_ER_CLOSE 3 /* S Closing zip archive failed */ +#define ZIP_ER_SEEK 4 /* S Seek error */ +#define ZIP_ER_READ 5 /* S Read error */ +#define ZIP_ER_WRITE 6 /* S Write error */ +#define ZIP_ER_CRC 7 /* N CRC error */ +#define ZIP_ER_ZIPCLOSED 8 /* N Containing zip archive was closed */ +#define ZIP_ER_NOENT 9 /* N No such file */ +#define ZIP_ER_EXISTS 10 /* N File already exists */ +#define ZIP_ER_OPEN 11 /* S Can't open file */ +#define ZIP_ER_TMPOPEN 12 /* S Failure to create temporary file */ +#define ZIP_ER_ZLIB 13 /* Z Zlib error */ +#define ZIP_ER_MEMORY 14 /* N Malloc failure */ +#define ZIP_ER_CHANGED 15 /* N Entry has been changed */ +#define ZIP_ER_COMPNOTSUPP 16 /* N Compression method not supported */ +#define ZIP_ER_EOF 17 /* N Premature end of file */ +#define ZIP_ER_INVAL 18 /* N Invalid argument */ +#define ZIP_ER_NOZIP 19 /* N Not a zip archive */ +#define ZIP_ER_INTERNAL 20 /* N Internal error */ +#define ZIP_ER_INCONS 21 /* L Zip archive inconsistent */ +#define ZIP_ER_REMOVE 22 /* S Can't remove file */ +#define ZIP_ER_DELETED 23 /* N Entry has been deleted */ +#define ZIP_ER_ENCRNOTSUPP 24 /* N Encryption method not supported */ +#define ZIP_ER_RDONLY 25 /* N Read-only archive */ +#define ZIP_ER_NOPASSWD 26 /* N No password provided */ +#define ZIP_ER_WRONGPASSWD 27 /* N Wrong password provided */ +#define ZIP_ER_OPNOTSUPP 28 /* N Operation not supported */ +#define ZIP_ER_INUSE 29 /* N Resource still in use */ +#define ZIP_ER_TELL 30 /* S Tell error */ +#define ZIP_ER_COMPRESSED_DATA 31 /* N Compressed data invalid */ +#define ZIP_ER_CANCELLED 32 /* N Operation cancelled */ +#define ZIP_ER_DATA_LENGTH 33 /* N Unexpected length of data */ +#define ZIP_ER_NOT_ALLOWED 34 /* N Not allowed in torrentzip */ + +/* type of system error value */ + +#define ZIP_ET_NONE 0 /* sys_err unused */ +#define ZIP_ET_SYS 1 /* sys_err is errno */ +#define ZIP_ET_ZLIB 2 /* sys_err is zlib error code */ +#define ZIP_ET_LIBZIP 3 /* sys_err is libzip error code */ + +/* compression methods */ + +#define ZIP_CM_DEFAULT -1 /* better of deflate or store */ +#define ZIP_CM_STORE 0 /* stored (uncompressed) */ +#define ZIP_CM_SHRINK 1 /* shrunk */ +#define ZIP_CM_REDUCE_1 2 /* reduced with factor 1 */ +#define ZIP_CM_REDUCE_2 3 /* reduced with factor 2 */ +#define ZIP_CM_REDUCE_3 4 /* reduced with factor 3 */ +#define ZIP_CM_REDUCE_4 5 /* reduced with factor 4 */ +#define ZIP_CM_IMPLODE 6 /* imploded */ +/* 7 - Reserved for Tokenizing compression algorithm */ +#define ZIP_CM_DEFLATE 8 /* deflated */ +#define ZIP_CM_DEFLATE64 9 /* deflate64 */ +#define ZIP_CM_PKWARE_IMPLODE 10 /* PKWARE imploding */ +/* 11 - Reserved by PKWARE */ +#define ZIP_CM_BZIP2 12 /* compressed using BZIP2 algorithm */ +/* 13 - Reserved by PKWARE */ +#define ZIP_CM_LZMA 14 /* LZMA (EFS) */ +/* 15-17 - Reserved by PKWARE */ +#define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */ +#define ZIP_CM_LZ77 19 /* IBM LZ77 z Architecture (PFS) */ +/* 20 - old value for Zstandard */ +#define ZIP_CM_LZMA2 33 +#define ZIP_CM_ZSTD 93 /* Zstandard compressed data */ +#define ZIP_CM_XZ 95 /* XZ compressed data */ +#define ZIP_CM_JPEG 96 /* Compressed Jpeg data */ +#define ZIP_CM_WAVPACK 97 /* WavPack compressed data */ +#define ZIP_CM_PPMD 98 /* PPMd version I, Rev 1 */ + +/* encryption methods */ + +#define ZIP_EM_NONE 0 /* not encrypted */ +#define ZIP_EM_TRAD_PKWARE 1 /* traditional PKWARE encryption */ +#if 0 /* Strong Encryption Header not parsed yet */ +#define ZIP_EM_DES 0x6601 /* strong encryption: DES */ +#define ZIP_EM_RC2_OLD 0x6602 /* strong encryption: RC2, version < 5.2 */ +#define ZIP_EM_3DES_168 0x6603 +#define ZIP_EM_3DES_112 0x6609 +#define ZIP_EM_PKZIP_AES_128 0x660e +#define ZIP_EM_PKZIP_AES_192 0x660f +#define ZIP_EM_PKZIP_AES_256 0x6610 +#define ZIP_EM_RC2 0x6702 /* strong encryption: RC2, version >= 5.2 */ +#define ZIP_EM_RC4 0x6801 +#endif +#define ZIP_EM_AES_128 0x0101 /* Winzip AES encryption */ +#define ZIP_EM_AES_192 0x0102 +#define ZIP_EM_AES_256 0x0103 +#define ZIP_EM_UNKNOWN 0xffff /* unknown algorithm */ + +#define ZIP_OPSYS_DOS 0x00u +#define ZIP_OPSYS_AMIGA 0x01u +#define ZIP_OPSYS_OPENVMS 0x02u +#define ZIP_OPSYS_UNIX 0x03u +#define ZIP_OPSYS_VM_CMS 0x04u +#define ZIP_OPSYS_ATARI_ST 0x05u +#define ZIP_OPSYS_OS_2 0x06u +#define ZIP_OPSYS_MACINTOSH 0x07u +#define ZIP_OPSYS_Z_SYSTEM 0x08u +#define ZIP_OPSYS_CPM 0x09u +#define ZIP_OPSYS_WINDOWS_NTFS 0x0au +#define ZIP_OPSYS_MVS 0x0bu +#define ZIP_OPSYS_VSE 0x0cu +#define ZIP_OPSYS_ACORN_RISC 0x0du +#define ZIP_OPSYS_VFAT 0x0eu +#define ZIP_OPSYS_ALTERNATE_MVS 0x0fu +#define ZIP_OPSYS_BEOS 0x10u +#define ZIP_OPSYS_TANDEM 0x11u +#define ZIP_OPSYS_OS_400 0x12u +#define ZIP_OPSYS_OS_X 0x13u + +#define ZIP_OPSYS_DEFAULT ZIP_OPSYS_UNIX + + +enum zip_source_cmd { + ZIP_SOURCE_OPEN, /* prepare for reading */ + ZIP_SOURCE_READ, /* read data */ + ZIP_SOURCE_CLOSE, /* reading is done */ + ZIP_SOURCE_STAT, /* get meta information */ + ZIP_SOURCE_ERROR, /* get error information */ + ZIP_SOURCE_FREE, /* cleanup and free resources */ + ZIP_SOURCE_SEEK, /* set position for reading */ + ZIP_SOURCE_TELL, /* get read position */ + ZIP_SOURCE_BEGIN_WRITE, /* prepare for writing */ + ZIP_SOURCE_COMMIT_WRITE, /* writing is done */ + ZIP_SOURCE_ROLLBACK_WRITE, /* discard written changes */ + ZIP_SOURCE_WRITE, /* write data */ + ZIP_SOURCE_SEEK_WRITE, /* set position for writing */ + ZIP_SOURCE_TELL_WRITE, /* get write position */ + ZIP_SOURCE_SUPPORTS, /* check whether source supports command */ + ZIP_SOURCE_REMOVE, /* remove file */ + ZIP_SOURCE_RESERVED_1, /* previously used internally */ + ZIP_SOURCE_BEGIN_WRITE_CLONING, /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */ + ZIP_SOURCE_ACCEPT_EMPTY, /* whether empty files are valid archives */ + ZIP_SOURCE_GET_FILE_ATTRIBUTES, /* get additional file attributes */ + ZIP_SOURCE_SUPPORTS_REOPEN /* allow reading from changed entry */ +}; +typedef enum zip_source_cmd zip_source_cmd_t; + +#define ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd) (((zip_int64_t)1) << (cmd)) + +#define ZIP_SOURCE_CHECK_SUPPORTED(supported, cmd) (((supported) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd)) != 0) + +/* clang-format off */ + +#define ZIP_SOURCE_SUPPORTS_READABLE (ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_OPEN) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_READ) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_CLOSE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_STAT) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ERROR) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_FREE)) + +#define ZIP_SOURCE_SUPPORTS_SEEKABLE (ZIP_SOURCE_SUPPORTS_READABLE \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SUPPORTS)) + +#define ZIP_SOURCE_SUPPORTS_WRITABLE (ZIP_SOURCE_SUPPORTS_SEEKABLE \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_COMMIT_WRITE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ROLLBACK_WRITE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_WRITE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK_WRITE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL_WRITE) \ + | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_REMOVE)) + +/* clang-format on */ + +/* for use by sources */ +struct zip_source_args_seek { + zip_int64_t offset; + int whence; +}; + +typedef struct zip_source_args_seek zip_source_args_seek_t; +#define ZIP_SOURCE_GET_ARGS(type, data, len, error) ((len) < sizeof(type) ? zip_error_set((error), ZIP_ER_INVAL, 0), (type *)NULL : (type *)(data)) + + +/* error information */ +/* use zip_error_*() to access */ +struct zip_error { + int zip_err; /* libzip error code (ZIP_ER_*) */ + int sys_err; /* copy of errno (E*) or zlib error code */ + char *_Nullable str; /* string representation or NULL */ +}; + +#define ZIP_STAT_NAME 0x0001u +#define ZIP_STAT_INDEX 0x0002u +#define ZIP_STAT_SIZE 0x0004u +#define ZIP_STAT_COMP_SIZE 0x0008u +#define ZIP_STAT_MTIME 0x0010u +#define ZIP_STAT_CRC 0x0020u +#define ZIP_STAT_COMP_METHOD 0x0040u +#define ZIP_STAT_ENCRYPTION_METHOD 0x0080u +#define ZIP_STAT_FLAGS 0x0100u + +struct fs_zip_stat { + zip_uint64_t valid; /* which fields have valid values */ + const char *_Nullable name; /* name of the file */ + zip_uint64_t index; /* index within archive */ + zip_uint64_t size; /* size of file (uncompressed) */ + zip_uint64_t comp_size; /* size of file (compressed) */ + time_t mtime; /* modification time */ + zip_uint32_t crc; /* crc of file data */ + zip_uint16_t comp_method; /* compression method used */ + zip_uint16_t encryption_method; /* encryption method used */ + zip_uint32_t flags; /* reserved for future use */ +}; + +struct zip_buffer_fragment { + zip_uint8_t *_Nonnull data; + zip_uint64_t length; +}; + +struct zip_file_attributes { + zip_uint64_t valid; /* which fields have valid values */ + zip_uint8_t version; /* version of this struct, currently 1 */ + zip_uint8_t host_system; /* host system on which file was created */ + zip_uint8_t ascii; /* flag whether file is ASCII text */ + zip_uint8_t version_needed; /* minimum version needed to extract file */ + zip_uint32_t external_file_attributes; /* external file attributes (host-system specific) */ + zip_uint16_t general_purpose_bit_flags; /* general purpose big flags, only some bits are honored */ + zip_uint16_t general_purpose_bit_mask; /* which bits in general_purpose_bit_flags are valid */ +}; + +#define ZIP_FILE_ATTRIBUTES_HOST_SYSTEM 0x0001u +#define ZIP_FILE_ATTRIBUTES_ASCII 0x0002u +#define ZIP_FILE_ATTRIBUTES_VERSION_NEEDED 0x0004u +#define ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES 0x0008u +#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS 0x0010u + +struct zip; +struct zip_file; +struct zip_source; + +typedef struct zip zip_t; +typedef struct zip_error zip_error_t; +typedef struct zip_file zip_file_t; +typedef struct zip_file_attributes zip_file_attributes_t; +typedef struct zip_source zip_source_t; +typedef struct fs_zip_stat zip_stat_t; +typedef struct zip_buffer_fragment zip_buffer_fragment_t; + +typedef zip_uint32_t zip_flags_t; + +typedef zip_int64_t (*zip_source_callback)(void *_Nullable, void *_Nullable, zip_uint64_t, zip_source_cmd_t); +typedef zip_int64_t (*zip_source_layered_callback)(zip_source_t *_Nonnull, void *_Nullable, void *_Nullable, zip_uint64_t, enum zip_source_cmd); +typedef void (*zip_progress_callback)(zip_t *_Nonnull, double, void *_Nullable); +typedef int (*zip_cancel_callback)(zip_t *_Nonnull, void *_Nullable); + +#ifndef ZIP_DISABLE_DEPRECATED +#define ZIP_FL_RECOMPRESS 16u /* force recompression of data */ + +typedef void (*zip_progress_callback_t)(double); +ZIP_DEPRECATED("use 'fs_zip_register_progress_callback_with_state' instead") ZIP_EXTERN void zip_register_progress_callback(zip_t *_Nonnull, zip_progress_callback_t _Nullable); + +ZIP_DEPRECATED("use 'fs_zip_file_add' instead") ZIP_EXTERN zip_int64_t zip_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull); +ZIP_DEPRECATED("use 'fs_zip_dir_add' instead") ZIP_EXTERN zip_int64_t zip_add_dir(zip_t *_Nonnull, const char *_Nonnull); +ZIP_DEPRECATED("use 'fs_zip_file_get_comment' instead") ZIP_EXTERN const char *_Nullable zip_get_file_comment(zip_t *_Nonnull, zip_uint64_t, int *_Nullable, int); +ZIP_DEPRECATED("use 'fs_zip_get_num_entries' instead") ZIP_EXTERN int zip_get_num_files(zip_t *_Nonnull); +ZIP_DEPRECATED("use 'fs_zip_file_rename' instead") ZIP_EXTERN int zip_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull); +ZIP_DEPRECATED("use 'fs_zip_file_replace' instead") ZIP_EXTERN int zip_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull); +ZIP_DEPRECATED("use 'fs_zip_file_set_comment' instead") ZIP_EXTERN int zip_set_file_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, int); +ZIP_DEPRECATED("use 'fs_zip_error_init_with_code' and 'zip_error_system_type' instead") ZIP_EXTERN int zip_error_get_sys_type(int); +ZIP_DEPRECATED("use 'fs_zip_get_error' instead") ZIP_EXTERN void zip_error_get(zip_t *_Nonnull, int *_Nullable, int *_Nullable); +ZIP_DEPRECATED("use 'zip_error_strerror' instead") ZIP_EXTERN int zip_error_to_str(char *_Nonnull, zip_uint64_t, int, int); +ZIP_DEPRECATED("use 'fs_zip_file_get_error' instead") ZIP_EXTERN void zip_file_error_get(zip_file_t *_Nonnull, int *_Nullable, int *_Nullable); +ZIP_DEPRECATED("use 'fs_zip_source_zip_file' instead") ZIP_EXTERN zip_source_t *_Nullable zip_source_zip(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t); +ZIP_DEPRECATED("use 'fs_zip_source_zip_file_create' instead") ZIP_EXTERN zip_source_t *_Nullable zip_source_zip_create(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); +#endif + +ZIP_EXTERN int fs_zip_close(zip_t *_Nonnull); +ZIP_EXTERN int fs_zip_delete(zip_t *_Nonnull, zip_uint64_t); +ZIP_EXTERN zip_int64_t fs_zip_dir_add(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t); +ZIP_EXTERN void fs_zip_discard(zip_t *_Nonnull); + +ZIP_EXTERN zip_error_t *_Nonnull fs_zip_get_error(zip_t *_Nonnull); +ZIP_EXTERN void fs_zip_error_clear(zip_t *_Nonnull); +ZIP_EXTERN int fs_zip_error_code_zip(const zip_error_t *_Nonnull); +ZIP_EXTERN int fs_zip_error_code_system(const zip_error_t *_Nonnull); +ZIP_EXTERN void fs_zip_error_fini(zip_error_t *_Nonnull); +ZIP_EXTERN void fs_zip_error_init(zip_error_t *_Nonnull); +ZIP_EXTERN void fs_zip_error_init_with_code(zip_error_t *_Nonnull, int); +ZIP_EXTERN void zip_error_set(zip_error_t *_Nullable, int, int); +ZIP_EXTERN void zip_error_set_from_source(zip_error_t *_Nonnull, zip_source_t *_Nullable); +ZIP_EXTERN const char *_Nonnull zip_error_strerror(zip_error_t *_Nonnull); +ZIP_EXTERN int zip_error_system_type(const zip_error_t *_Nonnull); +ZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t *_Nonnull, void *_Nonnull, zip_uint64_t); + +ZIP_EXTERN int fs_zip_fclose(zip_file_t *_Nonnull); +ZIP_EXTERN zip_t *_Nullable fs_zip_fdopen(int, int, int *_Nullable); +ZIP_EXTERN zip_int64_t fs_zip_file_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull, zip_flags_t); +ZIP_EXTERN void fs_zip_file_attributes_init(zip_file_attributes_t *_Nonnull); +ZIP_EXTERN void fs_zip_file_error_clear(zip_file_t *_Nonnull); +ZIP_EXTERN int fs_zip_file_extra_field_delete(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t); +ZIP_EXTERN int fs_zip_file_extra_field_delete_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t); +ZIP_EXTERN int fs_zip_file_extra_field_set(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *_Nullable, zip_uint16_t, zip_flags_t); +ZIP_EXTERN zip_int16_t fs_zip_file_extra_fields_count(zip_t *_Nonnull, zip_uint64_t, zip_flags_t); +ZIP_EXTERN zip_int16_t fs_zip_file_extra_fields_count_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t); +ZIP_EXTERN const zip_uint8_t *_Nullable fs_zip_file_extra_field_get(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_uint16_t *_Nullable, zip_flags_t); +ZIP_EXTERN const zip_uint8_t *_Nullable fs_zip_file_extra_field_get_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_flags_t); +ZIP_EXTERN const char *_Nullable fs_zip_file_get_comment(zip_t *_Nonnull, zip_uint64_t, zip_uint32_t *_Nullable, zip_flags_t); +ZIP_EXTERN zip_error_t *_Nonnull fs_zip_file_get_error(zip_file_t *_Nonnull); +ZIP_EXTERN int fs_zip_file_get_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t *_Nullable, zip_uint32_t *_Nullable); +ZIP_EXTERN int fs_zip_file_is_seekable(zip_file_t *_Nonnull); +ZIP_EXTERN int fs_zip_file_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull, zip_flags_t); +ZIP_EXTERN int fs_zip_file_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull, zip_flags_t); +ZIP_EXTERN int fs_zip_file_set_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, zip_uint16_t, zip_flags_t); +ZIP_EXTERN int fs_zip_file_set_dostime(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t); +ZIP_EXTERN int fs_zip_file_set_encryption(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, const char *_Nullable); +ZIP_EXTERN int fs_zip_file_set_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t); +ZIP_EXTERN int fs_zip_file_set_mtime(zip_t *_Nonnull, zip_uint64_t, time_t, zip_flags_t); +ZIP_EXTERN const char *_Nonnull fs_zip_file_strerror(zip_file_t *_Nonnull); +ZIP_EXTERN zip_file_t *_Nullable fs_zip_fopen(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t); +ZIP_EXTERN zip_file_t *_Nullable fs_zip_fopen_encrypted(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, const char *_Nullable); +ZIP_EXTERN zip_file_t *_Nullable fs_zip_fopen_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t); +ZIP_EXTERN zip_file_t *_Nullable fs_zip_fopen_index_encrypted(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, const char *_Nullable); +ZIP_EXTERN zip_int64_t fs_zip_fread(zip_file_t *_Nonnull, void *_Nonnull, zip_uint64_t); +ZIP_EXTERN zip_int8_t fs_zip_fseek(zip_file_t *_Nonnull, zip_int64_t, int); +ZIP_EXTERN zip_int64_t fs_zip_ftell(zip_file_t *_Nonnull); +ZIP_EXTERN const char *_Nullable fs_zip_get_archive_comment(zip_t *_Nonnull, int *_Nullable, zip_flags_t); +ZIP_EXTERN int fs_zip_get_archive_flag(zip_t *_Nonnull, zip_flags_t, zip_flags_t); +ZIP_EXTERN const char *_Nullable fs_zip_get_name(zip_t *_Nonnull, zip_uint64_t, zip_flags_t); +ZIP_EXTERN zip_int64_t fs_zip_get_num_entries(zip_t *_Nonnull, zip_flags_t); +ZIP_EXTERN const char *_Nonnull fs_zip_libzip_version(void); +ZIP_EXTERN zip_int64_t fs_zip_name_locate(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t); +ZIP_EXTERN zip_t *_Nullable fs_zip_open(const char *_Nonnull, int, int *_Nullable); +ZIP_EXTERN zip_t *_Nullable fs_zip_open_from_source(zip_source_t *_Nonnull, int, zip_error_t *_Nullable); +ZIP_EXTERN int fs_zip_register_progress_callback_with_state(zip_t *_Nonnull, double, zip_progress_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable); +ZIP_EXTERN int fs_zip_register_cancel_callback_with_state(zip_t *_Nonnull, zip_cancel_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable); +ZIP_EXTERN int fs_zip_set_archive_comment(zip_t *_Nonnull, const char *_Nullable, zip_uint16_t); +ZIP_EXTERN int fs_zip_set_archive_flag(zip_t *_Nonnull, zip_flags_t, int); +ZIP_EXTERN int fs_zip_set_default_password(zip_t *_Nonnull, const char *_Nullable); +ZIP_EXTERN int fs_zip_set_file_compression(zip_t *_Nonnull, zip_uint64_t, zip_int32_t, zip_uint32_t); +ZIP_EXTERN int fs_zip_source_begin_write(zip_source_t *_Nonnull); +ZIP_EXTERN int fs_zip_source_begin_write_cloning(zip_source_t *_Nonnull, zip_uint64_t); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_buffer(zip_t *_Nonnull, const void *_Nullable, zip_uint64_t, int); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_buffer_create(const void *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_buffer_fragment(zip_t *_Nonnull, const zip_buffer_fragment_t *_Nonnull, zip_uint64_t, int); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_buffer_fragment_create(const zip_buffer_fragment_t *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable); +ZIP_EXTERN int fs_zip_source_close(zip_source_t *_Nonnull); +ZIP_EXTERN int fs_zip_source_commit_write(zip_source_t *_Nonnull); +ZIP_EXTERN zip_error_t *_Nonnull fs_zip_source_error(zip_source_t *_Nonnull); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_file(zip_t *_Nonnull, const char *_Nonnull, zip_uint64_t, zip_int64_t); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_file_create(const char *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_filep(zip_t *_Nonnull, FILE *_Nonnull, zip_uint64_t, zip_int64_t); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_filep_create(FILE *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); +ZIP_EXTERN void zip_source_free(zip_source_t *_Nullable); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_function(zip_t *_Nonnull, zip_source_callback _Nonnull, void *_Nullable); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_function_create(zip_source_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable); +ZIP_EXTERN int fs_zip_source_get_file_attributes(zip_source_t *_Nonnull, zip_file_attributes_t *_Nonnull); +ZIP_EXTERN int fs_zip_source_is_deleted(zip_source_t *_Nonnull); +ZIP_EXTERN int fs_zip_source_is_seekable(zip_source_t *_Nonnull); +ZIP_EXTERN void fs_zip_source_keep(zip_source_t *_Nonnull); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_layered(zip_t *_Nullable, zip_source_t *_Nonnull, zip_source_layered_callback _Nonnull, void *_Nullable); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_layered_create(zip_source_t *_Nonnull, zip_source_layered_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable); +ZIP_EXTERN zip_int64_t fs_zip_source_make_command_bitmap(zip_source_cmd_t, ...); +ZIP_EXTERN int fs_zip_source_open(zip_source_t *_Nonnull); +ZIP_EXTERN zip_int64_t fs_zip_source_pass_to_lower_layer(zip_source_t *_Nonnull, void *_Nullable, zip_uint64_t, zip_source_cmd_t); +ZIP_EXTERN zip_int64_t fs_zip_source_read(zip_source_t *_Nonnull, void *_Nonnull, zip_uint64_t); +ZIP_EXTERN void fs_zip_source_rollback_write(zip_source_t *_Nonnull); +ZIP_EXTERN int fs_zip_source_seek(zip_source_t *_Nonnull, zip_int64_t, int); +ZIP_EXTERN zip_int64_t fs_zip_source_seek_compute_offset(zip_uint64_t, zip_uint64_t, void *_Nonnull, zip_uint64_t, zip_error_t *_Nullable); +ZIP_EXTERN int fs_zip_source_seek_write(zip_source_t *_Nonnull, zip_int64_t, int); +ZIP_EXTERN int fs_zip_source_stat(zip_source_t *_Nonnull, zip_stat_t *_Nonnull); +ZIP_EXTERN zip_int64_t fs_zip_source_tell(zip_source_t *_Nonnull); +ZIP_EXTERN zip_int64_t fs_zip_source_tell_write(zip_source_t *_Nonnull); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_window_create(zip_source_t *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable); +ZIP_EXTERN zip_int64_t fs_zip_source_write(zip_source_t *_Nonnull, const void *_Nullable, zip_uint64_t); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_zip_file(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, const char *_Nullable); +ZIP_EXTERN zip_source_t *_Nullable fs_zip_source_zip_file_create(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, const char *_Nullable, zip_error_t *_Nullable); +ZIP_EXTERN int fs_zip_stat(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, zip_stat_t *_Nonnull); +ZIP_EXTERN int fs_zip_stat_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_stat_t *_Nonnull); +ZIP_EXTERN void fs_zip_stat_init(zip_stat_t *_Nonnull); +ZIP_EXTERN const char *_Nonnull fs_zip_strerror(zip_t *_Nonnull); +ZIP_EXTERN int fs_zip_unchange(zip_t *_Nonnull, zip_uint64_t); +ZIP_EXTERN int fs_zip_unchange_all(zip_t *_Nonnull); +ZIP_EXTERN int fs_zip_unchange_archive(zip_t *_Nonnull); +ZIP_EXTERN int fs_zip_compression_method_supported(zip_int32_t method, int compress); +ZIP_EXTERN int fs_zip_encryption_method_supported(zip_uint16_t method, int encode); + +#ifdef __cplusplus +} +#endif + +#endif /* _HAD_ZIP_H */ diff --git a/src/libzip/zip_add.c b/src/libzip/zip_add.c new file mode 100644 index 0000000..58b5707 --- /dev/null +++ b/src/libzip/zip_add.c @@ -0,0 +1,49 @@ +/* + zip_add.c -- add file via callback function + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +/* + NOTE: Return type is signed so we can return -1 on error. + The index can not be larger than ZIP_INT64_MAX since the size + of the central directory cannot be larger than + ZIP_UINT64_MAX, and each entry is larger than 2 bytes. +*/ + +ZIP_EXTERN zip_int64_t +zip_add(zip_t *za, const char *name, zip_source_t *source) { + return fs_zip_file_add(za, name, source, 0); +} diff --git a/src/libzip/zip_add_dir.c b/src/libzip/zip_add_dir.c new file mode 100644 index 0000000..b08d3fb --- /dev/null +++ b/src/libzip/zip_add_dir.c @@ -0,0 +1,44 @@ +/* + zip_add_dir.c -- add directory + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +/* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ + +ZIP_EXTERN zip_int64_t +zip_add_dir(zip_t *za, const char *name) { + return fs_zip_dir_add(za, name, 0); +} diff --git a/src/libzip/zip_add_entry.c b/src/libzip/zip_add_entry.c new file mode 100644 index 0000000..bf12dd5 --- /dev/null +++ b/src/libzip/zip_add_entry.c @@ -0,0 +1,80 @@ +/* + zip_add_entry.c -- create and init struct zip_entry + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +/* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ + +zip_int64_t +_zip_add_entry(zip_t *za) { + zip_uint64_t idx; + + if (za->nentry + 1 >= za->nentry_alloc) { + zip_entry_t *rentries; + zip_uint64_t nalloc = za->nentry_alloc; + zip_uint64_t additional_entries = 2 * nalloc; + zip_uint64_t realloc_size; + + if (additional_entries < 16) { + additional_entries = 16; + } + else if (additional_entries > 1024) { + additional_entries = 1024; + } + /* neither + nor * overflows can happen: nentry_alloc * sizeof(struct zip_entry) < UINT64_MAX */ + nalloc += additional_entries; + realloc_size = sizeof(struct zip_entry) * (size_t)nalloc; + + if (sizeof(struct zip_entry) * (size_t)za->nentry_alloc > realloc_size) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + rentries = (zip_entry_t *)realloc(za->entry, sizeof(struct zip_entry) * (size_t)nalloc); + if (!rentries) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + za->entry = rentries; + za->nentry_alloc = nalloc; + } + + idx = za->nentry++; + + _zip_entry_init(za->entry + idx); + + return (zip_int64_t)idx; +} diff --git a/src/libzip/zip_algorithm_deflate.c b/src/libzip/zip_algorithm_deflate.c new file mode 100644 index 0000000..0773637 --- /dev/null +++ b/src/libzip/zip_algorithm_deflate.c @@ -0,0 +1,276 @@ +/* + zip_algorithm_deflate.c -- deflate (de)compression routines + Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipint.h" + +#include +#include +#include + +struct ctx { + zip_error_t *error; + bool compress; + int level; + int mem_level; + bool end_of_input; + zng_stream zstr; +}; + + +static zip_uint64_t +maximum_compressed_size(zip_uint64_t uncompressed_size) { + /* max deflate size increase: size + ceil(size/16k)*5+6 */ + + zip_uint64_t compressed_size = uncompressed_size + (uncompressed_size + 16383) / 16384 * 5 + 6; + + if (compressed_size < uncompressed_size) { + return ZIP_UINT64_MAX; + } + return compressed_size; +} + + +static void * +allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) { + struct ctx *ctx; + + if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) { + zip_error_set(error, ZIP_ET_SYS, errno); + return NULL; + } + + ctx->error = error; + ctx->compress = compress; + if (compression_flags >= 1 && compression_flags <= 9) { + ctx->level = (int)compression_flags; + } + else { + ctx->level = Z_BEST_COMPRESSION; + } + ctx->mem_level = compression_flags == TORRENTZIP_COMPRESSION_FLAGS ? TORRENTZIP_MEM_LEVEL : MAX_MEM_LEVEL; + ctx->end_of_input = false; + + ctx->zstr.zalloc = Z_NULL; + ctx->zstr.zfree = Z_NULL; + ctx->zstr.opaque = NULL; + + return ctx; +} + + +static void * +compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { + (void)method; + return allocate(true, compression_flags, error); +} + + +static void * +decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { + (void)method; + return allocate(false, compression_flags, error); +} + + +static void +deallocate(void *ud) { + struct ctx *ctx = (struct ctx *)ud; + + free(ctx); +} + + +static zip_uint16_t +general_purpose_bit_flags(void *ud) { + struct ctx *ctx = (struct ctx *)ud; + + if (!ctx->compress) { + return 0; + } + + if (ctx->level < 3) { + return 2 << 1; + } + else if (ctx->level > 7) { + return 1 << 1; + } + return 0; +} + + +static bool +start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) { + struct ctx *ctx = (struct ctx *)ud; + int ret; + + (void)st; + (void)attributes; + + ctx->zstr.avail_in = 0; + ctx->zstr.next_in = NULL; + ctx->zstr.avail_out = 0; + ctx->zstr.next_out = NULL; + + if (ctx->compress) { + /* negative value to tell zlib not to write a header */ + ret = zng_deflateInit2(&ctx->zstr, ctx->level, Z_DEFLATED, -MAX_WBITS, ctx->mem_level, Z_DEFAULT_STRATEGY); + } + else { + ret = zng_inflateInit2(&ctx->zstr, -MAX_WBITS); + } + + if (ret != Z_OK) { + zip_error_set(ctx->error, ZIP_ER_ZLIB, ret); + return false; + } + + + return true; +} + + +static bool +end(void *ud) { + struct ctx *ctx = (struct ctx *)ud; + int err; + + if (ctx->compress) { + err = zng_deflateEnd(&ctx->zstr); + } + else { + err = zng_inflateEnd(&ctx->zstr); + } + + if (err != Z_OK) { + zip_error_set(ctx->error, ZIP_ER_ZLIB, err); + return false; + } + + return true; +} + + +static bool +input(void *ud, zip_uint8_t *data, zip_uint64_t length) { + struct ctx *ctx = (struct ctx *)ud; + + if (length > UINT_MAX || ctx->zstr.avail_in > 0) { + zip_error_set(ctx->error, ZIP_ER_INVAL, 0); + return false; + } + + ctx->zstr.avail_in = (uInt)length; + ctx->zstr.next_in = (Bytef *)data; + + return true; +} + + +static void +end_of_input(void *ud) { + struct ctx *ctx = (struct ctx *)ud; + + ctx->end_of_input = true; +} + + +static zip_compression_status_t +process(void *ud, zip_uint8_t *data, zip_uint64_t *length) { + struct ctx *ctx = (struct ctx *)ud; + uInt avail_out; + + int ret; + + avail_out = (uInt)ZIP_MIN(UINT_MAX, *length); + ctx->zstr.avail_out = avail_out; + ctx->zstr.next_out = (Bytef *)data; + + if (ctx->compress) { + ret = zng_deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0); + } + else { + ret = zng_inflate(&ctx->zstr, Z_SYNC_FLUSH); + } + + *length = avail_out - ctx->zstr.avail_out; + + switch (ret) { + case Z_OK: + return ZIP_COMPRESSION_OK; + + case Z_STREAM_END: + return ZIP_COMPRESSION_END; + + case Z_BUF_ERROR: + if (ctx->zstr.avail_in == 0) { + return ZIP_COMPRESSION_NEED_DATA; + } + + /* fallthrough */ + + default: + zip_error_set(ctx->error, ZIP_ER_ZLIB, ret); + return ZIP_COMPRESSION_ERROR; + } +} + +/* clang-format off */ + +zip_compression_algorithm_t zip_algorithm_deflate_compress = { + maximum_compressed_size, + compress_allocate, + deallocate, + general_purpose_bit_flags, + 20, + start, + end, + input, + end_of_input, + process +}; + + +zip_compression_algorithm_t zip_algorithm_deflate_decompress = { + maximum_compressed_size, + decompress_allocate, + deallocate, + general_purpose_bit_flags, + 20, + start, + end, + input, + end_of_input, + process +}; + +/* clang-format on */ diff --git a/src/libzip/zip_buffer.c b/src/libzip/zip_buffer.c new file mode 100644 index 0000000..e2103f0 --- /dev/null +++ b/src/libzip/zip_buffer.c @@ -0,0 +1,337 @@ +/* + zip_buffer.c -- bounds checked access to memory buffer + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "zipint.h" + +zip_uint8_t * +_zip_buffer_data(zip_buffer_t *buffer) { + return buffer->data; +} + + +void +_zip_buffer_free(zip_buffer_t *buffer) { + if (buffer == NULL) { + return; + } + + if (buffer->free_data) { + free(buffer->data); + } + + free(buffer); +} + + +bool +_zip_buffer_eof(zip_buffer_t *buffer) { + return buffer->ok && buffer->offset == buffer->size; +} + + +zip_uint8_t * +_zip_buffer_get(zip_buffer_t *buffer, zip_uint64_t length) { + zip_uint8_t *data; + + data = _zip_buffer_peek(buffer, length); + + if (data != NULL) { + buffer->offset += length; + } + + return data; +} + + +zip_uint16_t +_zip_buffer_get_16(zip_buffer_t *buffer) { + zip_uint8_t *data = _zip_buffer_get(buffer, 2); + + if (data == NULL) { + return 0; + } + + return (zip_uint16_t)(data[0] + (data[1] << 8)); +} + + +zip_uint32_t +_zip_buffer_get_32(zip_buffer_t *buffer) { + zip_uint8_t *data = _zip_buffer_get(buffer, 4); + + if (data == NULL) { + return 0; + } + + return ((((((zip_uint32_t)data[3] << 8) + data[2]) << 8) + data[1]) << 8) + data[0]; +} + + +zip_uint64_t +_zip_buffer_get_64(zip_buffer_t *buffer) { + zip_uint8_t *data = _zip_buffer_get(buffer, 8); + + if (data == NULL) { + return 0; + } + + return ((zip_uint64_t)data[7] << 56) + ((zip_uint64_t)data[6] << 48) + ((zip_uint64_t)data[5] << 40) + ((zip_uint64_t)data[4] << 32) + ((zip_uint64_t)data[3] << 24) + ((zip_uint64_t)data[2] << 16) + ((zip_uint64_t)data[1] << 8) + (zip_uint64_t)data[0]; +} + + +zip_uint8_t +_zip_buffer_get_8(zip_buffer_t *buffer) { + zip_uint8_t *data = _zip_buffer_get(buffer, 1); + + if (data == NULL) { + return 0; + } + + return data[0]; +} + + +zip_uint64_t +_zip_buffer_left(zip_buffer_t *buffer) { + return buffer->ok ? buffer->size - buffer->offset : 0; +} + + +zip_uint64_t +_zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) { + zip_uint64_t copied; + + if (_zip_buffer_left(buffer) < length) { + length = _zip_buffer_left(buffer); + } + + copied = 0; + while (copied < length) { + size_t n = ZIP_MIN(length - copied, SIZE_MAX); + (void)memcpy_s(data + copied, n, _zip_buffer_get(buffer, n), n); + copied += n; + } + + return copied; +} + + +zip_buffer_t * +_zip_buffer_new(zip_uint8_t *data, zip_uint64_t size) { + bool free_data = (data == NULL); + zip_buffer_t *buffer; + +#if ZIP_UINT64_MAX > SIZE_MAX + if (size > SIZE_MAX) { + return NULL; + } +#endif + + if (data == NULL) { + if ((data = (zip_uint8_t *)malloc((size_t)size)) == NULL) { + return NULL; + } + } + + if ((buffer = (zip_buffer_t *)malloc(sizeof(*buffer))) == NULL) { + if (free_data) { + free(data); + } + return NULL; + } + + buffer->ok = true; + buffer->data = data; + buffer->size = size; + buffer->offset = 0; + buffer->free_data = free_data; + + return buffer; +} + + +zip_buffer_t * +_zip_buffer_new_from_source(zip_source_t *src, zip_uint64_t size, zip_uint8_t *buf, zip_error_t *error) { + zip_buffer_t *buffer; + + if ((buffer = _zip_buffer_new(buf, size)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (_zip_read(src, buffer->data, size, error) < 0) { + _zip_buffer_free(buffer); + return NULL; + } + + return buffer; +} + + +zip_uint64_t +_zip_buffer_offset(zip_buffer_t *buffer) { + return buffer->ok ? buffer->offset : 0; +} + + +bool +_zip_buffer_ok(zip_buffer_t *buffer) { + return buffer->ok; +} + + +zip_uint8_t * +_zip_buffer_peek(zip_buffer_t *buffer, zip_uint64_t length) { + zip_uint8_t *data; + + if (!buffer->ok || buffer->offset + length < length || buffer->offset + length > buffer->size) { + buffer->ok = false; + return NULL; + } + + data = buffer->data + buffer->offset; + return data; +} + +int +_zip_buffer_put(zip_buffer_t *buffer, const void *src, size_t length) { + zip_uint8_t *dst = _zip_buffer_get(buffer, length); + + if (dst == NULL) { + return -1; + } + + (void)memcpy_s(dst, length, src, length); + return 0; +} + + +int +_zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i) { + zip_uint8_t *data = _zip_buffer_get(buffer, 2); + + if (data == NULL) { + return -1; + } + + data[0] = (zip_uint8_t)(i & 0xff); + data[1] = (zip_uint8_t)((i >> 8) & 0xff); + + return 0; +} + + +int +_zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i) { + zip_uint8_t *data = _zip_buffer_get(buffer, 4); + + if (data == NULL) { + return -1; + } + + data[0] = (zip_uint8_t)(i & 0xff); + data[1] = (zip_uint8_t)((i >> 8) & 0xff); + data[2] = (zip_uint8_t)((i >> 16) & 0xff); + data[3] = (zip_uint8_t)((i >> 24) & 0xff); + + return 0; +} + + +int +_zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i) { + zip_uint8_t *data = _zip_buffer_get(buffer, 8); + + if (data == NULL) { + return -1; + } + + data[0] = (zip_uint8_t)(i & 0xff); + data[1] = (zip_uint8_t)((i >> 8) & 0xff); + data[2] = (zip_uint8_t)((i >> 16) & 0xff); + data[3] = (zip_uint8_t)((i >> 24) & 0xff); + data[4] = (zip_uint8_t)((i >> 32) & 0xff); + data[5] = (zip_uint8_t)((i >> 40) & 0xff); + data[6] = (zip_uint8_t)((i >> 48) & 0xff); + data[7] = (zip_uint8_t)((i >> 56) & 0xff); + + return 0; +} + + +int +_zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i) { + zip_uint8_t *data = _zip_buffer_get(buffer, 1); + + if (data == NULL) { + return -1; + } + + data[0] = i; + + return 0; +} + + +int +_zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset) { + if (offset > buffer->size) { + buffer->ok = false; + return -1; + } + + buffer->ok = true; + buffer->offset = offset; + + return 0; +} + + +int +_zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length) { + zip_uint64_t offset = buffer->offset + length; + + if (offset < buffer->offset) { + buffer->ok = false; + return -1; + } + return _zip_buffer_set_offset(buffer, offset); +} + +zip_uint64_t +_zip_buffer_size(zip_buffer_t *buffer) { + return buffer->size; +} diff --git a/src/libzip/zip_close.c b/src/libzip/zip_close.c new file mode 100644 index 0000000..4b47774 --- /dev/null +++ b/src/libzip/zip_close.c @@ -0,0 +1,745 @@ +/* + fs_zip_close.c -- close zip archive and update changes + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +#include +#include +#ifdef _WIN32 +#include +#include +#endif + + +static int add_data(zip_t *, zip_source_t *, zip_dirent_t *, zip_uint32_t); +static int copy_data(zip_t *, zip_uint64_t); +static int copy_source(zip_t *, zip_source_t *, zip_int64_t); +static int torrentzip_compare_names(const void *a, const void *b); +static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t); +static int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64); + +ZIP_EXTERN int +fs_zip_close(zip_t *za) { + zip_uint64_t i, j, survivors, unchanged_offset; + zip_int64_t off; + int error; + zip_filelist_t *filelist; + int changed; + + if (za == NULL) + return -1; + + changed = _zip_changed(za, &survivors); + + if (survivors == 0 && !(za->ch_flags & ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE)) { + /* don't create zip files with no entries */ + if ((za->open_flags & ZIP_TRUNCATE) || changed) { + if (zip_source_remove(za->src) < 0) { + if (!((fs_zip_error_code_zip(fs_zip_source_error(za->src)) == ZIP_ER_REMOVE) && (fs_zip_error_code_system(fs_zip_source_error(za->src)) == ENOENT))) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + } + } + fs_zip_discard(za); + return 0; + } + + /* Always write empty archive if we are told to keep it, otherwise it wouldn't be created if the file doesn't already exist. */ + if (!changed && survivors > 0) { + fs_zip_discard(za); + return 0; + } + + if (survivors > za->nentry) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return -1; + } + + if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL) + return -1; + + unchanged_offset = ZIP_UINT64_MAX; + /* create list of files with index into original archive */ + for (i = j = 0; i < za->nentry; i++) { + if (za->entry[i].orig != NULL && ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) { + unchanged_offset = ZIP_MIN(unchanged_offset, za->entry[i].orig->offset); + } + if (za->entry[i].deleted) { + continue; + } + + if (j >= survivors) { + free(filelist); + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return -1; + } + + filelist[j].idx = i; + filelist[j].name = fs_zip_get_name(za, i, 0); + j++; + } + if (j < survivors) { + free(filelist); + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return -1; + } + + if (ZIP_WANT_TORRENTZIP(za)) { + qsort(filelist, (size_t)survivors, sizeof(filelist[0]), torrentzip_compare_names); + } + + if (ZIP_WANT_TORRENTZIP(za) || (zip_source_supports(za->src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING)) == 0) { + unchanged_offset = 0; + } + else { + if (unchanged_offset == ZIP_UINT64_MAX) { + /* we're keeping all file data, find the end of the last one */ + zip_uint64_t last_index = ZIP_UINT64_MAX; + unchanged_offset = 0; + + for (i = 0; i < za->nentry; i++) { + if (za->entry[i].orig != NULL) { + if (za->entry[i].orig->offset >= unchanged_offset) { + unchanged_offset = za->entry[i].orig->offset; + last_index = i; + } + } + } + if (last_index != ZIP_UINT64_MAX) { + if ((unchanged_offset = _zip_file_get_end(za, last_index, &za->error)) == 0) { + free(filelist); + return -1; + } + } + } + if (unchanged_offset > 0) { + if (fs_zip_source_begin_write_cloning(za->src, unchanged_offset) < 0) { + /* cloning not supported, need to copy everything */ + unchanged_offset = 0; + } + } + } + if (unchanged_offset == 0) { + if (fs_zip_source_begin_write(za->src) < 0) { + zip_error_set_from_source(&za->error, za->src); + free(filelist); + return -1; + } + } + + if (_zip_progress_start(za->progress) != 0) { + zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); + fs_zip_source_rollback_write(za->src); + free(filelist); + return -1; + } + error = 0; + for (j = 0; j < survivors; j++) { + int new_data; + zip_entry_t *entry; + zip_dirent_t *de; + + if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) { + zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); + error = 1; + break; + } + + i = filelist[j].idx; + entry = za->entry + i; + + if (entry->orig != NULL && entry->orig->offset < unchanged_offset) { + /* already implicitly copied by cloning */ + continue; + } + + new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD)) || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za)); + + /* create new local directory entry */ + if (entry->changes == NULL) { + if ((entry->changes = _zip_dirent_clone(entry->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + error = 1; + break; + } + } + de = entry->changes; + + if (_zip_read_local_ef(za, i) < 0) { + error = 1; + break; + } + + if (ZIP_WANT_TORRENTZIP(za)) { + zip_dirent_torrentzip_normalize(entry->changes); + } + + if ((off = fs_zip_source_tell_write(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + error = 1; + break; + } + de->offset = (zip_uint64_t)off; + + if (new_data) { + zip_source_t *zs; + + zs = NULL; + if (!ZIP_ENTRY_DATA_CHANGED(entry)) { + if ((zs = fs_zip_source_zip_file_create(za, i, ZIP_FL_UNCHANGED, 0, -1, NULL, &za->error)) == NULL) { + error = 1; + break; + } + } + + /* add_data writes dirent */ + if (add_data(za, zs ? zs : entry->source, de, entry->changes ? entry->changes->changed : 0) < 0) { + error = 1; + if (zs) + zip_source_free(zs); + break; + } + if (zs) + zip_source_free(zs); + } + else { + zip_uint64_t offset; + + if (de->encryption_method != ZIP_EM_TRAD_PKWARE) { + /* when copying data, all sizes are known -> no data descriptor needed */ + /* except for PKWare encryption, where removing the data descriptor breaks password validation */ + de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; + } + if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) { + error = 1; + break; + } + if ((offset = _zip_file_get_offset(za, i, &za->error)) == 0) { + error = 1; + break; + } + if (fs_zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { + zip_error_set_from_source(&za->error, za->src); + error = 1; + break; + } + if (copy_data(za, de->comp_size) < 0) { + error = 1; + break; + } + + if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { + if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) { + error = 1; + break; + } + } + } + } + + if (!error) { + if (write_cdir(za, filelist, survivors) < 0) + error = 1; + } + + free(filelist); + + if (!error) { + if (fs_zip_source_commit_write(za->src) != 0) { + zip_error_set_from_source(&za->error, za->src); + error = 1; + } + _zip_progress_end(za->progress); + } + + if (error) { + fs_zip_source_rollback_write(za->src); + return -1; + } + + fs_zip_discard(za); + + return 0; +} + + +static int +add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) { + zip_int64_t offstart, offdata, offend, data_length; + zip_stat_t st; + zip_file_attributes_t attributes; + zip_source_t *src_final, *src_tmp; + int ret; + int is_zip64; + zip_flags_t flags; + bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt; + + if (fs_zip_source_stat(src, &st) < 0) { + zip_error_set_from_source(&za->error, src); + return -1; + } + + if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { + st.valid |= ZIP_STAT_COMP_METHOD; + st.comp_method = ZIP_CM_STORE; + } + + if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) + de->comp_method = st.comp_method; + else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { + st.valid |= ZIP_STAT_COMP_SIZE; + st.comp_size = st.size; + } + else { + /* we'll recompress */ + st.valid &= ~ZIP_STAT_COMP_SIZE; + } + + if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) { + st.valid |= ZIP_STAT_ENCRYPTION_METHOD; + st.encryption_method = ZIP_EM_NONE; + } + + flags = ZIP_EF_LOCAL; + + if ((st.valid & ZIP_STAT_SIZE) == 0) { + /* TODO: not valid for torrentzip */ + flags |= ZIP_FL_FORCE_ZIP64; + data_length = -1; + } + else { + de->uncomp_size = st.size; + /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */ + data_length = (zip_int64_t)st.size; + + if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { + zip_uint64_t max_compressed_size; + zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method); + + if (compression_method == ZIP_CM_STORE) { + max_compressed_size = st.size; + } + else { + zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true); + if (algorithm == NULL) { + max_compressed_size = ZIP_UINT64_MAX; + } + else { + max_compressed_size = algorithm->maximum_compressed_size(st.size); + } + } + + if (max_compressed_size > 0xffffffffu) { + /* TODO: not valid for torrentzip */ + flags |= ZIP_FL_FORCE_ZIP64; + } + } + else { + de->comp_size = st.comp_size; + data_length = (zip_int64_t)st.comp_size; + } + } + + if ((offstart = fs_zip_source_tell_write(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + + /* as long as we don't support non-seekable output, clear data descriptor bit */ + de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; + if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) { + return -1; + } + + needs_recompress = ZIP_WANT_TORRENTZIP(za) || st.comp_method != ZIP_CM_ACTUAL(de->comp_method); + needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE); + /* in these cases we can compute the CRC ourselves, so we do */ + needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress; + needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE); + + needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method); + needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE); + needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE); + + src_final = src; + fs_zip_source_keep(src_final); + + if (!needs_decrypt && st.encryption_method == ZIP_EM_TRAD_PKWARE && (de->changed & ZIP_DIRENT_LAST_MOD)) { + /* PKWare encryption uses the last modification time for password verification, therefore we can't change it without re-encrypting. Ignoring the requested modification time change seems more sensible than failing to close the archive. */ + de->changed &= ~ZIP_DIRENT_LAST_MOD; + } + + if (needs_decrypt) { + zip_encryption_implementation impl; + + if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { + zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); + zip_source_free(src_final); + return -1; + } + if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) { + /* error set by impl */ + zip_source_free(src_final); + return -1; + } + + src_final = src_tmp; + } + + if (needs_decompress) { + if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) { + zip_source_free(src_final); + return -1; + } + + src_final = src_tmp; + } + + if (needs_crc) { + if ((src_tmp = zip_source_crc_create(src_final, 0, &za->error)) == NULL) { + zip_source_free(src_final); + return -1; + } + + src_final = src_tmp; + } + + if (needs_compress) { + if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) { + zip_source_free(src_final); + return -1; + } + + src_final = src_tmp; + } + + + if (needs_encrypt) { + zip_encryption_implementation impl; + const char *password = NULL; + + if (de->password) { + password = de->password; + } + else if (za->default_password) { + password = za->default_password; + } + + if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) { + zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); + zip_source_free(src_final); + return -1; + } + + if (de->encryption_method == ZIP_EM_TRAD_PKWARE) { + de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR; + + /* PKWare encryption uses last_mod, make sure it gets the right value. */ + if (de->changed & ZIP_DIRENT_LAST_MOD) { + zip_stat_t st_mtime; + fs_zip_stat_init(&st_mtime); + st_mtime.valid = ZIP_STAT_MTIME; + st_mtime.mtime = de->last_mod; + if ((src_tmp = _zip_source_window_new(src_final, 0, -1, &st_mtime, 0, NULL, NULL, 0, true, &za->error)) == NULL) { + zip_source_free(src_final); + return -1; + } + src_final = src_tmp; + } + } + + if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) { + /* error set by impl */ + zip_source_free(src_final); + return -1; + } + + src_final = src_tmp; + } + + + if ((offdata = fs_zip_source_tell_write(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + + ret = copy_source(za, src_final, data_length); + + if (fs_zip_source_stat(src_final, &st) < 0) { + zip_error_set_from_source(&za->error, src_final); + ret = -1; + } + + if (fs_zip_source_get_file_attributes(src_final, &attributes) != 0) { + zip_error_set_from_source(&za->error, src_final); + ret = -1; + } + + zip_source_free(src_final); + + if (ret < 0) { + return -1; + } + + if ((offend = fs_zip_source_tell_write(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + + if (fs_zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + + if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return -1; + } + + if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) { + if (st.valid & ZIP_STAT_MTIME) + de->last_mod = st.mtime; + else + time(&de->last_mod); + } + de->comp_method = st.comp_method; + de->crc = st.crc; + de->uncomp_size = st.size; + de->comp_size = (zip_uint64_t)(offend - offdata); + _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed); + + if (ZIP_WANT_TORRENTZIP(za)) { + zip_dirent_torrentzip_normalize(de); + } + + if ((ret = _zip_dirent_write(za, de, flags)) < 0) + return -1; + + if (is_zip64 != ret) { + /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return -1; + } + + if (fs_zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + + if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { + if (write_data_descriptor(za, de, is_zip64) < 0) { + return -1; + } + } + + return 0; +} + + +static int +copy_data(zip_t *za, zip_uint64_t len) { + DEFINE_BYTE_ARRAY(buf, BUFSIZE); + double total = (double)len; + + if (!byte_array_init(buf, BUFSIZE)) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + while (len > 0) { + zip_uint64_t n = ZIP_MIN(len, BUFSIZE); + + if (_zip_read(za->src, buf, n, &za->error) < 0) { + byte_array_fini(buf); + return -1; + } + + if (_zip_write(za, buf, n) < 0) { + byte_array_fini(buf); + return -1; + } + + len -= n; + + if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) { + zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); + return -1; + } + } + + byte_array_fini(buf); + return 0; +} + + +static int +copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) { + DEFINE_BYTE_ARRAY(buf, BUFSIZE); + zip_int64_t n, current; + int ret; + + if (fs_zip_source_open(src) < 0) { + zip_error_set_from_source(&za->error, src); + return -1; + } + + if (!byte_array_init(buf, BUFSIZE)) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + ret = 0; + current = 0; + while ((n = fs_zip_source_read(src, buf, BUFSIZE)) > 0) { + if (_zip_write(za, buf, (zip_uint64_t)n) < 0) { + ret = -1; + break; + } + if (n == BUFSIZE && za->progress && data_length > 0) { + current += n; + if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) { + zip_error_set(&za->error, ZIP_ER_CANCELLED, 0); + ret = -1; + break; + } + } + } + + if (n < 0) { + zip_error_set_from_source(&za->error, src); + ret = -1; + } + + byte_array_fini(buf); + + fs_zip_source_close(src); + + return ret; +} + +static int +write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) { + if (fs_zip_source_tell_write(za->src) < 0) { + return -1; + } + + if (_zip_cdir_write(za, filelist, survivors) < 0) { + return -1; + } + + if (fs_zip_source_tell_write(za->src) < 0) { + return -1; + } + + return 0; +} + + +int +_zip_changed(const zip_t *za, zip_uint64_t *survivorsp) { + int changed; + zip_uint64_t i, survivors; + + changed = 0; + survivors = 0; + + if (za->comment_changed || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za))) { + changed = 1; + } + + for (i = 0; i < za->nentry; i++) { + if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) { + changed = 1; + } + if (!za->entry[i].deleted) { + survivors++; + } + } + + if (survivorsp) { + *survivorsp = survivors; + } + + return changed; +} + +static int +write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) { + zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH); + int ret = 0; + + if (buffer == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + _zip_buffer_put(buffer, DATADES_MAGIC, 4); + _zip_buffer_put_32(buffer, de->crc); + if (is_zip64) { + _zip_buffer_put_64(buffer, de->comp_size); + _zip_buffer_put_64(buffer, de->uncomp_size); + } + else { + _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); + _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); + } + + if (!_zip_buffer_ok(buffer)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + ret = -1; + } + else { + ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)); + } + + _zip_buffer_free(buffer); + + return ret; +} + + +static int torrentzip_compare_names(const void *a, const void *b) { + const char *aname = ((const zip_filelist_t *)a)->name; + const char *bname = ((const zip_filelist_t *)b)->name; + + if (aname == NULL) { + return (bname != NULL) * -1; + } + else if (bname == NULL) { + return 1; + } + + return strcasecmp(aname, bname); +} \ No newline at end of file diff --git a/src/libzip/zip_crypto.h b/src/libzip/zip_crypto.h new file mode 100644 index 0000000..0d74d1a --- /dev/null +++ b/src/libzip/zip_crypto.h @@ -0,0 +1,54 @@ +/* + zip_crypto.h -- crypto definitions + Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HAD_ZIP_CRYPTO_H +#define HAD_ZIP_CRYPTO_H + +#define ZIP_CRYPTO_SHA1_LENGTH 20 +#define ZIP_CRYPTO_AES_BLOCK_LENGTH 16 + +#if defined(HAVE_WINDOWS_CRYPTO) +#include "zip_crypto_win.h" +#elif defined(HAVE_COMMONCRYPTO) +#include "zip_crypto_commoncrypto.h" +#elif defined(HAVE_GNUTLS) +#include "zip_crypto_gnutls.h" +#elif defined(HAVE_OPENSSL) +#include "zip_crypto_openssl.h" +#elif defined(HAVE_MBEDTLS) +#include "zip_crypto_mbedtls.h" +#else +#error "no crypto backend found" +#endif + +#endif /* HAD_ZIP_CRYPTO_H */ diff --git a/src/libzip/zip_crypto_commoncrypto.h b/src/libzip/zip_crypto_commoncrypto.h new file mode 100644 index 0000000..01828cc --- /dev/null +++ b/src/libzip/zip_crypto_commoncrypto.h @@ -0,0 +1,53 @@ +/* + zip_crypto_commoncrypto.h -- definitions for CommonCrypto wrapper. + Copyright (C) 2018 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HAD_ZIP_CRYPTO_COMMONCRYPTO_H +#define HAD_ZIP_CRYPTO_COMMONCRYPTO_H + +#include + +#define _zip_crypto_aes_t struct _CCCryptor +#define _zip_crypto_hmac_t CCHmacContext + +void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); +bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); +_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); + +#define _zip_crypto_hmac(hmac, data, length) (CCHmacUpdate((hmac), (data), (length)), true) +void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); +_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); +#define _zip_crypto_hmac_output(hmac, data) (CCHmacFinal((hmac), (data)), true) + +#define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)(key), (key_length), (salt), (salt_length), kCCPRFHmacAlgSHA1, (iterations), (output), (output_length)) == kCCSuccess) + +#endif /* HAD_ZIP_CRYPTO_COMMONCRYPTO_H */ diff --git a/src/libzip/zip_crypto_gnutls.h b/src/libzip/zip_crypto_gnutls.h new file mode 100644 index 0000000..dc8b97a --- /dev/null +++ b/src/libzip/zip_crypto_gnutls.h @@ -0,0 +1,68 @@ +/* + zip_crypto_gnutls.h -- definitions for GnuTLS wrapper. + Copyright (C) 2018-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HAD_ZIP_CRYPTO_GNUTLS_H +#define HAD_ZIP_CRYPTO_GNUTLS_H + +#define HAVE_SECURE_RANDOM + +#include +#include + +#include + +#include + +typedef struct { + union { + struct aes128_ctx ctx_128; + struct aes192_ctx ctx_192; + struct aes256_ctx ctx_256; + } ctx; + zip_uint16_t key_size; +} _zip_crypto_aes_t; + +#define _zip_crypto_hmac_t gnutls_hmac_hd_t + +void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); +bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); +_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); + +#define _zip_crypto_hmac(hmac, data, length) (gnutls_hmac(*(hmac), (data), (length)) == 0) +void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); +_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); +#define _zip_crypto_hmac_output(hmac, data) (gnutls_hmac_output(*(hmac), (data)), true) + +#define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (pbkdf2_hmac_sha1((key_length), (key), (iterations), (salt_length), (salt), (output_length), (output)), true) + +#endif /* HAD_ZIP_CRYPTO_GNUTLS_H */ diff --git a/src/libzip/zip_crypto_mbedtls.h b/src/libzip/zip_crypto_mbedtls.h new file mode 100644 index 0000000..1151fff --- /dev/null +++ b/src/libzip/zip_crypto_mbedtls.h @@ -0,0 +1,56 @@ +/* + zip_crypto_mbedtls.h -- definitions for mbedtls wrapper + Copyright (C) 2018-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HAD_ZIP_CRYPTO_MBEDTLS_H +#define HAD_ZIP_CRYPTO_MBEDTLS_H + +#define HAVE_SECURE_RANDOM + +#include +#include + +#define _zip_crypto_aes_t mbedtls_aes_context +#define _zip_crypto_hmac_t mbedtls_md_context_t + +_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); +#define _zip_crypto_aes_encrypt_block(aes, in, out) (mbedtls_aes_crypt_ecb((aes), MBEDTLS_AES_ENCRYPT, (in), (out)) == 0) +void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); + +_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); +#define _zip_crypto_hmac(hmac, data, length) (mbedtls_md_hmac_update((hmac), (data), (length)) == 0) +#define _zip_crypto_hmac_output(hmac, data) (mbedtls_md_hmac_finish((hmac), (data)) == 0) +void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); + +bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length); + +#endif /* HAD_ZIP_CRYPTO_MBEDTLS_H */ diff --git a/src/libzip/zip_crypto_openssl.h b/src/libzip/zip_crypto_openssl.h new file mode 100644 index 0000000..198a907 --- /dev/null +++ b/src/libzip/zip_crypto_openssl.h @@ -0,0 +1,73 @@ +/* + zip_crypto_openssl.h -- definitions for OpenSSL wrapper. + Copyright (C) 2018-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HAD_ZIP_CRYPTO_OPENSSL_H +#define HAD_ZIP_CRYPTO_OPENSSL_H + +#define HAVE_SECURE_RANDOM + +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL) +#define USE_OPENSSL_1_0_API +#elif OPENSSL_VERSION_NUMBER < 0x3000000fL +#define USE_OPENSSL_1_1_API +#else +#define USE_OPENSSL_3_API +#endif + +#define _zip_crypto_aes_t EVP_CIPHER_CTX +#ifdef USE_OPENSSL_3_API +struct _zip_crypto_hmac_t { + EVP_MAC *mac; + EVP_MAC_CTX *ctx; +}; +typedef struct _zip_crypto_hmac_t _zip_crypto_hmac_t; +#define _zip_crypto_hmac(hmac, data, length) (EVP_MAC_update((hmac->ctx), (data), (length)) == 1) +#else +#define _zip_crypto_hmac_t HMAC_CTX +#define _zip_crypto_hmac(hmac, data, length) (HMAC_Update((hmac), (data), (length)) == 1) +#endif + +void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); +bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); +_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); + +void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); +_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); +bool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data); + +#define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (PKCS5_PBKDF2_HMAC_SHA1((const char *)(key), (key_length), (salt), (salt_length), (iterations), (output_length), (output))) + +#endif /* HAD_ZIP_CRYPTO_OPENSSL_H */ diff --git a/src/libzip/zip_crypto_win.h b/src/libzip/zip_crypto_win.h new file mode 100644 index 0000000..a533fe2 --- /dev/null +++ b/src/libzip/zip_crypto_win.h @@ -0,0 +1,53 @@ +/* + zip_crypto_win.h -- Windows Crypto API wrapper. + Copyright (C) 2018-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HAD_ZIP_CRYPTO_WIN_H +#define HAD_ZIP_CRYPTO_WIN_H + +#define HAVE_SECURE_RANDOM + +typedef struct _zip_crypto_aes_s _zip_crypto_aes_t; +typedef struct _zip_crypto_hmac_s _zip_crypto_hmac_t; + +void _zip_crypto_aes_free(_zip_crypto_aes_t *aes); +_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error); +bool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out); + +bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length); + +_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error); +void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac); +bool _zip_crypto_hmac(_zip_crypto_hmac_t *hmac, zip_uint8_t *data, zip_uint64_t length); +bool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data); + +#endif /* HAD_ZIP_CRYPTO_WIN_H */ diff --git a/src/libzip/zip_delete.c b/src/libzip/zip_delete.c new file mode 100644 index 0000000..6b7db26 --- /dev/null +++ b/src/libzip/zip_delete.c @@ -0,0 +1,68 @@ +/* + fs_zip_delete.c -- delete file from zip archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_delete(zip_t *za, zip_uint64_t idx) { + const char *name; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + + if ((name = _zip_get_name(za, idx, 0, &za->error)) == NULL) { + return -1; + } + + if (!_zip_hash_delete(za->names, (const zip_uint8_t *)name, &za->error)) { + return -1; + } + + /* allow duplicate file names, because the file will + * be removed directly afterwards */ + if (_zip_unchange(za, idx, 1) != 0) + return -1; + + za->entry[idx].deleted = 1; + + return 0; +} diff --git a/src/libzip/zip_dir_add.c b/src/libzip/zip_dir_add.c new file mode 100644 index 0000000..eaa0ad8 --- /dev/null +++ b/src/libzip/zip_dir_add.c @@ -0,0 +1,92 @@ +/* + fs_zip_dir_add.c -- add directory + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include "zipint.h" + + +/* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ + +ZIP_EXTERN zip_int64_t +fs_zip_dir_add(zip_t *za, const char *name, zip_flags_t flags) { + size_t len; + zip_int64_t idx; + char *s; + zip_source_t *source; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + + if (name == NULL) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + s = NULL; + len = strlen(name); + + if (name[len - 1] != '/') { + if (len > SIZE_MAX - 2 || (s = (char *)malloc(len + 2)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + (void)strncpy_s(s, len + 2, name, len); + s[len] = '/'; + s[len + 1] = '\0'; + } + + if ((source = fs_zip_source_buffer(za, NULL, 0, 0)) == NULL) { + free(s); + return -1; + } + + idx = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags); + + free(s); + + if (idx < 0) + zip_source_free(source); + else { + if (fs_zip_file_set_external_attributes(za, (zip_uint64_t)idx, 0, ZIP_OPSYS_DEFAULT, ZIP_EXT_ATTRIB_DEFAULT_DIR) < 0) { + fs_zip_delete(za, (zip_uint64_t)idx); + return -1; + } + } + + return idx; +} diff --git a/src/libzip/zip_dirent.c b/src/libzip/zip_dirent.c new file mode 100644 index 0000000..520dda9 --- /dev/null +++ b/src/libzip/zip_dirent.c @@ -0,0 +1,1207 @@ +/* + zip_dirent.c -- read directory entry (local or central), clean dirent + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include +#include +#include +#include + +#include "zipint.h" + +static zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str); +static zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *); +static bool _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error); + + +void +_zip_cdir_free(zip_cdir_t *cd) { + zip_uint64_t i; + + if (!cd) + return; + + for (i = 0; i < cd->nentry; i++) + _zip_entry_finalize(cd->entry + i); + free(cd->entry); + _zip_string_free(cd->comment); + free(cd); +} + + +zip_cdir_t * +_zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) { + zip_cdir_t *cd; + + if ((cd = (zip_cdir_t *)malloc(sizeof(*cd))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + cd->entry = NULL; + cd->nentry = cd->nentry_alloc = 0; + cd->size = cd->offset = 0; + cd->comment = NULL; + cd->is_zip64 = false; + + if (!_zip_cdir_grow(cd, nentry, error)) { + _zip_cdir_free(cd); + return NULL; + } + + return cd; +} + + +bool +_zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error) { + zip_uint64_t i, new_alloc; + zip_entry_t *new_entry; + + if (additional_entries == 0) { + return true; + } + + new_alloc = cd->nentry_alloc + additional_entries; + + if (new_alloc < additional_entries || new_alloc > SIZE_MAX / sizeof(*(cd->entry))) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + if ((new_entry = (zip_entry_t *)realloc(cd->entry, sizeof(*(cd->entry)) * (size_t)new_alloc)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + cd->entry = new_entry; + + for (i = cd->nentry; i < new_alloc; i++) { + _zip_entry_init(cd->entry + i); + } + + cd->nentry = cd->nentry_alloc = new_alloc; + + return true; +} + + +zip_int64_t +_zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) { + zip_uint64_t offset, size; + zip_string_t *comment; + zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN]; + zip_buffer_t *buffer; + zip_int64_t off; + zip_uint64_t i; + bool is_zip64; + int ret; + zip_uint32_t cdir_crc; + + if ((off = fs_zip_source_tell_write(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + offset = (zip_uint64_t)off; + + is_zip64 = false; + + if (ZIP_WANT_TORRENTZIP(za)) { + cdir_crc = (zip_uint32_t)zng_crc32(0, NULL, 0); + za->write_crc = &cdir_crc; + } + + for (i = 0; i < survivors; i++) { + zip_entry_t *entry = za->entry + filelist[i].idx; + + if ((ret = _zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL)) < 0) + return -1; + if (ret) + is_zip64 = true; + } + + za->write_crc = NULL; + + if ((off = fs_zip_source_tell_write(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + size = (zip_uint64_t)off - offset; + + if (offset > ZIP_UINT32_MAX || survivors > ZIP_UINT16_MAX) { + is_zip64 = true; + } + + if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + if (is_zip64) { + _zip_buffer_put(buffer, EOCD64_MAGIC, 4); + _zip_buffer_put_64(buffer, EOCD64LEN - 12); + _zip_buffer_put_16(buffer, 45); + _zip_buffer_put_16(buffer, 45); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_64(buffer, survivors); + _zip_buffer_put_64(buffer, survivors); + _zip_buffer_put_64(buffer, size); + _zip_buffer_put_64(buffer, offset); + _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_64(buffer, offset + size); + _zip_buffer_put_32(buffer, 1); + } + + _zip_buffer_put(buffer, EOCD_MAGIC, 4); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); + _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); + _zip_buffer_put_32(buffer, size >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)size); + _zip_buffer_put_32(buffer, offset >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)offset); + + comment = za->comment_changed ? za->comment_changes : za->comment_orig; + + if (ZIP_WANT_TORRENTZIP(za)) { + _zip_buffer_put_16(buffer, TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH); + } + else { + _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0)); + } + + + if (!_zip_buffer_ok(buffer)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(buffer); + return -1; + } + + if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) { + _zip_buffer_free(buffer); + return -1; + } + + _zip_buffer_free(buffer); + + if (ZIP_WANT_TORRENTZIP(za)) { + char torrentzip_comment[TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH + 1]; + snprintf(torrentzip_comment, sizeof(torrentzip_comment), TORRENTZIP_SIGNATURE "%08X", cdir_crc); + + if (_zip_write(za, torrentzip_comment, strlen(torrentzip_comment)) < 0) { + return -1; + } + } + else if (comment != NULL) { + if (_zip_write(za, comment->raw, comment->length) < 0) { + return -1; + } + } + + return (zip_int64_t)size; +} + + +zip_dirent_t * +_zip_dirent_clone(const zip_dirent_t *sde) { + zip_dirent_t *tde; + + if ((tde = (zip_dirent_t *)malloc(sizeof(*tde))) == NULL) + return NULL; + + if (sde) + (void)memcpy_s(tde, sizeof(*tde), sde, sizeof(*sde)); + else + _zip_dirent_init(tde); + + tde->changed = 0; + tde->cloned = 1; + + return tde; +} + + +void +_zip_dirent_finalize(zip_dirent_t *zde) { + if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) { + _zip_string_free(zde->filename); + zde->filename = NULL; + } + if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) { + _zip_ef_free(zde->extra_fields); + zde->extra_fields = NULL; + } + if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) { + _zip_string_free(zde->comment); + zde->comment = NULL; + } + if (!zde->cloned || zde->changed & ZIP_DIRENT_PASSWORD) { + if (zde->password) { + _zip_crypto_clear(zde->password, strlen(zde->password)); + } + free(zde->password); + zde->password = NULL; + } +} + + +void +_zip_dirent_free(zip_dirent_t *zde) { + if (zde == NULL) + return; + + _zip_dirent_finalize(zde); + free(zde); +} + + +void +_zip_dirent_init(zip_dirent_t *de) { + de->changed = 0; + de->local_extra_fields_read = 0; + de->cloned = 0; + + de->crc_valid = true; + de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8); + de->version_needed = 10; /* 1.0 */ + de->bitflags = 0; + de->comp_method = ZIP_CM_DEFAULT; + de->last_mod = 0; + de->crc = 0; + de->comp_size = 0; + de->uncomp_size = 0; + de->filename = NULL; + de->extra_fields = NULL; + de->comment = NULL; + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT; + de->offset = 0; + de->compression_level = 0; + de->encryption_method = ZIP_EM_NONE; + de->password = NULL; +} + + +bool +_zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) { + if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX)) + return true; + + return false; +} + + +zip_dirent_t * +_zip_dirent_new(void) { + zip_dirent_t *de; + + if ((de = (zip_dirent_t *)malloc(sizeof(*de))) == NULL) + return NULL; + + _zip_dirent_init(de); + return de; +} + + +/* _zip_dirent_read(zde, fp, bufp, left, localp, error): + Fills the zip directory entry zde. + + If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed. + + If local is true, it reads a local header instead of a central directory entry. + + Returns size of dirent read if successful. On error, error is filled in and -1 is returned. +*/ + +zip_int64_t +_zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error) { + zip_uint8_t buf[CDENTRYSIZE]; + zip_uint16_t dostime, dosdate; + zip_uint32_t size, variable_size; + zip_uint16_t filename_len, comment_len, ef_len; + + bool from_buffer = (buffer != NULL); + + size = local ? LENTRYSIZE : CDENTRYSIZE; + + if (buffer) { + if (_zip_buffer_left(buffer) < size) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + } + else { + if ((buffer = _zip_buffer_new_from_source(src, size, buf, error)) == NULL) { + return -1; + } + } + + if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + + /* convert buffercontents to zip_dirent */ + + _zip_dirent_init(zde); + if (!local) + zde->version_madeby = _zip_buffer_get_16(buffer); + else + zde->version_madeby = 0; + zde->version_needed = _zip_buffer_get_16(buffer); + zde->bitflags = _zip_buffer_get_16(buffer); + zde->comp_method = _zip_buffer_get_16(buffer); + + /* convert to time_t */ + dostime = _zip_buffer_get_16(buffer); + dosdate = _zip_buffer_get_16(buffer); + zde->last_mod = _zip_d2u_time(dostime, dosdate); + + zde->crc = _zip_buffer_get_32(buffer); + zde->comp_size = _zip_buffer_get_32(buffer); + zde->uncomp_size = _zip_buffer_get_32(buffer); + + filename_len = _zip_buffer_get_16(buffer); + ef_len = _zip_buffer_get_16(buffer); + + if (local) { + comment_len = 0; + zde->disk_number = 0; + zde->int_attrib = 0; + zde->ext_attrib = 0; + zde->offset = 0; + } + else { + comment_len = _zip_buffer_get_16(buffer); + zde->disk_number = _zip_buffer_get_16(buffer); + zde->int_attrib = _zip_buffer_get_16(buffer); + zde->ext_attrib = _zip_buffer_get_32(buffer); + zde->offset = _zip_buffer_get_32(buffer); + } + + if (!_zip_buffer_ok(buffer)) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + + if (zde->bitflags & ZIP_GPBF_ENCRYPTED) { + if (zde->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { + /* TODO */ + zde->encryption_method = ZIP_EM_UNKNOWN; + } + else { + zde->encryption_method = ZIP_EM_TRAD_PKWARE; + } + } + else { + zde->encryption_method = ZIP_EM_NONE; + } + + zde->filename = NULL; + zde->extra_fields = NULL; + zde->comment = NULL; + + variable_size = (zip_uint32_t)filename_len + (zip_uint32_t)ef_len + (zip_uint32_t)comment_len; + + if (from_buffer) { + if (_zip_buffer_left(buffer) < variable_size) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW); + return -1; + } + } + else { + _zip_buffer_free(buffer); + + if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) { + return -1; + } + } + + if (filename_len) { + zde->filename = _zip_read_string(buffer, src, filename_len, 1, error); + if (!zde->filename) { + if (fs_zip_error_code_zip(error) == ZIP_ER_EOF) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW); + } + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + + if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { + if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME); + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + } + } + + if (ef_len) { + zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error); + + if (ef == NULL) { + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) { + free(ef); + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + free(ef); + if (local) + zde->local_extra_fields_read = 1; + } + + if (comment_len) { + zde->comment = _zip_read_string(buffer, src, comment_len, 0, error); + if (!zde->comment) { + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { + if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT); + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + } + } + + zde->filename = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename); + zde->comment = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment); + + /* Zip64 */ + + if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) { + zip_uint16_t got_len; + const zip_uint8_t *ef = _zip_ef_get_by_id(zde->extra_fields, &got_len, ZIP_EF_ZIP64, 0, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error); + if (ef != NULL) { + if (!zip_dirent_process_ef_zip64(zde, ef, got_len, local, error)) { + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + } + } + + + if (!_zip_buffer_ok(buffer)) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; + } + if (!from_buffer) { + _zip_buffer_free(buffer); + } + + /* fs_zip_source_seek / fs_zip_source_tell don't support values > ZIP_INT64_MAX */ + if (zde->offset > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return -1; + } + + if (!_zip_dirent_process_winzip_aes(zde, error)) { + return -1; + } + + zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields); + + return (zip_int64_t)size + (zip_int64_t)variable_size; +} + +bool zip_dirent_process_ef_zip64(zip_dirent_t* zde, const zip_uint8_t* ef, zip_uint64_t got_len, bool local, zip_error_t* error) { + zip_buffer_t *ef_buffer; + + if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + if (zde->uncomp_size == ZIP_UINT32_MAX) { + zde->uncomp_size = _zip_buffer_get_64(ef_buffer); + } + else if (local) { + /* From appnote.txt: This entry in the Local header MUST + include BOTH original and compressed file size fields. */ + (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */ + } + if (zde->comp_size == ZIP_UINT32_MAX) { + zde->comp_size = _zip_buffer_get_64(ef_buffer); + } + if (!local) { + if (zde->offset == ZIP_UINT32_MAX) { + zde->offset = _zip_buffer_get_64(ef_buffer); + } + if (zde->disk_number == ZIP_UINT16_MAX) { + zde->disk_number = _zip_buffer_get_32(ef_buffer); + } + } + + if (!_zip_buffer_eof(ef_buffer)) { + /* accept additional fields if values match */ + bool ok = true; + switch (got_len) { + case 28: + _zip_buffer_set_offset(ef_buffer, 24); + if (zde->disk_number != _zip_buffer_get_32(ef_buffer)) { + ok = false; + } + /* fallthrough */ + case 24: + _zip_buffer_set_offset(ef_buffer, 0); + if ((zde->uncomp_size != _zip_buffer_get_64(ef_buffer)) || (zde->comp_size != _zip_buffer_get_64(ef_buffer)) || (zde->offset != _zip_buffer_get_64(ef_buffer))) { + ok = false; + } + break; + + default: + ok = false; + } + if (!ok) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_ZIP64_EF); + _zip_buffer_free(ef_buffer); + return false; + } + } + _zip_buffer_free(ef_buffer); + + return true; +} + + +static zip_string_t * +_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str) { + zip_uint16_t ef_len; + zip_uint32_t ef_crc; + zip_buffer_t *buffer; + + const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL); + + if (ef == NULL || ef_len < 5 || ef[0] != 1) { + return str; + } + + if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { + return str; + } + + _zip_buffer_get_8(buffer); + ef_crc = _zip_buffer_get_32(buffer); + + if (_zip_string_crc32(str) == ef_crc) { + zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer); + zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL); + + if (ef_str != NULL) { + _zip_string_free(str); + str = ef_str; + } + } + + _zip_buffer_free(buffer); + + return str; +} + + +static bool +_zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) { + zip_uint16_t ef_len; + zip_buffer_t *buffer; + const zip_uint8_t *ef; + bool crc_valid; + zip_uint16_t enc_method; + + + if (de->comp_method != ZIP_CM_WINZIP_AES) { + return true; + } + + ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, ZIP_EF_WINZIP_AES, 0, ZIP_EF_BOTH, NULL); + + if (ef == NULL || ef_len < 7) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF); + return false; + } + + if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return false; + } + + /* version */ + + crc_valid = true; + switch (_zip_buffer_get_16(buffer)) { + case 1: + break; + + case 2: + crc_valid = false; + /* TODO: When checking consistency, check that crc is 0. */ + break; + + default: + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + _zip_buffer_free(buffer); + return false; + } + + /* vendor */ + if (memcmp(_zip_buffer_get(buffer, 2), "AE", 2) != 0) { + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + _zip_buffer_free(buffer); + return false; + } + + /* mode */ + switch (_zip_buffer_get_8(buffer)) { + case 1: + enc_method = ZIP_EM_AES_128; + break; + case 2: + enc_method = ZIP_EM_AES_192; + break; + case 3: + enc_method = ZIP_EM_AES_256; + break; + default: + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + _zip_buffer_free(buffer); + return false; + } + + if (ef_len != 7) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF); + _zip_buffer_free(buffer); + return false; + } + + de->crc_valid = crc_valid; + de->encryption_method = enc_method; + de->comp_method = _zip_buffer_get_16(buffer); + + _zip_buffer_free(buffer); + return true; +} + + +zip_int32_t +_zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) { + zip_int32_t size; + bool local = (flags & ZIP_EF_LOCAL) != 0; + int i; + zip_uint8_t b[6]; + zip_buffer_t *buffer; + + size = local ? LENTRYSIZE : CDENTRYSIZE; + + if (fs_zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) { + zip_error_set_from_source(error, src); + return -1; + } + + if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) { + return -1; + } + + for (i = 0; i < (local ? 2 : 3); i++) { + size += _zip_buffer_get_16(buffer); + } + + if (!_zip_buffer_eof(buffer)) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(buffer); + return -1; + } + + _zip_buffer_free(buffer); + return size; +} + + +/* _zip_dirent_write + Writes zip directory entry. + + If flags & ZIP_EF_LOCAL, it writes a local header instead of a central + directory entry. If flags & ZIP_EF_FORCE_ZIP64, a ZIP64 extra field is written, even if not needed. + + Returns 0 if successful, 1 if successful and wrote ZIP64 extra field. On error, error is filled in and -1 is + returned. +*/ + +int +_zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) { + zip_uint16_t dostime, dosdate; + zip_encoding_type_t com_enc, name_enc; + zip_extra_field_t *ef; + zip_extra_field_t *ef64; + zip_uint32_t ef_total_size; + bool is_zip64; + bool is_really_zip64; + bool is_winzip_aes; + zip_uint8_t buf[CDENTRYSIZE]; + zip_buffer_t *buffer; + + ef = NULL; + + name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); + com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); + + if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) || (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN)) + de->bitflags |= ZIP_GPBF_ENCODING_UTF_8; + else { + de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8; + if (name_enc == ZIP_ENCODING_UTF8_KNOWN) { + ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error); + if (ef == NULL) + return -1; + } + if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN) { + zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error); + if (ef2 == NULL) { + _zip_ef_free(ef); + return -1; + } + ef2->next = ef; + ef = ef2; + } + } + + if (de->encryption_method == ZIP_EM_NONE) { + de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCRYPTED; + } + else { + de->bitflags |= (zip_uint16_t)ZIP_GPBF_ENCRYPTED; + } + + is_really_zip64 = _zip_dirent_needs_zip64(de, flags); + is_zip64 = (flags & (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64) || is_really_zip64; + is_winzip_aes = de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256; + + if (is_zip64) { + zip_uint8_t ef_zip64[EFZIP64SIZE]; + zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64)); + if (ef_buffer == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + _zip_ef_free(ef); + return -1; + } + + if (flags & ZIP_FL_LOCAL) { + if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) { + _zip_buffer_put_64(ef_buffer, de->uncomp_size); + _zip_buffer_put_64(ef_buffer, de->comp_size); + } + } + else { + if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) { + if (de->uncomp_size >= ZIP_UINT32_MAX) { + _zip_buffer_put_64(ef_buffer, de->uncomp_size); + } + if (de->comp_size >= ZIP_UINT32_MAX) { + _zip_buffer_put_64(ef_buffer, de->comp_size); + } + if (de->offset >= ZIP_UINT32_MAX) { + _zip_buffer_put_64(ef_buffer, de->offset); + } + } + } + + if (!_zip_buffer_ok(ef_buffer)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(ef_buffer); + _zip_ef_free(ef); + return -1; + } + + ef64 = _zip_ef_new(ZIP_EF_ZIP64, (zip_uint16_t)(_zip_buffer_offset(ef_buffer)), ef_zip64, ZIP_EF_BOTH); + _zip_buffer_free(ef_buffer); + ef64->next = ef; + ef = ef64; + } + + if (is_winzip_aes) { + zip_uint8_t data[EF_WINZIP_AES_SIZE]; + zip_buffer_t *ef_buffer = _zip_buffer_new(data, sizeof(data)); + zip_extra_field_t *ef_winzip; + + if (ef_buffer == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + _zip_ef_free(ef); + return -1; + } + + _zip_buffer_put_16(ef_buffer, 2); + _zip_buffer_put(ef_buffer, "AE", 2); + _zip_buffer_put_8(ef_buffer, (zip_uint8_t)(de->encryption_method & 0xff)); + _zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method); + + if (!_zip_buffer_ok(ef_buffer)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(ef_buffer); + _zip_ef_free(ef); + return -1; + } + + ef_winzip = _zip_ef_new(ZIP_EF_WINZIP_AES, EF_WINZIP_AES_SIZE, data, ZIP_EF_BOTH); + _zip_buffer_free(ef_buffer); + ef_winzip->next = ef; + ef = ef_winzip; + } + + if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + _zip_ef_free(ef); + return -1; + } + + _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4); + + if ((flags & ZIP_FL_LOCAL) == 0) { + _zip_buffer_put_16(buffer, de->version_madeby); + } + _zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed)); + _zip_buffer_put_16(buffer, de->bitflags); + if (is_winzip_aes) { + _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES); + } + else { + _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method); + } + + if (ZIP_WANT_TORRENTZIP(za)) { + dostime = 0xbc00; + dosdate = 0x2198; + } + else { + _zip_u2d_time(de->last_mod, &dostime, &dosdate); + } + _zip_buffer_put_16(buffer, dostime); + _zip_buffer_put_16(buffer, dosdate); + + if (is_winzip_aes && de->uncomp_size < 20) { + _zip_buffer_put_32(buffer, 0); + } + else { + _zip_buffer_put_32(buffer, de->crc); + } + + if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) { + /* In local headers, if a ZIP64 EF is written, it MUST contain + * both compressed and uncompressed sizes (even if one of the + * two is smaller than 0xFFFFFFFF); on the other hand, those + * may only appear when the corresponding standard entry is + * 0xFFFFFFFF. (appnote.txt 4.5.3) */ + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + } + else { + if (de->comp_size < ZIP_UINT32_MAX) { + _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); + } + else { + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + } + if (de->uncomp_size < ZIP_UINT32_MAX) { + _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); + } + else { + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + } + } + + _zip_buffer_put_16(buffer, _zip_string_length(de->filename)); + ef_total_size = (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH); + if (!ZIP_WANT_TORRENTZIP(za)) { + /* TODO: check for overflow */ + ef_total_size += (zip_uint32_t)_zip_ef_size(de->extra_fields, flags); + } + _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size); + + if ((flags & ZIP_FL_LOCAL) == 0) { + _zip_buffer_put_16(buffer, ZIP_WANT_TORRENTZIP(za) ? 0 : _zip_string_length(de->comment)); + _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number); + _zip_buffer_put_16(buffer, de->int_attrib); + _zip_buffer_put_32(buffer, de->ext_attrib); + if (de->offset < ZIP_UINT32_MAX) + _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset); + else + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + } + + if (!_zip_buffer_ok(buffer)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(buffer); + _zip_ef_free(ef); + return -1; + } + + if (_zip_write(za, buf, _zip_buffer_offset(buffer)) < 0) { + _zip_buffer_free(buffer); + _zip_ef_free(ef); + return -1; + } + + _zip_buffer_free(buffer); + + if (de->filename) { + if (_zip_string_write(za, de->filename) < 0) { + _zip_ef_free(ef); + return -1; + } + } + + if (ef) { + if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) { + _zip_ef_free(ef); + return -1; + } + } + _zip_ef_free(ef); + if (de->extra_fields && !ZIP_WANT_TORRENTZIP(za)) { + if (_zip_ef_write(za, de->extra_fields, flags) < 0) { + return -1; + } + } + + if ((flags & ZIP_FL_LOCAL) == 0 && !ZIP_WANT_TORRENTZIP(za)) { + if (de->comment) { + if (_zip_string_write(za, de->comment) < 0) { + return -1; + } + } + } + + + return is_zip64; +} + + +time_t +_zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) { + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + + /* let mktime decide if DST is in effect */ + tm.tm_isdst = -1; + + tm.tm_year = ((ddate >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((ddate >> 5) & 15) - 1; + tm.tm_mday = ddate & 31; + + tm.tm_hour = (dtime >> 11) & 31; + tm.tm_min = (dtime >> 5) & 63; + tm.tm_sec = (dtime << 1) & 62; + + return mktime(&tm); +} + + +static zip_extra_field_t * +_zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) { + const zip_uint8_t *raw; + zip_uint32_t len; + zip_buffer_t *buffer; + zip_extra_field_t *ef; + + if ((raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) { + /* error already set */ + return NULL; + } + + if (len + 5 > ZIP_UINT16_MAX) { + zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */ + return NULL; + } + + if ((buffer = _zip_buffer_new(NULL, len + 5)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + _zip_buffer_put_8(buffer, 1); + _zip_buffer_put_32(buffer, _zip_string_crc32(str)); + _zip_buffer_put(buffer, raw, len); + + if (!_zip_buffer_ok(buffer)) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(buffer); + return NULL; + } + + ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH); + _zip_buffer_free(buffer); + + return ef; +} + + +zip_dirent_t * +_zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) { + if (error == NULL) + error = &za->error; + + if (idx >= za->nentry) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) { + if (za->entry[idx].orig == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) { + zip_error_set(error, ZIP_ER_DELETED, 0); + return NULL; + } + return za->entry[idx].orig; + } + else + return za->entry[idx].changes; +} + + +void +_zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) { + struct tm *tpm; + struct tm tm; + tpm = zip_localtime(&intime, &tm); + if (tpm == NULL) { + /* if localtime fails, return an arbitrary date (1980-01-01 00:00:00) */ + *ddate = (1 << 5) + 1; + *dtime = 0; + return; + } + if (tpm->tm_year < 80) { + tpm->tm_year = 80; + } + + *ddate = (zip_uint16_t)(((tpm->tm_year + 1900 - 1980) << 9) + ((tpm->tm_mon + 1) << 5) + tpm->tm_mday); + *dtime = (zip_uint16_t)(((tpm->tm_hour) << 11) + ((tpm->tm_min) << 5) + ((tpm->tm_sec) >> 1)); +} + + +void +_zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64, zip_uint32_t changed) { + zip_uint16_t length; + + if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) { + zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; + de->bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask); + } + if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) { + de->int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0); + } + /* manually set attributes are preferred over attributes provided by source */ + if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) { + de->ext_attrib = attributes->external_file_attributes; + } + + if (de->comp_method == ZIP_CM_LZMA) { + de->version_needed = 63; + } + else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) { + de->version_needed = 51; + } + else if (de->comp_method == ZIP_CM_BZIP2) { + de->version_needed = 46; + } + else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) { + de->version_needed = 45; + } + else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) { + de->version_needed = 20; + } + else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') { + de->version_needed = 20; + } + else { + de->version_needed = 10; + } + + if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) { + de->version_needed = ZIP_MAX(de->version_needed, attributes->version_needed); + } + + de->version_madeby = 63 | (de->version_madeby & 0xff00); + if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) { + de->version_madeby = (de->version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8); + } +} + + +/* _zip_dirent_torrent_normalize(de); + Set values suitable for torrentzip. +*/ + +void zip_dirent_torrentzip_normalize(zip_dirent_t *de) { + de->version_madeby = 0; + de->version_needed = 20; /* 2.0 */ + de->bitflags = 2; /* maximum compression */ + de->comp_method = ZIP_CM_DEFLATE; + de->compression_level = TORRENTZIP_COMPRESSION_FLAGS; + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = 0; + + /* last_mod, extra_fields, and comment are normalized in zip_dirent_write() directly */ + +} diff --git a/src/libzip/zip_discard.c b/src/libzip/zip_discard.c new file mode 100644 index 0000000..dab506b --- /dev/null +++ b/src/libzip/zip_discard.c @@ -0,0 +1,80 @@ +/* + fs_zip_discard.c -- discard and free struct zip + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +/* fs_zip_discard: + frees the space allocated to a zipfile struct, and closes the + corresponding file. */ + +void +fs_zip_discard(zip_t *za) { + zip_uint64_t i; + + if (za == NULL) + return; + + if (za->src) { + fs_zip_source_close(za->src); + zip_source_free(za->src); + } + + free(za->default_password); + _zip_string_free(za->comment_orig); + _zip_string_free(za->comment_changes); + + _zip_hash_free(za->names); + + if (za->entry) { + for (i = 0; i < za->nentry; i++) + _zip_entry_finalize(za->entry + i); + free(za->entry); + } + + for (i = 0; i < za->nopen_source; i++) { + _zip_source_invalidate(za->open_source[i]); + } + free(za->open_source); + + _zip_progress_free(za->progress); + + fs_zip_error_fini(&za->error); + + free(za); + + return; +} diff --git a/src/libzip/zip_entry.c b/src/libzip/zip_entry.c new file mode 100644 index 0000000..35a36e4 --- /dev/null +++ b/src/libzip/zip_entry.c @@ -0,0 +1,51 @@ +/* + zip_entry.c -- struct zip_entry helper functions + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +void +_zip_entry_finalize(zip_entry_t *e) { + _zip_unchange_data(e); + _zip_dirent_free(e->orig); + _zip_dirent_free(e->changes); +} + + +void +_zip_entry_init(zip_entry_t *e) { + e->orig = NULL; + e->changes = NULL; + e->source = NULL; + e->deleted = 0; +} diff --git a/src/libzip/zip_err_str.c b/src/libzip/zip_err_str.c new file mode 100644 index 0000000..28af773 --- /dev/null +++ b/src/libzip/zip_err_str.c @@ -0,0 +1,79 @@ +/* + This file was generated automatically by CMake + from zip.h and zipint.h; make changes there. +*/ + +#include "zipint.h" + +#define L ZIP_ET_LIBZIP +#define N ZIP_ET_NONE +#define S ZIP_ET_SYS +#define Z ZIP_ET_ZLIB + +#define E ZIP_DETAIL_ET_ENTRY +#define G ZIP_DETAIL_ET_GLOBAL + +const struct _zip_err_info _zip_err_str[] = { + { N, "No error" }, + { N, "Multi-disk zip archives not supported" }, + { S, "Renaming temporary file failed" }, + { S, "Closing zip archive failed" }, + { S, "Seek error" }, + { S, "Read error" }, + { S, "Write error" }, + { N, "CRC error" }, + { N, "Containing zip archive was closed" }, + { N, "No such file" }, + { N, "File already exists" }, + { S, "Can't open file" }, + { S, "Failure to create temporary file" }, + { Z, "Zlib error" }, + { N, "Malloc failure" }, + { N, "Entry has been changed" }, + { N, "Compression method not supported" }, + { N, "Premature end of file" }, + { N, "Invalid argument" }, + { N, "Not a zip archive" }, + { N, "Internal error" }, + { L, "Zip archive inconsistent" }, + { S, "Can't remove file" }, + { N, "Entry has been deleted" }, + { N, "Encryption method not supported" }, + { N, "Read-only archive" }, + { N, "No password provided" }, + { N, "Wrong password provided" }, + { N, "Operation not supported" }, + { N, "Resource still in use" }, + { S, "Tell error" }, + { N, "Compressed data invalid" }, + { N, "Operation cancelled" }, + { N, "Unexpected length of data" }, + { N, "Not allowed in torrentzip" }, +}; + +const int _zip_err_str_count = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]); + +const struct _zip_err_info _zip_err_details[] = { + { G, "no detail" }, + { G, "central directory overlaps EOCD, or there is space between them" }, + { G, "archive comment length incorrect" }, + { G, "central directory length invalid" }, + { E, "central header invalid" }, + { G, "central directory count of entries is incorrect" }, + { E, "local and central headers do not match" }, + { G, "wrong EOCD length" }, + { G, "EOCD64 overlaps EOCD, or there is space between them" }, + { G, "EOCD64 magic incorrect" }, + { G, "EOCD64 and EOCD do not match" }, + { G, "invalid value in central directory" }, + { E, "variable size fields overflow header" }, + { E, "invalid UTF-8 in filename" }, + { E, "invalid UTF-8 in comment" }, + { E, "invalid Zip64 extra field" }, + { E, "invalid WinZip AES extra field" }, + { E, "garbage at end of extra fields" }, + { E, "extra field length is invalid" }, + { E, "file length in header doesn't match actual file length" }, +}; + +const int _zip_err_details_count = sizeof(_zip_err_details)/sizeof(_zip_err_details[0]); diff --git a/src/libzip/zip_error.c b/src/libzip/zip_error.c new file mode 100644 index 0000000..72a93a9 --- /dev/null +++ b/src/libzip/zip_error.c @@ -0,0 +1,156 @@ +/* + zip_error.c -- zip_error_t helper functions + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_error_code_system(const zip_error_t *error) { + return error->sys_err; +} + + +ZIP_EXTERN int +fs_zip_error_code_zip(const zip_error_t *error) { + return error->zip_err; +} + + +ZIP_EXTERN void +fs_zip_error_fini(zip_error_t *err) { + free(err->str); + err->str = NULL; +} + + +ZIP_EXTERN void +fs_zip_error_init(zip_error_t *err) { + err->zip_err = ZIP_ER_OK; + err->sys_err = 0; + err->str = NULL; +} + +ZIP_EXTERN void +fs_zip_error_init_with_code(zip_error_t *error, int ze) { + fs_zip_error_init(error); + error->zip_err = ze; + switch (zip_error_system_type(error)) { + case ZIP_ET_SYS: + case ZIP_ET_LIBZIP: + error->sys_err = errno; + break; + + default: + error->sys_err = 0; + break; + } +} + + +ZIP_EXTERN int +zip_error_system_type(const zip_error_t *error) { + if (error->zip_err < 0 || error->zip_err >= _zip_err_str_count) + return ZIP_ET_NONE; + + return _zip_err_str[error->zip_err].type; +} + + +void +_zip_error_clear(zip_error_t *err) { + if (err == NULL) + return; + + err->zip_err = ZIP_ER_OK; + err->sys_err = 0; +} + + +void +_zip_error_copy(zip_error_t *dst, const zip_error_t *src) { + if (dst == NULL) { + return; + } + + dst->zip_err = src->zip_err; + dst->sys_err = src->sys_err; +} + + +void +_zip_error_get(const zip_error_t *err, int *zep, int *sep) { + if (zep) + *zep = err->zip_err; + if (sep) { + if (zip_error_system_type(err) != ZIP_ET_NONE) + *sep = err->sys_err; + else + *sep = 0; + } +} + + +void +zip_error_set(zip_error_t *err, int ze, int se) { + if (err) { + err->zip_err = ze; + err->sys_err = se; + } +} + + +void +zip_error_set_from_source(zip_error_t *err, zip_source_t *src) { + if (src == NULL) { + zip_error_set(err, ZIP_ER_INVAL, 0); + return; + } + + _zip_error_copy(err, fs_zip_source_error(src)); +} + + +zip_int64_t +zip_error_to_data(const zip_error_t *error, void *data, zip_uint64_t length) { + int *e = (int *)data; + + if (length < sizeof(int) * 2) { + return -1; + } + + e[0] = fs_zip_error_code_zip(error); + e[1] = fs_zip_error_code_system(error); + return sizeof(int) * 2; +} diff --git a/src/libzip/zip_error_clear.c b/src/libzip/zip_error_clear.c new file mode 100644 index 0000000..84f9421 --- /dev/null +++ b/src/libzip/zip_error_clear.c @@ -0,0 +1,44 @@ +/* + fs_zip_error_clear.c -- clear zip error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN void +fs_zip_error_clear(zip_t *za) { + if (za == NULL) + return; + + _zip_error_clear(&za->error); +} diff --git a/src/libzip/zip_error_get.c b/src/libzip/zip_error_get.c new file mode 100644 index 0000000..eade426 --- /dev/null +++ b/src/libzip/zip_error_get.c @@ -0,0 +1,54 @@ +/* + zip_error_get.c -- get zip error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN void +zip_error_get(zip_t *za, int *zep, int *sep) { + _zip_error_get(&za->error, zep, sep); +} + + +ZIP_EXTERN zip_error_t * +fs_zip_get_error(zip_t *za) { + return &za->error; +} + + +ZIP_EXTERN zip_error_t * +fs_zip_file_get_error(zip_file_t *f) { + return &f->error; +} diff --git a/src/libzip/zip_error_get_sys_type.c b/src/libzip/zip_error_get_sys_type.c new file mode 100644 index 0000000..a22ffb0 --- /dev/null +++ b/src/libzip/zip_error_get_sys_type.c @@ -0,0 +1,45 @@ +/* + zip_error_get_sys_type.c -- return type of system error code + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN int +zip_error_get_sys_type(int ze) { + if (ze < 0 || ze >= _zip_err_str_count) { + return 0; + } + + return _zip_err_str[ze].type; +} diff --git a/src/libzip/zip_error_strerror.c b/src/libzip/zip_error_strerror.c new file mode 100644 index 0000000..5519dc7 --- /dev/null +++ b/src/libzip/zip_error_strerror.c @@ -0,0 +1,128 @@ +/* + zip_error_sterror.c -- get string representation of struct zip_error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include +#include + +#include "zipint.h" + +ZIP_EXTERN const char * +zip_error_strerror(zip_error_t *err) { + const char *zip_error_string, *system_error_string; + char *s; + char *system_error_buffer = NULL; + + fs_zip_error_fini(err); + + if (err->zip_err < 0 || err->zip_err >= _zip_err_str_count) { + system_error_buffer = (char *)malloc(128); + snprintf_s(system_error_buffer, 128, "Unknown error %d", err->zip_err); + system_error_buffer[128 - 1] = '\0'; /* make sure string is NUL-terminated */ + zip_error_string = NULL; + system_error_string = system_error_buffer; + } + else { + zip_error_string = _zip_err_str[err->zip_err].description; + + switch (_zip_err_str[err->zip_err].type) { + case ZIP_ET_SYS: { + size_t len = strerrorlen_s(err->sys_err) + 1; + system_error_buffer = malloc(len); + strerror_s(system_error_buffer, len, err->sys_err); + system_error_string = system_error_buffer; + break; + } + + case ZIP_ET_ZLIB: + system_error_string = zng_zError(err->sys_err); + break; + + case ZIP_ET_LIBZIP: { + zip_uint8_t error = GET_ERROR_FROM_DETAIL(err->sys_err); + int index = GET_INDEX_FROM_DETAIL(err->sys_err); + + if (error == 0) { + system_error_string = NULL; + } + else if (error >= _zip_err_details_count) { + system_error_buffer = (char *)malloc(128); + snprintf_s(system_error_buffer, 128, "invalid detail error %u", error); + system_error_buffer[128 - 1] = '\0'; /* make sure string is NUL-terminated */ + system_error_string = system_error_buffer; + } + else if (_zip_err_details[error].type == ZIP_DETAIL_ET_ENTRY && index < MAX_DETAIL_INDEX) { + system_error_buffer = (char *)malloc(128); + snprintf_s(system_error_buffer, 128, "entry %d: %s", index, _zip_err_details[error].description); + system_error_buffer[128 - 1] = '\0'; /* make sure string is NUL-terminated */ + system_error_string = system_error_buffer; + } + else { + system_error_string = _zip_err_details[error].description; + } + break; + } + + default: + system_error_string = NULL; + } + } + + if (system_error_string == NULL) { + free(system_error_buffer); + return zip_error_string; + } + else { + size_t length = strlen(system_error_string); + if (zip_error_string) { + size_t length_error = strlen(zip_error_string); + if (length + length_error + 2 < length) { + free(system_error_buffer); + return _zip_err_str[ZIP_ER_MEMORY].description; + } + length += length_error + 2; + } + if (length == SIZE_MAX || (s = (char *)malloc(length + 1)) == NULL) { + free(system_error_buffer); + return _zip_err_str[ZIP_ER_MEMORY].description; + } + + snprintf_s(s, length + 1, "%s%s%s", (zip_error_string ? zip_error_string : ""), (zip_error_string ? ": " : ""), system_error_string); + err->str = s; + + free(system_error_buffer); + return s; + } +} diff --git a/src/libzip/zip_error_to_str.c b/src/libzip/zip_error_to_str.c new file mode 100644 index 0000000..46677d0 --- /dev/null +++ b/src/libzip/zip_error_to_str.c @@ -0,0 +1,58 @@ +/* + zip_error_to_str.c -- get string representation of zip error code + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN int +zip_error_to_str(char *buf, zip_uint64_t len, int ze, int se) { + zip_error_t error; + const char *error_string; + int ret; + + fs_zip_error_init(&error); + zip_error_set(&error, ze, se); + + error_string = zip_error_strerror(&error); + + ret = snprintf_s(buf, ZIP_MIN(len, SIZE_MAX), error_string, strlen(error_string)); + + fs_zip_error_fini(&error); + + return ret; +} diff --git a/src/libzip/zip_extra_field.c b/src/libzip/zip_extra_field.c new file mode 100644 index 0000000..374e881 --- /dev/null +++ b/src/libzip/zip_extra_field.c @@ -0,0 +1,427 @@ +/* + zip_extra_field.c -- manipulate extra fields + Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "zipint.h" + + +zip_extra_field_t * +_zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error) { + zip_extra_field_t *head, *prev, *def; + + head = prev = NULL; + + while (ef) { + if ((def = _zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + _zip_ef_free(head); + return NULL; + } + + if (head == NULL) + head = def; + if (prev) + prev->next = def; + prev = def; + + ef = ef->next; + } + + return head; +} + + +zip_extra_field_t * +_zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags) { + zip_extra_field_t *head, *prev; + int i; + + i = 0; + head = ef; + prev = NULL; + for (; ef; ef = (prev ? prev->next : head)) { + if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) { + if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) { + ef->flags &= ~(flags & ZIP_EF_BOTH); + if ((ef->flags & ZIP_EF_BOTH) == 0) { + if (prev) + prev->next = ef->next; + else + head = ef->next; + ef->next = NULL; + _zip_ef_free(ef); + + if (id_idx == ZIP_EXTRA_FIELD_ALL) + continue; + } + } + + i++; + if (i > id_idx) + break; + } + prev = ef; + } + + return head; +} + + +void +_zip_ef_free(zip_extra_field_t *ef) { + zip_extra_field_t *ef2; + + while (ef) { + ef2 = ef->next; + free(ef->data); + free(ef); + ef = ef2; + } +} + + +const zip_uint8_t * +_zip_ef_get_by_id(const zip_extra_field_t *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, zip_error_t *error) { + static const zip_uint8_t empty[1] = {'\0'}; + + int i; + + i = 0; + for (; ef; ef = ef->next) { + if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) { + if (i < id_idx) { + i++; + continue; + } + + if (lenp) + *lenp = ef->size; + if (ef->size > 0) + return ef->data; + else + return empty; + } + } + + zip_error_set(error, ZIP_ER_NOENT, 0); + return NULL; +} + + +zip_extra_field_t * +_zip_ef_merge(zip_extra_field_t *to, zip_extra_field_t *from) { + zip_extra_field_t *ef2, *tt, *tail; + int duplicate; + + if (to == NULL) + return from; + + for (tail = to; tail->next; tail = tail->next) + ; + + for (; from; from = ef2) { + ef2 = from->next; + + duplicate = 0; + for (tt = to; tt; tt = tt->next) { + if (tt->id == from->id && tt->size == from->size && (tt->size == 0 || memcmp(tt->data, from->data, tt->size) == 0)) { + tt->flags |= (from->flags & ZIP_EF_BOTH); + duplicate = 1; + break; + } + } + + from->next = NULL; + if (duplicate) + _zip_ef_free(from); + else + tail = tail->next = from; + } + + return to; +} + + +zip_extra_field_t * +_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags) { + zip_extra_field_t *ef; + + if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL) + return NULL; + + ef->next = NULL; + ef->flags = flags; + ef->id = id; + ef->size = size; + if (size > 0) { + if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) { + free(ef); + return NULL; + } + } + else + ef->data = NULL; + + return ef; +} + + +bool +_zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error) { + zip_buffer_t *buffer; + zip_extra_field_t *ef, *ef2, *ef_head; + + if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + ef_head = ef = NULL; + + while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) { + zip_uint16_t fid, flen; + zip_uint8_t *ef_data; + + fid = _zip_buffer_get_16(buffer); + flen = _zip_buffer_get_16(buffer); + ef_data = _zip_buffer_get(buffer, flen); + + if (ef_data == NULL) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH); + _zip_buffer_free(buffer); + _zip_ef_free(ef_head); + return false; + } + + if ((ef2 = _zip_ef_new(fid, flen, ef_data, flags)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + _zip_buffer_free(buffer); + _zip_ef_free(ef_head); + return false; + } + + if (ef_head) { + ef->next = ef2; + ef = ef2; + } + else + ef_head = ef = ef2; + } + + if (!_zip_buffer_eof(buffer)) { + /* Android APK files align stored file data with padding in extra fields; ignore. */ + /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */ + /* buffer is at most 64k long, so this can't overflow. */ + size_t glen = _zip_buffer_left(buffer); + zip_uint8_t *garbage; + garbage = _zip_buffer_get(buffer, glen); + if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", (size_t)glen) != 0) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE); + _zip_buffer_free(buffer); + _zip_ef_free(ef_head); + return false; + } + } + + _zip_buffer_free(buffer); + + if (ef_head_p) { + *ef_head_p = ef_head; + } + else { + _zip_ef_free(ef_head); + } + + return true; +} + + +zip_extra_field_t * +_zip_ef_remove_internal(zip_extra_field_t *ef) { + zip_extra_field_t *ef_head; + zip_extra_field_t *prev, *next; + + ef_head = ef; + prev = NULL; + + while (ef) { + if (ZIP_EF_IS_INTERNAL(ef->id)) { + next = ef->next; + if (ef_head == ef) + ef_head = next; + ef->next = NULL; + _zip_ef_free(ef); + if (prev) + prev->next = next; + ef = next; + } + else { + prev = ef; + ef = ef->next; + } + } + + return ef_head; +} + + +zip_uint16_t +_zip_ef_size(const zip_extra_field_t *ef, zip_flags_t flags) { + zip_uint16_t size; + + size = 0; + for (; ef; ef = ef->next) { + if (ef->flags & flags & ZIP_EF_BOTH) + size = (zip_uint16_t)(size + 4 + ef->size); + } + + return size; +} + + +int +_zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags) { + zip_uint8_t b[4]; + zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b)); + + if (buffer == NULL) { + return -1; + } + + for (; ef; ef = ef->next) { + if (ef->flags & flags & ZIP_EF_BOTH) { + _zip_buffer_set_offset(buffer, 0); + _zip_buffer_put_16(buffer, ef->id); + _zip_buffer_put_16(buffer, ef->size); + if (!_zip_buffer_ok(buffer)) { + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + _zip_buffer_free(buffer); + return -1; + } + if (_zip_write(za, b, 4) < 0) { + _zip_buffer_free(buffer); + return -1; + } + if (ef->size > 0) { + if (_zip_write(za, ef->data, ef->size) < 0) { + _zip_buffer_free(buffer); + return -1; + } + } + } + } + + _zip_buffer_free(buffer); + return 0; +} + + +int +_zip_read_local_ef(zip_t *za, zip_uint64_t idx) { + zip_entry_t *e; + unsigned char b[4]; + zip_buffer_t *buffer; + zip_uint16_t fname_len, ef_len; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + e = za->entry + idx; + + if (e->orig == NULL || e->orig->local_extra_fields_read) + return 0; + + if (e->orig->offset + 26 > ZIP_INT64_MAX) { + zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG); + return -1; + } + + if (fs_zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + + if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) { + return -1; + } + + fname_len = _zip_buffer_get_16(buffer); + ef_len = _zip_buffer_get_16(buffer); + + if (!_zip_buffer_eof(buffer)) { + _zip_buffer_free(buffer); + zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return -1; + } + + _zip_buffer_free(buffer); + + if (ef_len > 0) { + zip_extra_field_t *ef; + zip_uint8_t *ef_raw; + + if (fs_zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) { + zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error); + + if (ef_raw == NULL) + return -1; + + if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) { + free(ef_raw); + return -1; + } + free(ef_raw); + + if (ef) { + ef = _zip_ef_remove_internal(ef); + e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef); + } + } + + e->orig->local_extra_fields_read = 1; + + if (e->changes && e->changes->local_extra_fields_read == 0) { + e->changes->extra_fields = e->orig->extra_fields; + e->changes->local_extra_fields_read = 1; + } + + return 0; +} diff --git a/src/libzip/zip_extra_field_api.c b/src/libzip/zip_extra_field_api.c new file mode 100644 index 0000000..58a296e --- /dev/null +++ b/src/libzip/zip_extra_field_api.c @@ -0,0 +1,367 @@ +/* + zip_extra_field_api.c -- public extra fields API functions + Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_file_extra_field_delete(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags) { + zip_dirent_t *de; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_get_dirent(za, idx, 0, NULL) == NULL) + return -1; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) + return -1; + + de = za->entry[idx].changes; + + de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags); + return 0; +} + + +ZIP_EXTERN int +fs_zip_file_extra_field_delete_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags) { + zip_dirent_t *de; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_get_dirent(za, idx, 0, NULL) == NULL) + return -1; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) + return -1; + + de = za->entry[idx].changes; + + de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags); + return 0; +} + + +ZIP_EXTERN const zip_uint8_t * +fs_zip_file_extra_field_get(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp, zip_flags_t flags) { + static const zip_uint8_t empty[1] = {'\0'}; + + zip_dirent_t *de; + zip_extra_field_t *ef; + int i; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return NULL; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return NULL; + + i = 0; + for (ef = de->extra_fields; ef; ef = ef->next) { + if (ef->flags & flags & ZIP_EF_BOTH) { + if (i < ef_idx) { + i++; + continue; + } + + if (idp) + *idp = ef->id; + if (lenp) + *lenp = ef->size; + if (ef->size > 0) + return ef->data; + else + return empty; + } + } + + zip_error_set(&za->error, ZIP_ER_NOENT, 0); + return NULL; +} + + +ZIP_EXTERN const zip_uint8_t * +fs_zip_file_extra_field_get_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags) { + zip_dirent_t *de; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return NULL; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return NULL; + + return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error); +} + + +ZIP_EXTERN zip_int16_t +fs_zip_file_extra_fields_count(zip_t *za, zip_uint64_t idx, zip_flags_t flags) { + zip_dirent_t *de; + zip_extra_field_t *ef; + zip_uint16_t n; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return -1; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return -1; + + n = 0; + for (ef = de->extra_fields; ef; ef = ef->next) + if (ef->flags & flags & ZIP_EF_BOTH) + n++; + + return (zip_int16_t)n; +} + + +ZIP_EXTERN zip_int16_t +fs_zip_file_extra_fields_count_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_flags_t flags) { + zip_dirent_t *de; + zip_extra_field_t *ef; + zip_uint16_t n; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return -1; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return -1; + + n = 0; + for (ef = de->extra_fields; ef; ef = ef->next) + if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) + n++; + + return (zip_int16_t)n; +} + + +ZIP_EXTERN int +fs_zip_file_extra_field_set(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags) { + zip_dirent_t *de; + zip_uint16_t ls, cs; + zip_extra_field_t *ef, *ef_prev, *ef_new; + int i, found, new_len; + + if ((flags & ZIP_EF_BOTH) == 0) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_get_dirent(za, idx, 0, NULL) == NULL) + return -1; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (ZIP_EF_IS_INTERNAL(ef_id)) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_file_extra_field_prepare_for_change(za, idx) < 0) + return -1; + + de = za->entry[idx].changes; + + ef = de->extra_fields; + ef_prev = NULL; + i = 0; + found = 0; + + for (; ef; ef = ef->next) { + if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) { + if (i == ef_idx) { + found = 1; + break; + } + i++; + } + ef_prev = ef; + } + + if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (flags & ZIP_EF_LOCAL) + ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL); + else + ls = 0; + if (flags & ZIP_EF_CENTRAL) + cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL); + else + cs = 0; + + new_len = ls > cs ? ls : cs; + if (found) + new_len -= ef->size + 4; + new_len += len + 4; + + if (new_len > ZIP_UINT16_MAX) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((ef_new = _zip_ef_new(ef_id, len, data, flags)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + if (found) { + if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) { + ef_new->next = ef->next; + ef->next = NULL; + _zip_ef_free(ef); + if (ef_prev) + ef_prev->next = ef_new; + else + de->extra_fields = ef_new; + } + else { + ef->flags &= ~(flags & ZIP_EF_BOTH); + ef_new->next = ef->next; + ef->next = ef_new; + } + } + else if (ef_prev) { + ef_new->next = ef_prev->next; + ef_prev->next = ef_new; + } + else + de->extra_fields = ef_new; + + return 0; +} + + +int +_zip_file_extra_field_prepare_for_change(zip_t *za, zip_uint64_t idx) { + zip_entry_t *e; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + e = za->entry + idx; + + if (e->changes && (e->changes->changed & ZIP_DIRENT_EXTRA_FIELD)) + return 0; + + if (e->orig) { + if (_zip_read_local_ef(za, idx) < 0) + return -1; + } + + if (e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + if (e->orig && e->orig->extra_fields) { + if ((e->changes->extra_fields = _zip_ef_clone(e->orig->extra_fields, &za->error)) == NULL) + return -1; + } + e->changes->changed |= ZIP_DIRENT_EXTRA_FIELD; + + return 0; +} diff --git a/src/libzip/zip_fclose.c b/src/libzip/zip_fclose.c new file mode 100644 index 0000000..06387b6 --- /dev/null +++ b/src/libzip/zip_fclose.c @@ -0,0 +1,54 @@ +/* + fs_zip_fclose.c -- close file in zip archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_fclose(zip_file_t *zf) { + int ret; + + if (zf->src) + zip_source_free(zf->src); + + ret = 0; + if (zf->error.zip_err) + ret = zf->error.zip_err; + + fs_zip_error_fini(&zf->error); + free(zf); + return ret; +} diff --git a/src/libzip/zip_fdopen.c b/src/libzip/zip_fdopen.c new file mode 100644 index 0000000..735f49e --- /dev/null +++ b/src/libzip/zip_fdopen.c @@ -0,0 +1,91 @@ +/* + fs_zip_fdopen.c -- open read-only archive from file descriptor + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" +#ifdef HAVE_UNISTD_H +#include +#endif + + +ZIP_EXTERN zip_t * +fs_zip_fdopen(int fd_orig, int _flags, int *zep) { + int fd; + FILE *fp; + zip_t *za; + zip_source_t *src; + struct zip_error error; + + if (_flags < 0 || (_flags & ~(ZIP_CHECKCONS | ZIP_RDONLY))) { + _zip_set_open_error(zep, NULL, ZIP_ER_INVAL); + return NULL; + } + +#ifndef ENABLE_FDOPEN + _zip_set_open_error(zep, NULL, ZIP_ER_OPNOTSUPP); + return NULL; +#else + /* We dup() here to avoid messing with the passed in fd. + We could not restore it to the original state in case of error. */ + + if ((fd = dup(fd_orig)) < 0) { + _zip_set_open_error(zep, NULL, ZIP_ER_OPEN); + return NULL; + } + + if ((fp = fdopen(fd, "rb")) == NULL) { + close(fd); + _zip_set_open_error(zep, NULL, ZIP_ER_OPEN); + return NULL; + } + + fs_zip_error_init(&error); + if ((src = fs_zip_source_filep_create(fp, 0, -1, &error)) == NULL) { + fclose(fp); + _zip_set_open_error(zep, &error, 0); + fs_zip_error_fini(&error); + return NULL; + } + + if ((za = fs_zip_open_from_source(src, _flags, &error)) == NULL) { + zip_source_free(src); + _zip_set_open_error(zep, &error, 0); + fs_zip_error_fini(&error); + return NULL; + } + + fs_zip_error_fini(&error); + close(fd_orig); + return za; +#endif +} diff --git a/src/libzip/zip_file_add.c b/src/libzip/zip_file_add.c new file mode 100644 index 0000000..d6db10a --- /dev/null +++ b/src/libzip/zip_file_add.c @@ -0,0 +1,52 @@ +/* + fs_zip_file_add.c -- add file via callback function + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +/* + NOTE: Return type is signed so we can return -1 on error. + The index can not be larger than ZIP_INT64_MAX since the size + of the central directory cannot be larger than + ZIP_UINT64_MAX, and each entry is larger than 2 bytes. +*/ + +ZIP_EXTERN zip_int64_t +fs_zip_file_add(zip_t *za, const char *name, zip_source_t *source, zip_flags_t flags) { + if (name == NULL || source == NULL) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_file_replace(za, ZIP_UINT64_MAX, name, source, flags); +} diff --git a/src/libzip/zip_file_error_clear.c b/src/libzip/zip_file_error_clear.c new file mode 100644 index 0000000..95920b2 --- /dev/null +++ b/src/libzip/zip_file_error_clear.c @@ -0,0 +1,44 @@ +/* + fs_zip_file_error_clear.c -- clear zip file error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN void +fs_zip_file_error_clear(zip_file_t *zf) { + if (zf == NULL) + return; + + _zip_error_clear(&zf->error); +} diff --git a/src/libzip/zip_file_error_get.c b/src/libzip/zip_file_error_get.c new file mode 100644 index 0000000..b93117b --- /dev/null +++ b/src/libzip/zip_file_error_get.c @@ -0,0 +1,41 @@ +/* + zip_file_error_get.c -- get zip file error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN void +zip_file_error_get(zip_file_t *zf, int *zep, int *sep) { + _zip_error_get(&zf->error, zep, sep); +} diff --git a/src/libzip/zip_file_get_comment.c b/src/libzip/zip_file_get_comment.c new file mode 100644 index 0000000..a6b5c3d --- /dev/null +++ b/src/libzip/zip_file_get_comment.c @@ -0,0 +1,55 @@ +/* + fs_zip_file_get_comment.c -- get file comment + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +/* lenp is 32 bit because converted comment can be longer than ZIP_UINT16_MAX */ + +ZIP_EXTERN const char * +fs_zip_file_get_comment(zip_t *za, zip_uint64_t idx, zip_uint32_t *lenp, zip_flags_t flags) { + zip_dirent_t *de; + zip_uint32_t len; + const zip_uint8_t *str; + + if ((de = _zip_get_dirent(za, idx, flags, NULL)) == NULL) + return NULL; + + if ((str = _zip_string_get(de->comment, &len, flags, &za->error)) == NULL) + return NULL; + + if (lenp) + *lenp = len; + + return (const char *)str; +} diff --git a/src/libzip/zip_file_get_external_attributes.c b/src/libzip/zip_file_get_external_attributes.c new file mode 100644 index 0000000..1da8bbf --- /dev/null +++ b/src/libzip/zip_file_get_external_attributes.c @@ -0,0 +1,50 @@ +/* + fs_zip_file_get_external_attributes.c -- get opsys/external attributes + Copyright (C) 2013-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipint.h" + +int +fs_zip_file_get_external_attributes(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t *opsys, zip_uint32_t *attributes) { + zip_dirent_t *de; + + if ((de = _zip_get_dirent(za, idx, flags, NULL)) == NULL) + return -1; + + if (opsys) + *opsys = (zip_uint8_t)((de->version_madeby >> 8) & 0xff); + + if (attributes) + *attributes = de->ext_attrib; + + return 0; +} diff --git a/src/libzip/zip_file_get_offset.c b/src/libzip/zip_file_get_offset.c new file mode 100644 index 0000000..e4d39fd --- /dev/null +++ b/src/libzip/zip_file_get_offset.c @@ -0,0 +1,117 @@ +/* + zip_file_get_offset.c -- get offset of file data in archive. + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include "zipint.h" + + +/* _zip_file_get_offset(za, ze): + Returns the offset of the file data for entry ze. + + On error, fills in za->error and returns 0. +*/ + +zip_uint64_t +_zip_file_get_offset(const zip_t *za, zip_uint64_t idx, zip_error_t *error) { + zip_uint64_t offset; + zip_int32_t size; + + if (za->entry[idx].orig == NULL) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return 0; + } + + offset = za->entry[idx].orig->offset; + + if (fs_zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { + zip_error_set_from_source(error, za->src); + return 0; + } + + /* TODO: cache? */ + if ((size = _zip_dirent_size(za->src, ZIP_EF_LOCAL, error)) < 0) + return 0; + + if (offset + (zip_uint32_t)size > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return 0; + } + + return offset + (zip_uint32_t)size; +} + +zip_uint64_t +_zip_file_get_end(const zip_t *za, zip_uint64_t index, zip_error_t *error) { + zip_uint64_t offset; + zip_dirent_t *entry; + + if ((offset = _zip_file_get_offset(za, index, error)) == 0) { + return 0; + } + + entry = za->entry[index].orig; + + if (offset + entry->comp_size < offset || offset + entry->comp_size > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return 0; + } + offset += entry->comp_size; + + if (entry->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { + zip_uint8_t buf[4]; + if (fs_zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { + zip_error_set_from_source(error, za->src); + return 0; + } + if (fs_zip_source_read(za->src, buf, 4) != 4) { + zip_error_set_from_source(error, za->src); + return 0; + } + if (memcmp(buf, DATADES_MAGIC, 4) == 0) { + offset += 4; + } + offset += 12; + if (_zip_dirent_needs_zip64(entry, 0)) { + offset += 8; + } + if (offset > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return 0; + } + } + + return offset; +} diff --git a/src/libzip/zip_file_rename.c b/src/libzip/zip_file_rename.c new file mode 100644 index 0000000..9a0b422 --- /dev/null +++ b/src/libzip/zip_file_rename.c @@ -0,0 +1,67 @@ +/* + fs_zip_file_rename.c -- rename file in zip archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_file_rename(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { + const char *old_name; + int old_is_dir, new_is_dir; + + if (idx >= za->nentry || (name != NULL && strlen(name) > ZIP_UINT16_MAX)) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + + if ((old_name = fs_zip_get_name(za, idx, 0)) == NULL) + return -1; + + new_is_dir = (name != NULL && name[strlen(name) - 1] == '/'); + old_is_dir = (old_name[strlen(old_name) - 1] == '/'); + + if (new_is_dir != old_is_dir) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_set_name(za, idx, name, flags); +} diff --git a/src/libzip/zip_file_replace.c b/src/libzip/zip_file_replace.c new file mode 100644 index 0000000..1581696 --- /dev/null +++ b/src/libzip/zip_file_replace.c @@ -0,0 +1,105 @@ +/* + fs_zip_file_replace.c -- replace file via callback function + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_file_replace(zip_t *za, zip_uint64_t idx, zip_source_t *source, zip_flags_t flags) { + if (idx >= za->nentry || source == NULL) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_file_replace(za, idx, NULL, source, flags) == -1) + return -1; + + return 0; +} + + +/* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ + +zip_int64_t +_zip_file_replace(zip_t *za, zip_uint64_t idx, const char *name, zip_source_t *source, zip_flags_t flags) { + zip_uint64_t za_nentry_prev; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + + za_nentry_prev = za->nentry; + if (idx == ZIP_UINT64_MAX) { + zip_int64_t i = -1; + + if (flags & ZIP_FL_OVERWRITE) + i = _zip_name_locate(za, name, flags, NULL); + + if (i == -1) { + /* create and use new entry, used by zip_add */ + if ((i = _zip_add_entry(za)) < 0) + return -1; + } + idx = (zip_uint64_t)i; + } + + if (name && _zip_set_name(za, idx, name, flags) != 0) { + if (za->nentry != za_nentry_prev) { + _zip_entry_finalize(za->entry + idx); + za->nentry = za_nentry_prev; + } + return -1; + } + + /* does not change any name related data, so we can do it here; + * needed for a double add of the same file name */ + _zip_unchange_data(za->entry + idx); + + if (za->entry[idx].orig != NULL && (za->entry[idx].changes == NULL || (za->entry[idx].changes->changed & ZIP_DIRENT_COMP_METHOD) == 0)) { + if (za->entry[idx].changes == NULL) { + if ((za->entry[idx].changes = _zip_dirent_clone(za->entry[idx].orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + za->entry[idx].changes->comp_method = ZIP_CM_REPLACED_DEFAULT; + za->entry[idx].changes->changed |= ZIP_DIRENT_COMP_METHOD; + } + + za->entry[idx].source = source; + + return (zip_int64_t)idx; +} diff --git a/src/libzip/zip_file_set_comment.c b/src/libzip/zip_file_set_comment.c new file mode 100644 index 0000000..610da00 --- /dev/null +++ b/src/libzip/zip_file_set_comment.c @@ -0,0 +1,105 @@ +/* + fs_zip_file_set_comment.c -- set comment for file in archive + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_file_set_comment(zip_t *za, zip_uint64_t idx, const char *comment, zip_uint16_t len, zip_flags_t flags) { + zip_entry_t *e; + zip_string_t *cstr; + int changed; + + if (_zip_get_dirent(za, idx, 0, NULL) == NULL) + return -1; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (len > 0 && comment == NULL) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (len > 0) { + if ((cstr = _zip_string_new((const zip_uint8_t *)comment, len, flags, &za->error)) == NULL) + return -1; + if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) + cstr->encoding = ZIP_ENCODING_UTF8_KNOWN; + } + else + cstr = NULL; + + e = za->entry + idx; + + if (e->changes) { + _zip_string_free(e->changes->comment); + e->changes->comment = NULL; + e->changes->changed &= ~ZIP_DIRENT_COMMENT; + } + + if (e->orig && e->orig->comment) + changed = !_zip_string_equal(e->orig->comment, cstr); + else + changed = (cstr != NULL); + + if (changed) { + if (e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + _zip_string_free(cstr); + return -1; + } + } + e->changes->comment = cstr; + e->changes->changed |= ZIP_DIRENT_COMMENT; + } + else { + _zip_string_free(cstr); + if (e->changes && e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + } + + return 0; +} diff --git a/src/libzip/zip_file_set_encryption.c b/src/libzip/zip_file_set_encryption.c new file mode 100644 index 0000000..cc53452 --- /dev/null +++ b/src/libzip/zip_file_set_encryption.c @@ -0,0 +1,120 @@ +/* + fs_zip_file_set_encryption.c -- set encryption for file in archive + Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +#include +#include + +ZIP_EXTERN int +fs_zip_file_set_encryption(zip_t *za, zip_uint64_t idx, zip_uint16_t method, const char *password) { + zip_entry_t *e; + zip_uint16_t old_method; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (method != ZIP_EM_NONE && _zip_get_encryption_implementation(method, ZIP_CODEC_ENCODE) == NULL) { + zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); + return -1; + } + + e = za->entry + idx; + + old_method = (e->orig == NULL ? ZIP_EM_NONE : e->orig->encryption_method); + + if (method == old_method && password == NULL) { + if (e->changes) { + if (e->changes->changed & ZIP_DIRENT_PASSWORD) { + _zip_crypto_clear(e->changes->password, strlen(e->changes->password)); + free(e->changes->password); + e->changes->password = (e->orig == NULL ? NULL : e->orig->password); + } + e->changes->changed &= ~(ZIP_DIRENT_ENCRYPTION_METHOD | ZIP_DIRENT_PASSWORD); + if (e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + } + } + else { + char *our_password = NULL; + + if (password) { + if ((our_password = strdup(password)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + if (e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + if (our_password) { + _zip_crypto_clear(our_password, strlen(our_password)); + } + free(our_password); + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + e->changes->encryption_method = method; + e->changes->changed |= ZIP_DIRENT_ENCRYPTION_METHOD; + if (password) { + e->changes->password = our_password; + e->changes->changed |= ZIP_DIRENT_PASSWORD; + } + else { + if (e->changes->changed & ZIP_DIRENT_PASSWORD) { + _zip_crypto_clear(e->changes->password, strlen(e->changes->password)); + free(e->changes->password); + e->changes->password = e->orig ? e->orig->password : NULL; + e->changes->changed &= ~ZIP_DIRENT_PASSWORD; + } + } + } + + return 0; +} diff --git a/src/libzip/zip_file_set_external_attributes.c b/src/libzip/zip_file_set_external_attributes.c new file mode 100644 index 0000000..e09fb18 --- /dev/null +++ b/src/libzip/zip_file_set_external_attributes.c @@ -0,0 +1,86 @@ +/* + fs_zip_file_set_external_attributes.c -- set external attributes for entry + Copyright (C) 2013-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipint.h" + +ZIP_EXTERN int +fs_zip_file_set_external_attributes(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t opsys, zip_uint32_t attributes) { + zip_entry_t *e; + int changed; + zip_uint8_t unchanged_opsys; + zip_uint32_t unchanged_attributes; + + if (_zip_get_dirent(za, idx, 0, NULL) == NULL) + return -1; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + e = za->entry + idx; + + unchanged_opsys = (e->orig ? (zip_uint8_t)(e->orig->version_madeby >> 8) : (zip_uint8_t)ZIP_OPSYS_DEFAULT); + unchanged_attributes = e->orig ? e->orig->ext_attrib : ZIP_EXT_ATTRIB_DEFAULT; + + changed = (opsys != unchanged_opsys || attributes != unchanged_attributes); + + if (changed) { + if (e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + e->changes->version_madeby = (zip_uint16_t)((opsys << 8) | (e->changes->version_madeby & 0xff)); + e->changes->ext_attrib = attributes; + e->changes->changed |= ZIP_DIRENT_ATTRIBUTES; + } + else if (e->changes) { + e->changes->changed &= ~ZIP_DIRENT_ATTRIBUTES; + if (e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + else { + e->changes->version_madeby = (zip_uint16_t)((unchanged_opsys << 8) | (e->changes->version_madeby & 0xff)); + e->changes->ext_attrib = unchanged_attributes; + } + } + + return 0; +} diff --git a/src/libzip/zip_file_set_mtime.c b/src/libzip/zip_file_set_mtime.c new file mode 100644 index 0000000..e80c0b3 --- /dev/null +++ b/src/libzip/zip_file_set_mtime.c @@ -0,0 +1,77 @@ +/* + fs_zip_file_set_mtime.c -- set modification time of entry. + Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "zipint.h" + +ZIP_EXTERN int +fs_zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags) { + time_t mtime; + mtime = _zip_d2u_time(dtime, ddate); + return fs_zip_file_set_mtime(za, idx, mtime, flags); +} + +ZIP_EXTERN int +fs_zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags) { + zip_entry_t *e; + + if (_zip_get_dirent(za, idx, 0, NULL) == NULL) + return -1; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + e = za->entry + idx; + + if (e->orig != NULL && e->orig->encryption_method == ZIP_EM_TRAD_PKWARE && !ZIP_ENTRY_CHANGED(e, ZIP_DIRENT_ENCRYPTION_METHOD) && !ZIP_ENTRY_DATA_CHANGED(e)) { + zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + e->changes->last_mod = mtime; + e->changes->changed |= ZIP_DIRENT_LAST_MOD; + + return 0; +} diff --git a/src/libzip/zip_file_strerror.c b/src/libzip/zip_file_strerror.c new file mode 100644 index 0000000..c8a1c31 --- /dev/null +++ b/src/libzip/zip_file_strerror.c @@ -0,0 +1,41 @@ +/* + zip_file_sterror.c -- get string representation of zip file error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN const char * +fs_zip_file_strerror(zip_file_t *zf) { + return zip_error_strerror(&zf->error); +} diff --git a/src/libzip/zip_fopen.c b/src/libzip/zip_fopen.c new file mode 100644 index 0000000..7fb5327 --- /dev/null +++ b/src/libzip/zip_fopen.c @@ -0,0 +1,46 @@ +/* + fs_zip_fopen.c -- open file in zip archive for reading + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_file_t * +fs_zip_fopen(zip_t *za, const char *fname, zip_flags_t flags) { + zip_int64_t idx; + + if ((idx = fs_zip_name_locate(za, fname, flags)) < 0) + return NULL; + + return fs_zip_fopen_index_encrypted(za, (zip_uint64_t)idx, flags, za->default_password); +} diff --git a/src/libzip/zip_fopen_encrypted.c b/src/libzip/zip_fopen_encrypted.c new file mode 100644 index 0000000..275f666 --- /dev/null +++ b/src/libzip/zip_fopen_encrypted.c @@ -0,0 +1,46 @@ +/* + fs_zip_fopen_encrypted.c -- open file for reading with password + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_file_t * +fs_zip_fopen_encrypted(zip_t *za, const char *fname, zip_flags_t flags, const char *password) { + zip_int64_t idx; + + if ((idx = fs_zip_name_locate(za, fname, flags)) < 0) + return NULL; + + return fs_zip_fopen_index_encrypted(za, (zip_uint64_t)idx, flags, password); +} diff --git a/src/libzip/zip_fopen_index.c b/src/libzip/zip_fopen_index.c new file mode 100644 index 0000000..4962526 --- /dev/null +++ b/src/libzip/zip_fopen_index.c @@ -0,0 +1,41 @@ +/* + fs_zip_fopen_index.c -- open file in zip archive for reading by index + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_file_t * +fs_zip_fopen_index(zip_t *za, zip_uint64_t index, zip_flags_t flags) { + return fs_zip_fopen_index_encrypted(za, index, flags, za->default_password); +} diff --git a/src/libzip/zip_fopen_index_encrypted.c b/src/libzip/zip_fopen_index_encrypted.c new file mode 100644 index 0000000..cb590f0 --- /dev/null +++ b/src/libzip/zip_fopen_index_encrypted.c @@ -0,0 +1,85 @@ +/* + fs_zip_fopen_index_encrypted.c -- open file for reading by index w/ password + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include "zipint.h" + +static zip_file_t *_zip_file_new(zip_t *za); + + +ZIP_EXTERN zip_file_t * +fs_zip_fopen_index_encrypted(zip_t *za, zip_uint64_t index, zip_flags_t flags, const char *password) { + zip_file_t *zf; + zip_source_t *src; + + if (password != NULL && password[0] == '\0') { + password = NULL; + } + + if ((src = fs_zip_source_zip_file_create(za, index, flags, 0, -1, password, &za->error)) == NULL) + return NULL; + + if (fs_zip_source_open(src) < 0) { + zip_error_set_from_source(&za->error, src); + zip_source_free(src); + return NULL; + } + + if ((zf = _zip_file_new(za)) == NULL) { + zip_source_free(src); + return NULL; + } + + zf->src = src; + + return zf; +} + + +static zip_file_t * +_zip_file_new(zip_t *za) { + zip_file_t *zf; + + if ((zf = (zip_file_t *)malloc(sizeof(struct zip_file))) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + fs_zip_error_init(&zf->error); + zf->src = NULL; + + return zf; +} diff --git a/src/libzip/zip_fread.c b/src/libzip/zip_fread.c new file mode 100644 index 0000000..3870c6e --- /dev/null +++ b/src/libzip/zip_fread.c @@ -0,0 +1,63 @@ +/* + fs_zip_fread.c -- read from file + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_int64_t +fs_zip_fread(zip_file_t *zf, void *outbuf, zip_uint64_t toread) { + zip_int64_t n; + + if (!zf) + return -1; + + if (zf->error.zip_err != 0) + return -1; + + if (toread > ZIP_INT64_MAX) { + zip_error_set(&zf->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (toread == 0) { + return 0; + } + + if ((n = fs_zip_source_read(zf->src, outbuf, toread)) < 0) { + zip_error_set_from_source(&zf->error, zf->src); + return -1; + } + + return n; +} diff --git a/src/libzip/zip_fseek.c b/src/libzip/zip_fseek.c new file mode 100644 index 0000000..d610875 --- /dev/null +++ b/src/libzip/zip_fseek.c @@ -0,0 +1,61 @@ +/* + fs_zip_fseek.c -- seek in file + Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +ZIP_EXTERN zip_int8_t +fs_zip_fseek(zip_file_t *zf, zip_int64_t offset, int whence) { + if (!zf) + return -1; + + if (zf->error.zip_err != 0) + return -1; + + if (fs_zip_source_seek(zf->src, offset, whence) < 0) { + zip_error_set_from_source(&zf->error, zf->src); + return -1; + } + + return 0; +} + + +ZIP_EXTERN int +fs_zip_file_is_seekable(zip_file_t *zfile) { + if (!zfile) { + return -1; + } + + return fs_zip_source_is_seekable(zfile->src); +} diff --git a/src/libzip/zip_ftell.c b/src/libzip/zip_ftell.c new file mode 100644 index 0000000..d6faaad --- /dev/null +++ b/src/libzip/zip_ftell.c @@ -0,0 +1,54 @@ +/* + fs_zip_ftell.c -- tell position in file + Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +ZIP_EXTERN zip_int64_t +fs_zip_ftell(zip_file_t *zf) { + zip_int64_t res; + + if (!zf) + return -1; + + if (zf->error.zip_err != 0) + return -1; + + res = fs_zip_source_tell(zf->src); + if (res < 0) { + zip_error_set_from_source(&zf->error, zf->src); + return -1; + } + + return res; +} diff --git a/src/libzip/zip_get_archive_comment.c b/src/libzip/zip_get_archive_comment.c new file mode 100644 index 0000000..3d4158d --- /dev/null +++ b/src/libzip/zip_get_archive_comment.c @@ -0,0 +1,58 @@ +/* + fs_zip_get_archive_comment.c -- get archive comment + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN const char * +fs_zip_get_archive_comment(zip_t *za, int *lenp, zip_flags_t flags) { + zip_string_t *comment; + zip_uint32_t len; + const zip_uint8_t *str; + + if ((flags & ZIP_FL_UNCHANGED) || (za->comment_changes == NULL)) + comment = za->comment_orig; + else + comment = za->comment_changes; + + if ((str = _zip_string_get(comment, &len, flags, &za->error)) == NULL) + return NULL; + + if (lenp) + *lenp = (int)len; + + return (const char *)str; +} diff --git a/src/libzip/zip_get_archive_flag.c b/src/libzip/zip_get_archive_flag.c new file mode 100644 index 0000000..c9fe5c0 --- /dev/null +++ b/src/libzip/zip_get_archive_flag.c @@ -0,0 +1,45 @@ +/* + fs_zip_get_archive_flag.c -- get archive global flag + Copyright (C) 2008-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_get_archive_flag(zip_t *za, zip_flags_t flag, zip_flags_t flags) { + unsigned int fl; + + fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags; + + return (fl & flag) ? 1 : 0; +} diff --git a/src/libzip/zip_get_encryption_implementation.c b/src/libzip/zip_get_encryption_implementation.c new file mode 100644 index 0000000..d9947b3 --- /dev/null +++ b/src/libzip/zip_get_encryption_implementation.c @@ -0,0 +1,62 @@ +/* + zip_get_encryption_implementation.c -- get encryption implementation + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +zip_encryption_implementation +_zip_get_encryption_implementation(zip_uint16_t em, int operation) { + switch (em) { + case ZIP_EM_TRAD_PKWARE: +// return operation == ZIP_CODEC_DECODE ? zip_source_pkware_decode : zip_source_pkware_encode; + +#if defined(HAVE_CRYPTO) + case ZIP_EM_AES_128: + case ZIP_EM_AES_192: + case ZIP_EM_AES_256: +// return operation == ZIP_CODEC_DECODE ? zip_source_winzip_aes_decode : zip_source_winzip_aes_encode; +#endif + + default: + return NULL; + } +} + +ZIP_EXTERN int +fs_zip_encryption_method_supported(zip_uint16_t method, int encode) { + if (method == ZIP_EM_NONE) { + return 1; + } + return _zip_get_encryption_implementation(method, encode ? ZIP_CODEC_ENCODE : ZIP_CODEC_DECODE) != NULL; +} diff --git a/src/libzip/zip_get_file_comment.c b/src/libzip/zip_get_file_comment.c new file mode 100644 index 0000000..cb840b0 --- /dev/null +++ b/src/libzip/zip_get_file_comment.c @@ -0,0 +1,50 @@ +/* + zip_get_file_comment.c -- get file comment + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN const char * +zip_get_file_comment(zip_t *za, zip_uint64_t idx, int *lenp, int flags) { + zip_uint32_t len; + const char *s; + + if ((s = fs_zip_file_get_comment(za, idx, &len, (zip_flags_t)flags)) != NULL) { + if (lenp) + *lenp = (int)len; + } + + return s; +} diff --git a/src/libzip/zip_get_name.c b/src/libzip/zip_get_name.c new file mode 100644 index 0000000..44104e5 --- /dev/null +++ b/src/libzip/zip_get_name.c @@ -0,0 +1,58 @@ +/* + fs_zip_get_name.c -- get filename for a file in zip file + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN const char * +fs_zip_get_name(zip_t *za, zip_uint64_t idx, zip_flags_t flags) { + return _zip_get_name(za, idx, flags, &za->error); +} + + +const char * +_zip_get_name(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) { + zip_dirent_t *de; + const zip_uint8_t *str; + + if ((de = _zip_get_dirent(za, idx, flags, error)) == NULL) + return NULL; + + if ((str = _zip_string_get(de->filename, NULL, flags, error)) == NULL) + return NULL; + + return (const char *)str; +} diff --git a/src/libzip/zip_get_num_entries.c b/src/libzip/zip_get_num_entries.c new file mode 100644 index 0000000..a7673b9 --- /dev/null +++ b/src/libzip/zip_get_num_entries.c @@ -0,0 +1,52 @@ +/* + fs_zip_get_num_entries.c -- get number of entries in archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_int64_t +fs_zip_get_num_entries(zip_t *za, zip_flags_t flags) { + zip_uint64_t n; + + if (za == NULL) + return -1; + + if (flags & ZIP_FL_UNCHANGED) { + n = za->nentry; + while (n > 0 && za->entry[n - 1].orig == NULL) + --n; + return (zip_int64_t)n; + } + return (zip_int64_t)za->nentry; +} diff --git a/src/libzip/zip_get_num_files.c b/src/libzip/zip_get_num_files.c new file mode 100644 index 0000000..140e34f --- /dev/null +++ b/src/libzip/zip_get_num_files.c @@ -0,0 +1,51 @@ +/* + zip_get_num_files.c -- get number of files in archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" +#include + + +ZIP_EXTERN int +zip_get_num_files(zip_t *za) { + if (za == NULL) + return -1; + + if (za->nentry > INT_MAX) { + zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + return (int)za->nentry; +} diff --git a/src/libzip/zip_hash.c b/src/libzip/zip_hash.c new file mode 100644 index 0000000..d3a954e --- /dev/null +++ b/src/libzip/zip_hash.c @@ -0,0 +1,410 @@ +/* + zip_hash.c -- hash table string -> uint64 + Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipint.h" +#include +#include + +/* parameter for the string hash function */ +#define HASH_MULTIPLIER 33 +#define HASH_START 5381 + +/* hash table's fill ratio is kept between these by doubling/halfing its size as necessary */ +#define HASH_MAX_FILL .75 +#define HASH_MIN_FILL .01 + +/* but hash table size is kept between these */ +#define HASH_MIN_SIZE 256 +#define HASH_MAX_SIZE 0x80000000ul + +struct zip_hash_entry { + const zip_uint8_t *name; + zip_int64_t orig_index; + zip_int64_t current_index; + struct zip_hash_entry *next; + zip_uint32_t hash_value; +}; +typedef struct zip_hash_entry zip_hash_entry_t; + +struct zip_hash { + zip_uint32_t table_size; + zip_uint64_t nentries; + zip_hash_entry_t **table; +}; + + +/* free list of entries */ +static void +free_list(zip_hash_entry_t *entry) { + while (entry != NULL) { + zip_hash_entry_t *next = entry->next; + free(entry); + entry = next; + } +} + + +/* compute hash of string, full 32 bit value */ +static zip_uint32_t +hash_string(const zip_uint8_t *name) { + zip_uint64_t value = HASH_START; + + if (name == NULL) { + return 0; + } + + while (*name != 0) { + value = (zip_uint64_t)(((value * HASH_MULTIPLIER) + (zip_uint8_t)*name) % 0x100000000ul); + name++; + } + + return (zip_uint32_t)value; +} + + +/* resize hash table; new_size must be a power of 2, can be larger or smaller than current size */ +static bool +hash_resize(zip_hash_t *hash, zip_uint32_t new_size, zip_error_t *error) { + zip_hash_entry_t **new_table; + + if (new_size == hash->table_size) { + return true; + } + + if ((new_table = (zip_hash_entry_t **)calloc(new_size, sizeof(zip_hash_entry_t *))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + if (hash->nentries > 0) { + zip_uint32_t i; + + for (i = 0; i < hash->table_size; i++) { + zip_hash_entry_t *entry = hash->table[i]; + while (entry) { + zip_hash_entry_t *next = entry->next; + + zip_uint32_t new_index = entry->hash_value % new_size; + + entry->next = new_table[new_index]; + new_table[new_index] = entry; + + entry = next; + } + } + } + + free(hash->table); + hash->table = new_table; + hash->table_size = new_size; + + return true; +} + + +static zip_uint32_t +size_for_capacity(zip_uint64_t capacity) { + double needed_size = capacity / HASH_MAX_FILL; + zip_uint32_t v; + + if (needed_size > ZIP_UINT32_MAX) { + v = ZIP_UINT32_MAX; + } + else { + v = (zip_uint32_t)needed_size; + } + + if (v > HASH_MAX_SIZE) { + return HASH_MAX_SIZE; + } + + /* From Bit Twiddling Hacks by Sean Eron Anderson + (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2). */ + + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + return v; +} + + +zip_hash_t * +_zip_hash_new(zip_error_t *error) { + zip_hash_t *hash; + + if ((hash = (zip_hash_t *)malloc(sizeof(zip_hash_t))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + hash->table_size = 0; + hash->nentries = 0; + hash->table = NULL; + + return hash; +} + + +void +_zip_hash_free(zip_hash_t *hash) { + zip_uint32_t i; + + if (hash == NULL) { + return; + } + + if (hash->table != NULL) { + for (i = 0; i < hash->table_size; i++) { + if (hash->table[i] != NULL) { + free_list(hash->table[i]); + } + } + free(hash->table); + } + free(hash); +} + + +/* insert into hash, return error on existence or memory issues */ +bool +_zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error) { + zip_uint32_t hash_value, table_index; + zip_hash_entry_t *entry; + + if (hash == NULL || name == NULL || index > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return false; + } + + if (hash->table_size == 0) { + if (!hash_resize(hash, HASH_MIN_SIZE, error)) { + return false; + } + } + + hash_value = hash_string(name); + table_index = hash_value % hash->table_size; + + for (entry = hash->table[table_index]; entry != NULL; entry = entry->next) { + if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) { + if (((flags & ZIP_FL_UNCHANGED) && entry->orig_index != -1) || entry->current_index != -1) { + zip_error_set(error, ZIP_ER_EXISTS, 0); + return false; + } + else { + break; + } + } + } + + if (entry == NULL) { + if ((entry = (zip_hash_entry_t *)malloc(sizeof(zip_hash_entry_t))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + entry->name = name; + entry->next = hash->table[table_index]; + hash->table[table_index] = entry; + entry->hash_value = hash_value; + entry->orig_index = -1; + hash->nentries++; + if (hash->nentries > hash->table_size * HASH_MAX_FILL && hash->table_size < HASH_MAX_SIZE) { + if (!hash_resize(hash, hash->table_size * 2, error)) { + return false; + } + } + } + + if (flags & ZIP_FL_UNCHANGED) { + entry->orig_index = (zip_int64_t)index; + } + entry->current_index = (zip_int64_t)index; + + return true; +} + + +/* remove entry from hash, error if not found */ +bool +_zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *name, zip_error_t *error) { + zip_uint32_t hash_value, index; + zip_hash_entry_t *entry, *previous; + + if (hash == NULL || name == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return false; + } + + if (hash->nentries > 0) { + hash_value = hash_string(name); + index = hash_value % hash->table_size; + previous = NULL; + entry = hash->table[index]; + while (entry) { + if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) { + if (entry->orig_index == -1) { + if (previous) { + previous->next = entry->next; + } + else { + hash->table[index] = entry->next; + } + free(entry); + hash->nentries--; + if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) { + if (!hash_resize(hash, hash->table_size / 2, error)) { + return false; + } + } + } + else { + entry->current_index = -1; + } + return true; + } + previous = entry; + entry = entry->next; + } + } + + zip_error_set(error, ZIP_ER_NOENT, 0); + return false; +} + + +/* find value for entry in hash, -1 if not found */ +zip_int64_t +_zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error) { + zip_uint32_t hash_value, index; + zip_hash_entry_t *entry; + + if (hash == NULL || name == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + if (hash->nentries > 0) { + hash_value = hash_string(name); + index = hash_value % hash->table_size; + for (entry = hash->table[index]; entry != NULL; entry = entry->next) { + if (strcmp((const char *)name, (const char *)entry->name) == 0) { + if (flags & ZIP_FL_UNCHANGED) { + if (entry->orig_index != -1) { + return entry->orig_index; + } + } + else { + if (entry->current_index != -1) { + return entry->current_index; + } + } + break; + } + } + } + + zip_error_set(error, ZIP_ER_NOENT, 0); + return -1; +} + + +bool +_zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error) { + zip_uint32_t new_size; + + if (capacity == 0) { + return true; + } + + new_size = size_for_capacity(capacity); + + if (new_size <= hash->table_size) { + return true; + } + + if (!hash_resize(hash, new_size, error)) { + return false; + } + + return true; +} + + +bool +_zip_hash_revert(zip_hash_t *hash, zip_error_t *error) { + zip_uint32_t i; + zip_hash_entry_t *entry, *previous; + + for (i = 0; i < hash->table_size; i++) { + previous = NULL; + entry = hash->table[i]; + while (entry) { + if (entry->orig_index == -1) { + zip_hash_entry_t *p; + if (previous) { + previous->next = entry->next; + } + else { + hash->table[i] = entry->next; + } + p = entry; + entry = entry->next; + /* previous does not change */ + free(p); + hash->nentries--; + } + else { + entry->current_index = entry->orig_index; + previous = entry; + entry = entry->next; + } + } + } + + if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) { + zip_uint32_t new_size = hash->table_size / 2; + while (hash->nentries < new_size * HASH_MIN_FILL && new_size > HASH_MIN_SIZE) { + new_size /= 2; + } + if (!hash_resize(hash, new_size, error)) { + return false; + } + } + + return true; +} diff --git a/src/libzip/zip_io_util.c b/src/libzip/zip_io_util.c new file mode 100644 index 0000000..7c01c7d --- /dev/null +++ b/src/libzip/zip_io_util.c @@ -0,0 +1,146 @@ +/* + zip_io_util.c -- I/O helper functions + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "zipint.h" + +int +_zip_read(zip_source_t *src, zip_uint8_t *b, zip_uint64_t length, zip_error_t *error) { + zip_int64_t n; + + if (length > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return -1; + } + + if ((n = fs_zip_source_read(src, b, length)) < 0) { + zip_error_set_from_source(error, src); + return -1; + } + + if (n < (zip_int64_t)length) { + zip_error_set(error, ZIP_ER_EOF, 0); + return -1; + } + + return 0; +} + + +zip_uint8_t * +_zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error) { + zip_uint8_t *r; + + if (length == 0 && !nulp) { + return NULL; + } + + r = (zip_uint8_t *)malloc(length + (nulp ? 1 : 0)); + if (!r) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (buffer) { + zip_uint8_t *data = _zip_buffer_get(buffer, length); + + if (data == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + free(r); + return NULL; + } + (void)memcpy_s(r, length, data, length); + } + else { + if (_zip_read(src, r, length, error) < 0) { + free(r); + return NULL; + } + } + + if (nulp) { + zip_uint8_t *o; + /* replace any in-string NUL characters with spaces */ + r[length] = 0; + for (o = r; o < r + length; o++) + if (*o == '\0') + *o = ' '; + } + + return r; +} + + +zip_string_t * +_zip_read_string(zip_buffer_t *buffer, zip_source_t *src, zip_uint16_t len, bool nulp, zip_error_t *error) { + zip_uint8_t *raw; + zip_string_t *s; + + if ((raw = _zip_read_data(buffer, src, len, nulp, error)) == NULL) + return NULL; + + s = _zip_string_new(raw, len, ZIP_FL_ENC_GUESS, error); + free(raw); + return s; +} + + +int +_zip_write(zip_t *za, const void *data, zip_uint64_t length) { + zip_int64_t n; + + if ((n = fs_zip_source_write(za->src, data, length)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return -1; + } + if ((zip_uint64_t)n != length) { + zip_error_set(&za->error, ZIP_ER_WRITE, EINTR); + return -1; + } + + if (za->write_crc != NULL) { + zip_uint64_t position = 0; + while (position < length) { + zip_uint64_t nn = ZIP_MIN(UINT_MAX, length - position); + + *za->write_crc = (zip_uint32_t)zng_crc32(*za->write_crc, (const Bytef *)data + position, (uInt)nn); + position += nn; + } + } + + return 0; +} diff --git a/src/libzip/zip_libzip_version.c b/src/libzip/zip_libzip_version.c new file mode 100644 index 0000000..d8c28af --- /dev/null +++ b/src/libzip/zip_libzip_version.c @@ -0,0 +1,41 @@ +/* + fs_zip_libzip_version.c -- return run-time version of library + Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN const char * +fs_zip_libzip_version(void) { + return LIBZIP_VERSION; +} diff --git a/src/libzip/zip_memdup.c b/src/libzip/zip_memdup.c new file mode 100644 index 0000000..75d72c6 --- /dev/null +++ b/src/libzip/zip_memdup.c @@ -0,0 +1,56 @@ +/* + zip_memdup.c -- internal zip function, "strdup" with len + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "zipint.h" + + +void * +_zip_memdup(const void *mem, size_t len, zip_error_t *error) { + void *ret; + + if (len == 0) + return NULL; + + ret = malloc(len); + if (!ret) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + (void)memcpy_s(ret, len, mem, len); + + return ret; +} diff --git a/src/libzip/zip_name_locate.c b/src/libzip/zip_name_locate.c new file mode 100644 index 0000000..ca5a94e --- /dev/null +++ b/src/libzip/zip_name_locate.c @@ -0,0 +1,116 @@ +/* + fs_zip_name_locate.c -- get index by name + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +#include "zipint.h" + + +ZIP_EXTERN zip_int64_t +fs_zip_name_locate(zip_t *za, const char *fname, zip_flags_t flags) { + return _zip_name_locate(za, fname, flags, &za->error); +} + + +zip_int64_t +_zip_name_locate(zip_t *za, const char *fname, zip_flags_t flags, zip_error_t *error) { + int (*cmp)(const char *, const char *); + size_t fname_length; + zip_string_t *str = NULL; + const char *fn, *p; + zip_uint64_t i; + + if (za == NULL) { + return -1; + } + + if (fname == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + fname_length = strlen(fname); + + if (fname_length > ZIP_UINT16_MAX) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((flags & (ZIP_FL_ENC_UTF_8 | ZIP_FL_ENC_RAW)) == 0 && fname[0] != '\0') { + if ((str = _zip_string_new((const zip_uint8_t *)fname, (zip_uint16_t)strlen(fname), flags, error)) == NULL) { + return -1; + } + if ((fname = (const char *)_zip_string_get(str, NULL, 0, error)) == NULL) { + _zip_string_free(str); + return -1; + } + } + + if (flags & (ZIP_FL_NOCASE | ZIP_FL_NODIR | ZIP_FL_ENC_RAW | ZIP_FL_ENC_STRICT)) { + /* can't use hash table */ + cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; + + for (i = 0; i < za->nentry; i++) { + fn = _zip_get_name(za, i, flags, error); + + /* newly added (partially filled) entry or error */ + if (fn == NULL) + continue; + + if (flags & ZIP_FL_NODIR) { + p = strrchr(fn, '/'); + if (p) + fn = p + 1; + } + + if (cmp(fname, fn) == 0) { + _zip_error_clear(error); + _zip_string_free(str); + return (zip_int64_t)i; + } + } + + zip_error_set(error, ZIP_ER_NOENT, 0); + _zip_string_free(str); + return -1; + } + else { + zip_int64_t ret = _zip_hash_lookup(za->names, (const zip_uint8_t *)fname, flags, error); + _zip_string_free(str); + return ret; + } +} diff --git a/src/libzip/zip_new.c b/src/libzip/zip_new.c new file mode 100644 index 0000000..df78681 --- /dev/null +++ b/src/libzip/zip_new.c @@ -0,0 +1,73 @@ +/* + zip_new.c -- create and init struct zip + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +/* _zip_new: + creates a new zipfile struct, and sets the contents to zero; returns + the new struct. */ + +zip_t * +_zip_new(zip_error_t *error) { + zip_t *za; + + za = (zip_t *)malloc(sizeof(struct zip)); + if (!za) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if ((za->names = _zip_hash_new(error)) == NULL) { + free(za); + return NULL; + } + + za->src = NULL; + za->open_flags = 0; + fs_zip_error_init(&za->error); + za->flags = za->ch_flags = 0; + za->default_password = NULL; + za->comment_orig = za->comment_changes = NULL; + za->comment_changed = 0; + za->nentry = za->nentry_alloc = 0; + za->entry = NULL; + za->nopen_source = za->nopen_source_alloc = 0; + za->open_source = NULL; + za->progress = NULL; + + return za; +} diff --git a/src/libzip/zip_open.c b/src/libzip/zip_open.c new file mode 100644 index 0000000..6dd5271 --- /dev/null +++ b/src/libzip/zip_open.c @@ -0,0 +1,967 @@ +/* + fs_zip_open.c -- open zip archive by name + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include +#include + +#include "zipint.h" + +typedef enum { EXISTS_ERROR = -1, EXISTS_NOT = 0, EXISTS_OK } exists_t; +static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error); +static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error); +static void zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir); +static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len); +static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error); +static int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *); +static const unsigned char *_zip_memmem(const unsigned char *, size_t, const unsigned char *, size_t); +static zip_cdir_t *_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error); +static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error); +static zip_cdir_t *_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error); + + +//ZIP_EXTERN zip_t * +//fs_zip_open(const char *fn, int _flags, int *zep) { +// zip_t *za; +// zip_source_t *src; +// struct zip_error error; +// +// fs_zip_error_init(&error); +// if ((src = fs_zip_source_file_create(fn, 0, -1, &error)) == NULL) { +// _zip_set_open_error(zep, &error, 0); +// fs_zip_error_fini(&error); +// return NULL; +// } +// +// if ((za = fs_zip_open_from_source(src, _flags, &error)) == NULL) { +// zip_source_free(src); +// _zip_set_open_error(zep, &error, 0); +// fs_zip_error_fini(&error); +// return NULL; +// } +// +// fs_zip_error_fini(&error); +// return za; +//} + + +ZIP_EXTERN zip_t * +fs_zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error) { + unsigned int flags; + zip_int64_t supported; + exists_t exists; + + if (_flags < 0 || src == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + flags = (unsigned int)_flags; + + supported = zip_source_supports(src); + if ((supported & ZIP_SOURCE_SUPPORTS_SEEKABLE) != ZIP_SOURCE_SUPPORTS_SEEKABLE) { + zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); + return NULL; + } + if ((supported & ZIP_SOURCE_SUPPORTS_WRITABLE) != ZIP_SOURCE_SUPPORTS_WRITABLE) { + flags |= ZIP_RDONLY; + } + + if ((flags & (ZIP_RDONLY | ZIP_TRUNCATE)) == (ZIP_RDONLY | ZIP_TRUNCATE)) { + zip_error_set(error, ZIP_ER_RDONLY, 0); + return NULL; + } + + exists = _zip_file_exists(src, error); + switch (exists) { + case EXISTS_ERROR: + return NULL; + + case EXISTS_NOT: + if ((flags & ZIP_CREATE) == 0) { + zip_error_set(error, ZIP_ER_NOENT, 0); + return NULL; + } + return _zip_allocate_new(src, flags, error); + + default: { + zip_t *za; + if (flags & ZIP_EXCL) { + zip_error_set(error, ZIP_ER_EXISTS, 0); + return NULL; + } + if (fs_zip_source_open(src) < 0) { + zip_error_set_from_source(error, src); + return NULL; + } + + if (flags & ZIP_TRUNCATE) { + za = _zip_allocate_new(src, flags, error); + } + else { + /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */ + za = _zip_open(src, flags, error); + } + + if (za == NULL) { + fs_zip_source_close(src); + return NULL; + } + return za; + } + } +} + + +zip_t * +_zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) { + zip_t *za; + zip_cdir_t *cdir; + struct fs_zip_stat st; + zip_uint64_t len, idx; + + fs_zip_stat_init(&st); + if (fs_zip_source_stat(src, &st) < 0) { + zip_error_set_from_source(error, src); + return NULL; + } + if ((st.valid & ZIP_STAT_SIZE) == 0) { + zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP); + return NULL; + } + len = st.size; + + + if ((za = _zip_allocate_new(src, flags, error)) == NULL) { + return NULL; + } + + /* treat empty files as empty archives */ + if (len == 0 && zip_source_accept_empty(src)) { + return za; + } + + if ((cdir = _zip_find_central_dir(za, len)) == NULL) { + _zip_error_copy(error, &za->error); + /* keep src so discard does not get rid of it */ + fs_zip_source_keep(src); + fs_zip_discard(za); + return NULL; + } + + za->entry = cdir->entry; + za->nentry = cdir->nentry; + za->nentry_alloc = cdir->nentry_alloc; + + zip_check_torrentzip(za, cdir); + + if (ZIP_IS_TORRENTZIP(za)) { + /* Torrentzip uses the archive comment to detect changes by tools that are not torrentzip aware. */ + _zip_string_free(cdir->comment); + } + else { + za->comment_orig = cdir->comment; + } + + free(cdir); + + _zip_hash_reserve_capacity(za->names, za->nentry, &za->error); + + for (idx = 0; idx < za->nentry; idx++) { + const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error); + if (name == NULL) { + /* keep src so discard does not get rid of it */ + fs_zip_source_keep(src); + fs_zip_discard(za); + return NULL; + } + + if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) { + if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) { + _zip_error_copy(error, &za->error); + /* keep src so discard does not get rid of it */ + fs_zip_source_keep(src); + fs_zip_discard(za); + return NULL; + } + } + } + + za->ch_flags = za->flags; + + return za; +} + + +void +_zip_set_open_error(int *zep, const zip_error_t *err, int ze) { + if (err) { + ze = fs_zip_error_code_zip(err); + switch (zip_error_system_type(err)) { + case ZIP_ET_SYS: + case ZIP_ET_LIBZIP: + errno = fs_zip_error_code_system(err); + break; + + default: + break; + } + } + + if (zep) + *zep = ze; +} + + +/* _zip_readcdir: + tries to find a valid end-of-central-directory at the beginning of + buf, and then the corresponding central directory entries. + Returns a struct zip_cdir which contains the central directory + entries, or NULL if unsuccessful. */ + +static zip_cdir_t * +_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error) { + zip_cdir_t *cd; + zip_uint16_t comment_len; + zip_uint64_t i, left; + zip_uint64_t eocd_offset = _zip_buffer_offset(buffer); + zip_buffer_t *cd_buffer; + + if (_zip_buffer_left(buffer) < EOCDLEN) { + /* not enough bytes left for comment */ + zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + /* check for end-of-central-dir magic */ + if (memcmp(_zip_buffer_get(buffer, 4), EOCD_MAGIC, 4) != 0) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) { + _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN); + cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error); + } + else { + _zip_buffer_set_offset(buffer, eocd_offset); + cd = _zip_read_eocd(buffer, buf_offset, za->flags, error); + } + + if (cd == NULL) + return NULL; + + _zip_buffer_set_offset(buffer, eocd_offset + 20); + comment_len = _zip_buffer_get_16(buffer); + + if (cd->offset + cd->size > buf_offset + eocd_offset) { + /* cdir spans past EOCD record */ + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD); + _zip_cdir_free(cd); + return NULL; + } + + if (comment_len || (za->open_flags & ZIP_CHECKCONS)) { + zip_uint64_t tail_len; + + _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN); + tail_len = _zip_buffer_left(buffer); + + if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID); + _zip_cdir_free(cd); + return NULL; + } + + if (comment_len) { + if ((cd->comment = _zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) { + _zip_cdir_free(cd); + return NULL; + } + } + } + + if (cd->offset >= buf_offset) { + zip_uint8_t *data; + /* if buffer already read in, use it */ + _zip_buffer_set_offset(buffer, cd->offset - buf_offset); + + if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID); + _zip_cdir_free(cd); + return NULL; + } + if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + _zip_cdir_free(cd); + return NULL; + } + } + else { + cd_buffer = NULL; + + if (fs_zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) { + zip_error_set_from_source(error, za->src); + _zip_cdir_free(cd); + return NULL; + } + + /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */ + if (fs_zip_source_tell(za->src) != (zip_int64_t)cd->offset) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + _zip_cdir_free(cd); + return NULL; + } + } + + left = (zip_uint64_t)cd->size; + i = 0; + while (left > 0) { + bool grown = false; + zip_int64_t entry_size; + + if (i == cd->nentry) { + /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */ + /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */ + + if (cd->is_zip64 || left < CDENTRYSIZE) { + break; + } + + if (!_zip_cdir_grow(cd, 0x10000, error)) { + _zip_cdir_free(cd); + _zip_buffer_free(cd_buffer); + return NULL; + } + grown = true; + } + + if ((cd->entry[i].orig = _zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, error)) < 0) { + if (fs_zip_error_code_zip(error) == ZIP_ER_INCONS) { + zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(fs_zip_error_code_system(error), i)); + } + else if (grown && fs_zip_error_code_zip(error) == ZIP_ER_NOZIP) { + zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, i)); + } + _zip_cdir_free(cd); + _zip_buffer_free(cd_buffer); + return NULL; + } + i++; + left -= (zip_uint64_t)entry_size; + } + + if (i != cd->nentry || left > 0) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT); + _zip_buffer_free(cd_buffer); + _zip_cdir_free(cd); + return NULL; + } + + if (za->open_flags & ZIP_CHECKCONS) { + bool ok; + + if (cd_buffer) { + ok = _zip_buffer_eof(cd_buffer); + } + else { + zip_int64_t offset = fs_zip_source_tell(za->src); + + if (offset < 0) { + zip_error_set_from_source(error, za->src); + _zip_cdir_free(cd); + return NULL; + } + ok = ((zip_uint64_t)offset == cd->offset + cd->size); + } + + if (!ok) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID); + _zip_buffer_free(cd_buffer); + _zip_cdir_free(cd); + return NULL; + } + } + + _zip_buffer_free(cd_buffer); + return cd; +} + + +/* _zip_checkcons: + Checks the consistency of the central directory by comparing central + directory entries with local headers and checking for plausible + file and header offsets. Returns -1 if not plausible, else the + difference between the lowest and the highest fileposition reached */ + +static zip_int64_t +_zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error) { + zip_uint64_t i; + zip_uint64_t min, max, j; + struct zip_dirent temp; + + _zip_dirent_init(&temp); + if (cd->nentry) { + max = cd->entry[0].orig->offset; + min = cd->entry[0].orig->offset; + } + else + min = max = 0; + + for (i = 0; i < cd->nentry; i++) { + if (cd->entry[i].orig->offset < min) + min = cd->entry[i].orig->offset; + if (min > (zip_uint64_t)cd->offset) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE; + if (j > max) + max = j; + if (max > (zip_uint64_t)cd->offset) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + if (fs_zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) { + zip_error_set_from_source(error, za->src); + return -1; + } + + if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) { + if (fs_zip_error_code_zip(error) == ZIP_ER_INCONS) { + zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(fs_zip_error_code_system(error), i)); + } + _zip_dirent_finalize(&temp); + return -1; + } + + if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) { + zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH, i)); + _zip_dirent_finalize(&temp); + return -1; + } + + cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields); + cd->entry[i].orig->local_extra_fields_read = 1; + temp.extra_fields = NULL; + + _zip_dirent_finalize(&temp); + } + + return (max - min) < ZIP_INT64_MAX ? (zip_int64_t)(max - min) : ZIP_INT64_MAX; +} + + +/* _zip_headercomp: + compares a central directory entry and a local file header + Return 0 if they are consistent, -1 if not. */ + +static int +_zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local) { + if ((central->version_needed < local->version_needed) +#if 0 + /* some zip-files have different values in local + and global headers for the bitflags */ + || (central->bitflags != local->bitflags) +#endif + || (central->comp_method != local->comp_method) || (central->last_mod != local->last_mod) || !_zip_string_equal(central->filename, local->filename)) + return -1; + + if ((central->crc != local->crc) || (central->comp_size != local->comp_size) || (central->uncomp_size != local->uncomp_size)) { + /* InfoZip stores valid values in local header even when data descriptor is used. + This is in violation of the appnote. + macOS Archive sets the compressed size even when data descriptor is used ( but not the others), + also in violation of the appnote. + */ + /* if data descriptor is not used, the values must match */ + if ((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0) { + return -1; + } + /* when using a data descriptor, the local header value must be zero or match */ + if ((local->crc != 0 && central->crc != local->crc) || + (local->comp_size != 0 && central->comp_size != local->comp_size) || + (local->uncomp_size != 0 && central->uncomp_size != local->uncomp_size)) { + return -1; + } + } + + return 0; +} + + +static zip_t * +_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error) { + zip_t *za; + + if ((za = _zip_new(error)) == NULL) { + return NULL; + } + + za->src = src; + za->open_flags = flags; + za->flags = 0; + za->ch_flags = 0; + za->write_crc = NULL; + + if (flags & ZIP_RDONLY) { + za->flags |= ZIP_AFL_RDONLY; + za->ch_flags |= ZIP_AFL_RDONLY; + } + + return za; +} + + +/* + * tests for file existence + */ +static exists_t +_zip_file_exists(zip_source_t *src, zip_error_t *error) { + struct fs_zip_stat st; + + fs_zip_stat_init(&st); + if (fs_zip_source_stat(src, &st) != 0) { + zip_error_t *src_error = fs_zip_source_error(src); + if (fs_zip_error_code_zip(src_error) == ZIP_ER_READ && fs_zip_error_code_system(src_error) == ENOENT) { + return EXISTS_NOT; + } + _zip_error_copy(error, src_error); + return EXISTS_ERROR; + } + + return EXISTS_OK; +} + + +static zip_cdir_t * +_zip_find_central_dir(zip_t *za, zip_uint64_t len) { + zip_cdir_t *cdir, *cdirnew; + const zip_uint8_t *match; + zip_int64_t buf_offset; + zip_uint64_t buflen; + zip_int64_t a; + zip_int64_t best; + zip_error_t error; + zip_buffer_t *buffer; + + if (len < EOCDLEN) { + zip_error_set(&za->error, ZIP_ER_NOZIP, 0); + return NULL; + } + + buflen = (len < CDBUFSIZE ? len : CDBUFSIZE); + if (fs_zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) { + zip_error_t *src_error = fs_zip_source_error(za->src); + if (fs_zip_error_code_zip(src_error) != ZIP_ER_SEEK || fs_zip_error_code_system(src_error) != EFBIG) { + /* seek before start of file on my machine */ + _zip_error_copy(&za->error, src_error); + return NULL; + } + } + if ((buf_offset = fs_zip_source_tell(za->src)) < 0) { + zip_error_set_from_source(&za->error, za->src); + return NULL; + } + + if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) { + return NULL; + } + + best = -1; + cdir = NULL; + if (buflen >= CDBUFSIZE) { + /* EOCD64 locator is before EOCD, so leave place for it */ + _zip_buffer_set_offset(buffer, EOCD64LOCLEN); + } + zip_error_set(&error, ZIP_ER_NOZIP, 0); + + match = _zip_buffer_get(buffer, 0); + /* The size of buffer never greater than CDBUFSIZE. */ + while (_zip_buffer_left(buffer) >= EOCDLEN && (match = _zip_memmem(match, (size_t)_zip_buffer_left(buffer) - (EOCDLEN - 4), (const unsigned char *)EOCD_MAGIC, 4)) != NULL) { + _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer))); + if ((cdirnew = _zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &error)) != NULL) { + if (cdir) { + if (best <= 0) { + best = _zip_checkcons(za, cdir, &error); + } + + a = _zip_checkcons(za, cdirnew, &error); + if (best < a) { + _zip_cdir_free(cdir); + cdir = cdirnew; + best = a; + } + else { + _zip_cdir_free(cdirnew); + } + } + else { + cdir = cdirnew; + if (za->open_flags & ZIP_CHECKCONS) + best = _zip_checkcons(za, cdir, &error); + else { + best = 0; + } + } + cdirnew = NULL; + } + + match++; + _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer))); + } + + _zip_buffer_free(buffer); + + if (best < 0) { + _zip_error_copy(&za->error, &error); + _zip_cdir_free(cdir); + return NULL; + } + + return cdir; +} + + +static const unsigned char *_zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen) { + const unsigned char *p; + + if (littlelen == 0) { + return big; + } + + if (biglen < littlelen) { + return NULL; + } + + p = big; + while (true) { + p = (const unsigned char *)memchr(p, little[0], biglen - (littlelen - 1) - (size_t)(p - big)); + if (p == NULL) { + return NULL; + } + if (memcmp(p + 1, little + 1, littlelen - 1) == 0) { + return p; + } + p += 1; + } +} + + +static zip_cdir_t * +_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) { + zip_cdir_t *cd; + zip_uint64_t i, nentry, size, offset, eocd_offset; + + if (_zip_buffer_left(buffer) < EOCDLEN) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD_LENGTH_INVALID); + return NULL; + } + + eocd_offset = _zip_buffer_offset(buffer); + + _zip_buffer_get(buffer, 4); /* magic already verified */ + + if (_zip_buffer_get_32(buffer) != 0) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } + + /* number of cdir-entries on this disk */ + i = _zip_buffer_get_16(buffer); + /* number of cdir-entries */ + nentry = _zip_buffer_get_16(buffer); + + if (nentry != i) { + zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + size = _zip_buffer_get_32(buffer); + offset = _zip_buffer_get_32(buffer); + + if (offset + size < offset) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return NULL; + } + + if (offset + size > buf_offset + eocd_offset) { + /* cdir spans past EOCD record */ + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD); + return NULL; + } + + if ((flags & ZIP_CHECKCONS) && offset + size != buf_offset + eocd_offset) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID); + return NULL; + } + + if ((cd = _zip_cdir_new(nentry, error)) == NULL) + return NULL; + + cd->is_zip64 = false; + cd->size = size; + cd->offset = offset; + + return cd; +} + + +static zip_cdir_t * +_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) { + zip_cdir_t *cd; + zip_uint64_t offset; + zip_uint8_t eocd[EOCD64LEN]; + zip_uint64_t eocd_offset; + zip_uint64_t size, nentry, i, eocdloc_offset; + bool free_buffer; + zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64; + + eocdloc_offset = _zip_buffer_offset(buffer); + + _zip_buffer_get(buffer, 4); /* magic already verified */ + + num_disks = _zip_buffer_get_16(buffer); + eocd_disk = _zip_buffer_get_16(buffer); + eocd_offset = _zip_buffer_get_64(buffer); + + /* valid seek value for start of EOCD */ + if (eocd_offset > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return NULL; + } + + /* does EOCD fit before EOCD locator? */ + if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD); + return NULL; + } + + /* make sure current position of buffer is beginning of EOCD */ + if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) { + _zip_buffer_set_offset(buffer, eocd_offset - buf_offset); + free_buffer = false; + } + else { + if (fs_zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) { + zip_error_set_from_source(error, src); + return NULL; + } + if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) { + return NULL; + } + free_buffer = true; + } + + if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC); + if (free_buffer) { + _zip_buffer_free(buffer); + } + return NULL; + } + + /* size of EOCD */ + size = _zip_buffer_get_64(buffer); + + /* is there a hole between EOCD and EOCD locator, or do they overlap? */ + if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD); + if (free_buffer) { + _zip_buffer_free(buffer); + } + return NULL; + } + + _zip_buffer_get(buffer, 4); /* skip version made by/needed */ + + num_disks64 = _zip_buffer_get_32(buffer); + eocd_disk64 = _zip_buffer_get_32(buffer); + + /* if eocd values are 0xffff, we have to use eocd64 values. + otherwise, if the values are not the same, it's inconsistent; + in any case, if the value is not 0, we don't support it */ + if (num_disks == 0xffff) { + num_disks = num_disks64; + } + if (eocd_disk == 0xffff) { + eocd_disk = eocd_disk64; + } + if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_MISMATCH); + if (free_buffer) { + _zip_buffer_free(buffer); + } + return NULL; + } + if (num_disks != 0 || eocd_disk != 0) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + if (free_buffer) { + _zip_buffer_free(buffer); + } + return NULL; + } + + nentry = _zip_buffer_get_64(buffer); + i = _zip_buffer_get_64(buffer); + + if (nentry != i) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + if (free_buffer) { + _zip_buffer_free(buffer); + } + return NULL; + } + + size = _zip_buffer_get_64(buffer); + offset = _zip_buffer_get_64(buffer); + + /* did we read past the end of the buffer? */ + if (!_zip_buffer_ok(buffer)) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + if (free_buffer) { + _zip_buffer_free(buffer); + } + return NULL; + } + + if (free_buffer) { + _zip_buffer_free(buffer); + } + + if (offset > ZIP_INT64_MAX || offset + size < offset) { + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return NULL; + } + if (offset + size > buf_offset + eocd_offset) { + /* cdir spans past EOCD record */ + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD); + return NULL; + } + if ((flags & ZIP_CHECKCONS) && offset + size != buf_offset + eocd_offset) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD); + return NULL; + } + + if (nentry > size / CDENTRYSIZE) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_INVALID); + return NULL; + } + + if ((cd = _zip_cdir_new(nentry, error)) == NULL) + return NULL; + + cd->is_zip64 = true; + cd->size = size; + cd->offset = offset; + + return cd; +} + + +static int decode_hex(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + else if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + else { + return -1; + } +} + +/* _zip_check_torrentzip: + check whether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */ + +static void zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir) { + zip_uint32_t crc_should; + char buf[8+1]; + size_t i; + + if (cdir == NULL) { + return; + } + + if (_zip_string_length(cdir->comment) != TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH + || strncmp((const char *)cdir->comment->raw, TORRENTZIP_SIGNATURE, TORRENTZIP_SIGNATURE_LENGTH) != 0) + return; + + memcpy(buf, cdir->comment->raw + TORRENTZIP_SIGNATURE_LENGTH, TORRENTZIP_CRC_LENGTH); + buf[TORRENTZIP_CRC_LENGTH] = '\0'; + crc_should = 0; + for (i = 0; i < TORRENTZIP_CRC_LENGTH; i += 2) { + int low, high; + high = decode_hex((buf[i])); + low = decode_hex(buf[i + 1]); + if (high < 0 || low < 0) { + return; + } + crc_should = (crc_should << 8) + (high << 4) + low; + } + + { + zip_stat_t st; + zip_source_t* src_window; + zip_source_t* src_crc; + zip_uint8_t buffer[512]; + zip_int64_t ret; + + fs_zip_stat_init(&st); + st.valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC; + st.size = cdir->size; + st.crc = crc_should; + if ((src_window = _zip_source_window_new(za->src, cdir->offset, cdir->size, &st, 0, NULL, NULL, 0, false, NULL)) == NULL) { + return; + } + if ((src_crc = zip_source_crc_create(src_window, 1, NULL)) == NULL) { + zip_source_free(src_window); + return; + } + if (fs_zip_source_open(src_crc) != 0) { + zip_source_free(src_crc); + return; + } + while ((ret = fs_zip_source_read(src_crc, buffer, sizeof(buffer))) > 0) { + } + zip_source_free(src_crc); + if (ret < 0) { + return; + } + } + + /* TODO: if check consistency, check cdir entries for valid values */ + za->flags |= ZIP_AFL_IS_TORRENTZIP; +} diff --git a/src/libzip/zip_progress.c b/src/libzip/zip_progress.c new file mode 100644 index 0000000..05f6d5c --- /dev/null +++ b/src/libzip/zip_progress.c @@ -0,0 +1,293 @@ +/* + zip_progress.c -- progress reporting + Copyright (C) 2017-2020 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + +struct zip_progress { + zip_t *za; + + zip_progress_callback callback_progress; + void (*ud_progress_free)(void *); + void *ud_progress; + + zip_cancel_callback callback_cancel; + void (*ud_cancel_free)(void *); + void *ud_cancel; + + double precision; + + /* state */ + double last_update; /* last value callback function was called with */ + + double start; /* start of sub-progress section */ + double end; /* end of sub-progress section */ +}; + +static void _zip_progress_free_cancel_callback(zip_progress_t *progress); +static void _zip_progress_free_progress_callback(zip_progress_t *progress); +static zip_progress_t *_zip_progress_new(zip_t *za); +static void _zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud); +static void _zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud); + +void +_zip_progress_end(zip_progress_t *progress) { + _zip_progress_update(progress, 1.0); +} + + +void +_zip_progress_free(zip_progress_t *progress) { + if (progress == NULL) { + return; + } + + _zip_progress_free_progress_callback(progress); + _zip_progress_free_cancel_callback(progress); + + free(progress); +} + + +static zip_progress_t * +_zip_progress_new(zip_t *za) { + zip_progress_t *progress = (zip_progress_t *)malloc(sizeof(*progress)); + + if (progress == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + progress->za = za; + + progress->callback_progress = NULL; + progress->ud_progress_free = NULL; + progress->ud_progress = NULL; + progress->precision = 0.0; + + progress->callback_cancel = NULL; + progress->ud_cancel_free = NULL; + progress->ud_cancel = NULL; + + return progress; +} + +static void +_zip_progress_free_progress_callback(zip_progress_t *progress) { + if (progress->ud_progress_free) { + progress->ud_progress_free(progress->ud_progress); + } + + progress->callback_progress = NULL; + progress->ud_progress = NULL; + progress->ud_progress_free = NULL; +} + +static void +_zip_progress_free_cancel_callback(zip_progress_t *progress) { + if (progress->ud_cancel_free) { + progress->ud_cancel_free(progress->ud_cancel); + } + + progress->callback_cancel = NULL; + progress->ud_cancel = NULL; + progress->ud_cancel_free = NULL; +} + +static void +_zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) { + _zip_progress_free_progress_callback(progress); + + progress->callback_progress = callback; + progress->ud_progress_free = ud_free; + progress->ud_progress = ud; + progress->precision = precision; +} + +void +_zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) { + _zip_progress_free_cancel_callback(progress); + + progress->callback_cancel = callback; + progress->ud_cancel_free = ud_free; + progress->ud_cancel = ud; +} + +int +_zip_progress_start(zip_progress_t *progress) { + if (progress == NULL) { + return 0; + } + + if (progress->callback_progress != NULL) { + progress->last_update = 0.0; + progress->callback_progress(progress->za, 0.0, progress->ud_progress); + } + + if (progress->callback_cancel != NULL) { + if (progress->callback_cancel(progress->za, progress->ud_cancel)) { + return -1; + } + } + + return 0; +} + + +int +_zip_progress_subrange(zip_progress_t *progress, double start, double end) { + if (progress == NULL) { + return 0; + } + + progress->start = start; + progress->end = end; + + return _zip_progress_update(progress, 0.0); +} + +int +_zip_progress_update(zip_progress_t *progress, double sub_current) { + double current; + + if (progress == NULL) { + return 0; + } + + if (progress->callback_progress != NULL) { + current = ZIP_MIN(ZIP_MAX(sub_current, 0.0), 1.0) * (progress->end - progress->start) + progress->start; + + if (current - progress->last_update > progress->precision) { + progress->callback_progress(progress->za, current, progress->ud_progress); + progress->last_update = current; + } + } + + if (progress->callback_cancel != NULL) { + if (progress->callback_cancel(progress->za, progress->ud_cancel)) { + return -1; + } + } + + return 0; +} + + +ZIP_EXTERN int +fs_zip_register_progress_callback_with_state(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) { + if (callback != NULL) { + if (za->progress == NULL) { + if ((za->progress = _zip_progress_new(za)) == NULL) { + return -1; + } + } + + _zip_progress_set_progress_callback(za->progress, precision, callback, ud_free, ud); + } + else { + if (za->progress != NULL) { + if (za->progress->callback_cancel == NULL) { + _zip_progress_free(za->progress); + za->progress = NULL; + } + else { + _zip_progress_free_progress_callback(za->progress); + } + } + } + + return 0; +} + + +ZIP_EXTERN int +fs_zip_register_cancel_callback_with_state(zip_t *za, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) { + if (callback != NULL) { + if (za->progress == NULL) { + if ((za->progress = _zip_progress_new(za)) == NULL) { + return -1; + } + } + + _zip_progress_set_cancel_callback(za->progress, callback, ud_free, ud); + } + else { + if (za->progress != NULL) { + if (za->progress->callback_progress == NULL) { + _zip_progress_free(za->progress); + za->progress = NULL; + } + else { + _zip_progress_free_cancel_callback(za->progress); + } + } + } + + return 0; +} + + +struct legacy_ud { + zip_progress_callback_t callback; +}; + + +static void +_zip_legacy_progress_callback(zip_t *za, double progress, void *vud) { + struct legacy_ud *ud = (struct legacy_ud *)vud; + + ud->callback(progress); +} + +ZIP_EXTERN void +zip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback) { + struct legacy_ud *ud; + + if (progress_callback == NULL) { + fs_zip_register_progress_callback_with_state(za, 0, NULL, NULL, NULL); + } + + if ((ud = (struct legacy_ud *)malloc(sizeof(*ud))) == NULL) { + return; + } + + ud->callback = progress_callback; + + if (fs_zip_register_progress_callback_with_state(za, 0.001, _zip_legacy_progress_callback, free, ud) < 0) { + free(ud); + } +} diff --git a/src/libzip/zip_rename.c b/src/libzip/zip_rename.c new file mode 100644 index 0000000..c87ec63 --- /dev/null +++ b/src/libzip/zip_rename.c @@ -0,0 +1,42 @@ +/* + zip_rename.c -- rename file in zip archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN int +zip_rename(zip_t *za, zip_uint64_t idx, const char *name) { + return fs_zip_file_rename(za, idx, name, 0); +} diff --git a/src/libzip/zip_replace.c b/src/libzip/zip_replace.c new file mode 100644 index 0000000..94c1f64 --- /dev/null +++ b/src/libzip/zip_replace.c @@ -0,0 +1,42 @@ +/* + zip_replace.c -- replace file via callback function + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN int +zip_replace(zip_t *za, zip_uint64_t idx, zip_source_t *source) { + return fs_zip_file_replace(za, idx, source, 0); +} diff --git a/src/libzip/zip_set_archive_comment.c b/src/libzip/zip_set_archive_comment.c new file mode 100644 index 0000000..9605d2c --- /dev/null +++ b/src/libzip/zip_set_archive_comment.c @@ -0,0 +1,84 @@ +/* + fs_zip_set_archive_comment.c -- set archive comment + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_set_archive_comment(zip_t *za, const char *comment, zip_uint16_t len) { + zip_string_t *cstr; + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (len > 0 && comment == NULL) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (len > 0) { + if ((cstr = _zip_string_new((const zip_uint8_t *)comment, len, ZIP_FL_ENC_GUESS, &za->error)) == NULL) + return -1; + + if (_zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_CP437) { + _zip_string_free(cstr); + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + } + else + cstr = NULL; + + _zip_string_free(za->comment_changes); + za->comment_changes = NULL; + + if (((za->comment_orig && _zip_string_equal(za->comment_orig, cstr)) || (za->comment_orig == NULL && cstr == NULL))) { + _zip_string_free(cstr); + za->comment_changed = 0; + } + else { + za->comment_changes = cstr; + za->comment_changed = 1; + } + + return 0; +} diff --git a/src/libzip/zip_set_archive_flag.c b/src/libzip/zip_set_archive_flag.c new file mode 100644 index 0000000..e23fcf7 --- /dev/null +++ b/src/libzip/zip_set_archive_flag.c @@ -0,0 +1,76 @@ +/* + fs_zip_get_archive_flag.c -- set archive global flag + Copyright (C) 2008-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_set_archive_flag(zip_t *za, zip_flags_t flag, int value) { + unsigned int new_flags; + + if (flag == ZIP_AFL_IS_TORRENTZIP) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + /* TODO: when setting ZIP_AFL_WANT_TORRENTZIP, we should error out if any changes have been made that are not allowed for torrentzip. */ + + if (value) { + new_flags = za->ch_flags | flag; + } + else { + new_flags = za->ch_flags & ~flag; + } + + if (new_flags == za->ch_flags) { + return 0; + } + + /* Allow removing ZIP_AFL_RDONLY if manually set, not if archive was opened read-only. */ + if (za->flags & ZIP_AFL_RDONLY) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + + if ((flag & ZIP_AFL_RDONLY) && value && (za->ch_flags & ZIP_AFL_RDONLY) == 0) { + if (_zip_changed(za, NULL)) { + zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return -1; + } + } + + za->ch_flags = new_flags; + + return 0; +} diff --git a/src/libzip/zip_set_default_password.c b/src/libzip/zip_set_default_password.c new file mode 100644 index 0000000..da61271 --- /dev/null +++ b/src/libzip/zip_set_default_password.c @@ -0,0 +1,58 @@ +/* + fs_zip_set_default_password.c -- set default password for decryption + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_set_default_password(zip_t *za, const char *passwd) { + if (za == NULL) + return -1; + + free(za->default_password); + + if (passwd && passwd[0] != '\0') { + if ((za->default_password = strdup(passwd)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + else + za->default_password = NULL; + + return 0; +} diff --git a/src/libzip/zip_set_file_comment.c b/src/libzip/zip_set_file_comment.c new file mode 100644 index 0000000..de4107f --- /dev/null +++ b/src/libzip/zip_set_file_comment.c @@ -0,0 +1,46 @@ +/* + zip_set_file_comment.c -- set comment for file in archive + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + + +ZIP_EXTERN int +zip_set_file_comment(zip_t *za, zip_uint64_t idx, const char *comment, int len) { + if (len < 0 || len > ZIP_UINT16_MAX) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + return fs_zip_file_set_comment(za, idx, comment, (zip_uint16_t)len, 0); +} diff --git a/src/libzip/zip_set_file_compression.c b/src/libzip/zip_set_file_compression.c new file mode 100644 index 0000000..1a83fc8 --- /dev/null +++ b/src/libzip/zip_set_file_compression.c @@ -0,0 +1,95 @@ +/* + fs_zip_set_file_compression.c -- set compression for file in archive + Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_uint32_t flags) { + zip_entry_t *e; + zip_int32_t old_method; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (ZIP_WANT_TORRENTZIP(za)) { + zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0); + return -1; + } + + if (!fs_zip_compression_method_supported(method, true)) { + zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); + return -1; + } + + e = za->entry + idx; + + old_method = (e->orig == NULL ? ZIP_CM_DEFAULT : e->orig->comp_method); + + /* TODO: do we want to recompress if level is set? Only if it's + * different than what bit flags tell us, but those are not + * defined for all compression methods, or not directly mappable + * to levels */ + + if (method == old_method) { + if (e->changes) { + e->changes->changed &= ~ZIP_DIRENT_COMP_METHOD; + e->changes->compression_level = 0; + if (e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + } + } + else { + if (e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + e->changes->comp_method = method; + e->changes->compression_level = (zip_uint16_t)flags; + e->changes->changed |= ZIP_DIRENT_COMP_METHOD; + } + + return 0; +} diff --git a/src/libzip/zip_set_name.c b/src/libzip/zip_set_name.c new file mode 100644 index 0000000..f1bf703 --- /dev/null +++ b/src/libzip/zip_set_name.c @@ -0,0 +1,157 @@ +/* + zip_set_name.c -- rename helper function + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include "zipint.h" + + +int +_zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { + zip_entry_t *e; + zip_string_t *str; + bool same_as_orig; + zip_int64_t i; + const zip_uint8_t *old_name, *new_name; + zip_string_t *old_str; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (ZIP_IS_RDONLY(za)) { + zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + + if (name && name[0] != '\0') { + /* TODO: check for string too long */ + if ((str = _zip_string_new((const zip_uint8_t *)name, (zip_uint16_t)strlen(name), flags, &za->error)) == NULL) + return -1; + if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(str, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) + str->encoding = ZIP_ENCODING_UTF8_KNOWN; + } + else + str = NULL; + + /* TODO: encoding flags needed for CP437? */ + if ((i = _zip_name_locate(za, name, 0, NULL)) >= 0 && (zip_uint64_t)i != idx) { + _zip_string_free(str); + zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + + /* no effective name change */ + if (i >= 0 && (zip_uint64_t)i == idx) { + _zip_string_free(str); + return 0; + } + + e = za->entry + idx; + + if (e->orig) + same_as_orig = _zip_string_equal(e->orig->filename, str); + else + same_as_orig = false; + + if (!same_as_orig && e->changes == NULL) { + if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + _zip_string_free(str); + return -1; + } + } + + if ((new_name = _zip_string_get(same_as_orig ? e->orig->filename : str, NULL, 0, &za->error)) == NULL) { + _zip_string_free(str); + return -1; + } + + if (e->changes) { + old_str = e->changes->filename; + } + else if (e->orig) { + old_str = e->orig->filename; + } + else { + old_str = NULL; + } + + if (old_str) { + if ((old_name = _zip_string_get(old_str, NULL, 0, &za->error)) == NULL) { + _zip_string_free(str); + return -1; + } + } + else { + old_name = NULL; + } + + if (_zip_hash_add(za->names, new_name, idx, 0, &za->error) == false) { + _zip_string_free(str); + return -1; + } + if (old_name) { + _zip_hash_delete(za->names, old_name, NULL); + } + + if (same_as_orig) { + if (e->changes) { + if (e->changes->changed & ZIP_DIRENT_FILENAME) { + _zip_string_free(e->changes->filename); + e->changes->changed &= ~ZIP_DIRENT_FILENAME; + if (e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + else { + /* TODO: what if not cloned? can that happen? */ + e->changes->filename = e->orig->filename; + } + } + } + _zip_string_free(str); + } + else { + if (e->changes->changed & ZIP_DIRENT_FILENAME) { + _zip_string_free(e->changes->filename); + } + e->changes->changed |= ZIP_DIRENT_FILENAME; + e->changes->filename = str; + } + + return 0; +} diff --git a/src/libzip/zip_source_accept_empty.c b/src/libzip/zip_source_accept_empty.c new file mode 100644 index 0000000..e772aee --- /dev/null +++ b/src/libzip/zip_source_accept_empty.c @@ -0,0 +1,52 @@ +/* + zip_source_accept_empty.c -- if empty source is a valid archive + Copyright (C) 2019-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +bool +zip_source_accept_empty(zip_source_t *src) { + zip_int64_t ret; + + if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY)) == 0) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + return zip_source_accept_empty(src->src); + } + return true; + } + + ret = _zip_source_call(src, NULL, 0, ZIP_SOURCE_ACCEPT_EMPTY); + + return ret != 0; +} diff --git a/src/libzip/zip_source_begin_write.c b/src/libzip/zip_source_begin_write.c new file mode 100644 index 0000000..c537617 --- /dev/null +++ b/src/libzip/zip_source_begin_write.c @@ -0,0 +1,57 @@ +/* + fs_zip_source_begin_write.c -- start a new file for writing + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_begin_write(zip_source_t *src) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (ZIP_SOURCE_IS_OPEN_WRITING(src)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_BEGIN_WRITE) < 0) { + return -1; + } + + src->write_state = ZIP_SOURCE_WRITE_OPEN; + + return 0; +} diff --git a/src/libzip/zip_source_begin_write_cloning.c b/src/libzip/zip_source_begin_write_cloning.c new file mode 100644 index 0000000..a0c66ac --- /dev/null +++ b/src/libzip/zip_source_begin_write_cloning.c @@ -0,0 +1,57 @@ +/* + fs_zip_source_begin_write_cloning.c -- clone part of file for writing + Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_begin_write_cloning(zip_source_t *src, zip_uint64_t offset) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (ZIP_SOURCE_IS_OPEN_WRITING(src)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_source_call(src, NULL, offset, ZIP_SOURCE_BEGIN_WRITE_CLONING) < 0) { + return -1; + } + + src->write_state = ZIP_SOURCE_WRITE_OPEN; + + return 0; +} diff --git a/src/libzip/zip_source_buffer.c b/src/libzip/zip_source_buffer.c new file mode 100644 index 0000000..29f11db --- /dev/null +++ b/src/libzip/zip_source_buffer.c @@ -0,0 +1,643 @@ +/* + fs_zip_source_buffer.c -- create zip data source from buffer + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "zipint.h" + +#ifndef WRITE_FRAGMENT_SIZE +#define WRITE_FRAGMENT_SIZE (64 * 1024) +#endif + +struct buffer { + zip_buffer_fragment_t *fragments; /* fragments */ + zip_uint64_t *fragment_offsets; /* offset of each fragment from start of buffer, nfragments+1 entries */ + zip_uint64_t nfragments; /* number of allocated fragments */ + zip_uint64_t fragments_capacity; /* size of fragments (number of pointers) */ + + zip_uint64_t first_owned_fragment; /* first fragment to free data from */ + + zip_uint64_t shared_fragments; /* number of shared fragments */ + struct buffer *shared_buffer; /* buffer fragments are shared with */ + + zip_uint64_t size; /* size of buffer */ + zip_uint64_t offset; /* current offset in buffer */ + zip_uint64_t current_fragment; /* fragment current offset is in */ +}; + +typedef struct buffer buffer_t; + +struct read_data { + zip_error_t error; + time_t mtime; + zip_file_attributes_t attributes; + buffer_t *in; + buffer_t *out; +}; + +#define buffer_capacity(buffer) ((buffer)->fragment_offsets[(buffer)->nfragments]) +#define buffer_size(buffer) ((buffer)->size) + +static buffer_t *buffer_clone(buffer_t *buffer, zip_uint64_t length, zip_error_t *error); +static zip_uint64_t buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset); +static void buffer_free(buffer_t *buffer); +static bool buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error); +static buffer_t *buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error); +static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length); +static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error); +static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *); + +static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t); + +zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error); +zip_source_t *zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error); + + +ZIP_EXTERN zip_source_t * +fs_zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) { + if (za == NULL) + return NULL; + + return zip_source_buffer_with_attributes_create(data, len, freep, NULL, &za->error); +} + + +ZIP_EXTERN zip_source_t * +fs_zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) { + return zip_source_buffer_with_attributes_create(data, len, freep, NULL, error); +} + + +zip_source_t * +zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error) { + zip_buffer_fragment_t fragment; + + if (data == NULL) { + if (len > 0) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + return zip_source_buffer_fragment_with_attributes_create(NULL, 0, freep, attributes, error); + } + + fragment.data = (zip_uint8_t *)data; + fragment.length = len; + + return zip_source_buffer_fragment_with_attributes_create(&fragment, 1, freep, attributes, error); +} + + +ZIP_EXTERN zip_source_t * +fs_zip_source_buffer_fragment(zip_t *za, const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep) { + if (za == NULL) { + return NULL; + } + + return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, &za->error); +} + + +ZIP_EXTERN zip_source_t * +fs_zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) { + return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, error); +} + +zip_source_t * +zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error) { + struct read_data *ctx; + zip_source_t *zs; + buffer_t *buffer; + + if (fragments == NULL && nfragments > 0) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((buffer = buffer_new(fragments, nfragments, freep, error)) == NULL) { + return NULL; + } + + if ((ctx = (struct read_data *)malloc(sizeof(*ctx))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + buffer_free(buffer); + return NULL; + } + + ctx->in = buffer; + ctx->out = NULL; + ctx->mtime = time(NULL); + if (attributes) { + (void)memcpy_s(&ctx->attributes, sizeof(ctx->attributes), attributes, sizeof(ctx->attributes)); + } + else { + fs_zip_file_attributes_init(&ctx->attributes); + } + fs_zip_error_init(&ctx->error); + + if ((zs = fs_zip_source_function_create(read_data, ctx, error)) == NULL) { + buffer_free(ctx->in); + free(ctx); + return NULL; + } + + return zs; +} + + +zip_source_t * +zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes) { + return zip_source_buffer_with_attributes_create(data, len, freep, attributes, &za->error); +} + +static zip_int64_t +read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { + struct read_data *ctx = (struct read_data *)state; + + switch (cmd) { + case ZIP_SOURCE_BEGIN_WRITE: + if ((ctx->out = buffer_new(NULL, 0, 0, &ctx->error)) == NULL) { + return -1; + } + ctx->out->offset = 0; + ctx->out->current_fragment = 0; + return 0; + + case ZIP_SOURCE_BEGIN_WRITE_CLONING: + if ((ctx->out = buffer_clone(ctx->in, len, &ctx->error)) == NULL) { + return -1; + } + ctx->out->offset = len; + ctx->out->current_fragment = ctx->out->nfragments; + return 0; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_COMMIT_WRITE: + buffer_free(ctx->in); + ctx->in = ctx->out; + ctx->out = NULL; + return 0; + + case ZIP_SOURCE_ERROR: + return zip_error_to_data(&ctx->error, data, len); + + case ZIP_SOURCE_FREE: + buffer_free(ctx->in); + buffer_free(ctx->out); + free(ctx); + return 0; + + case ZIP_SOURCE_GET_FILE_ATTRIBUTES: { + if (len < sizeof(ctx->attributes)) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + + (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes)); + + return sizeof(ctx->attributes); + } + + case ZIP_SOURCE_OPEN: + ctx->in->offset = 0; + ctx->in->current_fragment = 0; + return 0; + + case ZIP_SOURCE_READ: + if (len > ZIP_INT64_MAX) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + return buffer_read(ctx->in, data, len); + + case ZIP_SOURCE_REMOVE: { + buffer_t *empty = buffer_new(NULL, 0, 0, &ctx->error); + if (empty == NULL) { + return -1; + } + + buffer_free(ctx->in); + ctx->in = empty; + return 0; + } + + case ZIP_SOURCE_ROLLBACK_WRITE: + buffer_free(ctx->out); + ctx->out = NULL; + return 0; + + case ZIP_SOURCE_SEEK: + return buffer_seek(ctx->in, data, len, &ctx->error); + + case ZIP_SOURCE_SEEK_WRITE: + return buffer_seek(ctx->out, data, len, &ctx->error); + + case ZIP_SOURCE_STAT: { + zip_stat_t *st; + + if (len < sizeof(*st)) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + + st = (zip_stat_t *)data; + + fs_zip_stat_init(st); + st->mtime = ctx->mtime; + st->size = ctx->in->size; + st->comp_size = st->size; + st->comp_method = ZIP_CM_STORE; + st->encryption_method = ZIP_EM_NONE; + st->valid = ZIP_STAT_MTIME | ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; + + return sizeof(*st); + } + + case ZIP_SOURCE_SUPPORTS: + return fs_zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, ZIP_SOURCE_SUPPORTS_REOPEN, -1); + + case ZIP_SOURCE_TELL: + if (ctx->in->offset > ZIP_INT64_MAX) { + zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW); + return -1; + } + return (zip_int64_t)ctx->in->offset; + + + case ZIP_SOURCE_TELL_WRITE: + if (ctx->out->offset > ZIP_INT64_MAX) { + zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW); + return -1; + } + return (zip_int64_t)ctx->out->offset; + + case ZIP_SOURCE_WRITE: + if (len > ZIP_INT64_MAX) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + return buffer_write(ctx->out, data, len, &ctx->error); + + default: + zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } +} + + +static buffer_t * +buffer_clone(buffer_t *buffer, zip_uint64_t offset, zip_error_t *error) { + zip_uint64_t fragment, fragment_offset, waste; + buffer_t *clone; + + if (offset == 0) { + return buffer_new(NULL, 0, 1, error); + } + + if (offset > buffer->size) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + if (buffer->shared_buffer != NULL) { + zip_error_set(error, ZIP_ER_INUSE, 0); + return NULL; + } + + fragment = buffer_find_fragment(buffer, offset); + fragment_offset = offset - buffer->fragment_offsets[fragment]; + + if (fragment_offset == 0) { + fragment--; + fragment_offset = buffer->fragments[fragment].length; + } + + /* TODO: This should also consider the length of the fully shared fragments */ + waste = buffer->fragments[fragment].length - fragment_offset; + if (waste > offset) { + zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); + return NULL; + } + + if ((clone = buffer_new(buffer->fragments, fragment + 1, 0, error)) == NULL) { + return NULL; + } + +#ifndef __clang_analyzer__ + /* clone->fragments can't be null, since it was created with at least one fragment */ + clone->fragments[fragment].length = fragment_offset; +#endif + clone->fragment_offsets[clone->nfragments] = offset; + clone->size = offset; + + clone->first_owned_fragment = ZIP_MIN(buffer->first_owned_fragment, clone->nfragments); + + buffer->shared_buffer = clone; + clone->shared_buffer = buffer; + buffer->shared_fragments = fragment + 1; + clone->shared_fragments = fragment + 1; + + return clone; +} + + +static zip_uint64_t +buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset) { + zip_uint64_t low, high, mid; + + if (buffer->nfragments == 0) { + return 0; + } + + low = 0; + high = buffer->nfragments - 1; + + while (low < high) { + mid = (high - low) / 2 + low; + if (buffer->fragment_offsets[mid] > offset) { + high = mid - 1; + } + else if (mid == buffer->nfragments || buffer->fragment_offsets[mid + 1] > offset) { + return mid; + } + else { + low = mid + 1; + } + } + + return low; +} + + +static void +buffer_free(buffer_t *buffer) { + zip_uint64_t i; + + if (buffer == NULL) { + return; + } + + if (buffer->shared_buffer != NULL) { + buffer->shared_buffer->shared_buffer = NULL; + buffer->shared_buffer->shared_fragments = 0; + + buffer->first_owned_fragment = ZIP_MAX(buffer->first_owned_fragment, buffer->shared_fragments); + } + + for (i = buffer->first_owned_fragment; i < buffer->nfragments; i++) { + free(buffer->fragments[i].data); + } + free(buffer->fragments); + free(buffer->fragment_offsets); + free(buffer); +} + + +static bool +buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error) { + zip_buffer_fragment_t *fragments; + zip_uint64_t *offsets; + + if (capacity < buffer->fragments_capacity) { + return true; + } + + zip_uint64_t fragments_size = sizeof(buffer->fragments[0]) * capacity; + zip_uint64_t offsets_size = sizeof(buffer->fragment_offsets[0]) * (capacity + 1); + + if (capacity == ZIP_UINT64_MAX || fragments_size < capacity || fragments_size > SIZE_MAX|| offsets_size < capacity || offsets_size > SIZE_MAX) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + if ((fragments = realloc(buffer->fragments, (size_t)fragments_size)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + buffer->fragments = fragments; + if ((offsets = realloc(buffer->fragment_offsets, (size_t)offsets_size)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + buffer->fragment_offsets = offsets; + buffer->fragments_capacity = capacity; + + return true; +} + + +static buffer_t * +buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error) { + buffer_t *buffer; + + if ((buffer = malloc(sizeof(*buffer))) == NULL) { + return NULL; + } + + buffer->offset = 0; + buffer->first_owned_fragment = 0; + buffer->size = 0; + buffer->fragments = NULL; + buffer->fragment_offsets = NULL; + buffer->nfragments = 0; + buffer->fragments_capacity = 0; + buffer->shared_buffer = NULL; + buffer->shared_fragments = 0; + + if (nfragments == 0) { + if ((buffer->fragment_offsets = malloc(sizeof(buffer->fragment_offsets[0]))) == NULL) { + free(buffer); + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + buffer->fragment_offsets[0] = 0; + } + else { + zip_uint64_t i, j, offset; + + if (!buffer_grow_fragments(buffer, nfragments, NULL)) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + buffer_free(buffer); + return NULL; + } + + offset = 0; + for (i = 0, j = 0; i < nfragments; i++) { + if (fragments[i].length == 0) { + continue; + } + if (fragments[i].data == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + buffer_free(buffer); + return NULL; + } + buffer->fragments[j].data = fragments[i].data; + buffer->fragments[j].length = fragments[i].length; + buffer->fragment_offsets[i] = offset; + /* TODO: overflow */ + offset += fragments[i].length; + j++; + } + buffer->nfragments = j; + buffer->first_owned_fragment = free_data ? 0 : buffer->nfragments; + buffer->fragment_offsets[buffer->nfragments] = offset; + buffer->size = offset; + } + + return buffer; +} + +static zip_int64_t +buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) { + zip_uint64_t n, i, fragment_offset; + + length = ZIP_MIN(length, buffer->size - buffer->offset); + + if (length == 0) { + return 0; + } + if (length > ZIP_INT64_MAX) { + return -1; + } + + i = buffer->current_fragment; + fragment_offset = buffer->offset - buffer->fragment_offsets[i]; + n = 0; + while (n < length) { + zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset); +#if ZIP_UINT64_MAX > SIZE_MAX + left = ZIP_MIN(left, SIZE_MAX); +#endif + + (void)memcpy_s(data + n, (size_t)left, buffer->fragments[i].data + fragment_offset, (size_t)left); + + if (left == buffer->fragments[i].length - fragment_offset) { + i++; + } + n += left; + fragment_offset = 0; + } + + buffer->offset += n; + buffer->current_fragment = i; + return (zip_int64_t)n; +} + + +static int +buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error) { + zip_int64_t new_offset = fs_zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error); + + if (new_offset < 0) { + return -1; + } + + buffer->offset = (zip_uint64_t)new_offset; + buffer->current_fragment = buffer_find_fragment(buffer, buffer->offset); + return 0; +} + + +static zip_int64_t +buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) { + zip_uint64_t copied, i, fragment_offset, capacity; + + if (buffer->offset + length + WRITE_FRAGMENT_SIZE - 1 < length) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + /* grow buffer if needed */ + capacity = buffer_capacity(buffer); + if (buffer->offset + length > capacity) { + zip_uint64_t needed_fragments = buffer->nfragments + (length - (capacity - buffer->offset) + WRITE_FRAGMENT_SIZE - 1) / WRITE_FRAGMENT_SIZE; + + if (needed_fragments > buffer->fragments_capacity) { + zip_uint64_t new_capacity = buffer->fragments_capacity; + + if (new_capacity == 0) { + new_capacity = 16; + } + while (new_capacity < needed_fragments) { + new_capacity *= 2; + } + + if (!buffer_grow_fragments(buffer, new_capacity, error)) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + while (buffer->nfragments < needed_fragments) { + if ((buffer->fragments[buffer->nfragments].data = malloc(WRITE_FRAGMENT_SIZE)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return -1; + } + buffer->fragments[buffer->nfragments].length = WRITE_FRAGMENT_SIZE; + buffer->nfragments++; + capacity += WRITE_FRAGMENT_SIZE; + buffer->fragment_offsets[buffer->nfragments] = capacity; + } + } + + i = buffer->current_fragment; + fragment_offset = buffer->offset - buffer->fragment_offsets[i]; + copied = 0; + while (copied < length) { + zip_uint64_t n = ZIP_MIN(ZIP_MIN(length - copied, buffer->fragments[i].length - fragment_offset), SIZE_MAX); +#if ZIP_UINT64_MAX > SIZE_MAX + n = ZIP_MIN(n, SIZE_MAX); +#endif + + (void)memcpy_s(buffer->fragments[i].data + fragment_offset, (size_t)n, data + copied, (size_t)n); + + if (n == buffer->fragments[i].length - fragment_offset) { + i++; + fragment_offset = 0; + } + else { + fragment_offset += n; + } + copied += n; + } + + buffer->offset += copied; + buffer->current_fragment = i; + if (buffer->offset > buffer->size) { + buffer->size = buffer->offset; + } + + return (zip_int64_t)copied; +} diff --git a/src/libzip/zip_source_call.c b/src/libzip/zip_source_call.c new file mode 100644 index 0000000..8c98fc2 --- /dev/null +++ b/src/libzip/zip_source_call.c @@ -0,0 +1,68 @@ +/* + zip_source_call.c -- invoke callback command on zip_source + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "zipint.h" + + +zip_int64_t +_zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command) { + zip_int64_t ret; + + if ((src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(command)) == 0) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (src->src == NULL) { + ret = src->cb.f(src->ud, data, length, command); + } + else { + ret = src->cb.l(src->src, src->ud, data, length, command); + } + + if (ret < 0) { + if (command != ZIP_SOURCE_ERROR && command != ZIP_SOURCE_SUPPORTS) { + int e[2]; + + if (_zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR) < 0) { + zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); + } + else { + zip_error_set(&src->error, e[0], e[1]); + } + } + } + + return ret; +} diff --git a/src/libzip/zip_source_close.c b/src/libzip/zip_source_close.c new file mode 100644 index 0000000..1ab6219 --- /dev/null +++ b/src/libzip/zip_source_close.c @@ -0,0 +1,57 @@ +/* + fs_zip_source_close.c -- close zip_source (stop reading) + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +int +fs_zip_source_close(zip_source_t *src) { + if (!ZIP_SOURCE_IS_OPEN_READING(src)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + src->open_count--; + if (src->open_count == 0) { + _zip_source_call(src, NULL, 0, ZIP_SOURCE_CLOSE); + + if (ZIP_SOURCE_IS_LAYERED(src)) { + if (fs_zip_source_close(src->src) < 0) { + zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); + } + } + } + + return 0; +} diff --git a/src/libzip/zip_source_commit_write.c b/src/libzip/zip_source_commit_write.c new file mode 100644 index 0000000..b83800d --- /dev/null +++ b/src/libzip/zip_source_commit_write.c @@ -0,0 +1,68 @@ +/* + fs_zip_source_commit_write.c -- commit changes to file + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_commit_write(zip_source_t *src) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (!ZIP_SOURCE_IS_OPEN_WRITING(src)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (src->open_count > 1) { + zip_error_set(&src->error, ZIP_ER_INUSE, 0); + return -1; + } + else if (ZIP_SOURCE_IS_OPEN_READING(src)) { + if (fs_zip_source_close(src) < 0) { + return -1; + } + } + + if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_COMMIT_WRITE) < 0) { + src->write_state = ZIP_SOURCE_WRITE_FAILED; + return -1; + } + + src->write_state = ZIP_SOURCE_WRITE_CLOSED; + + return 0; +} diff --git a/src/libzip/zip_source_compress.c b/src/libzip/zip_source_compress.c new file mode 100644 index 0000000..4de70a4 --- /dev/null +++ b/src/libzip/zip_source_compress.c @@ -0,0 +1,398 @@ +/* + zip_source_compress.c -- (de)compression routines + Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "zipint.h" + +struct context { + zip_error_t error; + + bool end_of_input; + bool end_of_stream; + bool can_store; + bool is_stored; /* only valid if end_of_stream is true */ + bool compress; + zip_int32_t method; + + zip_uint64_t size; + zip_int64_t first_read; + zip_uint8_t buffer[BUFSIZE]; + + zip_compression_algorithm_t *algorithm; + void *ud; +}; + + +struct implementation { + zip_uint16_t method; + zip_compression_algorithm_t *compress; + zip_compression_algorithm_t *decompress; +}; + +static struct implementation implementations[] = { + {ZIP_CM_DEFLATE, &zip_algorithm_deflate_compress, &zip_algorithm_deflate_decompress}, +#if defined(HAVE_LIBBZ2) + {ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress}, +#endif +#if defined(HAVE_LIBLZMA) + {ZIP_CM_LZMA, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress}, + /* Disabled - because 7z isn't able to unpack ZIP+LZMA2 + archives made this way - and vice versa. + + {ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress}, + */ + {ZIP_CM_XZ, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress}, +#endif +#if defined(HAVE_LIBZSTD) + {ZIP_CM_ZSTD, &zip_algorithm_zstd_compress, &zip_algorithm_zstd_decompress}, +#endif + +}; + +static size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]); + +static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, zip_uint32_t compression_flags); +static zip_int64_t compress_callback(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); +static void context_free(struct context *ctx); +static struct context *context_new(zip_int32_t method, bool compress, zip_uint32_t compression_flags, zip_compression_algorithm_t *algorithm); +static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t); + +zip_compression_algorithm_t * +_zip_get_compression_algorithm(zip_int32_t method, bool compress) { + size_t i; + zip_uint16_t real_method = ZIP_CM_ACTUAL(method); + + for (i = 0; i < implementations_size; i++) { + if (implementations[i].method == real_method) { + if (compress) { + return implementations[i].compress; + } + else { + return implementations[i].decompress; + } + } + } + + return NULL; +} + +ZIP_EXTERN int +fs_zip_compression_method_supported(zip_int32_t method, int compress) { + if (method == ZIP_CM_STORE) { + return 1; + } + return _zip_get_compression_algorithm(method, compress) != NULL; +} + +zip_source_t * +zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t method, zip_uint32_t compression_flags) { + return compression_source_new(za, src, method, true, compression_flags); +} + +zip_source_t * +zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t method) { + return compression_source_new(za, src, method, false, 0); +} + + +static zip_source_t * +compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, zip_uint32_t compression_flags) { + struct context *ctx; + zip_source_t *s2; + zip_compression_algorithm_t *algorithm = NULL; + + if (src == NULL) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((algorithm = _zip_get_compression_algorithm(method, compress)) == NULL) { + zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); + return NULL; + } + + if ((ctx = context_new(method, compress, compression_flags, algorithm)) == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if ((s2 = fs_zip_source_layered(za, src, compress_callback, ctx)) == NULL) { + context_free(ctx); + return NULL; + } + + return s2; +} + + +static struct context * +context_new(zip_int32_t method, bool compress, zip_uint32_t compression_flags, zip_compression_algorithm_t *algorithm) { + struct context *ctx; + + if ((ctx = (struct context *)malloc(sizeof(*ctx))) == NULL) { + return NULL; + } + fs_zip_error_init(&ctx->error); + ctx->can_store = compress ? ZIP_CM_IS_DEFAULT(method) : false; + ctx->algorithm = algorithm; + ctx->method = method; + ctx->compress = compress; + ctx->end_of_input = false; + ctx->end_of_stream = false; + ctx->is_stored = false; + + if ((ctx->ud = ctx->algorithm->allocate(ZIP_CM_ACTUAL(method), compression_flags, &ctx->error)) == NULL) { + fs_zip_error_fini(&ctx->error); + free(ctx); + return NULL; + } + + return ctx; +} + + +static void +context_free(struct context *ctx) { + if (ctx == NULL) { + return; + } + + ctx->algorithm->deallocate(ctx->ud); + fs_zip_error_fini(&ctx->error); + + free(ctx); +} + + +static zip_int64_t +compress_read(zip_source_t *src, struct context *ctx, void *data, zip_uint64_t len) { + zip_compression_status_t ret; + bool end; + zip_int64_t n; + zip_uint64_t out_offset; + zip_uint64_t out_len; + + if (fs_zip_error_code_zip(&ctx->error) != ZIP_ER_OK) { + return -1; + } + + if (len == 0 || ctx->end_of_stream) { + return 0; + } + + out_offset = 0; + + end = false; + while (!end && out_offset < len) { + out_len = len - out_offset; + ret = ctx->algorithm->process(ctx->ud, (zip_uint8_t *)data + out_offset, &out_len); + + if (ret != ZIP_COMPRESSION_ERROR) { + out_offset += out_len; + } + + switch (ret) { + case ZIP_COMPRESSION_END: + ctx->end_of_stream = true; + + if (!ctx->end_of_input) { + /* TODO: garbage after stream, or compression ended before all data read */ + } + + if (ctx->first_read < 0) { + /* we got end of processed stream before reading any input data */ + zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); + end = true; + break; + } + if (ctx->can_store && (zip_uint64_t)ctx->first_read <= out_offset) { + ctx->is_stored = true; + ctx->size = (zip_uint64_t)ctx->first_read; + (void)memcpy_s(data, ctx->size, ctx->buffer, ctx->size); + return (zip_int64_t)ctx->size; + } + end = true; + break; + + case ZIP_COMPRESSION_OK: + break; + + case ZIP_COMPRESSION_NEED_DATA: + if (ctx->end_of_input) { + /* TODO: error: stream not ended, but no more input */ + end = true; + break; + } + + if ((n = fs_zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) { + zip_error_set_from_source(&ctx->error, src); + end = true; + break; + } + else if (n == 0) { + ctx->end_of_input = true; + ctx->algorithm->end_of_input(ctx->ud); + if (ctx->first_read < 0) { + ctx->first_read = 0; + } + } + else { + if (ctx->first_read >= 0) { + /* we overwrote a previously filled ctx->buffer */ + ctx->can_store = false; + } + else { + ctx->first_read = n; + } + + ctx->algorithm->input(ctx->ud, ctx->buffer, (zip_uint64_t)n); + } + break; + + case ZIP_COMPRESSION_ERROR: + /* error set by algorithm */ + if (fs_zip_error_code_zip(&ctx->error) == ZIP_ER_OK) { + zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); + } + end = true; + break; + } + } + + if (out_offset > 0) { + ctx->can_store = false; + ctx->size += out_offset; + return (zip_int64_t)out_offset; + } + + return (fs_zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1; +} + + +static zip_int64_t +compress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { + struct context *ctx; + + ctx = (struct context *)ud; + + switch (cmd) { + case ZIP_SOURCE_OPEN: { + zip_stat_t st; + zip_file_attributes_t attributes; + + ctx->size = 0; + ctx->end_of_input = false; + ctx->end_of_stream = false; + ctx->is_stored = false; + ctx->first_read = -1; + + if (fs_zip_source_stat(src, &st) < 0 || fs_zip_source_get_file_attributes(src, &attributes) < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + + if (!ctx->algorithm->start(ctx->ud, &st, &attributes)) { + return -1; + } + + return 0; + } + + case ZIP_SOURCE_READ: + return compress_read(src, ctx, data, len); + + case ZIP_SOURCE_CLOSE: + if (!ctx->algorithm->end(ctx->ud)) { + return -1; + } + return 0; + + case ZIP_SOURCE_STAT: { + zip_stat_t *st; + + st = (zip_stat_t *)data; + + if (ctx->compress) { + if (ctx->end_of_stream) { + st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_ACTUAL(ctx->method); + st->comp_size = ctx->size; + st->valid |= ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD; + } + else { + st->valid &= ~(ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD); + } + } + else { + st->comp_method = ZIP_CM_STORE; + st->valid |= ZIP_STAT_COMP_METHOD; + st->valid &= ~ZIP_STAT_COMP_SIZE; + if (ctx->end_of_stream) { + st->size = ctx->size; + st->valid |= ZIP_STAT_SIZE; + } + } + } + return 0; + + case ZIP_SOURCE_ERROR: + return zip_error_to_data(&ctx->error, data, len); + + case ZIP_SOURCE_FREE: + context_free(ctx); + return 0; + + case ZIP_SOURCE_GET_FILE_ATTRIBUTES: { + zip_file_attributes_t *attributes = (zip_file_attributes_t *)data; + + if (len < sizeof(*attributes)) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + + attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; + attributes->version_needed = ctx->algorithm->version_needed; + attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; + attributes->general_purpose_bit_flags = (ctx->is_stored ? 0 : ctx->algorithm->general_purpose_bit_flags(ctx->ud)); + + return sizeof(*attributes); + } + + case ZIP_SOURCE_SUPPORTS: + return ZIP_SOURCE_SUPPORTS_READABLE | fs_zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS_REOPEN, -1); + + default: + return fs_zip_source_pass_to_lower_layer(src, data, len, cmd); + } +} diff --git a/src/libzip/zip_source_crc.c b/src/libzip/zip_source_crc.c new file mode 100644 index 0000000..b131325 --- /dev/null +++ b/src/libzip/zip_source_crc.c @@ -0,0 +1,203 @@ +/* + zip_source_crc.c -- pass-through source that calculates CRC32 and size + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include + +#include "zipint.h" + +struct crc_context { + int validate; /* whether to check CRC on EOF and return error on mismatch */ + int crc_complete; /* whether CRC was computed for complete file */ + zip_error_t error; + zip_uint64_t size; + zip_uint64_t position; /* current reading position */ + zip_uint64_t crc_position; /* how far we've computed the CRC */ + zip_uint32_t crc; +}; + +static zip_int64_t crc_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); + + +zip_source_t * +zip_source_crc_create(zip_source_t *src, int validate, zip_error_t *error) { + struct crc_context *ctx; + + if (src == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((ctx = (struct crc_context *)malloc(sizeof(*ctx))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + fs_zip_error_init(&ctx->error); + ctx->validate = validate; + ctx->crc_complete = 0; + ctx->crc_position = 0; + ctx->crc = (zip_uint32_t)zng_crc32(0, NULL, 0); + ctx->size = 0; + + return fs_zip_source_layered_create(src, crc_read, ctx, error); +} + + +static zip_int64_t +crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { + struct crc_context *ctx; + zip_int64_t n; + + ctx = (struct crc_context *)_ctx; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + ctx->position = 0; + return 0; + + case ZIP_SOURCE_READ: + if ((n = fs_zip_source_read(src, data, len)) < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + + if (n == 0) { + if (ctx->crc_position == ctx->position) { + ctx->crc_complete = 1; + ctx->size = ctx->position; + + if (ctx->validate) { + struct fs_zip_stat st; + + if (fs_zip_source_stat(src, &st) < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + + if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { + zip_error_set(&ctx->error, ZIP_ER_CRC, 0); + return -1; + } + if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { + /* We don't have the index here, but the caller should know which file they are reading from. */ + zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_INVALID_FILE_LENGTH, MAX_DETAIL_INDEX)); + return -1; + } + } + } + } + else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) { + zip_uint64_t i, nn; + + for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) { + nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n - i); + + ctx->crc = (zip_uint32_t)zng_crc32(ctx->crc, (const Bytef *)data + i, (uInt)nn); + ctx->crc_position += nn; + } + } + ctx->position += (zip_uint64_t)n; + return n; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_STAT: { + zip_stat_t *st; + + st = (zip_stat_t *)data; + + if (ctx->crc_complete) { + if ((st->valid & ZIP_STAT_SIZE) && st->size != ctx->size) { + zip_error_set(&ctx->error, ZIP_ER_DATA_LENGTH, 0); + return -1; + } + /* TODO: Set comp_size, comp_method, encryption_method? + After all, this only works for uncompressed data. */ + st->size = ctx->size; + st->crc = ctx->crc; + st->comp_size = ctx->size; + st->comp_method = ZIP_CM_STORE; + st->encryption_method = ZIP_EM_NONE; + st->valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; + } + return 0; + } + + case ZIP_SOURCE_ERROR: + return zip_error_to_data(&ctx->error, data, len); + + case ZIP_SOURCE_FREE: + free(ctx); + return 0; + + case ZIP_SOURCE_SUPPORTS: { + zip_int64_t mask = zip_source_supports(src); + + if (mask < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + + mask &= ~fs_zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1); + mask |= fs_zip_source_make_command_bitmap(ZIP_SOURCE_FREE, -1); + return mask; + } + + case ZIP_SOURCE_SEEK: { + zip_int64_t new_position; + zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); + + if (args == NULL) { + return -1; + } + if (fs_zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = fs_zip_source_tell(src)) < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + + ctx->position = (zip_uint64_t)new_position; + + return 0; + } + + case ZIP_SOURCE_TELL: + return (zip_int64_t)ctx->position; + + default: + return fs_zip_source_pass_to_lower_layer(src, data, len, cmd); + } +} diff --git a/src/libzip/zip_source_error.c b/src/libzip/zip_source_error.c new file mode 100644 index 0000000..e06197b --- /dev/null +++ b/src/libzip/zip_source_error.c @@ -0,0 +1,46 @@ +/* + fs_zip_source_error.c -- get last error from zip_source + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +zip_error_t * +fs_zip_source_error(zip_source_t *src) { + return &src->error; +} + +bool +_zip_source_had_error(zip_source_t *src) { + return fs_zip_source_error(src)->zip_err != ZIP_ER_OK; +} diff --git a/src/libzip/zip_source_file.h b/src/libzip/zip_source_file.h new file mode 100644 index 0000000..2db8009 --- /dev/null +++ b/src/libzip/zip_source_file.h @@ -0,0 +1,90 @@ +/* + fs_zip_source_file.h -- header for common file operations + Copyright (C) 2020-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +struct zip_source_file_stat { + zip_uint64_t size; /* must be valid for regular files */ + time_t mtime; /* must always be valid, is initialized to current time */ + bool exists; /* must always be valid */ + bool regular_file; /* must always be valid */ +}; + +typedef struct zip_source_file_context zip_source_file_context_t; +typedef struct zip_source_file_operations zip_source_file_operations_t; +typedef struct zip_source_file_stat zip_source_file_stat_t; + +struct zip_source_file_context { + zip_error_t error; /* last error information */ + zip_int64_t supports; + + /* reading */ + char *fname; /* name of file to read from */ + void *f; /* file to read from */ + zip_stat_t st; /* stat information passed in */ + zip_file_attributes_t attributes; /* additional file attributes */ + zip_error_t stat_error; /* error returned for stat */ + zip_uint64_t start; /* start offset of data to read */ + zip_uint64_t len; /* length of the file, 0 for up to EOF */ + zip_uint64_t offset; /* current offset relative to start (0 is beginning of part we read) */ + + /* writing */ + char *tmpname; + void *fout; + + zip_source_file_operations_t *ops; + void *ops_userdata; +}; + + +/* The following methods must be implemented to support each feature: + - close, read, seek, and stat must always be implemented. + - To support specifying the file by name, open, and strdup must be implemented. + - For write support, the file must be specified by name and close, commit_write, create_temp_output, remove, rollback_write, and tell must be implemented. + - create_temp_output_cloning is always optional. */ + +struct zip_source_file_operations { + void (*close)(zip_source_file_context_t *ctx); + zip_int64_t (*commit_write)(zip_source_file_context_t *ctx); + zip_int64_t (*create_temp_output)(zip_source_file_context_t *ctx); + zip_int64_t (*create_temp_output_cloning)(zip_source_file_context_t *ctx, zip_uint64_t len); + bool (*open)(zip_source_file_context_t *ctx); + zip_int64_t (*read)(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len); + zip_int64_t (*remove)(zip_source_file_context_t *ctx); + void (*rollback_write)(zip_source_file_context_t *ctx); + bool (*seek)(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence); + bool (*stat)(zip_source_file_context_t *ctx, zip_source_file_stat_t *st); + char *(*string_duplicate)(zip_source_file_context_t *ctx, const char *); + zip_int64_t (*tell)(zip_source_file_context_t *ctx, void *f); + zip_int64_t (*write)(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len); +}; + +zip_source_t *zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error); diff --git a/src/libzip/zip_source_file_common.c b/src/libzip/zip_source_file_common.c new file mode 100644 index 0000000..f855212 --- /dev/null +++ b/src/libzip/zip_source_file_common.c @@ -0,0 +1,388 @@ +/* + zip_source_file_common.c -- create data source from file + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "zipint.h" + +#include "zip_source_file.h" + +static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd); + +static void +zip_source_file_stat_init(zip_source_file_stat_t *st) { + st->size = 0; + st->mtime = time(NULL); + st->exists = false; + st->regular_file = false; +} + +zip_source_t * +zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error) { + zip_source_file_context_t *ctx; + zip_source_t *zs; + zip_source_file_stat_t sb; + zip_uint64_t length; + + if (ops == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (ops->close == NULL || ops->read == NULL || ops->seek == NULL || ops->stat == NULL) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return NULL; + } + + if (ops->write != NULL && (ops->commit_write == NULL || ops->create_temp_output == NULL || ops->remove == NULL || ops->rollback_write == NULL || ops->tell == NULL)) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return NULL; + } + + if (fname != NULL) { + if (ops->open == NULL || ops->string_duplicate == NULL) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return NULL; + } + } + else if (file == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (len < 0) { + if (len == -1) { + len = ZIP_LENGTH_TO_END; + } + // TODO: return ZIP_ER_INVAL if len != ZIP_LENGTH_UNCHECKED? + length = 0; + } + else { + length = (zip_uint64_t)len; + } + + if (start > ZIP_INT64_MAX || start + length < start) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((ctx = (zip_source_file_context_t *)malloc(sizeof(zip_source_file_context_t))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + ctx->ops = ops; + ctx->ops_userdata = ops_userdata; + ctx->fname = NULL; + if (fname) { + if ((ctx->fname = ops->string_duplicate(ctx, fname)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + free(ctx); + return NULL; + } + } + ctx->f = file; + ctx->start = start; + ctx->len = length; + if (st) { + (void)memcpy_s(&ctx->st, sizeof(ctx->st), st, sizeof(*st)); + ctx->st.name = NULL; + ctx->st.valid &= ~ZIP_STAT_NAME; + } + else { + fs_zip_stat_init(&ctx->st); + } + + if (ctx->len > 0) { + ctx->st.size = ctx->len; + ctx->st.valid |= ZIP_STAT_SIZE; + } + + fs_zip_error_init(&ctx->stat_error); + + ctx->tmpname = NULL; + ctx->fout = NULL; + + fs_zip_error_init(&ctx->error); + fs_zip_file_attributes_init(&ctx->attributes); + + ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | fs_zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, ZIP_SOURCE_SUPPORTS_REOPEN, -1); + + zip_source_file_stat_init(&sb); + if (!ops->stat(ctx, &sb)) { + _zip_error_copy(error, &ctx->error); + free(ctx->fname); + free(ctx); + return NULL; + } + + if (!sb.exists) { + if (ctx->fname && ctx->start == 0 && ctx->len == 0 && ops->write != NULL) { + ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; + /* fs_zip_open_from_source checks for this to detect non-existing files */ + zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT); + } + else { + zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT); + free(ctx->fname); + free(ctx); + return NULL; + } + } + else { + if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) { + ctx->st.mtime = sb.mtime; + ctx->st.valid |= ZIP_STAT_MTIME; + } + if (sb.regular_file) { + ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE; + + if (ctx->start + ctx->len > sb.size) { + zip_error_set(error, ZIP_ER_INVAL, 0); + free(ctx->fname); + free(ctx); + return NULL; + } + + if (ctx->len == 0) { + if (len != ZIP_LENGTH_UNCHECKED) { + ctx->len = sb.size - ctx->start; + ctx->st.size = ctx->len; + ctx->st.valid |= ZIP_STAT_SIZE; + } + + /* when using a partial file, don't allow writing */ + if (ctx->fname && start == 0 && ops->write != NULL) { + ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; + } + } + } + + ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES); + } + + ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY); + if (ops->create_temp_output_cloning != NULL) { + if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) { + ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING); + } + } + + if ((zs = fs_zip_source_function_create(read_file, ctx, error)) == NULL) { + free(ctx->fname); + free(ctx); + return NULL; + } + + return zs; +} + + +static zip_int64_t +read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { + zip_source_file_context_t *ctx; + char *buf; + + ctx = (zip_source_file_context_t *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_ACCEPT_EMPTY: + return 0; + + case ZIP_SOURCE_BEGIN_WRITE: + /* write support should not be set if fname is NULL */ + if (ctx->fname == NULL) { + zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); + return -1; + } + return ctx->ops->create_temp_output(ctx); + + case ZIP_SOURCE_BEGIN_WRITE_CLONING: + /* write support should not be set if fname is NULL */ + if (ctx->fname == NULL) { + zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0); + return -1; + } + return ctx->ops->create_temp_output_cloning(ctx, len); + + case ZIP_SOURCE_CLOSE: + if (ctx->fname) { + ctx->ops->close(ctx); + ctx->f = NULL; + } + return 0; + + case ZIP_SOURCE_COMMIT_WRITE: { + zip_int64_t ret = ctx->ops->commit_write(ctx); + ctx->fout = NULL; + if (ret == 0) { + free(ctx->tmpname); + ctx->tmpname = NULL; + } + return ret; + } + + case ZIP_SOURCE_ERROR: + return zip_error_to_data(&ctx->error, data, len); + + case ZIP_SOURCE_FREE: + free(ctx->fname); + free(ctx->tmpname); + if (ctx->f) { + ctx->ops->close(ctx); + } + free(ctx); + return 0; + + case ZIP_SOURCE_GET_FILE_ATTRIBUTES: + if (len < sizeof(ctx->attributes)) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes)); + return sizeof(ctx->attributes); + + case ZIP_SOURCE_OPEN: + if (ctx->fname) { + if (ctx->ops->open(ctx) == false) { + return -1; + } + } + + if (ctx->start > 0) { /* TODO: rewind on re-open */ + if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)ctx->start, SEEK_SET) == false) { + /* TODO: skip by reading */ + return -1; + } + } + ctx->offset = 0; + return 0; + + case ZIP_SOURCE_READ: { + zip_int64_t i; + zip_uint64_t n; + + if (ctx->len > 0) { + n = ZIP_MIN(ctx->len - ctx->offset, len); + } + else { + n = len; + } + + if ((i = ctx->ops->read(ctx, buf, n)) < 0) { + zip_error_set(&ctx->error, ZIP_ER_READ, errno); + return -1; + } + ctx->offset += (zip_uint64_t)i; + + return i; + } + + case ZIP_SOURCE_REMOVE: + return ctx->ops->remove(ctx); + + case ZIP_SOURCE_ROLLBACK_WRITE: + ctx->ops->rollback_write(ctx); + ctx->fout = NULL; + free(ctx->tmpname); + ctx->tmpname = NULL; + return 0; + + case ZIP_SOURCE_SEEK: { + zip_int64_t new_offset = fs_zip_source_seek_compute_offset(ctx->offset, ctx->len, data, len, &ctx->error); + + if (new_offset < 0) { + return -1; + } + + /* The actual offset inside the file must be representable as zip_int64_t. */ + if (new_offset > ZIP_INT64_MAX - (zip_int64_t)ctx->start) { + zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW); + return -1; + } + + ctx->offset = (zip_uint64_t)new_offset; + + if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)(ctx->offset + ctx->start), SEEK_SET) == false) { + return -1; + } + return 0; + } + + case ZIP_SOURCE_SEEK_WRITE: { + zip_source_args_seek_t *args; + + args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); + if (args == NULL) { + return -1; + } + + if (ctx->ops->seek(ctx, ctx->fout, args->offset, args->whence) == false) { + return -1; + } + return 0; + } + + case ZIP_SOURCE_STAT: { + if (len < sizeof(ctx->st)) + return -1; + + if (fs_zip_error_code_zip(&ctx->stat_error) != 0) { + zip_error_set(&ctx->error, fs_zip_error_code_zip(&ctx->stat_error), fs_zip_error_code_system(&ctx->stat_error)); + return -1; + } + + (void)memcpy_s(data, sizeof(ctx->st), &ctx->st, sizeof(ctx->st)); + return sizeof(ctx->st); + } + + case ZIP_SOURCE_SUPPORTS: + return ctx->supports; + + case ZIP_SOURCE_TELL: + return (zip_int64_t)ctx->offset; + + case ZIP_SOURCE_TELL_WRITE: + return ctx->ops->tell(ctx, ctx->fout); + + case ZIP_SOURCE_WRITE: + return ctx->ops->write(ctx, data, len); + + default: + zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } +} diff --git a/src/libzip/zip_source_free.c b/src/libzip/zip_source_free.c new file mode 100644 index 0000000..5266039 --- /dev/null +++ b/src/libzip/zip_source_free.c @@ -0,0 +1,71 @@ +/* + zip_source_free.c -- free zip data source + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN void +zip_source_free(zip_source_t *src) { + if (src == NULL) + return; + + if (src->refcount > 0) { + src->refcount--; + } + if (src->refcount > 0) { + return; + } + + if (ZIP_SOURCE_IS_OPEN_READING(src)) { + src->open_count = 1; /* force close */ + fs_zip_source_close(src); + } + if (ZIP_SOURCE_IS_OPEN_WRITING(src)) { + fs_zip_source_rollback_write(src); + } + + if (src->source_archive && !src->source_closed) { + _zip_deregister_source(src->source_archive, src); + } + + (void)_zip_source_call(src, NULL, 0, ZIP_SOURCE_FREE); + + if (src->src) { + zip_source_free(src->src); + } + + free(src); +} diff --git a/src/libzip/zip_source_function.c b/src/libzip/zip_source_function.c new file mode 100644 index 0000000..8374e6f --- /dev/null +++ b/src/libzip/zip_source_function.c @@ -0,0 +1,99 @@ +/* + fs_zip_source_function.c -- create zip data source from callback function + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN zip_source_t * +fs_zip_source_function(zip_t *za, zip_source_callback zcb, void *ud) { + if (za == NULL) { + return NULL; + } + + return fs_zip_source_function_create(zcb, ud, &za->error); +} + + +ZIP_EXTERN zip_source_t * +fs_zip_source_function_create(zip_source_callback zcb, void *ud, zip_error_t *error) { + zip_source_t *zs; + + if ((zs = _zip_source_new(error)) == NULL) + return NULL; + + zs->cb.f = zcb; + zs->ud = ud; + + zs->supports = zcb(ud, NULL, 0, ZIP_SOURCE_SUPPORTS); + if (zs->supports < 0) { + zs->supports = ZIP_SOURCE_SUPPORTS_READABLE; + } + zs->supports |= fs_zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, -1); + + return zs; +} + + +ZIP_EXTERN void +fs_zip_source_keep(zip_source_t *src) { + src->refcount++; +} + + +zip_source_t * +_zip_source_new(zip_error_t *error) { + zip_source_t *src; + + if ((src = (zip_source_t *)malloc(sizeof(*src))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + src->src = NULL; + src->cb.f = NULL; + src->ud = NULL; + src->open_count = 0; + src->write_state = ZIP_SOURCE_WRITE_CLOSED; + src->source_closed = false; + src->source_archive = NULL; + src->refcount = 1; + fs_zip_error_init(&src->error); + src->eof = false; + src->had_read_error = false; + src->bytes_read = 0; + + return src; +} diff --git a/src/libzip/zip_source_get_file_attributes.c b/src/libzip/zip_source_get_file_attributes.c new file mode 100644 index 0000000..a071236 --- /dev/null +++ b/src/libzip/zip_source_get_file_attributes.c @@ -0,0 +1,108 @@ +/* + fs_zip_source_get_file_attributes.c -- get attributes for file from source + Copyright (C) 2020 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipint.h" + +ZIP_EXTERN void +fs_zip_file_attributes_init(zip_file_attributes_t *attributes) { + attributes->valid = 0; + attributes->version = 1; +} + +int +fs_zip_source_get_file_attributes(zip_source_t *src, zip_file_attributes_t *attributes) { + if (src->source_closed) { + return -1; + } + if (attributes == NULL) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + fs_zip_file_attributes_init(attributes); + + if (src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES)) { + if (_zip_source_call(src, attributes, sizeof(*attributes), ZIP_SOURCE_GET_FILE_ATTRIBUTES) < 0) { + return -1; + } + } + + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_file_attributes_t lower_attributes; + + fs_zip_file_attributes_init(&lower_attributes); + + if (fs_zip_source_get_file_attributes(src->src, &lower_attributes) < 0) { + zip_error_set_from_source(&src->error, src->src); + return -1; + } + + if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) == 0) { + attributes->host_system = lower_attributes.host_system; + attributes->valid |= ZIP_FILE_ATTRIBUTES_HOST_SYSTEM; + } + if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_ASCII) && (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) == 0) { + attributes->ascii = lower_attributes.ascii; + attributes->valid |= ZIP_FILE_ATTRIBUTES_ASCII; + } + if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED)) { + if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) { + attributes->version_needed = ZIP_MAX(lower_attributes.version_needed, attributes->version_needed); + } + else { + attributes->version_needed = lower_attributes.version_needed; + attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED; + } + } + if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) == 0) { + attributes->external_file_attributes = lower_attributes.external_file_attributes; + attributes->valid |= ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES; + } + if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS)) { + if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) { + /* only take from lower level what is not defined at current level */ + lower_attributes.general_purpose_bit_mask &= ~attributes->general_purpose_bit_mask; + + attributes->general_purpose_bit_flags |= lower_attributes.general_purpose_bit_flags & lower_attributes.general_purpose_bit_mask; + attributes->general_purpose_bit_mask |= lower_attributes.general_purpose_bit_mask; + } + else { + attributes->valid |= ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; + attributes->general_purpose_bit_flags = lower_attributes.general_purpose_bit_flags; + attributes->general_purpose_bit_mask = lower_attributes.general_purpose_bit_mask; + } + } + } + + return 0; +} diff --git a/src/libzip/zip_source_is_deleted.c b/src/libzip/zip_source_is_deleted.c new file mode 100644 index 0000000..720b821 --- /dev/null +++ b/src/libzip/zip_source_is_deleted.c @@ -0,0 +1,41 @@ +/* + fs_zip_source_is_deleted.c -- was archive was removed? + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_is_deleted(zip_source_t *src) { + return src->write_state == ZIP_SOURCE_WRITE_REMOVED; +} diff --git a/src/libzip/zip_source_layered.c b/src/libzip/zip_source_layered.c new file mode 100644 index 0000000..f1524ec --- /dev/null +++ b/src/libzip/zip_source_layered.c @@ -0,0 +1,75 @@ +/* + fs_zip_source_layered.c -- create layered source + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +zip_source_t * +fs_zip_source_layered(zip_t *za, zip_source_t *src, zip_source_layered_callback cb, void *ud) { + if (za == NULL) + return NULL; + + return fs_zip_source_layered_create(src, cb, ud, &za->error); +} + + +zip_source_t * +fs_zip_source_layered_create(zip_source_t *src, zip_source_layered_callback cb, void *ud, zip_error_t *error) { + zip_source_t *zs; + zip_int64_t lower_supports, supports; + + lower_supports = zip_source_supports(src); + supports = cb(src, ud, &lower_supports, sizeof(lower_supports), ZIP_SOURCE_SUPPORTS); + if (supports < 0) { + zip_error_set(error,ZIP_ER_INVAL, 0); /* Initialize in case cb doesn't return valid error. */ + cb(src, ud, error, sizeof(*error), ZIP_SOURCE_ERROR); + return NULL; + } + + if ((zs = _zip_source_new(error)) == NULL) { + return NULL; + } + + zs->src = src; + zs->cb.l = cb; + zs->ud = ud; + zs->supports = supports; + + /* Layered sources can't support writing, since we currently have no use case. If we want to revisit this, we have to define how the two sources interact. */ + zs->supports &= ~(ZIP_SOURCE_SUPPORTS_WRITABLE & ~ZIP_SOURCE_SUPPORTS_SEEKABLE); + + return zs; +} diff --git a/src/libzip/zip_source_open.c b/src/libzip/zip_source_open.c new file mode 100644 index 0000000..45a43eb --- /dev/null +++ b/src/libzip/zip_source_open.c @@ -0,0 +1,76 @@ +/* + fs_zip_source_open.c -- open zip_source (prepare for reading) + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +ZIP_EXTERN int +fs_zip_source_open(zip_source_t *src) { + if (src->source_closed) { + return -1; + } + if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { + zip_error_set(&src->error, ZIP_ER_DELETED, 0); + return -1; + } + + if (ZIP_SOURCE_IS_OPEN_READING(src)) { + if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) == 0) { + zip_error_set(&src->error, ZIP_ER_INUSE, 0); + return -1; + } + } + else { + if (ZIP_SOURCE_IS_LAYERED(src)) { + if (fs_zip_source_open(src->src) < 0) { + zip_error_set_from_source(&src->error, src->src); + return -1; + } + } + + if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + fs_zip_source_close(src->src); + } + return -1; + } + } + + src->eof = false; + src->had_read_error = false; + _zip_error_clear(&src->error); + src->bytes_read = 0; + src->open_count++; + + return 0; +} diff --git a/src/libzip/zip_source_pass_to_lower_layer.c b/src/libzip/zip_source_pass_to_lower_layer.c new file mode 100644 index 0000000..54fcf8c --- /dev/null +++ b/src/libzip/zip_source_pass_to_lower_layer.c @@ -0,0 +1,78 @@ +/* + fs_zip_source_pass_to_lower_layer.c -- pass command to lower layer + Copyright (C) 2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "zipint.h" + +zip_int64_t fs_zip_source_pass_to_lower_layer(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command) { + switch (command) { + case ZIP_SOURCE_OPEN: + case ZIP_SOURCE_CLOSE: + case ZIP_SOURCE_FREE: + case ZIP_SOURCE_GET_FILE_ATTRIBUTES: + case ZIP_SOURCE_SUPPORTS_REOPEN: + return 0; + + case ZIP_SOURCE_STAT: + return sizeof(zip_stat_t); + + case ZIP_SOURCE_ACCEPT_EMPTY: + case ZIP_SOURCE_ERROR: + case ZIP_SOURCE_READ: + case ZIP_SOURCE_SEEK: + case ZIP_SOURCE_TELL: + return _zip_source_call(src, data, length, command); + + + case ZIP_SOURCE_BEGIN_WRITE: + case ZIP_SOURCE_BEGIN_WRITE_CLONING: + case ZIP_SOURCE_COMMIT_WRITE: + case ZIP_SOURCE_REMOVE: + case ZIP_SOURCE_ROLLBACK_WRITE: + case ZIP_SOURCE_SEEK_WRITE: + case ZIP_SOURCE_TELL_WRITE: + case ZIP_SOURCE_WRITE: + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + + case ZIP_SOURCE_SUPPORTS: + if (length < sizeof(zip_int64_t)) { + zip_error_set(&src->error, ZIP_ER_INTERNAL, 0); + return -1; + } + return *(zip_int64_t *)data; + + default: + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } +} \ No newline at end of file diff --git a/src/libzip/zip_source_read.c b/src/libzip/zip_source_read.c new file mode 100644 index 0000000..9d393fa --- /dev/null +++ b/src/libzip/zip_source_read.c @@ -0,0 +1,96 @@ +/* + fs_zip_source_read.c -- read data from zip_source + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +zip_int64_t +fs_zip_source_read(zip_source_t *src, void *data, zip_uint64_t len) { + zip_uint64_t bytes_read; + zip_int64_t n; + + if (src->source_closed) { + return -1; + } + if (!ZIP_SOURCE_IS_OPEN_READING(src) || len > ZIP_INT64_MAX || (len > 0 && data == NULL)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (src->had_read_error) { + return -1; + } + + if (_zip_source_eof(src)) { + return 0; + } + + if (len == 0) { + return 0; + } + + bytes_read = 0; + while (bytes_read < len) { + if ((n = _zip_source_call(src, (zip_uint8_t *)data + bytes_read, len - bytes_read, ZIP_SOURCE_READ)) < 0) { + src->had_read_error = true; + if (bytes_read == 0) { + return -1; + } + else { + return (zip_int64_t)bytes_read; + } + } + + if (n == 0) { + src->eof = 1; + break; + } + + bytes_read += (zip_uint64_t)n; + } + + if (src->bytes_read + bytes_read < src->bytes_read) { + src->bytes_read = ZIP_UINT64_MAX; + } + else { + src->bytes_read += bytes_read; + } + return (zip_int64_t)bytes_read; +} + + +bool +_zip_source_eof(zip_source_t *src) { + return src->eof; +} diff --git a/src/libzip/zip_source_remove.c b/src/libzip/zip_source_remove.c new file mode 100644 index 0000000..1139c16 --- /dev/null +++ b/src/libzip/zip_source_remove.c @@ -0,0 +1,65 @@ +/* + zip_source_remove.c -- remove empty archive + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "zipint.h" + + +int +zip_source_remove(zip_source_t *src) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { + return 0; + } + + if (ZIP_SOURCE_IS_OPEN_READING(src)) { + if (fs_zip_source_close(src) < 0) { + return -1; + } + } + if (src->write_state != ZIP_SOURCE_WRITE_CLOSED) { + fs_zip_source_rollback_write(src); + } + + if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_REMOVE) < 0) { + return -1; + } + + src->write_state = ZIP_SOURCE_WRITE_REMOVED; + + return 0; +} diff --git a/src/libzip/zip_source_rollback_write.c b/src/libzip/zip_source_rollback_write.c new file mode 100644 index 0000000..c35045e --- /dev/null +++ b/src/libzip/zip_source_rollback_write.c @@ -0,0 +1,50 @@ +/* + fs_zip_source_rollback_write.c -- discard changes + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN void +fs_zip_source_rollback_write(zip_source_t *src) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + return; + } + + if (src->write_state != ZIP_SOURCE_WRITE_OPEN && src->write_state != ZIP_SOURCE_WRITE_FAILED) { + return; + } + + _zip_source_call(src, NULL, 0, ZIP_SOURCE_ROLLBACK_WRITE); + src->write_state = ZIP_SOURCE_WRITE_CLOSED; +} diff --git a/src/libzip/zip_source_seek.c b/src/libzip/zip_source_seek.c new file mode 100644 index 0000000..d4669ca --- /dev/null +++ b/src/libzip/zip_source_seek.c @@ -0,0 +1,95 @@ +/* + fs_zip_source_seek.c -- seek to offset + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_seek(zip_source_t *src, zip_int64_t offset, int whence) { + zip_source_args_seek_t args; + + if (src->source_closed) { + return -1; + } + if (!ZIP_SOURCE_IS_OPEN_READING(src) || (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + args.offset = offset; + args.whence = whence; + + if (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK) < 0) { + return -1; + } + + src->eof = 0; + return 0; +} + + +zip_int64_t +fs_zip_source_seek_compute_offset(zip_uint64_t offset, zip_uint64_t length, void *data, zip_uint64_t data_length, zip_error_t *error) { + zip_int64_t new_offset; + zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, data_length, error); + + if (args == NULL) { + return -1; + } + + switch (args->whence) { + case SEEK_CUR: + new_offset = (zip_int64_t)offset + args->offset; + break; + + case SEEK_END: + new_offset = (zip_int64_t)length + args->offset; + break; + + case SEEK_SET: + new_offset = args->offset; + break; + + default: + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + if (new_offset < 0 || (zip_uint64_t)new_offset > length) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + return new_offset; +} diff --git a/src/libzip/zip_source_seek_write.c b/src/libzip/zip_source_seek_write.c new file mode 100644 index 0000000..94b5b17 --- /dev/null +++ b/src/libzip/zip_source_seek_write.c @@ -0,0 +1,56 @@ +/* + fs_zip_source_seek_write.c -- seek to offset for writing + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_seek_write(zip_source_t *src, zip_int64_t offset, int whence) { + zip_source_args_seek_t args; + + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (!ZIP_SOURCE_IS_OPEN_WRITING(src) || (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + args.offset = offset; + args.whence = whence; + + return (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK_WRITE) < 0 ? -1 : 0); +} diff --git a/src/libzip/zip_source_stat.c b/src/libzip/zip_source_stat.c new file mode 100644 index 0000000..7267cc7 --- /dev/null +++ b/src/libzip/zip_source_stat.c @@ -0,0 +1,66 @@ +/* + fs_zip_source_stat.c -- get meta information from zip_source + Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_source_stat(zip_source_t *src, zip_stat_t *st) { + if (src->source_closed) { + return -1; + } + if (st == NULL) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { + zip_error_set(&src->error, ZIP_ER_READ, ENOENT); + } + + fs_zip_stat_init(st); + + if (ZIP_SOURCE_IS_LAYERED(src)) { + if (fs_zip_source_stat(src->src, st) < 0) { + zip_error_set_from_source(&src->error, src->src); + return -1; + } + } + + if (_zip_source_call(src, st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { + return -1; + } + + return 0; +} diff --git a/src/libzip/zip_source_supports.c b/src/libzip/zip_source_supports.c new file mode 100644 index 0000000..4ae9add --- /dev/null +++ b/src/libzip/zip_source_supports.c @@ -0,0 +1,74 @@ +/* + zip_source_supports.c -- check for supported functions + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +zip_int64_t +zip_source_supports(zip_source_t *src) { + return src->supports; +} + +bool +zip_source_supports_reopen(zip_source_t *src) { + return (zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SUPPORTS_REOPEN)) != 0; +} + +ZIP_EXTERN zip_int64_t +fs_zip_source_make_command_bitmap(zip_source_cmd_t cmd0, ...) { + zip_int64_t bitmap; + va_list ap; + + bitmap = ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd0); + + + va_start(ap, cmd0); + for (;;) { + int cmd = va_arg(ap, int); + if (cmd < 0) { + break; + } + bitmap |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd); + } + va_end(ap); + + return bitmap; +} + + +ZIP_EXTERN int fs_zip_source_is_seekable(zip_source_t *src) { + return ZIP_SOURCE_CHECK_SUPPORTED(zip_source_supports(src->src), ZIP_SOURCE_SEEK); +} diff --git a/src/libzip/zip_source_tell.c b/src/libzip/zip_source_tell.c new file mode 100644 index 0000000..2108113 --- /dev/null +++ b/src/libzip/zip_source_tell.c @@ -0,0 +1,57 @@ +/* + fs_zip_source_tell.c -- report current offset + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_int64_t +fs_zip_source_tell(zip_source_t *src) { + if (src->source_closed) { + return -1; + } + if (!ZIP_SOURCE_IS_OPEN_READING(src)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((src->supports & (ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL) | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK))) == 0) { + if (src->bytes_read > ZIP_INT64_MAX) { + zip_error_set(&src->error, ZIP_ER_TELL, EOVERFLOW); + return -1; + } + return (zip_int64_t)src->bytes_read; + } + + return _zip_source_call(src, NULL, 0, ZIP_SOURCE_TELL); +} diff --git a/src/libzip/zip_source_tell_write.c b/src/libzip/zip_source_tell_write.c new file mode 100644 index 0000000..e71ce4d --- /dev/null +++ b/src/libzip/zip_source_tell_write.c @@ -0,0 +1,51 @@ +/* + fs_zip_source_tell_write.c -- report current offset for writing + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_int64_t +fs_zip_source_tell_write(zip_source_t *src) { + if (ZIP_SOURCE_IS_LAYERED(src)) { + zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + + if (!ZIP_SOURCE_IS_OPEN_WRITING(src)) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_source_call(src, NULL, 0, ZIP_SOURCE_TELL_WRITE); +} diff --git a/src/libzip/zip_source_window.c b/src/libzip/zip_source_window.c new file mode 100644 index 0000000..19515ed --- /dev/null +++ b/src/libzip/zip_source_window.c @@ -0,0 +1,357 @@ +/* + zip_source_window.c -- return part of lower source + Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include + +#include "zipint.h" + +struct window { + zip_uint64_t start; /* where in file we start reading */ + zip_uint64_t end; /* where in file we stop reading */ + bool end_valid; /* whether end is set, otherwise read until EOF */ + + /* if not NULL, read file data for this file */ + zip_t *source_archive; + zip_uint64_t source_index; + + zip_uint64_t offset; /* offset in src for next read */ + + zip_stat_t stat; + zip_uint64_t stat_invalid; + zip_file_attributes_t attributes; + zip_error_t error; + zip_int64_t supports; + bool needs_seek; +}; + +static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t); + + +ZIP_EXTERN zip_source_t * +fs_zip_source_window_create(zip_source_t *src, zip_uint64_t start, zip_int64_t len, zip_error_t *error) { + return _zip_source_window_new(src, start, len, NULL, 0, NULL, NULL, 0, false, error); +} + + +zip_source_t * +_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_uint64_t st_invalid, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, bool take_ownership, zip_error_t *error) { + zip_source_t* window_source; + struct window *ctx; + + if (src == NULL || length < -1 || (source_archive == NULL && source_index != 0)) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (length >= 0) { + if (start + (zip_uint64_t)length < start) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + } + + if ((ctx = (struct window *)malloc(sizeof(*ctx))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + ctx->start = start; + if (length == -1) { + ctx->end_valid = false; + } + else { + ctx->end = start + (zip_uint64_t)length; + ctx->end_valid = true; + } + fs_zip_stat_init(&ctx->stat); + ctx->stat_invalid = st_invalid; + if (attributes != NULL) { + (void)memcpy_s(&ctx->attributes, sizeof(ctx->attributes), attributes, sizeof(ctx->attributes)); + } + else { + fs_zip_file_attributes_init(&ctx->attributes); + } + ctx->source_archive = source_archive; + ctx->source_index = source_index; + fs_zip_error_init(&ctx->error); + ctx->supports = (zip_source_supports(src) & (ZIP_SOURCE_SUPPORTS_SEEKABLE | ZIP_SOURCE_SUPPORTS_REOPEN)) | (fs_zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, ZIP_SOURCE_FREE, -1)); + ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false; + + if (st) { + if (_zip_stat_merge(&ctx->stat, st, error) < 0) { + free(ctx); + return NULL; + } + } + + window_source = fs_zip_source_layered_create(src, window_read, ctx, error); + if (window_source != NULL && !take_ownership) { + fs_zip_source_keep(src); + } + return window_source; +} + + +int +_zip_source_set_source_archive(zip_source_t *src, zip_t *za) { + src->source_archive = za; + return _zip_register_source(za, src); +} + + +/* called by fs_zip_discard to avoid operating on file from closed archive */ +void +_zip_source_invalidate(zip_source_t *src) { + src->source_closed = 1; + + if (fs_zip_error_code_zip(&src->error) == ZIP_ER_OK) { + zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0); + } +} + + +static zip_int64_t +window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { + struct window *ctx; + zip_int64_t ret; + zip_uint64_t n, i; + + ctx = (struct window *)_ctx; + + switch (cmd) { + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_ERROR: + return zip_error_to_data(&ctx->error, data, len); + + case ZIP_SOURCE_FREE: + free(ctx); + return 0; + + case ZIP_SOURCE_OPEN: + if (ctx->source_archive) { + zip_uint64_t offset; + + if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) { + return -1; + } + if (ctx->end + offset < ctx->end) { + /* zip archive data claims end of data past zip64 limits */ + zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, ctx->source_index)); + return -1; + } + ctx->start += offset; + ctx->end += offset; + ctx->source_archive = NULL; + } + + if (!ctx->needs_seek) { + DEFINE_BYTE_ARRAY(b, BUFSIZE); + + if (!byte_array_init(b, BUFSIZE)) { + zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); + return -1; + } + + for (n = 0; n < ctx->start; n += (zip_uint64_t)ret) { + i = (ctx->start - n > BUFSIZE ? BUFSIZE : ctx->start - n); + if ((ret = fs_zip_source_read(src, b, i)) < 0) { + zip_error_set_from_source(&ctx->error, src); + byte_array_fini(b); + return -1; + } + if (ret == 0) { + zip_error_set(&ctx->error, ZIP_ER_EOF, 0); + byte_array_fini(b); + return -1; + } + } + + byte_array_fini(b); + } + + ctx->offset = ctx->start; + return 0; + + case ZIP_SOURCE_READ: + if (ctx->end_valid && len > ctx->end - ctx->offset) { + len = ctx->end - ctx->offset; + } + + if (len == 0) { + return 0; + } + + if (ctx->needs_seek) { + if (fs_zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + } + + if ((ret = fs_zip_source_read(src, data, len)) < 0) { + zip_error_set(&ctx->error, ZIP_ER_EOF, 0); + return -1; + } + + ctx->offset += (zip_uint64_t)ret; + + if (ret == 0) { + if (ctx->end_valid && ctx->offset < ctx->end) { + zip_error_set(&ctx->error, ZIP_ER_EOF, 0); + return -1; + } + } + return ret; + + case ZIP_SOURCE_SEEK: { + zip_int64_t new_offset; + + if (!ctx->end_valid) { + zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); + + if (args == NULL) { + return -1; + } + if (args->whence == SEEK_END) { + if (fs_zip_source_seek(src, args->offset, args->whence) < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + new_offset = fs_zip_source_tell(src); + if (new_offset < 0) { + zip_error_set_from_source(&ctx->error, src); + return -1; + } + if ((zip_uint64_t)new_offset < ctx->start) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + (void)fs_zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET); + return -1; + } + ctx->offset = (zip_uint64_t)new_offset; + return 0; + } + } + + new_offset = fs_zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error); + + if (new_offset < 0) { + return -1; + } + + ctx->offset = (zip_uint64_t)new_offset + ctx->start; + return 0; + } + + case ZIP_SOURCE_STAT: { + zip_stat_t *st; + + st = (zip_stat_t *)data; + + if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) { + return -1; + } + + if (!(ctx->stat.valid & ZIP_STAT_SIZE)) { + if (ctx->end_valid) { + st->valid |= ZIP_STAT_SIZE; + st->size = ctx->end - ctx->start; + } + else if (st->valid & ZIP_STAT_SIZE) { + st->size -= ctx->start; + } + } + + st->valid &= ~ctx->stat_invalid; + + return 0; + } + + case ZIP_SOURCE_GET_FILE_ATTRIBUTES: + if (len < sizeof(ctx->attributes)) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + + (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes)); + return sizeof(ctx->attributes); + + case ZIP_SOURCE_SUPPORTS: + return ctx->supports; + + case ZIP_SOURCE_TELL: + return (zip_int64_t)(ctx->offset - ctx->start); + + default: + return fs_zip_source_pass_to_lower_layer(src, data, len, cmd); + } +} + + +void +_zip_deregister_source(zip_t *za, zip_source_t *src) { + unsigned int i; + + for (i = 0; i < za->nopen_source; i++) { + if (za->open_source[i] == src) { + za->open_source[i] = za->open_source[za->nopen_source - 1]; + za->nopen_source--; + break; + } + } +} + + +int +_zip_register_source(zip_t *za, zip_source_t *src) { + zip_source_t **open_source; + + if (za->nopen_source + 1 >= za->nopen_source_alloc) { + unsigned int n; + n = za->nopen_source_alloc + 10; + open_source = (zip_source_t **)realloc(za->open_source, n * sizeof(zip_source_t *)); + if (open_source == NULL) { + zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + za->nopen_source_alloc = n; + za->open_source = open_source; + } + + za->open_source[za->nopen_source++] = src; + + return 0; +} diff --git a/src/libzip/zip_source_write.c b/src/libzip/zip_source_write.c new file mode 100644 index 0000000..30e3a29 --- /dev/null +++ b/src/libzip/zip_source_write.c @@ -0,0 +1,46 @@ +/* + fs_zip_source_write.c -- start a new file for writing + Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN zip_int64_t +fs_zip_source_write(zip_source_t *src, const void *data, zip_uint64_t length) { + if (!ZIP_SOURCE_IS_OPEN_WRITING(src) || length > ZIP_INT64_MAX) { + zip_error_set(&src->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_source_call(src, (void *)data, length, ZIP_SOURCE_WRITE); +} diff --git a/src/libzip/zip_source_zip.c b/src/libzip/zip_source_zip.c new file mode 100644 index 0000000..f0a4dab --- /dev/null +++ b/src/libzip/zip_source_zip.c @@ -0,0 +1,63 @@ +/* + zip_source_zip.c -- create data source from zip file + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#define _ZIP_COMPILING_DEPRECATED +#include "zipint.h" + +ZIP_EXTERN zip_source_t *zip_source_zip_create(zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, zip_error_t *error) { + if (len < -1) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (len == 0) { + len = -1; + } + + if (start == 0 && len == -1) { + flags |= ZIP_FL_COMPRESSED; + } + else { + flags &= ~ZIP_FL_COMPRESSED; + } + + return fs_zip_source_zip_file_create(srcza, srcidx, flags, start, len, NULL, error); +} + + +ZIP_EXTERN zip_source_t *zip_source_zip(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len) { + return zip_source_zip_create(srcza, srcidx, flags, start, len, &za->error); +} diff --git a/src/libzip/zip_source_zip_new.c b/src/libzip/zip_source_zip_new.c new file mode 100644 index 0000000..746642a --- /dev/null +++ b/src/libzip/zip_source_zip_new.c @@ -0,0 +1,312 @@ +/* + zip_source_zip_new.c -- prepare data structures for fs_zip_fopen/zip_source_zip + Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + +static void _zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de); + +ZIP_EXTERN zip_source_t *fs_zip_source_zip_file(zip_t* za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, const char *password) { + return fs_zip_source_zip_file_create(srcza, srcidx, flags, start, len, password, &za->error); +} + + +ZIP_EXTERN zip_source_t *fs_zip_source_zip_file_create(zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, const char *password, zip_error_t *error) { + /* TODO: We need to make sure that the returned source is invalidated when srcza is closed. */ + zip_source_t *src, *s2; + zip_stat_t st; + zip_file_attributes_t attributes; + zip_dirent_t *de; + bool partial_data, needs_crc, encrypted, needs_decrypt, compressed, needs_decompress, changed_data, have_size, have_comp_size; + zip_flags_t stat_flags; + zip_int64_t data_len; + bool take_ownership = false; + bool empty_data = false; + + if (srcza == NULL || srcidx >= srcza->nentry || len < -1) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (flags & ZIP_FL_ENCRYPTED) { + flags |= ZIP_FL_COMPRESSED; + } + + changed_data = false; + if ((flags & ZIP_FL_UNCHANGED) == 0) { + zip_entry_t *entry = srcza->entry + srcidx; + if (ZIP_ENTRY_DATA_CHANGED(entry)) { + if ((flags & ZIP_FL_COMPRESSED) || !zip_source_supports_reopen(entry->source)) { + zip_error_set(error, ZIP_ER_CHANGED, 0); + return NULL; + } + + changed_data = true; + } + else if (entry->deleted) { + zip_error_set(error, ZIP_ER_CHANGED, 0); + return NULL; + } + } + + stat_flags = flags; + if (!changed_data) { + stat_flags |= ZIP_FL_UNCHANGED; + } + + if (fs_zip_stat_index(srcza, srcidx, stat_flags, &st) < 0) { + zip_error_set(error, ZIP_ER_INTERNAL, 0); + return NULL; + } + + if ((start > 0 || len >= 0) && (flags & ZIP_FL_COMPRESSED)) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + have_size = (st.valid & ZIP_STAT_SIZE) != 0; + /* overflow or past end of file */ + if (len >= 0 && ((start > 0 && start + len < start) || (have_size && start + len > st.size))) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (len == -1) { + if (have_size) { + if (st.size - start > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + data_len = (zip_int64_t)(st.size - start); + } + else { + data_len = -1; + } + } + else { + data_len = len; + } + + if (have_size) { + partial_data = (zip_uint64_t)(data_len) < st.size; + } + else { + partial_data = true; + } + encrypted = (st.valid & ZIP_STAT_ENCRYPTION_METHOD) && (st.encryption_method != ZIP_EM_NONE); + needs_decrypt = ((flags & ZIP_FL_ENCRYPTED) == 0) && encrypted; + compressed = (st.valid & ZIP_STAT_COMP_METHOD) && (st.comp_method != ZIP_CM_STORE); + needs_decompress = ((flags & ZIP_FL_COMPRESSED) == 0) && compressed; + /* when reading the whole file, check for CRC errors */ + needs_crc = ((flags & ZIP_FL_COMPRESSED) == 0 || !compressed) && !partial_data && (st.valid & ZIP_STAT_CRC) != 0; + + if (needs_decrypt) { + if (password == NULL) { + password = srcza->default_password; + } + if (password == NULL) { + zip_error_set(error, ZIP_ER_NOPASSWD, 0); + return NULL; + } + } + + if ((de = _zip_get_dirent(srcza, srcidx, flags, error)) == NULL) { + return NULL; + } + _zip_file_attributes_from_dirent(&attributes, de); + + have_comp_size = (st.valid & ZIP_STAT_COMP_SIZE) != 0; + if (needs_decrypt || needs_decompress) { + empty_data = (have_comp_size && st.comp_size == 0); + } + else { + empty_data = (have_size && st.size == 0); + } + if (empty_data) { + src = zip_source_buffer_with_attributes_create(NULL, 0, 0, &attributes, error); + } + else { + src = NULL; + } + + + /* If we created source buffer above, we want the window source to take ownership of it. */ + take_ownership = src != NULL; + /* if we created a buffer source above, then treat it as if + reading the changed data - that way we don't need add another + special case to the code below that wraps it in the window + source */ + changed_data = changed_data || (src != NULL); + + if (partial_data && !needs_decrypt && !needs_decompress) { + struct fs_zip_stat st2; + zip_t *source_archive; + zip_uint64_t source_index; + + if (changed_data) { + if (src == NULL) { + src = srcza->entry[srcidx].source; + } + source_archive = NULL; + source_index = 0; + } + else { + src = srcza->src; + source_archive = srcza; + source_index = srcidx; + } + + st2.comp_method = ZIP_CM_STORE; + st2.valid = ZIP_STAT_COMP_METHOD; + if (data_len >= 0) { + st2.size = (zip_uint64_t)data_len; + st2.comp_size = (zip_uint64_t)data_len; + st2.valid |= ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE; + } + if (st.valid & ZIP_STAT_MTIME) { + st2.mtime = st.mtime; + st2.valid |= ZIP_STAT_MTIME; + } + + if ((src = _zip_source_window_new(src, start, data_len, &st2, ZIP_STAT_NAME, &attributes, source_archive, source_index, take_ownership, error)) == NULL) { + return NULL; + } + } + /* here we restrict src to file data, so no point in doing it for + source that already represents only the file data */ + else if (!changed_data) { + /* this branch is executed only for archive sources; we know + that stat data come from the archive too, so it's safe to + assume that st has a comp_size specified */ + if (st.comp_size > ZIP_INT64_MAX) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + /* despite the fact that we want the whole data file, we still + wrap the source into a window source to add st and + attributes and to have a source that positions the read + offset properly before each read for multiple zip_file_t + referring to the same underlying source */ + if ((src = _zip_source_window_new(srcza->src, 0, (zip_int64_t)st.comp_size, &st, ZIP_STAT_NAME, &attributes, srcza, srcidx, take_ownership, error)) == NULL) { + return NULL; + } + } + else { + /* this branch gets executed when reading the whole changed + data file or when "reading" from a zero-sized source buffer + that we created above */ + if (src == NULL) { + src = srcza->entry[srcidx].source; + } + /* despite the fact that we want the whole data file, we still + wrap the source into a window source to add st and + attributes and to have a source that positions the read + offset properly before each read for multiple zip_file_t + referring to the same underlying source */ + if ((src = _zip_source_window_new(src, 0, data_len, &st, ZIP_STAT_NAME, &attributes, NULL, 0, take_ownership, error)) == NULL) { + return NULL; + } + } + + /* In all cases, src is a window source and therefore is owned by this function. */ + + if (_zip_source_set_source_archive(src, srcza) < 0) { + zip_source_free(src); + return NULL; + } + + /* creating a layered source calls zip_keep() on the lower layer, so we free it */ + + if (needs_decrypt) { + zip_encryption_implementation enc_impl; + + if ((enc_impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + return NULL; + } + + s2 = enc_impl(srcza, src, st.encryption_method, 0, password); + if (s2 == NULL) { + zip_source_free(src); + return NULL; + } + + src = s2; + } + if (needs_decompress) { + s2 = zip_source_decompress(srcza, src, st.comp_method); + if (s2 == NULL) { + zip_source_free(src); + return NULL; + } + src = s2; + } + if (needs_crc) { + s2 = zip_source_crc_create(src, 1, error); + if (s2 == NULL) { + zip_source_free(src); + return NULL; + } + src = s2; + } + + if (partial_data && (needs_decrypt || needs_decompress)) { + zip_stat_t st2; + fs_zip_stat_init(&st2); + if (data_len >= 0) { + st2.valid = ZIP_STAT_SIZE; + st2.size = (zip_uint64_t)data_len; + } + s2 = _zip_source_window_new(src, start, data_len, &st2, ZIP_STAT_NAME, NULL, NULL, 0, true, error); + if (s2 == NULL) { + zip_source_free(src); + return NULL; + } + src = s2; + } + + return src; +} + +static void +_zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de) { + fs_zip_file_attributes_init(attributes); + attributes->valid = ZIP_FILE_ATTRIBUTES_ASCII | ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS; + attributes->ascii = de->int_attrib & 1; + attributes->host_system = de->version_madeby >> 8; + attributes->external_file_attributes = de->ext_attrib; + attributes->general_purpose_bit_flags = de->bitflags; + attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; +} diff --git a/src/libzip/zip_stat.c b/src/libzip/zip_stat.c new file mode 100644 index 0000000..7830046 --- /dev/null +++ b/src/libzip/zip_stat.c @@ -0,0 +1,46 @@ +/* + fs_zip_stat.c -- get information about file by name + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_stat(zip_t *za, const char *fname, zip_flags_t flags, zip_stat_t *st) { + zip_int64_t idx; + + if ((idx = fs_zip_name_locate(za, fname, flags)) < 0) + return -1; + + return fs_zip_stat_index(za, (zip_uint64_t)idx, flags, st); +} diff --git a/src/libzip/zip_stat_index.c b/src/libzip/zip_stat_index.c new file mode 100644 index 0000000..aff9917 --- /dev/null +++ b/src/libzip/zip_stat_index.c @@ -0,0 +1,111 @@ +/* + fs_zip_stat_index.c -- get information about file by index + Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st) { + const char *name; + zip_dirent_t *de; + zip_entry_t *entry; + + if ((de = _zip_get_dirent(za, index, flags, NULL)) == NULL) { + return -1; + } + + if ((name = fs_zip_get_name(za, index, flags)) == NULL) { + return -1; + } + + entry = za->entry + index; + + if ((flags & ZIP_FL_UNCHANGED) == 0 && ZIP_ENTRY_DATA_CHANGED(za->entry + index)) { + + if (fs_zip_source_stat(entry->source, st) < 0) { + zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return -1; + } + + if (ZIP_CM_IS_DEFAULT(de->comp_method)) { + if (!(st->valid & ZIP_STAT_COMP_METHOD) || st->comp_method == ZIP_CM_STORE) { + st->valid &= ~(ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD); + } + } + else { + if ((st->valid & ZIP_STAT_COMP_METHOD) && st->comp_method != de->comp_method) { + st->valid &= ~ZIP_STAT_COMP_SIZE; + } + st->valid |= ZIP_STAT_COMP_METHOD; + st->comp_method = de->comp_method; + } + + if (((st->valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_SIZE)) == (ZIP_STAT_COMP_METHOD|ZIP_STAT_SIZE)) && st->comp_method == ZIP_CM_STORE) { + st->valid |= ZIP_STAT_COMP_SIZE; + st->comp_size = st->size; + } + + if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_LAST_MOD) { + st->mtime = de->last_mod; + st->valid |= ZIP_STAT_MTIME; + } + } + else { + fs_zip_stat_init(st); + + st->crc = de->crc; + st->size = de->uncomp_size; + st->mtime = de->last_mod; + st->comp_size = de->comp_size; + st->comp_method = (zip_uint16_t)de->comp_method; + st->encryption_method = de->encryption_method; + st->valid = (de->crc_valid ? ZIP_STAT_CRC : 0) | ZIP_STAT_SIZE | ZIP_STAT_MTIME | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; + if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_COMP_METHOD) { + st->valid &= ~ZIP_STAT_COMP_SIZE; + } + } + + if ((za->ch_flags & ZIP_AFL_WANT_TORRENTZIP) && (flags & ZIP_FL_UNCHANGED) == 0) { + st->comp_method = ZIP_CM_DEFLATE; + st->mtime = _zip_d2u_time(0xbc00, 0x2198); + st->valid |= ZIP_STAT_MTIME | ZIP_STAT_COMP_METHOD; + st->valid &= ~ZIP_STAT_COMP_SIZE; + } + + st->index = index; + st->name = name; + st->valid |= ZIP_STAT_INDEX | ZIP_STAT_NAME; + + return 0; +} diff --git a/src/libzip/zip_stat_init.c b/src/libzip/zip_stat_init.c new file mode 100644 index 0000000..1347f08 --- /dev/null +++ b/src/libzip/zip_stat_init.c @@ -0,0 +1,83 @@ +/* + fs_zip_stat_init.c -- initialize struct fs_zip_stat. + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "zipint.h" + + +ZIP_EXTERN void +fs_zip_stat_init(zip_stat_t *st) { + st->valid = 0; + st->name = NULL; + st->index = ZIP_UINT64_MAX; + st->crc = 0; + st->mtime = (time_t)-1; + st->size = 0; + st->comp_size = 0; + st->comp_method = ZIP_CM_STORE; + st->encryption_method = ZIP_EM_NONE; +} + + +int +_zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error) { + /* name is not merged, since zip_stat_t doesn't own it, and src may not be valid as long as dst */ + if (src->valid & ZIP_STAT_INDEX) { + dst->index = src->index; + } + if (src->valid & ZIP_STAT_SIZE) { + dst->size = src->size; + } + if (src->valid & ZIP_STAT_COMP_SIZE) { + dst->comp_size = src->comp_size; + } + if (src->valid & ZIP_STAT_MTIME) { + dst->mtime = src->mtime; + } + if (src->valid & ZIP_STAT_CRC) { + dst->crc = src->crc; + } + if (src->valid & ZIP_STAT_COMP_METHOD) { + dst->comp_method = src->comp_method; + } + if (src->valid & ZIP_STAT_ENCRYPTION_METHOD) { + dst->encryption_method = src->encryption_method; + } + if (src->valid & ZIP_STAT_FLAGS) { + dst->flags = src->flags; + } + dst->valid |= src->valid; + + return 0; +} diff --git a/src/libzip/zip_strerror.c b/src/libzip/zip_strerror.c new file mode 100644 index 0000000..52b8f2a --- /dev/null +++ b/src/libzip/zip_strerror.c @@ -0,0 +1,41 @@ +/* + zip_sterror.c -- get string representation of zip error + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN const char * +fs_zip_strerror(zip_t *za) { + return zip_error_strerror(&za->error); +} diff --git a/src/libzip/zip_string.c b/src/libzip/zip_string.c new file mode 100644 index 0000000..bdfdde6 --- /dev/null +++ b/src/libzip/zip_string.c @@ -0,0 +1,178 @@ +/* + zip_string.c -- string handling (with encoding) + Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include + +#include "zipint.h" + +zip_uint32_t +_zip_string_crc32(const zip_string_t *s) { + zip_uint32_t crc; + + crc = (zip_uint32_t)zng_crc32(0L, Z_NULL, 0); + + if (s != NULL) + crc = (zip_uint32_t)zng_crc32(crc, s->raw, s->length); + + return crc; +} + + +int +_zip_string_equal(const zip_string_t *a, const zip_string_t *b) { + if (a == NULL || b == NULL) + return a == b; + + if (a->length != b->length) + return 0; + + /* TODO: encoding */ + + return (memcmp(a->raw, b->raw, a->length) == 0); +} + + +void +_zip_string_free(zip_string_t *s) { + if (s == NULL) + return; + + free(s->raw); + free(s->converted); + free(s); +} + + +const zip_uint8_t * +_zip_string_get(zip_string_t *string, zip_uint32_t *lenp, zip_flags_t flags, zip_error_t *error) { + static const zip_uint8_t empty[1] = ""; + + if (string == NULL) { + if (lenp) + *lenp = 0; + return empty; + } + + if ((flags & ZIP_FL_ENC_RAW) == 0) { + /* start guessing */ + if (string->encoding == ZIP_ENCODING_UNKNOWN) + _zip_guess_encoding(string, ZIP_ENCODING_UNKNOWN); + + if (((flags & ZIP_FL_ENC_STRICT) && string->encoding != ZIP_ENCODING_ASCII && string->encoding != ZIP_ENCODING_UTF8_KNOWN) || (string->encoding == ZIP_ENCODING_CP437)) { + if (string->converted == NULL) { + if ((string->converted = _zip_cp437_to_utf8(string->raw, string->length, &string->converted_length, error)) == NULL) + return NULL; + } + if (lenp) + *lenp = string->converted_length; + return string->converted; + } + } + + if (lenp) + *lenp = string->length; + return string->raw; +} + + +zip_uint16_t +_zip_string_length(const zip_string_t *s) { + if (s == NULL) + return 0; + + return s->length; +} + + +zip_string_t * +_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, zip_error_t *error) { + zip_string_t *s; + zip_encoding_type_t expected_encoding; + + if (length == 0) + return NULL; + + switch (flags & ZIP_FL_ENCODING_ALL) { + case ZIP_FL_ENC_GUESS: + expected_encoding = ZIP_ENCODING_UNKNOWN; + break; + case ZIP_FL_ENC_UTF_8: + expected_encoding = ZIP_ENCODING_UTF8_KNOWN; + break; + case ZIP_FL_ENC_CP437: + expected_encoding = ZIP_ENCODING_CP437; + break; + default: + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((s = (zip_string_t *)malloc(sizeof(*s))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if ((s->raw = (zip_uint8_t *)malloc((size_t)length + 1)) == NULL) { + free(s); + return NULL; + } + + (void)memcpy_s(s->raw, length + 1, raw, length); + s->raw[length] = '\0'; + s->length = length; + s->encoding = ZIP_ENCODING_UNKNOWN; + s->converted = NULL; + s->converted_length = 0; + + if (expected_encoding != ZIP_ENCODING_UNKNOWN) { + if (_zip_guess_encoding(s, expected_encoding) == ZIP_ENCODING_ERROR) { + _zip_string_free(s); + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + } + + return s; +} + + +int +_zip_string_write(zip_t *za, const zip_string_t *s) { + if (s == NULL) + return 0; + + return _zip_write(za, s->raw, s->length); +} diff --git a/src/libzip/zip_unchange.c b/src/libzip/zip_unchange.c new file mode 100644 index 0000000..0c93251 --- /dev/null +++ b/src/libzip/zip_unchange.c @@ -0,0 +1,98 @@ +/* + fs_zip_unchange.c -- undo changes to file in zip archive + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_unchange(zip_t *za, zip_uint64_t idx) { + return _zip_unchange(za, idx, 0); +} + + +int +_zip_unchange(zip_t *za, zip_uint64_t idx, int allow_duplicates) { + zip_int64_t i; + bool renamed; + + if (idx >= za->nentry) { + zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + renamed = za->entry[idx].changes && (za->entry[idx].changes->changed & ZIP_DIRENT_FILENAME); + if (!allow_duplicates && (renamed || za->entry[idx].deleted)) { + const char *orig_name = NULL; + const char *changed_name = NULL; + + if (za->entry[idx].orig != NULL) { + if ((orig_name = _zip_get_name(za, idx, ZIP_FL_UNCHANGED, &za->error)) == NULL) { + return -1; + } + + i = _zip_name_locate(za, orig_name, 0, NULL); + if (i >= 0 && (zip_uint64_t)i != idx) { + zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + } + + if (renamed) { + if ((changed_name = _zip_get_name(za, idx, 0, &za->error)) == NULL) { + return -1; + } + } + + if (orig_name) { + if (_zip_hash_add(za->names, (const zip_uint8_t *)orig_name, idx, 0, &za->error) == false) { + return -1; + } + } + if (changed_name) { + if (_zip_hash_delete(za->names, (const zip_uint8_t *)changed_name, &za->error) == false) { + _zip_hash_delete(za->names, (const zip_uint8_t *)orig_name, NULL); + return -1; + } + } + } + + _zip_dirent_free(za->entry[idx].changes); + za->entry[idx].changes = NULL; + + _zip_unchange_data(za->entry + idx); + + return 0; +} diff --git a/src/libzip/zip_unchange_all.c b/src/libzip/zip_unchange_all.c new file mode 100644 index 0000000..d77656a --- /dev/null +++ b/src/libzip/zip_unchange_all.c @@ -0,0 +1,54 @@ +/* + fs_zip_unchange.c -- undo changes to all files in zip archive + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_unchange_all(zip_t *za) { + int ret; + zip_uint64_t i; + + if (!_zip_hash_revert(za->names, &za->error)) { + return -1; + } + + ret = 0; + for (i = 0; i < za->nentry; i++) + ret |= _zip_unchange(za, i, 1); + + ret |= fs_zip_unchange_archive(za); + + return ret; +} diff --git a/src/libzip/zip_unchange_archive.c b/src/libzip/zip_unchange_archive.c new file mode 100644 index 0000000..50c1375 --- /dev/null +++ b/src/libzip/zip_unchange_archive.c @@ -0,0 +1,51 @@ +/* + fs_zip_unchange_archive.c -- undo global changes to ZIP archive + Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include "zipint.h" + + +ZIP_EXTERN int +fs_zip_unchange_archive(zip_t *za) { + if (za->comment_changed) { + _zip_string_free(za->comment_changes); + za->comment_changes = NULL; + za->comment_changed = 0; + } + + za->ch_flags = za->flags; + + return 0; +} diff --git a/src/libzip/zip_unchange_data.c b/src/libzip/zip_unchange_data.c new file mode 100644 index 0000000..6bdecd1 --- /dev/null +++ b/src/libzip/zip_unchange_data.c @@ -0,0 +1,53 @@ +/* + zip_unchange_data.c -- undo helper function + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +void +_zip_unchange_data(zip_entry_t *ze) { + if (ze->source) { + zip_source_free(ze->source); + ze->source = NULL; + } + + if (ze->changes != NULL && (ze->changes->changed & ZIP_DIRENT_COMP_METHOD) && ze->changes->comp_method == ZIP_CM_REPLACED_DEFAULT) { + ze->changes->changed &= ~ZIP_DIRENT_COMP_METHOD; + if (ze->changes->changed == 0) { + _zip_dirent_free(ze->changes); + ze->changes = NULL; + } + } + + ze->deleted = 0; +} diff --git a/src/libzip/zip_utf-8.c b/src/libzip/zip_utf-8.c new file mode 100644 index 0000000..678912f --- /dev/null +++ b/src/libzip/zip_utf-8.c @@ -0,0 +1,226 @@ +/* + zip_utf-8.c -- UTF-8 support functions for libzip + Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "zipint.h" + +#include + + +static const zip_uint16_t _cp437_to_unicode[256] = { + /* 0x00 - 0x0F */ + 0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + + /* 0x10 - 0x1F */ + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + + /* 0x20 - 0x2F */ + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + + /* 0x30 - 0x3F */ + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + + /* 0x40 - 0x4F */ + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + + /* 0x50 - 0x5F */ + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + + /* 0x60 - 0x6F */ + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + + /* 0x70 - 0x7F */ + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302, + + /* 0x80 - 0x8F */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + + /* 0x90 - 0x9F */ + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + + /* 0xA0 - 0xAF */ + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + + /* 0xB0 - 0xBF */ + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + + /* 0xC0 - 0xCF */ + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + + /* 0xD0 - 0xDF */ + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + + /* 0xE0 - 0xEF */ + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + + /* 0xF0 - 0xFF */ + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0}; + +#define UTF_8_LEN_2_MASK 0xe0 +#define UTF_8_LEN_2_MATCH 0xc0 +#define UTF_8_LEN_3_MASK 0xf0 +#define UTF_8_LEN_3_MATCH 0xe0 +#define UTF_8_LEN_4_MASK 0xf8 +#define UTF_8_LEN_4_MATCH 0xf0 +#define UTF_8_CONTINUE_MASK 0xc0 +#define UTF_8_CONTINUE_MATCH 0x80 + + +zip_encoding_type_t +_zip_guess_encoding(zip_string_t *str, zip_encoding_type_t expected_encoding) { + zip_encoding_type_t enc; + const zip_uint8_t *name; + zip_uint32_t i, j, ulen; + + if (str == NULL) + return ZIP_ENCODING_ASCII; + + name = str->raw; + + if (str->encoding != ZIP_ENCODING_UNKNOWN) + enc = str->encoding; + else { + enc = ZIP_ENCODING_ASCII; + for (i = 0; i < str->length; i++) { + if ((name[i] > 31 && name[i] < 128) || name[i] == '\r' || name[i] == '\n' || name[i] == '\t') + continue; + + enc = ZIP_ENCODING_UTF8_GUESSED; + if ((name[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH) + ulen = 1; + else if ((name[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH) + ulen = 2; + else if ((name[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH) + ulen = 3; + else { + enc = ZIP_ENCODING_CP437; + break; + } + + if (i + ulen >= str->length) { + enc = ZIP_ENCODING_CP437; + break; + } + + for (j = 1; j <= ulen; j++) { + if ((name[i + j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH) { + enc = ZIP_ENCODING_CP437; + goto done; + } + } + i += ulen; + } + } + +done: + str->encoding = enc; + + if (expected_encoding != ZIP_ENCODING_UNKNOWN) { + if (expected_encoding == ZIP_ENCODING_UTF8_KNOWN && enc == ZIP_ENCODING_UTF8_GUESSED) + str->encoding = enc = ZIP_ENCODING_UTF8_KNOWN; + + if (expected_encoding != enc && enc != ZIP_ENCODING_ASCII) + return ZIP_ENCODING_ERROR; + } + + return enc; +} + + +static zip_uint32_t +_zip_unicode_to_utf8_len(zip_uint32_t codepoint) { + if (codepoint < 0x0080) + return 1; + if (codepoint < 0x0800) + return 2; + if (codepoint < 0x10000) + return 3; + return 4; +} + + +static zip_uint32_t +_zip_unicode_to_utf8(zip_uint32_t codepoint, zip_uint8_t *buf) { + if (codepoint < 0x0080) { + buf[0] = codepoint & 0xff; + return 1; + } + if (codepoint < 0x0800) { + buf[0] = (zip_uint8_t)(UTF_8_LEN_2_MATCH | ((codepoint >> 6) & 0x1f)); + buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f)); + return 2; + } + if (codepoint < 0x10000) { + buf[0] = (zip_uint8_t)(UTF_8_LEN_3_MATCH | ((codepoint >> 12) & 0x0f)); + buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f)); + buf[2] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f)); + return 3; + } + buf[0] = (zip_uint8_t)(UTF_8_LEN_4_MATCH | ((codepoint >> 18) & 0x07)); + buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 12) & 0x3f)); + buf[2] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f)); + buf[3] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f)); + return 4; +} + + +zip_uint8_t * +_zip_cp437_to_utf8(const zip_uint8_t *const _cp437buf, zip_uint32_t len, zip_uint32_t *utf8_lenp, zip_error_t *error) { + zip_uint8_t *cp437buf = (zip_uint8_t *)_cp437buf; + zip_uint8_t *utf8buf; + zip_uint32_t buflen, i, offset; + + if (len == 0) { + if (utf8_lenp) + *utf8_lenp = 0; + return NULL; + } + + buflen = 1; + for (i = 0; i < len; i++) + buflen += _zip_unicode_to_utf8_len(_cp437_to_unicode[cp437buf[i]]); + + if ((utf8buf = (zip_uint8_t *)malloc(buflen)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + offset = 0; + for (i = 0; i < len; i++) + offset += _zip_unicode_to_utf8(_cp437_to_unicode[cp437buf[i]], utf8buf + offset); + + utf8buf[buflen - 1] = 0; + if (utf8_lenp) + *utf8_lenp = buflen - 1; + return utf8buf; +} diff --git a/src/libzip/zipconf.h b/src/libzip/zipconf.h new file mode 100644 index 0000000..472e06c --- /dev/null +++ b/src/libzip/zipconf.h @@ -0,0 +1,57 @@ +#ifndef _HAD_ZIPCONF_H +#define _HAD_ZIPCONF_H + +/* + zipconf.h -- platform specific include file + + This file was generated automatically by CMake + based on ../cmake-zipconf.h.in. + */ + +#define LIBZIP_VERSION "1.10.1" +#define LIBZIP_VERSION_MAJOR 1 +#define LIBZIP_VERSION_MINOR 10 +#define LIBZIP_VERSION_MICRO 1 + +/* #undef ZIP_STATIC */ + +#define _Nullable +#define _Nonnull + +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS 1 +#endif +#if defined(_MSC_VER) && _MSC_VER < 1700 +#include +#define PRIu32 "lu" +#define PRIu64 "llu" +#else +#include +#endif + +typedef int8_t zip_int8_t; +typedef uint8_t zip_uint8_t; +typedef int16_t zip_int16_t; +typedef uint16_t zip_uint16_t; +typedef int32_t zip_int32_t; +typedef uint32_t zip_uint32_t; +typedef int64_t zip_int64_t; +typedef uint64_t zip_uint64_t; + +#define ZIP_INT8_MIN (-ZIP_INT8_MAX-1) +#define ZIP_INT8_MAX 0x7f +#define ZIP_UINT8_MAX 0xff + +#define ZIP_INT16_MIN (-ZIP_INT16_MAX-1) +#define ZIP_INT16_MAX 0x7fff +#define ZIP_UINT16_MAX 0xffff + +#define ZIP_INT32_MIN (-ZIP_INT32_MAX-1L) +#define ZIP_INT32_MAX 0x7fffffffL +#define ZIP_UINT32_MAX 0xffffffffLU + +#define ZIP_INT64_MIN (-ZIP_INT64_MAX-1LL) +#define ZIP_INT64_MAX 0x7fffffffffffffffLL +#define ZIP_UINT64_MAX 0xffffffffffffffffULL + +#endif /* zipconf.h */ diff --git a/src/libzip/zipint.h b/src/libzip/zipint.h new file mode 100644 index 0000000..a7f7693 --- /dev/null +++ b/src/libzip/zipint.h @@ -0,0 +1,655 @@ +#ifndef _HAD_ZIPINT_H +#define _HAD_ZIPINT_H + +/* + zipint.h -- internal declarations. + Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" + +#include "compat.h" + +#ifdef ZIP_ALLOCATE_BUFFER +#include +#endif + +#ifdef _ZIP_COMPILING_DEPRECATED +#define ZIP_DEPRECATED(x) +#else +#define ZIP_DISABLE_DEPRECATED +#endif + +#include "zip.h" + +#define CENTRAL_MAGIC "PK\1\2" +#define LOCAL_MAGIC "PK\3\4" +#define EOCD_MAGIC "PK\5\6" +#define DATADES_MAGIC "PK\7\10" +#define EOCD64LOC_MAGIC "PK\6\7" +#define EOCD64_MAGIC "PK\6\6" +#define CDENTRYSIZE 46u +#define LENTRYSIZE 30 +#define MAXCOMLEN 65536 +#define MAXEXTLEN 65536 +#define EOCDLEN 22 +#define EOCD64LOCLEN 20 +#define EOCD64LEN 56 +#define CDBUFSIZE (MAXCOMLEN + EOCDLEN + EOCD64LOCLEN) +#define BUFSIZE 8192 +#define EFZIP64SIZE 28 +#define EF_WINZIP_AES_SIZE 7 +#define MAX_DATA_DESCRIPTOR_LENGTH 24 + +#define TORRENTZIP_SIGNATURE "TORRENTZIPPED-" +#define TORRENTZIP_SIGNATURE_LENGTH 14 +#define TORRENTZIP_CRC_LENGTH 8 +#define TORRENTZIP_MEM_LEVEL 8 +#define TORRENTZIP_COMPRESSION_FLAGS ZIP_UINT16_MAX + +#define ZIP_CRYPTO_PKWARE_HEADERLEN 12 + +#define ZIP_CM_REPLACED_DEFAULT (-2) +#define ZIP_CM_WINZIP_AES 99 /* Winzip AES encrypted */ + +#define WINZIP_AES_PASSWORD_VERIFY_LENGTH 2 +#define WINZIP_AES_MAX_HEADER_LENGTH (16 + WINZIP_AES_PASSWORD_VERIFY_LENGTH) +#define AES_BLOCK_SIZE 16 +#define HMAC_LENGTH 10 +#define SALT_LENGTH(method) ((method) == ZIP_EM_AES_128 ? 8 : ((method) == ZIP_EM_AES_192 ? 12 : 16)) + +#define ZIP_CM_IS_DEFAULT(x) ((x) == ZIP_CM_DEFAULT || (x) == ZIP_CM_REPLACED_DEFAULT) +#define ZIP_CM_ACTUAL(x) ((zip_uint16_t)(ZIP_CM_IS_DEFAULT(x) ? ZIP_CM_DEFLATE : (x))) + +#define ZIP_EF_UTF_8_COMMENT 0x6375 +#define ZIP_EF_UTF_8_NAME 0x7075 +#define ZIP_EF_WINZIP_AES 0x9901 +#define ZIP_EF_ZIP64 0x0001 + +#define ZIP_EF_IS_INTERNAL(id) ((id) == ZIP_EF_UTF_8_COMMENT || (id) == ZIP_EF_UTF_8_NAME || (id) == ZIP_EF_WINZIP_AES || (id) == ZIP_EF_ZIP64) + +/* according to unzip-6.0's zipinfo.c, this corresponds to a regular file with rw permissions for everyone */ +#define ZIP_EXT_ATTRIB_DEFAULT (0100666u << 16) +/* according to unzip-6.0's zipinfo.c, this corresponds to a directory with rwx permissions for everyone */ +#define ZIP_EXT_ATTRIB_DEFAULT_DIR (0040777u << 16) + +#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK 0x0836 + +#define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* This section contains API that won't materialize like this. It's + placed in the internal section, pending cleanup. */ + +/* flags for compression and encryption sources */ + +#define ZIP_CODEC_DECODE 0 /* decompress/decrypt (encode flag not set) */ +#define ZIP_CODEC_ENCODE 1 /* compress/encrypt */ + +typedef zip_source_t *(*zip_encryption_implementation)(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); + +zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t method, int operation); + +/* clang-format off */ +enum zip_compression_status { + ZIP_COMPRESSION_OK, + ZIP_COMPRESSION_END, + ZIP_COMPRESSION_ERROR, + ZIP_COMPRESSION_NEED_DATA +}; +/* clang-format on */ +typedef enum zip_compression_status zip_compression_status_t; + +struct zip_compression_algorithm { + /* Return maximum compressed size for uncompressed data of given size. */ + zip_uint64_t (*maximum_compressed_size)(zip_uint64_t uncompressed_size); + + /* called once to create new context */ + void *(*allocate)(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error); + /* called once to free context */ + void (*deallocate)(void *ctx); + + /* get compression specific general purpose bitflags */ + zip_uint16_t (*general_purpose_bit_flags)(void *ctx); + /* minimum version needed when using this algorithm */ + zip_uint8_t version_needed; + + /* start processing */ + bool (*start)(void *ctx, zip_stat_t *st, zip_file_attributes_t *attributes); + /* stop processing */ + bool (*end)(void *ctx); + + /* provide new input data, remains valid until next call to input or end */ + bool (*input)(void *ctx, zip_uint8_t *data, zip_uint64_t length); + + /* all input data has been provided */ + void (*end_of_input)(void *ctx); + + /* process input data, writing to data, which has room for length bytes, update length to number of bytes written */ + zip_compression_status_t (*process)(void *ctx, zip_uint8_t *data, zip_uint64_t *length); +}; +typedef struct zip_compression_algorithm zip_compression_algorithm_t; + +extern zip_compression_algorithm_t zip_algorithm_bzip2_compress; +extern zip_compression_algorithm_t zip_algorithm_bzip2_decompress; +extern zip_compression_algorithm_t zip_algorithm_deflate_compress; +extern zip_compression_algorithm_t zip_algorithm_deflate_decompress; +extern zip_compression_algorithm_t zip_algorithm_xz_compress; +extern zip_compression_algorithm_t zip_algorithm_xz_decompress; +extern zip_compression_algorithm_t zip_algorithm_zstd_compress; +extern zip_compression_algorithm_t zip_algorithm_zstd_decompress; + +zip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t method, bool compress); + +/* This API is not final yet, but we need it internally, so it's private for now. */ + +const zip_uint8_t *zip_get_extra_field_by_id(zip_t *, int, int, zip_uint16_t, int, zip_uint16_t *); + +/* This section contains API that is of limited use until support for + user-supplied compression/encryption implementation is finished. + Thus we will keep it private for now. */ + +zip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t cm, zip_uint32_t compression_flags); +zip_source_t *zip_source_crc_create(zip_source_t *, int, zip_error_t *error); +zip_source_t *zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t cm); +zip_source_t *zip_source_pkware_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); +zip_source_t *zip_source_pkware_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); +int zip_source_remove(zip_source_t *); +zip_int64_t zip_source_supports(zip_source_t *src); +bool zip_source_supports_reopen(zip_source_t *src); +zip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); +zip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *); +zip_source_t *zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes); +zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error); + +/* error source for layered sources */ + +enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL }; + +#define ZIP_DETAIL_ET_GLOBAL 0 +#define ZIP_DETAIL_ET_ENTRY 1 + +struct _zip_err_info { + int type; + const char *description; +}; + +extern const struct _zip_err_info _zip_err_str[]; +extern const int _zip_err_str_count; +extern const struct _zip_err_info _zip_err_details[]; +extern const int _zip_err_details_count; + +/* macros for libzip-internal errors */ +#define MAX_DETAIL_INDEX 0x7fffff +#define MAKE_DETAIL_WITH_INDEX(error, index) ((((index) > MAX_DETAIL_INDEX) ? MAX_DETAIL_INDEX : (int)(index)) << 8 | (error)) +#define GET_INDEX_FROM_DETAIL(error) (((error) >> 8) & MAX_DETAIL_INDEX) +#define GET_ERROR_FROM_DETAIL(error) ((error) & 0xff) +#define ADD_INDEX_TO_DETAIL(error, index) MAKE_DETAIL_WITH_INDEX(GET_ERROR_FROM_DETAIL(error), (index)) + +/* error code for libzip-internal errors */ +#define ZIP_ER_DETAIL_NO_DETAIL 0 /* G no detail */ +#define ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD 1 /* G central directory overlaps EOCD, or there is space between them */ +#define ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID 2 /* G archive comment length incorrect */ +#define ZIP_ER_DETAIL_CDIR_LENGTH_INVALID 3 /* G central directory length invalid */ +#define ZIP_ER_DETAIL_CDIR_ENTRY_INVALID 4 /* E central header invalid */ +#define ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT 5 /* G central directory count of entries is incorrect */ +#define ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH 6 /* E local and central headers do not match */ +#define ZIP_ER_DETAIL_EOCD_LENGTH_INVALID 7 /* G wrong EOCD length */ +#define ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD 8 /* G EOCD64 overlaps EOCD, or there is space between them */ +#define ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC 9 /* G EOCD64 magic incorrect */ +#define ZIP_ER_DETAIL_EOCD64_MISMATCH 10 /* G EOCD64 and EOCD do not match */ +#define ZIP_ER_DETAIL_CDIR_INVALID 11 /* G invalid value in central directory */ +#define ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW 12 /* E variable size fields overflow header */ +#define ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME 13 /* E invalid UTF-8 in filename */ +#define ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT 13 /* E invalid UTF-8 in comment */ +#define ZIP_ER_DETAIL_INVALID_ZIP64_EF 14 /* E invalid Zip64 extra field */ +#define ZIP_ER_DETAIL_INVALID_WINZIPAES_EF 14 /* E invalid WinZip AES extra field */ +#define ZIP_ER_DETAIL_EF_TRAILING_GARBAGE 15 /* E garbage at end of extra fields */ +#define ZIP_ER_DETAIL_INVALID_EF_LENGTH 16 /* E extra field length is invalid */ +#define ZIP_ER_DETAIL_INVALID_FILE_LENGTH 17 /* E file length in header doesn't match actual file length */ + +/* directory entry: general purpose bit flags */ + +#define ZIP_GPBF_ENCRYPTED 0x0001u /* is encrypted */ +#define ZIP_GPBF_DATA_DESCRIPTOR 0x0008u /* crc/size after file data */ +#define ZIP_GPBF_STRONG_ENCRYPTION 0x0040u /* uses strong encryption */ +#define ZIP_GPBF_ENCODING_UTF_8 0x0800u /* file name encoding is UTF-8 */ + + +/* extra fields */ +#define ZIP_EF_LOCAL ZIP_FL_LOCAL /* include in local header */ +#define ZIP_EF_CENTRAL ZIP_FL_CENTRAL /* include in central directory */ +#define ZIP_EF_BOTH (ZIP_EF_LOCAL | ZIP_EF_CENTRAL) /* include in both */ + +#define ZIP_FL_FORCE_ZIP64 1024 /* force zip64 extra field (_zip_dirent_write) */ + +#define ZIP_FL_ENCODING_ALL (ZIP_FL_ENC_GUESS | ZIP_FL_ENC_CP437 | ZIP_FL_ENC_UTF_8) + + +/* encoding type */ +enum zip_encoding_type { + ZIP_ENCODING_UNKNOWN, /* not yet analyzed */ + ZIP_ENCODING_ASCII, /* plain ASCII */ + ZIP_ENCODING_UTF8_KNOWN, /* is UTF-8 */ + ZIP_ENCODING_UTF8_GUESSED, /* possibly UTF-8 */ + ZIP_ENCODING_CP437, /* Code Page 437 */ + ZIP_ENCODING_ERROR /* should be UTF-8 but isn't */ +}; + +typedef enum zip_encoding_type zip_encoding_type_t; + +struct zip_hash; +struct zip_progress; + +typedef struct zip_cdir zip_cdir_t; +typedef struct zip_dirent zip_dirent_t; +typedef struct zip_entry zip_entry_t; +typedef struct zip_extra_field zip_extra_field_t; +typedef struct zip_string zip_string_t; +typedef struct zip_buffer zip_buffer_t; +typedef struct zip_hash zip_hash_t; +typedef struct zip_progress zip_progress_t; + +/* zip archive, part of API */ + +struct zip { + zip_source_t *src; /* data source for archive */ + unsigned int open_flags; /* flags passed to fs_zip_open */ + zip_error_t error; /* error information */ + + unsigned int flags; /* archive global flags */ + unsigned int ch_flags; /* changed archive global flags */ + + char *default_password; /* password used when no other supplied */ + + zip_string_t *comment_orig; /* archive comment */ + zip_string_t *comment_changes; /* changed archive comment */ + bool comment_changed; /* whether archive comment was changed */ + + zip_uint64_t nentry; /* number of entries */ + zip_uint64_t nentry_alloc; /* number of entries allocated */ + zip_entry_t *entry; /* entries */ + + unsigned int nopen_source; /* number of open sources using archive */ + unsigned int nopen_source_alloc; /* number of sources allocated */ + zip_source_t **open_source; /* open sources using archive */ + + zip_hash_t *names; /* hash table for name lookup */ + + zip_progress_t *progress; /* progress callback for fs_zip_close() */ + + zip_uint32_t* write_crc; /* have _zip_write() compute CRC */ +}; + +/* file in zip archive, part of API */ + +struct zip_file { + zip_error_t error; /* error information */ + zip_source_t *src; /* data source */ +}; + +/* zip archive directory entry (central or local) */ + +#define ZIP_DIRENT_COMP_METHOD 0x0001u +#define ZIP_DIRENT_FILENAME 0x0002u +#define ZIP_DIRENT_COMMENT 0x0004u +#define ZIP_DIRENT_EXTRA_FIELD 0x0008u +#define ZIP_DIRENT_ATTRIBUTES 0x0010u +#define ZIP_DIRENT_LAST_MOD 0x0020u +#define ZIP_DIRENT_ENCRYPTION_METHOD 0x0040u +#define ZIP_DIRENT_PASSWORD 0x0080u +#define ZIP_DIRENT_ALL ZIP_UINT32_MAX + +struct zip_dirent { + zip_uint32_t changed; + bool local_extra_fields_read; /* whether we already read in local header extra fields */ + bool cloned; /* whether this instance is cloned, and thus shares non-changed strings */ + + bool crc_valid; /* if CRC is valid (sometimes not for encrypted archives) */ + + zip_uint16_t version_madeby; /* (c) version of creator */ + zip_uint16_t version_needed; /* (cl) version needed to extract */ + zip_uint16_t bitflags; /* (cl) general purpose bit flag */ + zip_int32_t comp_method; /* (cl) compression method used (uint16 and ZIP_CM_DEFAULT (-1)) */ + time_t last_mod; /* (cl) time of last modification */ + zip_uint32_t crc; /* (cl) CRC-32 of uncompressed data */ + zip_uint64_t comp_size; /* (cl) size of compressed data */ + zip_uint64_t uncomp_size; /* (cl) size of uncompressed data */ + zip_string_t *filename; /* (cl) file name (NUL-terminated) */ + zip_extra_field_t *extra_fields; /* (cl) extra fields, parsed */ + zip_string_t *comment; /* (c) file comment */ + zip_uint32_t disk_number; /* (c) disk number start */ + zip_uint16_t int_attrib; /* (c) internal file attributes */ + zip_uint32_t ext_attrib; /* (c) external file attributes */ + zip_uint64_t offset; /* (c) offset of local header */ + + zip_uint32_t compression_level; /* level of compression to use (never valid in orig) */ + zip_uint16_t encryption_method; /* encryption method, computed from other fields */ + char *password; /* file specific encryption password */ +}; + +/* zip archive central directory */ + +struct zip_cdir { + zip_entry_t *entry; /* directory entries */ + zip_uint64_t nentry; /* number of entries */ + zip_uint64_t nentry_alloc; /* number of entries allocated */ + + zip_uint64_t size; /* size of central directory */ + zip_uint64_t offset; /* offset of central directory in file */ + zip_string_t *comment; /* zip archive comment */ + bool is_zip64; /* central directory in zip64 format */ +}; + +struct zip_extra_field { + zip_extra_field_t *next; + zip_flags_t flags; /* in local/central header */ + zip_uint16_t id; /* header id */ + zip_uint16_t size; /* data size */ + zip_uint8_t *data; +}; + +enum zip_source_write_state { + ZIP_SOURCE_WRITE_CLOSED, /* write is not in progress */ + ZIP_SOURCE_WRITE_OPEN, /* write is in progress */ + ZIP_SOURCE_WRITE_FAILED, /* commit failed, only rollback allowed */ + ZIP_SOURCE_WRITE_REMOVED /* file was removed */ +}; +typedef enum zip_source_write_state zip_source_write_state_t; + +struct zip_source { + zip_source_t *src; + union { + zip_source_callback f; + zip_source_layered_callback l; + } cb; + void *ud; + zip_error_t error; + zip_int64_t supports; /* supported commands */ + unsigned int open_count; /* number of times source was opened (directly or as lower layer) */ + zip_source_write_state_t write_state; /* whether source is open for writing */ + bool source_closed; /* set if source archive is closed */ + zip_t *source_archive; /* zip archive we're reading from, NULL if not from archive */ + unsigned int refcount; + bool eof; /* EOF reached */ + bool had_read_error; /* a previous ZIP_SOURCE_READ reported an error */ + zip_uint64_t bytes_read; /* for sources that don't support ZIP_SOURCE_TELL. */ +}; + +#define ZIP_SOURCE_IS_OPEN_READING(src) ((src)->open_count > 0) +#define ZIP_SOURCE_IS_OPEN_WRITING(src) ((src)->write_state == ZIP_SOURCE_WRITE_OPEN) +#define ZIP_SOURCE_IS_LAYERED(src) ((src)->src != NULL) + +/* entry in zip archive directory */ + +struct zip_entry { + zip_dirent_t *orig; + zip_dirent_t *changes; + zip_source_t *source; + bool deleted; +}; + + +/* file or archive comment, or filename */ + +struct zip_string { + zip_uint8_t *raw; /* raw string */ + zip_uint16_t length; /* length of raw string */ + enum zip_encoding_type encoding; /* autorecognized encoding */ + zip_uint8_t *converted; /* autoconverted string */ + zip_uint32_t converted_length; /* length of converted */ +}; + + +/* byte array */ + +/* For performance, we usually keep 8k byte arrays on the stack. + However, there are (embedded) systems with a stack size of 12k; + for those, use malloc()/free() */ + +#ifdef ZIP_ALLOCATE_BUFFER +#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t *buf +#define byte_array_init(buf, size) (((buf) = (zip_uint8_t *)malloc(size)) != NULL) +#define byte_array_fini(buf) (free(buf)) +#else +#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t buf[size] +#define byte_array_init(buf, size) (1) +#define byte_array_fini(buf) ((void)0) +#endif + + +/* bounds checked access to memory buffer */ + +struct zip_buffer { + bool ok; + bool free_data; + + zip_uint8_t *data; + zip_uint64_t size; + zip_uint64_t offset; +}; + +/* which files to write in which order */ + +struct zip_filelist { + zip_uint64_t idx; + const char *name; +}; + +typedef struct zip_filelist zip_filelist_t; + +struct _zip_winzip_aes; +typedef struct _zip_winzip_aes zip_winzip_aes_t; + +struct _zip_pkware_keys { + zip_uint32_t key[3]; +}; +typedef struct _zip_pkware_keys zip_pkware_keys_t; + +#define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define ZIP_ENTRY_CHANGED(e, f) ((e)->changes && ((e)->changes->changed & (f))) +#define ZIP_ENTRY_DATA_CHANGED(x) ((x)->source != NULL) +#define ZIP_ENTRY_HAS_CHANGES(e) (ZIP_ENTRY_DATA_CHANGED(e) || (e)->deleted || ZIP_ENTRY_CHANGED((e), ZIP_DIRENT_ALL)) + +#define ZIP_IS_RDONLY(za) ((za)->ch_flags & ZIP_AFL_RDONLY) +#define ZIP_IS_TORRENTZIP(za) ((za)->flags & ZIP_AFL_IS_TORRENTZIP) +#define ZIP_WANT_TORRENTZIP(za) ((za)->ch_flags & ZIP_AFL_WANT_TORRENTZIP) + + +#ifdef HAVE_EXPLICIT_MEMSET +#define _zip_crypto_clear(b, l) explicit_memset((b), 0, (l)) +#else +#ifdef HAVE_EXPLICIT_BZERO +#define _zip_crypto_clear(b, l) explicit_bzero((b), (l)) +#else +#include +#define _zip_crypto_clear(b, l) memset((b), 0, (l)) +#endif +#endif + + +zip_int64_t _zip_add_entry(zip_t *); + +zip_uint8_t *_zip_buffer_data(zip_buffer_t *buffer); +bool _zip_buffer_eof(zip_buffer_t *buffer); +void _zip_buffer_free(zip_buffer_t *buffer); +zip_uint8_t *_zip_buffer_get(zip_buffer_t *buffer, zip_uint64_t length); +zip_uint16_t _zip_buffer_get_16(zip_buffer_t *buffer); +zip_uint32_t _zip_buffer_get_32(zip_buffer_t *buffer); +zip_uint64_t _zip_buffer_get_64(zip_buffer_t *buffer); +zip_uint8_t _zip_buffer_get_8(zip_buffer_t *buffer); +zip_uint64_t _zip_buffer_left(zip_buffer_t *buffer); +zip_buffer_t *_zip_buffer_new(zip_uint8_t *data, zip_uint64_t size); +zip_buffer_t *_zip_buffer_new_from_source(zip_source_t *src, zip_uint64_t size, zip_uint8_t *buf, zip_error_t *error); +zip_uint64_t _zip_buffer_offset(zip_buffer_t *buffer); +bool _zip_buffer_ok(zip_buffer_t *buffer); +zip_uint8_t *_zip_buffer_peek(zip_buffer_t *buffer, zip_uint64_t length); +int _zip_buffer_put(zip_buffer_t *buffer, const void *src, size_t length); +int _zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i); +int _zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i); +int _zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i); +int _zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i); +zip_uint64_t _zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length); +int _zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length); +int _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset); +zip_uint64_t _zip_buffer_size(zip_buffer_t *buffer); + +void _zip_cdir_free(zip_cdir_t *); +bool _zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error); +zip_cdir_t *_zip_cdir_new(zip_uint64_t, zip_error_t *); +zip_int64_t _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors); +time_t _zip_d2u_time(zip_uint16_t, zip_uint16_t); +void _zip_deregister_source(zip_t *za, zip_source_t *src); + +void _zip_dirent_apply_attributes(zip_dirent_t *, zip_file_attributes_t *, bool, zip_uint32_t); +zip_dirent_t *_zip_dirent_clone(const zip_dirent_t *); +void _zip_dirent_free(zip_dirent_t *); +void _zip_dirent_finalize(zip_dirent_t *); +void _zip_dirent_init(zip_dirent_t *); +bool _zip_dirent_needs_zip64(const zip_dirent_t *, zip_flags_t); +zip_dirent_t *_zip_dirent_new(void); +bool zip_dirent_process_ef_zip64(zip_dirent_t * zde, const zip_uint8_t * ef, zip_uint64_t got_len, bool local, zip_error_t * error); +zip_int64_t _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error); +void _zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64); +void zip_dirent_torrentzip_normalize(zip_dirent_t *de); + +zip_int32_t _zip_dirent_size(zip_source_t *src, zip_uint16_t, zip_error_t *); +int _zip_dirent_write(zip_t *za, zip_dirent_t *dirent, zip_flags_t flags); + +zip_extra_field_t *_zip_ef_clone(const zip_extra_field_t *, zip_error_t *); +zip_extra_field_t *_zip_ef_delete_by_id(zip_extra_field_t *, zip_uint16_t, zip_uint16_t, zip_flags_t); +void _zip_ef_free(zip_extra_field_t *); +const zip_uint8_t *_zip_ef_get_by_id(const zip_extra_field_t *, zip_uint16_t *, zip_uint16_t, zip_uint16_t, zip_flags_t, zip_error_t *); +zip_extra_field_t *_zip_ef_merge(zip_extra_field_t *, zip_extra_field_t *); +zip_extra_field_t *_zip_ef_new(zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_flags_t); +bool _zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_flags_t, zip_extra_field_t **, zip_error_t *); +zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *); +zip_uint16_t _zip_ef_size(const zip_extra_field_t *, zip_flags_t); +int _zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags); + +void _zip_entry_finalize(zip_entry_t *); +void _zip_entry_init(zip_entry_t *); + +void _zip_error_clear(zip_error_t *); +void _zip_error_get(const zip_error_t *, int *, int *); + +void _zip_error_copy(zip_error_t *dst, const zip_error_t *src); + +const zip_uint8_t *_zip_extract_extra_field_by_id(zip_error_t *, zip_uint16_t, int, const zip_uint8_t *, zip_uint16_t, zip_uint16_t *); + +int _zip_file_extra_field_prepare_for_change(zip_t *, zip_uint64_t); +int _zip_file_fillbuf(void *, size_t, zip_file_t *); +zip_uint64_t _zip_file_get_end(const zip_t *za, zip_uint64_t index, zip_error_t *error); +zip_uint64_t _zip_file_get_offset(const zip_t *, zip_uint64_t, zip_error_t *); + +zip_dirent_t *_zip_get_dirent(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *); + +enum zip_encoding_type _zip_guess_encoding(zip_string_t *, enum zip_encoding_type); +zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t *const, zip_uint32_t, zip_uint32_t *, zip_error_t *); + +bool _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error); +bool _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *key, zip_error_t *error); +void _zip_hash_free(zip_hash_t *hash); +zip_int64_t _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error); +zip_hash_t *_zip_hash_new(zip_error_t *error); +bool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error); +bool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error); + +int _zip_mkstempm(char *path, int mode, bool create_file); + +zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *); + +void _zip_progress_end(zip_progress_t *progress); +void _zip_progress_free(zip_progress_t *progress); +int _zip_progress_start(zip_progress_t *progress); +int _zip_progress_subrange(zip_progress_t *progress, double start, double end); +int _zip_progress_update(zip_progress_t *progress, double value); + +/* this symbol is extern so it can be overridden for regression testing */ +ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length); +zip_uint32_t zip_random_uint32(void); + +int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error); +int _zip_read_at_offset(zip_source_t *src, zip_uint64_t offset, unsigned char *b, size_t length, zip_error_t *error); +zip_uint8_t *_zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error); +int _zip_read_local_ef(zip_t *, zip_uint64_t); +zip_string_t *_zip_read_string(zip_buffer_t *buffer, zip_source_t *src, zip_uint16_t length, bool nulp, zip_error_t *error); +int _zip_register_source(zip_t *za, zip_source_t *src); + +void _zip_set_open_error(int *zep, const zip_error_t *err, int ze); + +bool zip_source_accept_empty(zip_source_t *src); +zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command); +bool _zip_source_eof(zip_source_t *); +zip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error); +bool _zip_source_had_error(zip_source_t *); +void _zip_source_invalidate(zip_source_t *src); +zip_source_t *_zip_source_new(zip_error_t *error); +int _zip_source_set_source_archive(zip_source_t *, zip_t *); +zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_uint64_t st_invalid, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, bool take_ownership, zip_error_t *error); + +int _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error); +int _zip_string_equal(const zip_string_t *a, const zip_string_t *b); +void _zip_string_free(zip_string_t *string); +zip_uint32_t _zip_string_crc32(const zip_string_t *string); +const zip_uint8_t *_zip_string_get(zip_string_t *string, zip_uint32_t *lenp, zip_flags_t flags, zip_error_t *error); +zip_uint16_t _zip_string_length(const zip_string_t *string); +zip_string_t *_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, zip_error_t *error); +int _zip_string_write(zip_t *za, const zip_string_t *string); +bool _zip_winzip_aes_decrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length); +bool _zip_winzip_aes_encrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length); +bool _zip_winzip_aes_finish(zip_winzip_aes_t *ctx, zip_uint8_t *hmac); +void _zip_winzip_aes_free(zip_winzip_aes_t *ctx); +zip_winzip_aes_t *_zip_winzip_aes_new(const zip_uint8_t *password, zip_uint64_t password_length, const zip_uint8_t *salt, zip_uint16_t key_size, zip_uint8_t *password_verify, zip_error_t *error); + +void _zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len); +void _zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len); +zip_pkware_keys_t *_zip_pkware_keys_new(zip_error_t *error); +void _zip_pkware_keys_free(zip_pkware_keys_t *keys); +void _zip_pkware_keys_reset(zip_pkware_keys_t *keys); + +int _zip_changed(const zip_t *, zip_uint64_t *); +const char *_zip_get_name(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *); +int _zip_local_header_read(zip_t *, int); +void *_zip_memdup(const void *, size_t, zip_error_t *); +zip_int64_t _zip_name_locate(zip_t *, const char *, zip_flags_t, zip_error_t *); +zip_t *_zip_new(zip_error_t *); + +zip_int64_t _zip_file_replace(zip_t *, zip_uint64_t, const char *, zip_source_t *, zip_flags_t); +int _zip_set_name(zip_t *, zip_uint64_t, const char *, zip_flags_t); +void _zip_u2d_time(time_t, zip_uint16_t *, zip_uint16_t *); +int _zip_unchange(zip_t *, zip_uint64_t, int); +void _zip_unchange_data(zip_entry_t *); +int _zip_write(zip_t *za, const void *data, zip_uint64_t length); + +#endif /* zipint.h */ diff --git a/src/zip/DeflateFileWriter.cpp b/src/zip/DeflateFileWriter.cpp deleted file mode 100644 index ad44303..0000000 --- a/src/zip/DeflateFileWriter.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "StdAfx.h" - -#include "fs/zip/DeflateFileWriter.h" -#include "fs/IFilesystem.h" -#include "fs/zip/DeflateSinkWriter.h" - -namespace fs -{ - -////////////////////////////////////////////////////////////////////////// - -DeflateFileWriter::DeflateFileWriter(AbsPathView filePath, tl::lent_ref filesystem, uint8_t compressionLevel) - : m_filePath(std::move(filePath)) - , m_filesystem(std::move(filesystem)) - , m_compressionLevel(compressionLevel) -{ -} - -////////////////////////////////////////////////////////////////////////// - -ZipWriter::DataWriterResult DeflateFileWriter::operator()(IStreamSink& sink) -{ - auto result = m_filesystem->openSource(m_filePath); - if (result.has_error()) - return tl::make_generic_error("Error opening input file '{}' to deflate: {}", m_filePath, result.error()); - return DeflateSinkWriter(*result.value(), m_compressionLevel)(sink); -} - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/zip/DeflateSinkWriter.cpp b/src/zip/DeflateSinkWriter.cpp deleted file mode 100644 index 44dea32..0000000 --- a/src/zip/DeflateSinkWriter.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "StdAfx.h" - -#include "fs/zip/DeflateSinkWriter.h" - -#include "fs/CRCStream.h" -#include "fs/CopyStream.h" -#include "fs/IStreamSink.h" -#include "fs/DeflateStreamSink.h" -#include "fs/ISource.h" - -namespace fs -{ -////////////////////////////////////////////////////////////////////////// - -DeflateSinkWriter::DeflateSinkWriter(IStreamSource& source, uint8_t compressionLevel) - : m_source(&source) - , m_compressionLevel(compressionLevel) -{ -} - -////////////////////////////////////////////////////////////////////////// - -DeflateSinkWriter::DeflateSinkWriter(tl::span data, uint8_t compressionLevel) - : m_data(data) - , m_compressionLevel(compressionLevel) -{ -} - -////////////////////////////////////////////////////////////////////////// - -ZipWriter::DataWriterResult DeflateSinkWriter::operator()(IStreamSink& sink) -{ - DeflateStreamSink deflateSink(sink); - deflateSink.setCompressionLevel(m_compressionLevel); - - if (m_source) - { - uint32_t crc = computeCRC32(0, {}); //zip precondition - auto processFunc = [&crc](tl::span data) - { - crc = computeCRC32(crc, data); - }; - - CopyStreamResult copyResult = copyStream(deflateSink, *m_source, processFunc); - if (copyResult.has_error()) - return tl::make_generic_error("{}", copyResult.error()); - - return ZipWriter::DataWriterPayload{ZipBase::CompressionMethod::Deflate, crc, copyResult.value()}; - } - else - { - uint32_t crc = computeCRC32(0, {}); //zip precondition - crc = computeCRC32(crc, m_data); - deflateSink.write(m_data); - return ZipWriter::DataWriterPayload{ZipBase::CompressionMethod::Deflate, crc, m_data.size()}; - } -} - -////////////////////////////////////////////////////////////////////////// -} diff --git a/src/zip/StoreFileWriter.cpp b/src/zip/StoreFileWriter.cpp deleted file mode 100644 index d98f3e1..0000000 --- a/src/zip/StoreFileWriter.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "StdAfx.h" - -#include "fs/zip/StoreFileWriter.h" - -#include "fs/IFilesystem.h" -#include "fs/zip/StoreSinkWriter.h" - -namespace fs -{ - -////////////////////////////////////////////////////////////////////////// - -StoreFileWriter::StoreFileWriter(AbsPathView filePath, tl::lent_ref filesystem) - : m_filePath(std::move(filePath)) - , m_filesystem(std::move(filesystem)) -{ -} - -////////////////////////////////////////////////////////////////////////// - -ZipWriter::DataWriterResult StoreFileWriter::operator()(IStreamSink& sink) -{ - auto openResult = m_filesystem->openSource(m_filePath); - if (openResult.has_error()) - return tl::make_generic_error("Error opening input file '{}' to store: {}", m_filePath, openResult.error()); - - const tl::unique_ref inputSource = std::move(openResult.value()); - return StoreSinkWriter(*inputSource)(sink); -} - -////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/zip/StoreSinkWriter.cpp b/src/zip/StoreSinkWriter.cpp deleted file mode 100644 index 3f44d1b..0000000 --- a/src/zip/StoreSinkWriter.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "StdAfx.h" - -#include "fs/zip/StoreSinkWriter.h" - -#include "fs/CRCStream.h" -#include "fs/CopyStream.h" -#include "fs/IStreamSink.h" -#include "fs/DeflateStreamSink.h" -#include "fs/ISource.h" - -#include "Logger.h" - -namespace fs -{ -////////////////////////////////////////////////////////////////////////// - -StoreSinkWriter::StoreSinkWriter(ISource& source) - : m_inSource(source) -{ -} - -////////////////////////////////////////////////////////////////////////// - -ZipWriter::DataWriterResult StoreSinkWriter::operator()(IStreamSink& sink) -{ - uint32_t crc = computeCRC32(0, {}); //zip precondition - auto processFunc = [&crc](tl::span data) - { - crc = computeCRC32(crc, data); - }; - - auto copyRes = copyStream(sink, m_inSource.get(), processFunc); - if (copyRes.has_error()) - return tl::make_generic_error("{}", copyRes.error()); - - return ZipWriter::DataWriterPayload{ZipBase::CompressionMethod::Store, crc, copyRes.value()}; -} - -////////////////////////////////////////////////////////////////////////// -} diff --git a/src/zip/ZipBase.cpp b/src/zip/ZipBase.cpp deleted file mode 100644 index 71278b9..0000000 --- a/src/zip/ZipBase.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "StdAfx.h" -#include "fs/zip/ZipBase.h" -#include - -namespace fs -{ - -const uint32_t ZipBase::LocalFileHeader::k_signature; -const uint32_t ZipBase::CentralDirectoryFileHeader::k_signature; -const uint32_t ZipBase::EndOfCentralDirectoryRecord::k_signature; -const uint32_t ZipBase::ExtendedInformationExtraField64::k_tag; -const uint32_t ZipBase::EndOfCentralDirectoryRecord64::k_signature; -const uint32_t ZipBase::EndOfCentralDirectoryLocator64::k_signature; - -////////////////////////////////////////////////////////////////////////// - -void ZipBase::computeMsDosTime(time_t time, uint16_t& o_date, uint16_t& o_time) -{ -#ifdef TL_PLATFORM_WINDOWS_FAMILY - struct tm tm_struct; - struct tm *tm = &tm_struct; - if (errno_t err = localtime_s(tm, &time)) - { - o_date = 0; - o_time = 0; - return; - } -#else - struct tm *tm = std::localtime(&time); -#endif /* #ifdef _MSC_VER */ - - o_time = (uint16_t)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); - o_date = (uint16_t)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -} - -////////////////////////////////////////////////////////////////////////// - -ZipBase::CentralDirectoryFileHeader ZipBase::computeCentralDirectoryFileHeader(const LocalFileHeader& header, bool zip64) -{ - CentralDirectoryFileHeader centralHeader; - centralHeader.versionMadeBy = 0; - centralHeader.versionNeededToExtract = header.versionNeededToExtract; - centralHeader.generalBitFlag = header.generalBitFlag; - centralHeader.compressionMethod = header.compressionMethod; - centralHeader.lastModFileTime = header.lastModFileTime; - centralHeader.lastModFileDate = header.lastModFileDate; - centralHeader.crc32 = header.crc32; - centralHeader.compressedSize = header.compressedSize; - centralHeader.uncompressedSize = header.uncompressedSize; - centralHeader.filenameLength = header.filenameLength; - centralHeader.extraFieldLength = header.extraFieldLength; - centralHeader.diskNumberStart = zip64 ? static_cast(-1) : 0; - centralHeader.internalFileAttributes = 0; - centralHeader.externalFileAttributes = 0; - return centralHeader; -} - -////////////////////////////////////////////////////////////////////////// -} diff --git a/src/zip/ZipFileSource.cpp b/src/zip/ZipFileSource.cpp new file mode 100644 index 0000000..2e69b08 --- /dev/null +++ b/src/zip/ZipFileSource.cpp @@ -0,0 +1,145 @@ +#include "StdAfx.h" +#include "ZipFileSource.h" + +extern "C" +{ +#include "zip.h" +} +#include "fs/MemorySink.h" +#include "tl/narrow_cast.h" + +namespace fs +{ +////////////////////////////////////////////////////////////////////////// + +ZipFileSource::ZipFileSource(tl::shared_ptr zipData, tl::unique_ref zipFile, size_t uncompressedSize) noexcept + : m_zipData(std::move(zipData)) + , m_zipFile(std::move(zipFile)) + , m_uncompressedSize(uncompressedSize) +{ +} + +////////////////////////////////////////////////////////////////////////// + +size_t ZipFileSource::read(tl::span data) +{ + if (m_optLastError.has_value()) + { + TL_FAIL(); + return 0; + } + + const size_t sz = tl::min(data.size(), m_uncompressedSize - m_offset); + if (sz == 0) + return 0; + + const zip_int64_t read = fs_zip_fread(m_zipFile.get(), data.data(), sz); + if (read < 0) + { + zip_error_t* error = fs_zip_file_get_error(m_zipFile.get()); + const int ze = fs_zip_error_code_zip(error); + const int se = fs_zip_error_code_system(error); + m_optLastError = tl::make_error(ErrorCode::SystemError, "Zip file error: {}/{} ('{}')", ze, se, zip_error_strerror(error)); + + return 0; + } + + m_offset += read; + return read; +} + +////////////////////////////////////////////////////////////////////////// + +tl::optional ZipFileSource::getLastError() const +{ + auto error = m_optLastError; + m_optLastError = tl::nullopt; + return error; +} + +////////////////////////////////////////////////////////////////////////// + +void ZipFileSource::seekBeg(uint64_t offset) +{ + if (m_optLastError.has_value()) + { + TL_FAIL(); + return; + } + + const uint64_t newOffset = tl::clamp(offset, 0u, m_uncompressedSize); + if (newOffset != m_offset) + { + if (const zip_int8_t res = fs_zip_fseek(m_zipFile.get(), static_cast(offset), SEEK_SET); res < 0) + { + zip_error_t* error = fs_zip_file_get_error(m_zipFile.get()); + const int ze = fs_zip_error_code_zip(error); + const int se = fs_zip_error_code_system(error); + m_optLastError = tl::make_error(ErrorCode::SystemError, "Zip file seekBeg error: {}/{} ('{}')", ze, se, zip_error_strerror(error)); + } + else + m_offset = offset; + } +} + +////////////////////////////////////////////////////////////////////////// + +void ZipFileSource::seekRel(int64_t offset) +{ + if (m_optLastError.has_value()) + { + TL_FAIL(); + return; + } + + if (offset != 0) + { + int64_t newOffset = static_cast(tell()); + newOffset += offset; + newOffset = tl::max(newOffset, 0); + seekBeg(static_cast(tl::min(newOffset, (int64_t)getSize()))); + } +} + +////////////////////////////////////////////////////////////////////////// + +uint64_t ZipFileSource::tell() const +{ + if (m_optLastError.has_value()) + { + TL_FAIL(); + return 0; + } + + return m_offset; +} + +////////////////////////////////////////////////////////////////////////// + +uint64_t ZipFileSource::getSize() const +{ + if (m_optLastError.has_value()) + { + TL_FAIL(); + return 0; + } + + return m_uncompressedSize; +} + +////////////////////////////////////////////////////////////////////////// + +bool ZipFileSource::isEOS() const +{ + return m_offset >= m_uncompressedSize; +} + +////////////////////////////////////////////////////////////////////////// + +size_t ZipFileSource::getPreferredBufferSize() const +{ + return 0; +} + +////////////////////////////////////////////////////////////////////////// +} diff --git a/src/zip/ZipFileSource.h b/src/zip/ZipFileSource.h new file mode 100644 index 0000000..f542c26 --- /dev/null +++ b/src/zip/ZipFileSource.h @@ -0,0 +1,44 @@ +#pragma once + +#include "fs/ISource.h" +#include "fs/Api.h" +#include "fs/zip/ZipPack.h" + +namespace fs +{ +class MemorySink; + +class FS_API ZipFileSource final : public ISource +{ +public: + ZipFileSource(tl::shared_ptr zipData, tl::unique_ref zipFile, uint64_t uncompressedSize) noexcept; + + ZipFileSource(ZipFileSource&&) noexcept = default; + ZipFileSource& operator=(ZipFileSource&&) noexcept = default; + + ~ZipFileSource() override = default; + + tl::optional getLastError() const override; + + size_t read(tl::span data) override; + + void seekBeg(uint64_t offset) override; + void seekRel(int64_t offset) override; + + uint64_t tell() const override; + uint64_t getSize() const override; + + bool isEOS() const override; + + size_t getPreferredBufferSize() const override; + +private: + tl::shared_ptr m_zipData; + tl::unique_ref m_zipFile; + uint64_t m_uncompressedSize = 0; + uint64_t m_offset = 0; + mutable tl::optional m_optLastError; +}; + +} + diff --git a/src/zip/ZipFileStreamSource.cpp b/src/zip/ZipFileStreamSource.cpp new file mode 100644 index 0000000..d5ea8d4 --- /dev/null +++ b/src/zip/ZipFileStreamSource.cpp @@ -0,0 +1,75 @@ +#include "StdAfx.h" +#include "ZipFileStreamSource.h" + +extern "C" +{ +#include "zip.h" +} +#include "fs/MemorySink.h" +#include "tl/narrow_cast.h" + +namespace fs +{ +////////////////////////////////////////////////////////////////////////// + +ZipFileStreamSource::ZipFileStreamSource(tl::shared_ptr zipData, tl::unique_ref zipFile, uint64_t uncompressedSize) noexcept + : m_zipData(std::move(zipData)) + , m_zipFile(std::move(zipFile)) + , m_uncompressedSize(uncompressedSize) +{ +} + +////////////////////////////////////////////////////////////////////////// + +size_t ZipFileStreamSource::read(tl::span data) +{ + if (m_optLastError.has_value()) + { + TL_FAIL(); + return 0; + } + + const size_t sz = tl::min(data.size(), m_uncompressedSize - m_offset); + if (sz == 0) + return 0; + + const zip_int64_t read = fs_zip_fread(m_zipFile.get(), data.data(), sz); + if (read < 0) + { + zip_error_t* error = fs_zip_file_get_error(m_zipFile.get()); + const int ze = fs_zip_error_code_zip(error); + const int se = fs_zip_error_code_system(error); + m_optLastError = tl::make_error(ErrorCode::SystemError, "Zip file error: {}/{} ('{}')", ze, se, zip_error_strerror(error)); + + return 0; + } + + m_offset += read; + return read; +} + +////////////////////////////////////////////////////////////////////////// + +tl::optional ZipFileStreamSource::getLastError() const +{ + auto error = m_optLastError; + m_optLastError = tl::nullopt; + return error; +} + +////////////////////////////////////////////////////////////////////////// + +bool ZipFileStreamSource::isEOS() const +{ + return m_offset >= m_uncompressedSize; +} + +////////////////////////////////////////////////////////////////////////// + +size_t ZipFileStreamSource::getPreferredBufferSize() const +{ + return 0; +} + +////////////////////////////////////////////////////////////////////////// +} diff --git a/src/zip/ZipFileStreamSource.h b/src/zip/ZipFileStreamSource.h new file mode 100644 index 0000000..afaf33a --- /dev/null +++ b/src/zip/ZipFileStreamSource.h @@ -0,0 +1,38 @@ +#pragma once + +#include "fs/IStreamSource.h" +#include "fs/Api.h" +#include "fs/zip/ZipPack.h" + +namespace fs +{ +class MemorySink; + +class FS_API ZipFileStreamSource final : public IStreamSource +{ +public: + ZipFileStreamSource(tl::shared_ptr zipData, tl::unique_ref zipFile, uint64_t uncompressedSize) noexcept; + + ZipFileStreamSource(ZipFileStreamSource&&) noexcept = default; + ZipFileStreamSource& operator=(ZipFileStreamSource&&) noexcept = default; + + ~ZipFileStreamSource() override = default; + + tl::optional getLastError() const override; + + size_t read(tl::span data) override; + + bool isEOS() const override; + + size_t getPreferredBufferSize() const override; + +private: + tl::shared_ptr m_zipData; + tl::unique_ref m_zipFile; + uint64_t m_uncompressedSize = 0; + uint64_t m_offset = 0; + mutable tl::optional m_optLastError; +}; + +} + diff --git a/src/zip/ZipPack.cpp b/src/zip/ZipPack.cpp index 0089011..77cdd3c 100644 --- a/src/zip/ZipPack.cpp +++ b/src/zip/ZipPack.cpp @@ -2,20 +2,23 @@ #include "fs/zip/ZipPack.h" -#include "fs/MapSourceView.h" -#include "fs/MemorySource.h" #include "fs/NativeFilesystem.h" -#include "fs/StreamSourceToSourceAdapter.h" -#include "fs/SourceView.h" -#include "fs/DeflateStreamSource.h" +#include "fs/StreamSourceToMapSourceAdapter.h" #include "tl/crash.h" #include "Logger.h" #include +#include #include "tl/narrow_cast.h" +extern "C" +{ +#include "zip.h" +} +#include "ZipFileSource.h" +#include "ZipFileStreamSource.h" ////////////////////////////////////////////////////////////////////////// @@ -24,6 +27,15 @@ namespace fs { namespace { +void my_zip_fclose(zip_file* file) +{ + fs_zip_fclose(file); +} +void my_zip_close(zip* file) +{ + fs_zip_close(file); +} + uint64_t computePersistentHash(AbsPathView path) { uint64_t hash = 0; @@ -31,80 +43,201 @@ uint64_t computePersistentHash(AbsPathView path) tl::hash_and_combine(hash, e); return hash; } -} -////////////////////////////////////////////////////////////////////////// - -ZipPack::ZipPack(tl::unique_ref zipFileSource, ZipReader zipReader) - : m_zipMapSource(std::move(zipFileSource)) +zip_int64_t mapSourceCallback(void* userdata, void* data, zip_uint64_t len, zip_source_cmd_t cmd) { - TL_ASSERT(!m_zipFileLocation.is_valid()); - TL_ASSERT(m_zipMapSource); - createEntries(std::move(zipReader)); + ZipPack::ZipData& zipData = *(ZipPack::ZipData*)userdata; + + switch (cmd) + { + case ZIP_SOURCE_SUPPORTS: + return ZIP_SOURCE_SUPPORTS_READABLE | ZIP_SOURCE_SUPPORTS_SEEKABLE; + case ZIP_SOURCE_OPEN: + { + zipData.fsMapSource->seekBeg(0); + break; + } + case ZIP_SOURCE_READ: + { + return zipData.fsMapSource->read({ (uint8_t*)data, len }); + } + case ZIP_SOURCE_SEEK: + { + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); + const zip_source_args_seek* args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek, data, len, &error); + if (!args) + return -1; + if (args->whence == SEEK_SET) + zipData.fsMapSource->seekBeg(args->offset); + else if (args->whence == SEEK_CUR) + zipData.fsMapSource->seekRel(args->offset); + else + return -1; + return zipData.fsMapSource->getLastError().has_value() ? -1 : 0; + } + case ZIP_SOURCE_TELL: + return zipData.fsMapSource->tell(); + case ZIP_SOURCE_STAT: + { + zip_stat_t* stat = (zip_stat_t*)data; + fs_zip_stat_init(stat); + stat->valid = ZIP_STAT_SIZE; + stat->size = zipData.fsMapSource->getSize(); + return sizeof(zip_stat_t); + } + } + + return 0; } -////////////////////////////////////////////////////////////////////////// - -ZipPack::ZipPack(tl::lent_ref filesystem, AbsPathView zipFileLocation, ZipReader zipReader) - : m_filesystem(std::move(filesystem)) - , m_zipFileLocation(std::move(zipFileLocation)) +zip_int64_t fileSourceCallback(void* userdata, void* data, zip_uint64_t len, zip_source_cmd_t cmd) { - TL_ASSERT(m_zipFileLocation.is_valid()); - TL_ASSERT(m_filesystem); - TL_ASSERT(!m_zipMapSource); - createEntries(std::move(zipReader)); + ZipPack::ZipData& zipData = *(ZipPack::ZipData*)userdata; + + switch (cmd) + { + case ZIP_SOURCE_SUPPORTS: + return ZIP_SOURCE_SUPPORTS_READABLE | ZIP_SOURCE_SUPPORTS_SEEKABLE; + case ZIP_SOURCE_OPEN: + { + auto result = zipData.filesystem->openSource(zipData.path); + if (result.has_value()) + zipData.fsSource = std::move(result.value()); + else + LOGE("Error opening zip file source: {}", result.error()); + break; + } + case ZIP_SOURCE_CLOSE: + { + if (zipData.fsSource) + zipData.fsSource = {}; + break; + } + case ZIP_SOURCE_READ: + { + if (zipData.fsSource) + return zipData.fsSource->read({ (uint8_t*)data, len }); + return 0; + } + case ZIP_SOURCE_SEEK: + { + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); + const zip_source_args_seek* args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek, data, len, &error); + if (!args || !zipData.fsSource) + return -1; + if (args->whence == SEEK_SET) + zipData.fsSource->seekBeg(args->offset); + else if (args->whence == SEEK_CUR) + zipData.fsSource->seekRel(args->offset); + else if (args->whence == SEEK_END) + zipData.fsSource->seekBeg(zipData.fsSource->getSize() + args->offset); + else + return -1; + return zipData.fsSource->getLastError().has_value() ? -1 : 0; + } + case ZIP_SOURCE_TELL: + if (!zipData.fsSource) + return -1; + return zipData.fsSource->tell(); + case ZIP_SOURCE_STAT: + { + zip_stat_t* stat = (zip_stat_t*)data; + fs_zip_stat_init(stat); + stat->valid = ZIP_STAT_SIZE; + if (zipData.cachedSize == uint64_t(-1)) + { + if (auto result = zipData.filesystem->getStat(zipData.path); result.has_value()) + zipData.cachedSize = result.value().size; + } + stat->size = zipData.cachedSize; + return sizeof(zip_stat_t); + } + } + + return 0; +} + } ////////////////////////////////////////////////////////////////////////// -ZipPack::CreateResult ZipPack::create(tl::unique_ref zipFileSource) +ZipPack::ZipPack(tl::shared_ptr zipData) + : m_zipData(std::move(zipData)) { - ZipReader::CreateResult zipResult = ZipReader::create(*zipFileSource); - if (zipResult.has_error()) - return tl::make_error(Error::code_t::SystemError, "Faild to create zip reader: {}", zipResult.error()); - - ZipReader zipReader = std::move(zipResult.value()); - if (zipReader.getEntryCount() > 65535) - return tl::make_error(Error::code_t::NotSupported, - "ZipPack failed to initialize because the zip has too many entries ({} > 65536 max)", - zipReader.getEntryCount()); - - return tl::unique_ref(new ZipPack(std::move(zipFileSource), std::move(zipReader))); + createEntries(*m_zipData->zipArchive); } ////////////////////////////////////////////////////////////////////////// -ZipPack::CreateResult ZipPack::create(tl::lent_ref filesystem, AbsPathView zipFileLocation) +ZipPack::CreateResult ZipPack::create(tl::unique_ref source) { - tl::result, Error> openResult = filesystem->openSource(zipFileLocation); - if (openResult.has_error()) - return openResult.error(); + tl::shared_ptr zipData = tl::make_shared(); + zipData->fsMapSource = std::move(source); - const tl::unique_ref source = std::move(openResult.value()); + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); - ZipReader::CreateResult zipResult = ZipReader::create(*source); - if (zipResult.has_error()) - return tl::make_error(Error::code_t::SystemError, "Faild to create zip reader: {}", zipResult.error()); + zip_source* zipSource = fs_zip_source_function_create(mapSourceCallback, zipData.get(), &error); - ZipReader zipReader = std::move(zipResult.value()); - if (zipReader.getEntryCount() > 65535) - return tl::make_error(Error::code_t::NotSupported, - "ZipPack failed to initialize because the zip has too many entries ({} > 65536 max)", - zipReader.getEntryCount()); + zip* _zipArchive = fs_zip_open_from_source(zipSource, 0, &error); + if (!_zipArchive) + { + zip_source_free(zipSource); + const int ze = fs_zip_error_code_zip(&error); + const int se = fs_zip_error_code_system(&error); + return tl::make_error(ErrorCode::SystemError, "Failed to create zip archive: {}/{} ('{}')", ze, se, zip_error_strerror(&error)); + } + tl::unique_ref zipArchive = tl::unique_ref(_zipArchive, &my_zip_close); - return tl::unique_ref(new ZipPack(std::move(filesystem), std::move(zipFileLocation), std::move(zipReader))); + zipData->zipArchive = std::move(zipArchive); + + return tl::unique_ref(new ZipPack(std::move(zipData))); } ////////////////////////////////////////////////////////////////////////// -void ZipPack::createEntries(ZipReader zipReader) +ZipPack::CreateResult ZipPack::create(tl::lent_ref filesystem, AbsPathView path) +{ + tl::shared_ptr zipData = tl::make_shared(); + zipData->filesystem = std::move(filesystem); + zipData->path = path; + + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); + + zip_source* zipSource = fs_zip_source_function_create(fileSourceCallback, zipData.get(), &error); + zip* _zipArchive = fs_zip_open_from_source(zipSource, 0, &error); + if (!_zipArchive) + { + zip_source_free(zipSource); + const int ze = fs_zip_error_code_zip(&error); + const int se = fs_zip_error_code_system(&error); + return tl::make_error(ErrorCode::SystemError, "Failed to create zip archive: {}/{} ('{}')", ze, se, zip_error_strerror(&error)); + } + + tl::unique_ref zipArchive = tl::unique_ref(_zipArchive, &my_zip_close); + + zipData->zipArchive = std::move(zipArchive); + + return tl::unique_ref(new ZipPack(std::move(zipData))); +} + +////////////////////////////////////////////////////////////////////////// + +void ZipPack::createEntries(zip& archive) { m_files.clear(); m_folders.clear(); m_pathToIndex.clear(); m_childrenIndices.clear(); - const size_t readerEntryCount = zipReader.getEntryCount(); + const size_t readerEntryCount = fs_zip_get_num_entries(&archive, 0); m_files.reserve(readerEntryCount + 1); m_folders.reserve(readerEntryCount / 2); @@ -119,50 +252,39 @@ void ZipPack::createEntries(ZipReader zipReader) AbsPath path; + zip_stat_t stat; for (size_t readerEntryIndex = 0; readerEntryIndex < readerEntryCount; readerEntryIndex++) { - const ZipReader::Entry& readerEntry = zipReader.getEntry(readerEntryIndex); - if (readerEntry.compressionMethod != ZipReader::CompressionMethod::Store && readerEntry.compressionMethod != ZipReader::CompressionMethod::Deflate) + if (fs_zip_stat_index(&archive, readerEntryIndex, 0, &stat) != 0) { - LOGE("ZipPack entry '{}' because it uses an unsupported compression", readerEntry.name); + LOGE("ZipPack entry '{}' stat failed", readerEntryIndex); continue; } - if (readerEntry.generalBitFlags.test(ZipReader::GeneralBitFlag::Encrypted)) + + const char* name = stat.name; + if (!name || name[0] == 0) { - LOGE("ZipPack entry '{}' because it uses encryption", readerEntry.name); + LOGE("ZipPack entry '{}' name empty", readerEntryIndex); continue; } - if ((readerEntry.uncompressedSize >> 32) > 255) + + if (stat.comp_method != ZIP_CM_STORE && stat.comp_method != ZIP_CM_DEFLATE) { - LOGE("ZipPack entry '{}' because its uncompressedSize is too big ({} > {} max)", - readerEntry.name, - readerEntry.uncompressedSize, - (uint64_t(255) << 32) | uint64_t(0xFFFFFFFF)); + LOGE("ZipPack entry '{}' because it uses an unsupported compression", name); continue; } - if ((readerEntry.compressedSize >> 32) > 255) + if (stat.encryption_method != ZIP_EM_NONE) { - LOGE("ZipPack entry '{}' because its compressedSize is too big ({} > {} max)", - readerEntry.name, - readerEntry.compressedSize, - (uint64_t(255) << 32) | uint64_t(0xFFFFFFFF)); - continue; - } - if ((readerEntry.dataOffset >> 32) > 255) - { - LOGE("ZipPack entry '{}' because its dataOffset is too big ({} > {} max)", - readerEntry.name, - readerEntry.dataOffset, - (uint64_t(255) << 32) | uint64_t(0xFFFFFFFF)); + LOGE("ZipPack entry '{}' because it uses encryption", name); continue; } bool isFolder = false; - if (!readerEntry.name.empty() && (readerEntry.name.back() == '/' || readerEntry.name.back() == '\\')) + if (name[0] == '/' || name[0] == '\\') isFolder = true; path = PosixRootTag::value(); - path += readerEntry.name; + path += name; AbsPath parentPath = path; parentPath.pop_back(); @@ -180,8 +302,8 @@ void ZipPack::createEntries(ZipReader zipReader) Folder& folder = m_folders.back(); folder.name = path.back(); + folder.zipIndex = static_cast(readerEntryIndex); folder.parentIndex = parentIndex; - folder.lastModTimePoint = (uint32_t)readerEntry.lastModTimePoint; } else { @@ -193,15 +315,7 @@ void ZipPack::createEntries(ZipReader zipReader) File& file = m_files.back(); file.name = path.back(); - file.isCompressed = readerEntry.compressionMethod == ZipReader::CompressionMethod::Deflate; - file.parentIndex = parentIndex; - file.uncompressedSizeH = (uint8_t)(readerEntry.uncompressedSize >> 32); - file.uncompressedSizeL = (uint32_t)(readerEntry.uncompressedSize & 0xFFFFFFFF); - file.compressedSizeH = (uint8_t)(readerEntry.compressedSize >> 32); - file.compressedSizeL = (uint32_t)(readerEntry.compressedSize & 0xFFFFFFFF); - file.dataOffsetH = (uint8_t)(readerEntry.dataOffset >> 32); - file.dataOffsetL = (uint32_t)(readerEntry.dataOffset & 0xFFFFFFFF); - file.lastModTimePoint = (uint32_t)readerEntry.lastModTimePoint; + file.zipIndex = static_cast(readerEntryIndex); } if (parentIndex >= childrenIndices.size()) @@ -286,16 +400,6 @@ void ZipPack::setEncryptionData(const tl::string& key, uint32_t rounds) ////////////////////////////////////////////////////////////////////////// -namespace -{ -uint64_t decodeValue(uint8_t h, uint32_t l) -{ - return (uint64_t(h) << 32) | uint64_t(l); -} -} - -////////////////////////////////////////////////////////////////////////// - OpenSourceResult ZipPack::openSource(AbsPathView path, IPack::SourceFlags flags) const { if (!path.is_valid()) @@ -310,19 +414,8 @@ OpenSourceResult ZipPack::openSource(AbsPathView path, IPack::SourceFlags flags) return tl::make_error(ErrorCode::NotFound, "Trying to open a source on a folder"); const File& file = m_files[entryIndex.index]; - const uint64_t uncompressedSize = decodeValue(file.uncompressedSizeH, file.uncompressedSizeL); - if (!file.isCompressed) - { - if (uncompressedSize == 0) - return tl::make_unique(); // we return an empty source - // Not compressed - the most simple and fast case - return openRawSource(file); - } - - - - return openZipSource(file); + return _openSource(file); } ////////////////////////////////////////////////////////////////////////// @@ -340,7 +433,7 @@ OpenStreamSourceResult ZipPack::openStreamSource(AbsPathView path, IPack::Source if (entryIndex.isFolder) return tl::make_error(ErrorCode::NotFound, "Trying to open a source on a folder"); - return openZipStreamSource(m_files[entryIndex.index]); + return _openStreamSource(m_files[entryIndex.index]); } ////////////////////////////////////////////////////////////////////////// @@ -359,18 +452,8 @@ OpenMapSourceResult ZipPack::openMapSource(AbsPathView path, MapView mapView, So return tl::make_error(ErrorCode::NotFound, "Trying to open a source on a folder"); const File& file = m_files[entryIndex.index]; - const uint64_t uncompressedSize = decodeValue(file.uncompressedSizeH, file.uncompressedSizeL); - if (!file.isCompressed) - { - if (uncompressedSize == 0) - return tl::make_unique(); // we return an empty source - // Not compressed - the most simple and fast case - return openRawMapSource(file, mapView); - } - - - return openZipMapSource(file); + return _openMapSource(file); } ////////////////////////////////////////////////////////////////////////// @@ -436,7 +519,11 @@ GetStatResult ZipPack::getStat(AbsPathView path) const return tl::make_error(ErrorCode::InvalidArgument, "Cannot stat a folder: '{}'", path); const File& file = m_files[entryIndex.index]; - return Stat{ decodeValue(file.uncompressedSizeH, file.uncompressedSizeL), (time_t)file.lastModTimePoint }; + zip_stat_t stat; + if (fs_zip_stat_index(m_zipData->zipArchive.get(), file.zipIndex, 0, &stat) != 0) + return tl::make_error(ErrorCode::SystemError, "Failed to stat: '{}'", path); + + return Stat{ stat.size, stat.mtime }; } ////////////////////////////////////////////////////////////////////////// @@ -466,12 +553,12 @@ cppcoro::generator ZipPack::enumerate(AbsPath path) const if (childEntryIndex.isFolder) { const Folder& f = m_folders[childEntryIndex.index]; - co_yield{RelPath(f.name), true}; + co_yield{ RelPath(f.name), true }; } else { const File& f = m_files[childEntryIndex.index]; - co_yield{RelPath(f.name), false}; + co_yield{ RelPath(f.name), false }; } } } @@ -507,7 +594,6 @@ void ZipPack::buildUpPath(RelPath& path, const File& file, uint32_t toIndex) con } } - cppcoro::generator ZipPack::enumerateRecursively(AbsPath path) const { TL_ASSERT(path.is_valid()); @@ -540,14 +626,14 @@ cppcoro::generator ZipPack::enumerateRecursively(AbsPath path) c { const Folder& f = m_folders[childEntryIndex.index]; buildUpPath(relPath, f, entryIndex.index); - co_yield{relPath, true}; + co_yield{ relPath, true }; stack.push_back(&f); } else { const File& f = m_files[childEntryIndex.index]; buildUpPath(relPath, f, entryIndex.index); - co_yield{relPath, false}; + co_yield{ relPath, false }; } } } @@ -555,107 +641,51 @@ cppcoro::generator ZipPack::enumerateRecursively(AbsPath path) c ////////////////////////////////////////////////////////////////////////// -OpenMapSourceResult ZipPack::openRawMapSource(const File& file, MapView mapView) const +OpenMapSourceResult ZipPack::_openMapSource(const File& file) const { - const uint64_t compressedSize = decodeValue(file.compressedSizeH, file.compressedSizeL); - if (compressedSize > tl::numeric_limits::max()) - return tl::make_error(ErrorCode::InvalidArgument, - "Cannot map a file {} of size {}. Maximum mappable size is {}", - m_zipFileLocation, - compressedSize, - tl::numeric_limits::max()); + zip_stat_t stat; + if (fs_zip_stat_index(m_zipData->zipArchive.get(), file.zipIndex, 0, &stat) != 0) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}': failed to stat", file.name); - if (mapView.size == 0) - mapView.size = tl::narrow(compressedSize); - else - mapView.size = tl::min(mapView.size, tl::narrow(compressedSize)); + zip_file* zipFile = fs_zip_fopen_index(m_zipData->zipArchive.get(), file.zipIndex, 0); + if (!zipFile) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}': fopen failed", file.name); - const uint64_t dataOffset = decodeValue(file.dataOffsetH, file.dataOffsetL); - mapView.offset = dataOffset + mapView.offset; - - if (m_zipFileLocation.is_valid()) - { - TL_ASSERT(m_filesystem); - tl::result, Error> result = m_filesystem->openMapSource(m_zipFileLocation, mapView); - if (result.has_error()) - return tl::make_error(result.error().code, - "Failed to open mmap source '{}', offset {}, size {}: {}", - m_zipFileLocation, - dataOffset, - compressedSize, - result.error()); - - return std::move(result.value()); - } - - TL_ASSERT(m_zipMapSource); - - std::lock_guard guard(m_zipMapSourceLock); - return tl::make_unique(tl::promote(m_zipMapSource), mapView.offset, mapView.size); + //we can use an adapter to convert a stream source into a regular source + return tl::make_unique(tl::make_unique(m_zipData, tl::unique_ref(zipFile, my_zip_fclose), stat.size)); } ////////////////////////////////////////////////////////////////////////// -OpenSourceResult ZipPack::openRawSource(const File& file) const +OpenSourceResult ZipPack::_openSource(const File& file) const { - uint64_t compressedSize = decodeValue(file.compressedSizeH, file.compressedSizeL); - uint64_t dataOffset = decodeValue(file.dataOffsetH, file.dataOffsetL); + zip_stat_t stat; + if (fs_zip_stat_index(m_zipData->zipArchive.get(), file.zipIndex, 0, &stat) != 0) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}': failed to stat", file.name); - if (m_zipFileLocation.is_valid()) - { - TL_ASSERT(m_filesystem); - tl::result, Error> result = m_filesystem->openSource(m_zipFileLocation); - if (result.has_error()) - return result.error(); + zip_file* zipFile = fs_zip_fopen_index(m_zipData->zipArchive.get(), file.zipIndex, 0); + if (!zipFile) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}': fopen failed", file.name); - return tl::make_unique(std::move(result.value()), dataOffset, compressedSize); - } + if (stat.comp_method == ZIP_CM_STORE) //we can use a ZipFileSource, since seeking is supported in this case + return tl::make_unique(m_zipData, tl::unique_ref(zipFile, my_zip_fclose), stat.size); - TL_ASSERT(m_zipMapSource); - - if (compressedSize > tl::numeric_limits::max()) - return tl::make_error(ErrorCode::InvalidArgument, - "Cannot map a file {} of size {}. Maximum mappable size is {}", - m_zipFileLocation, - compressedSize, - tl::numeric_limits::max()); - - std::lock_guard guard(m_zipMapSourceLock); - return tl::make_unique(tl::promote(m_zipMapSource), dataOffset, compressedSize); + //we can use an adapter to convert a stream source into a regular source + return tl::make_unique(tl::make_unique(m_zipData, tl::unique_ref(zipFile, my_zip_fclose), stat.size)); } ////////////////////////////////////////////////////////////////////////// -OpenMapSourceResult ZipPack::openZipMapSource(const File& file) const +OpenStreamSourceResult ZipPack::_openStreamSource(const File& file) const { - OUTCOME_TRY(auto source, openRawMapSource(file, MapView())); + zip_stat_t stat; + if (fs_zip_stat_index(m_zipData->zipArchive.get(), file.zipIndex, 0, &stat) != 0) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}': failed to stat", file.name); - if (file.isCompressed) - { - tl::unique_ref cmpSource = tl::make_unique(std::move(source)); - return tl::make_unique(std::move(cmpSource)); - } + zip_file* zipFile = fs_zip_fopen_index(m_zipData->zipArchive.get(), file.zipIndex, 0); + if (!zipFile) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}': fopen failed", file.name); - return std::move(source); -} - -////////////////////////////////////////////////////////////////////////// - -OpenSourceResult ZipPack::openZipSource(const File& file) const -{ - OUTCOME_TRY(auto source, openZipMapSource(file)); - return source; -} - -////////////////////////////////////////////////////////////////////////// - -OpenStreamSourceResult ZipPack::openZipStreamSource(const File& file) const -{ - OUTCOME_TRY(auto source, openRawSource(file)); - - if (file.isCompressed) - return tl::make_unique(std::move(source)); - - return std::move(source); + return tl::make_unique(m_zipData, tl::unique_ref(zipFile, my_zip_fclose), stat.size); } } diff --git a/src/zip/ZipReader.cpp b/src/zip/ZipReader.cpp deleted file mode 100644 index d5b9c00..0000000 --- a/src/zip/ZipReader.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "StdAfx.h" - -#include "fs/zip/ZipReader.h" - -#include "fs/ISource.h" - -// This reader is implemented pretty close to the https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT standard - -namespace fs -{ -////////////////////////////////////////////////////////////////////////// - -ZipReader::ZipReader(tl::vector entries) - : m_entries(std::move(entries)) -{ -} - -////////////////////////////////////////////////////////////////////////// - -size_t ZipReader::getEntryCount() const -{ - return m_entries.size(); -} - -////////////////////////////////////////////////////////////////////////// - -const ZipReader::Entry& ZipReader::getEntry(size_t index) const -{ - return m_entries[index]; -} - -////////////////////////////////////////////////////////////////////////// - -ZipReader::SeekResult ZipReader::seekSourceToEntryData(const Entry& entry, ISource& o_source) const -{ - o_source.seekRel(entry.localHeaderOffset); - - LocalFileHeader localHeader; - const size_t read = o_source.read({ reinterpret_cast(&localHeader), sizeof(LocalFileHeader) }); - tl::optional optLastError = o_source.getLastError(); - if (read != sizeof(LocalFileHeader) || optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to seek to entry '{}': {}", entry.name, *optLastError); - - o_source.seekRel(localHeader.filenameLength); - o_source.seekRel(localHeader.extraFieldLength); - - optLastError = o_source.getLastError(); - if (optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to seek to entry '{}': {}", entry.name, *optLastError); - - return tl::success(); -} - -////////////////////////////////////////////////////////////////////////// - -ZipReader::CentralDirectoryResult ZipReader::findCentralDirectoryBounds(ISource& source) -{ - const uint64_t sourceSize = source.getSize(); - - ////////////////////////////////////////////////////////////////////////// - // Try the end of central directory - uint64_t endOfCentralDirectoryRecordStart = sourceSize - sizeof(EndOfCentralDirectoryRecord); - - EndOfCentralDirectoryRecord endOfCentralDirectoryRecord; - source.seekBeg(endOfCentralDirectoryRecordStart); - - source.read({ reinterpret_cast(&endOfCentralDirectoryRecord), sizeof(EndOfCentralDirectoryRecord) }); - if (endOfCentralDirectoryRecord.signature != EndOfCentralDirectoryRecord::k_signature) - return tl::make_error(ErrorCode::BadSignature, "The central directory appears corrupt (bad signature)"); - - ////////////////////////////////////////////////////////////////////////// - // Try the end of central directory locator for zip64 - if (endOfCentralDirectoryRecordStart >= sizeof(EndOfCentralDirectoryLocator64)) - { - const uint64_t endOfCentralDirectoryLocator64Start = endOfCentralDirectoryRecordStart - sizeof(EndOfCentralDirectoryLocator64); - - EndOfCentralDirectoryLocator64 endOfCentralDirectoryLocator64; - source.seekBeg(endOfCentralDirectoryLocator64Start); - - source.read({ reinterpret_cast(&endOfCentralDirectoryLocator64), sizeof(EndOfCentralDirectoryLocator64) }); - if (endOfCentralDirectoryLocator64.signature == EndOfCentralDirectoryLocator64::k_signature && - endOfCentralDirectoryLocator64.endOfCentralDirectoryRecordOffset < endOfCentralDirectoryLocator64Start) - { - // now try the end of central directory 64 - EndOfCentralDirectoryRecord64 endOfCentralDirectoryRecord64; - source.seekBeg(endOfCentralDirectoryLocator64.endOfCentralDirectoryRecordOffset); - - source.read({ reinterpret_cast(&endOfCentralDirectoryRecord64), sizeof(EndOfCentralDirectoryRecord64) }); - if (endOfCentralDirectoryRecord64.signature == EndOfCentralDirectoryRecord64::k_signature) - { - // we definitely are in zip64 mode! - if (endOfCentralDirectoryRecord64.centralDirectoryOffset > endOfCentralDirectoryLocator64.endOfCentralDirectoryRecordOffset) - return tl::make_error(ErrorCode::BadOffset, "The zip64 central directory appears corrupt (bad offset)"); - - return tl::make_pair(endOfCentralDirectoryRecord64.centralDirectoryOffset, endOfCentralDirectoryLocator64.endOfCentralDirectoryRecordOffset); - } - } - } - - if (endOfCentralDirectoryRecord.centralDirectoryOffset > endOfCentralDirectoryRecordStart) - return tl::make_error(ErrorCode::BadOffset, "The central directory appears corrupt (bad offset)"); - - return tl::make_pair(endOfCentralDirectoryRecord.centralDirectoryOffset, endOfCentralDirectoryRecordStart); -} - -////////////////////////////////////////////////////////////////////////// - -ZipReader::CreateResult ZipReader::create(ISource& source) -{ - CentralDirectoryResult centralDirectoryResult = findCentralDirectoryBounds(source); - if (centralDirectoryResult.has_error()) - return tl::make_error(centralDirectoryResult.error().code, "{}", centralDirectoryResult.error()); - - uint64_t centralDirectoryStartOffset = centralDirectoryResult.value().first; - uint64_t centralDirectoryEndOffset = centralDirectoryResult.value().second; - TL_ASSERT(centralDirectoryStartOffset <= centralDirectoryEndOffset); - - tl::vector entries; - entries.reserve(1024); - - tl::memory_buffer stringBuffer; - - source.seekBeg(centralDirectoryStartOffset); - - while (source.tell() < centralDirectoryEndOffset) - { - CentralDirectoryFileHeader fileHeader; - size_t read = source.read({ reinterpret_cast(&fileHeader), sizeof(CentralDirectoryFileHeader) }); - tl::optional optLastError = source.getLastError(); - if (read != sizeof(CentralDirectoryFileHeader) || optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read central directory: {}", *optLastError); - - if (fileHeader.signature != CentralDirectoryFileHeader::k_signature) - { - return tl::make_error( - ErrorCode::CorruptedFile, - "Central directory header signature mismatch. Expected {}, got {}", CentralDirectoryFileHeader::k_signature, fileHeader.signature); - } - - stringBuffer.resize(fileHeader.filenameLength); - read = source.read({ stringBuffer.data(), fileHeader.filenameLength }); - optLastError = source.getLastError(); - if (read != fileHeader.filenameLength || optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read central directory filename: {}", *optLastError); - - Entry entry; - entry.name = tl::string(reinterpret_cast(stringBuffer.data()), reinterpret_cast(stringBuffer.data() + stringBuffer.size())); - entry.compressionMethod = static_cast(fileHeader.compressionMethod); - entry.generalBitFlags = GeneralBitFlags(fileHeader.generalBitFlag); - entry.uncompressedSize = fileHeader.uncompressedSize; - entry.compressedSize = fileHeader.compressedSize; - entry.crc32 = fileHeader.crc32; - entry.localHeaderOffset = fileHeader.localHeaderOffset; - - { - struct tm parts; - parts.tm_sec = (fileHeader.lastModFileTime & 0x001f) << 1; - parts.tm_min = (fileHeader.lastModFileTime & 0x07e0) >> 5; - parts.tm_hour = (fileHeader.lastModFileTime & 0xf800) >> 11; - parts.tm_mday = (fileHeader.lastModFileDate & 0x001f); - parts.tm_mon = ((fileHeader.lastModFileDate & 0x01e0) >> 5) - 1; - parts.tm_year = ((fileHeader.lastModFileDate & 0xfe00) >> 9) + 80; - parts.tm_wday = parts.tm_yday = 0; - parts.tm_isdst = -1; // DST info "not available" - entry.lastModTimePoint = mktime(&parts); - } - - // check for extended info for zip64 formats - if (fileHeader.extraFieldLength >= sizeof(ExtendedInformationExtraField64) - 4) - { - // the ExtendedInformationExtraField64 is the first one of the extended fields - ExtendedInformationExtraField64 extended; - read = source.read({ reinterpret_cast(&extended), sizeof(ExtendedInformationExtraField64) }); - optLastError = source.getLastError(); - if (read != sizeof(ExtendedInformationExtraField64) || optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read central directory extra fields: {}", *optLastError); - - if (extended.tag == ExtendedInformationExtraField64::k_tag && extended.size == (sizeof(ExtendedInformationExtraField64)- 4)) - { - entry.uncompressedSize = extended.originalSize; - entry.compressedSize = extended.compressedSize; - entry.localHeaderOffset = extended.localHeaderOffset; - } - else - { - // not the tag we're looking for, skip the remaining extra fields - source.seekRel(fileHeader.extraFieldLength - sizeof(ExtendedInformationExtraField64)); - optLastError = source.getLastError(); - if (optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read central directory extra fields: {}", *optLastError); - } - } - else - { - source.seekRel(fileHeader.extraFieldLength); - optLastError = source.getLastError(); - if (optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read central directory extra fields: {}", *optLastError); - } - - if (fileHeader.fileCommentLength > 0) - { - entry.comment.resize(fileHeader.fileCommentLength); - read = source.read({ entry.comment.data(), fileHeader.fileCommentLength }); - optLastError = source.getLastError(); - if (read != fileHeader.fileCommentLength || optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read central directory filename: {}", *optLastError); - } - - entries.push_back(std::move(entry)); - } - - // now go through all the entries, read the local header to calculate the precise data offset - for (Entry& entry : entries) - { - source.seekBeg(entry.localHeaderOffset); - tl::optional optLastError = source.getLastError(); - if (optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to seek to local file header for entry '{}': {}", entry.name, *optLastError); - - LocalFileHeader fileHeader; - size_t read = source.read({ reinterpret_cast(&fileHeader), sizeof(LocalFileHeader) }); - if (read != sizeof(LocalFileHeader)) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read local file header for entry '{}': insufficient data", entry.name); - - optLastError = source.getLastError(); - if (optLastError.has_value()) - return tl::make_error(ErrorCode::CorruptedFile, "Failed to read local file header for entry '{}': {}", entry.name, *optLastError); - - entry.dataOffset = entry.localHeaderOffset + sizeof(LocalFileHeader) + fileHeader.filenameLength + fileHeader.extraFieldLength; - } - - return ZipReader(std::move(entries)); -} - -////////////////////////////////////////////////////////////////////////// -} diff --git a/src/zip/ZipUtils.cpp b/src/zip/ZipUtils.cpp index 9f41c82..4b6339e 100644 --- a/src/zip/ZipUtils.cpp +++ b/src/zip/ZipUtils.cpp @@ -47,17 +47,18 @@ UnzipResult unzipFile(IFilesystem& dstFilesystem, AbsPathView filePath, tl::lent return unzip(dstFilesystem, filePath, std::move(pack)); } -ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel, size_t fileDataAlignment) +ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel) { - ZipWriter writer(sink, fileDataAlignment); + ZipWriter writer(sink); OUTCOME_TRY(const bool isFile, filesystem->isFile(path)); if (isFile) { - tl::result addResult = writer.addFile(path.str(), [&filesystem, &path, compressionLevel](IStreamSink& sink) - { - return DeflateFileWriter(path, filesystem, compressionLevel)(sink); - }); + const auto openResult = filesystem->openSource(path); + if (openResult.has_error()) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}' zip: {}", path, openResult.error()); + + const auto addResult = writer.addFile(path.str(), compressionLevel, *openResult.value()); if (addResult.has_error()) return tl::make_error(ErrorCode::SystemError, "Cannot add file '{}' zip: {}", path, addResult.error()); } @@ -67,12 +68,14 @@ ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathVi { if (!ee.isFolder) { - tl::result addResult = writer.addFile(ee.path.str(), [&filesystem, &path, &ee, compressionLevel](IStreamSink& sink) - { - return DeflateFileWriter(path + ee.path, filesystem, compressionLevel)(sink); - }); + auto localPath = path + ee.path; + const auto openResult = filesystem->openSource(localPath); + if (openResult.has_error()) + return tl::make_error(ErrorCode::SystemError, "Cannot open file '{}' zip: {}", localPath, openResult.error()); + + const auto addResult = writer.addFile(localPath.str(), compressionLevel, *openResult.value()); if (addResult.has_error()) - return {tl::make_error(ErrorCode::SystemError, "Cannot add file '{}' zip: {}", path + ee.path, addResult.error())}; + return tl::make_error(ErrorCode::SystemError, "Cannot add file '{}' zip: {}", localPath, addResult.error()); } } } @@ -81,10 +84,10 @@ ZipResult zipToSink(ISink& sink, tl::lent_ref filesystem, AbsPathVi return tl::success(); } -ZipResult zipToFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel, size_t fileDataAlignment) +ZipResult zipToFile(IFilesystem& dstFilesystem, AbsPathView dstFilePath, tl::lent_ref filesystem, AbsPathView path, uint8_t compressionLevel) { OUTCOME_TRY(const auto sink, dstFilesystem.openSink(dstFilePath, Mode::CreateOrOpenAndClear)); - return zipToSink(*sink, std::move(filesystem), path, compressionLevel, fileDataAlignment); + return zipToSink(*sink, std::move(filesystem), path, compressionLevel); } } diff --git a/src/zip/ZipWriter.cpp b/src/zip/ZipWriter.cpp index c3ab69d..c28313f 100644 --- a/src/zip/ZipWriter.cpp +++ b/src/zip/ZipWriter.cpp @@ -2,228 +2,299 @@ #include "fs/zip/ZipWriter.h" +extern "C" +{ +#include "zip.h" +} + #include "fs/CRCStream.h" -#include "fs/IStreamSource.h" +#include "fs/ISource.h" #include "fs/ISink.h" #include "tl/narrow_cast.h" - -// This writer is implemented pretty close to the https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT standard +#include namespace fs { ////////////////////////////////////////////////////////////////////////// -ZipWriter::ZipWriter(ISink& sink, size_t fileDataAlignment) +namespace +{ +void my_zip_fclose(zip_file* file) +{ + fs_zip_fclose(file); +} +void my_zip_close(zip* file) +{ + fs_zip_close(file); +} + +zip_int64_t sourceCallback(void* userdata, void* data, zip_uint64_t len, zip_source_cmd_t cmd) +{ + ISource& source = *(ISource*)userdata; + + switch (cmd) + { + case ZIP_SOURCE_SUPPORTS: + return ZIP_SOURCE_SUPPORTS_SEEKABLE; + case ZIP_SOURCE_OPEN: + return 0; + case ZIP_SOURCE_CLOSE: + return 0; + case ZIP_SOURCE_READ: + return source.read({ (uint8_t*)data, len }); + case ZIP_SOURCE_SEEK: + { + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); + const zip_source_args_seek* args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek, data, len, &error); + if (!args) + return -1; + if (args->whence == SEEK_SET) + source.seekBeg(args->offset); + else if (args->whence == SEEK_CUR) + source.seekRel(args->offset); + else + return -1; + return source.getLastError().has_value() ? -1 : 0; + } + case ZIP_SOURCE_TELL: + return source.tell(); + case ZIP_SOURCE_STAT: + { + zip_stat_t* stat = (zip_stat_t*)data; + fs_zip_stat_init(stat); + stat->valid = ZIP_STAT_SIZE; + stat->size = source.getSize(); + return sizeof(zip_stat_t); + } + } + + return 0; +} + +zip_int64_t sinkCallback(void* userdata, void* data, zip_uint64_t len, zip_source_cmd_t cmd) +{ + ISink& sink = *(ISink*)userdata; + + switch (cmd) + { + case ZIP_SOURCE_SUPPORTS: + return ZIP_SOURCE_SUPPORTS_WRITABLE; + case ZIP_SOURCE_OPEN: + return 0; + case ZIP_SOURCE_BEGIN_WRITE: + case ZIP_SOURCE_COMMIT_WRITE: + return 0; + case ZIP_SOURCE_WRITE: + { + return sink.write({ (uint8_t*)data, len }); + } + case ZIP_SOURCE_SEEK: + case ZIP_SOURCE_SEEK_WRITE: + { + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); + const zip_source_args_seek* args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek, data, len, &error); + if (!args) + { + return -1; + } + if (args->whence == SEEK_SET) + sink.seekBeg(args->offset); + else if (args->whence == SEEK_CUR) + sink.seekRel(args->offset); + else + return -1; + return sink.getLastError().has_value() ? -1 : 0; + } + case ZIP_SOURCE_TELL: + case ZIP_SOURCE_TELL_WRITE: + return sink.tell(); + case ZIP_SOURCE_STAT: + { + zip_stat_t* stat = (zip_stat_t*)data; + fs_zip_stat_init(stat); + stat->valid = ZIP_STAT_SIZE; + stat->size = sink.getSize(); + return sizeof(zip_stat_t); + } + } + + return 0; +} +} + +ZipWriter::ZipWriter(ISink& sink) : m_sink(sink) - , m_fileDataAlignment(fileDataAlignment == 0 ? 1 : fileDataAlignment) -{} +{ + zip_error error; + fs_zip_error_init(&error); + tl::finally finally([&] { fs_zip_error_fini(&error); }); + zip_source* zipSink = fs_zip_source_function_create(sinkCallback, &m_sink, &error); + + zip* _zipArchive = fs_zip_open_from_source(zipSink, ZIP_CREATE | ZIP_TRUNCATE, &error); + if (!_zipArchive) + { + const int ze = fs_zip_error_code_zip(&error); + const int se = fs_zip_error_code_system(&error); + zip_source_free(zipSink); + return; + } + m_zipArchive = tl::unique_ref(_zipArchive, &my_zip_close); +} + +ZipWriter::~ZipWriter() +{ + finish(); +} + ////////////////////////////////////////////////////////////////////////// -tl::result ZipWriter::addFile(tl::string name, const DataWriter& dataWriter) +tl::result ZipWriter::addBuffer(tl::string name, Compression compression, tl::span buffer) { - return addFile(std::move(name), - // - {}, - {}, - GeneralBitFlags(), - tl::nullopt, - dataWriter); + return addBuffer(std::move(name), + {}, + {}, + 0, + compression, buffer); } -tl::result ZipWriter::addFile(tl::string name, tl::optional lastModificationTime, const DataWriter& dataWriter) +tl::result ZipWriter::addBuffer(tl::string name, time_t lastModificationTime, Compression compression, tl::span buffer) { - return addFile(std::move(name), - // - {}, - {}, - GeneralBitFlags(), - std::move(lastModificationTime), - dataWriter); + return addBuffer(std::move(name), + {}, + {}, + lastModificationTime, + compression, buffer); } ////////////////////////////////////////////////////////////////////////// -tl::result ZipWriter::addFile(tl::string name, - tl::span comment, - tl::span extraField, - GeneralBitFlags generalBitFlags, - tl::optional lastModificationTime, - const DataWriter& dataWriter) +tl::result ZipWriter::addBuffer(tl::string name, + tl::span comment, + tl::span extraField, + time_t lastModificationTime, + Compression compression, + tl::span buffer) { + if (!m_zipArchive) + return tl::make_generic_error("Cannot create archive"); + if (name.size() > tl::numeric_limits::max()) return tl::make_generic_error("Name too long"); if (comment.size() > tl::numeric_limits::max()) return tl::make_generic_error("Comment too long"); - if (extraField.size() + sizeof(ExtendedInformationExtraField64) > tl::numeric_limits::max()) - return tl::make_generic_error("Extra field too long"); + uint8_t* newBuffer = new uint8_t[buffer.size()]; + memcpy(newBuffer, buffer.data(), buffer.size()); - ////////////////////////////////////////////////////////////////////////// - // Cannot compute the whole header as we don't know how big the data will be. - // So we compute as much as possible from the header, enough to figure out the padding. - // The we skip to the data section and write it - computing its size at the same time. - // Then we go back to the header section, fill in all the info (since we now know the size, and implictly if it's zip32/64 format) and write the header, name - // etc) NOTE - because of this we always have to write the ExtendedInformationExtraField64 section, even if the final format will not be zip64 + zip_source* zipSource = fs_zip_source_buffer(m_zipArchive.get(), newBuffer, buffer.size(), 1); - LocalFileHeader header; - header.extraFieldLength = tl::narrow(extraField.size()) + sizeof(ExtendedInformationExtraField64); - header.generalBitFlag = generalBitFlags.value() | tl::narrow(GeneralBitFlag::LanguageEncodingFlag); - - header.lastModFileDate = 0; - header.lastModFileTime = 0; - if (lastModificationTime != tl::nullopt) - computeMsDosTime(*lastModificationTime, header.lastModFileDate, header.lastModFileTime); - - header.filenameLength = tl::narrow(name.size()); - - const uint64_t padding = computePadding(m_sink.tell(), header); - m_sink.seekRel(padding); - - const uint64_t localHeaderOffset = m_sink.tell(); - - // now skip to the data - m_sink.seekRel(sizeof(LocalFileHeader) + header.filenameLength + header.extraFieldLength); - - const uint64_t startOffset = m_sink.tell(); - - // write the data - this computes the size as well - DataWriterResult dataProviderRes = dataWriter(m_sink); - if (!dataProviderRes) - return dataProviderRes.error(); - - const DataWriterPayload payload = dataProviderRes.value(); - - header.compressionMethod = tl::narrow(payload.compressionMethod); - header.crc32 = payload.uncompressedCRC32; - - const uint64_t endOffset = m_sink.tell(); - const uint64_t compressedSize = endOffset - startOffset; - const uint64_t uncompressedSize = payload.uncompressedSize ? payload.uncompressedSize : compressedSize; - - // write the size fields (in zip64, these are -1) - header.compressedSize = static_cast(-1); - header.uncompressedSize = static_cast(-1); - - // now go back and write the header - m_sink.seekBeg(localHeaderOffset); - m_sink.write({ reinterpret_cast(&header), sizeof(LocalFileHeader) }); - - // the filename - if (!name.empty()) - m_sink.write({ reinterpret_cast(name.data()), name.size() }); - - // extended field - always present! + auto result = _addSource(name, comment, extraField, lastModificationTime, compression, zipSource); + if (result.has_error()) { - ExtendedInformationExtraField64 extended; - extended.size = static_cast(sizeof(ExtendedInformationExtraField64) - 4); // Substract the tag + size fields. - extended.compressedSize = compressedSize; - extended.originalSize = uncompressedSize; - extended.localHeaderOffset = localHeaderOffset; - m_sink.write({ reinterpret_cast(&extended), sizeof(ExtendedInformationExtraField64) }); + zip_source_free(zipSource); + return tl::make_generic_error("{}", result.error()); } - // custom fields - if (!extraField.empty()) - m_sink.write(extraField); + fs_zip_set_file_compression(m_zipArchive.get(), result.value(), compression == 0 ? ZIP_CM_STORE : ZIP_CM_DEFLATE, compression); + fs_zip_file_set_mtime(m_zipArchive.get(), result.value(), lastModificationTime, 0); + return tl::success(); +} - m_sink.seekBeg(endOffset); +tl::result ZipWriter::addFile(tl::string name, Compression compression, ISource& source) +{ + return addFile(std::move(name), + {}, + {}, + 0, + compression, source); +} - // store the central directory record - CentralDirectoryRecord record; - record.header = computeCentralDirectoryFileHeader(header, true); - record.compressedSize = compressedSize; - record.uncompressedSize = uncompressedSize; - record.localHeaderOffset = localHeaderOffset; - record.header.localHeaderOffset = static_cast(-1); //zip64 mandates -1 - record.zip64 = true; - record.header.fileCommentLength = tl::narrow(comment.size()); - record.name = std::move(name); - record.comment.assign(comment.begin(), comment.end()); - record.extraField.assign(extraField.begin(), extraField.end()); - m_records.push_back(std::move(record)); +tl::result ZipWriter::addFile(tl::string name, time_t lastModificationTime, Compression compression, ISource& source) +{ + return addFile(std::move(name), + {}, + {}, + lastModificationTime, + compression, source); +} + +////////////////////////////////////////////////////////////////////////// + +tl::result ZipWriter::addFile(tl::string name, + tl::span comment, + tl::span extraField, + time_t lastModificationTime, + Compression compression, + ISource& source) +{ + if (!m_zipArchive) + return tl::make_generic_error("Cannot create archive"); + + if (name.size() > tl::numeric_limits::max()) + return tl::make_generic_error("Name too long"); + + if (comment.size() > tl::numeric_limits::max()) + return tl::make_generic_error("Comment too long"); + + zip_source* zipSource = fs_zip_source_function(m_zipArchive.get(), sourceCallback, &source); + + auto result = _addSource(name, comment, extraField, lastModificationTime, compression, zipSource); + if (result.has_error()) + { + zip_source_free(zipSource); + return tl::make_generic_error("{}", result.error()); + } + + fs_zip_set_file_compression(m_zipArchive.get(), result.value(), compression == 0 ? ZIP_CM_STORE : ZIP_CM_DEFLATE, compression); + fs_zip_file_set_mtime(m_zipArchive.get(), result.value(), lastModificationTime, 0); return tl::success(); } + +tl::result ZipWriter::_addSource(tl::string name, + tl::span comment, + tl::span extraField, + time_t lastModificationTime, + Compression compression, + zip_source* source) +{ + const RelPath path = RelPath(name); + //if (!path.empty()) + //{ + // for (size_t i = 0; i < path.size() - 1; i++) + // { + // RelPath subPath = path.subpath(0, i); + // if (m_folders.find(subPath) == m_folders.end()) + // { + // if (fs_zip_dir_add(m_zipArchive.get(), subPath.str().c_str(), ZIP_FL_ENC_UTF_8) < 0) + // return tl::make_generic_error("Error adding zip file: {}", fs_zip_strerror(m_zipArchive.get())); + + // m_folders.emplace(subPath); + // } + // } + //} + + const int64_t res = fs_zip_file_add(m_zipArchive.get(), name.c_str(), source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8); + if (res < 0) + return tl::make_generic_error("Error adding zip file: {}", fs_zip_strerror(m_zipArchive.get())); + + return static_cast(res); +} + ////////////////////////////////////////////////////////////////////////// void ZipWriter::finish() { - const uint64_t centralDirectoryRecordsOffset = m_sink.tell(); - - for (const CentralDirectoryRecord& record : m_records) - { - TL_ASSERT(record.header.filenameLength == record.name.size()); - TL_ASSERT(record.header.extraFieldLength == record.extraField.size() + (record.zip64 ? sizeof(ExtendedInformationExtraField64) : 0)); - TL_ASSERT(record.header.fileCommentLength == record.comment.size()); - - m_sink.write({ reinterpret_cast(&record.header), sizeof(CentralDirectoryFileHeader) }); - if (!record.name.empty()) - m_sink.write({ reinterpret_cast(record.name.data()), record.name.size() }); - - if (!record.extraField.empty()) - m_sink.write(record.extraField); - - if (record.zip64) - { - ExtendedInformationExtraField64 extended; - extended.size = tl::narrow(sizeof(ExtendedInformationExtraField64) - 4); // Subtract the tag + size fields. - extended.originalSize = record.uncompressedSize; - extended.compressedSize = record.compressedSize; - extended.localHeaderOffset = record.localHeaderOffset; - m_sink.write({ reinterpret_cast(&extended), sizeof(ExtendedInformationExtraField64) }); - } - if (!record.comment.empty()) - m_sink.write(record.comment); - } - const uint64_t sizeOfCentralDirectoryRecords = m_sink.tell() - centralDirectoryRecordsOffset; - - const bool zip64 = centralDirectoryRecordsOffset >= tl::numeric_limits::max() || // - sizeOfCentralDirectoryRecords >= tl::numeric_limits::max() || // - m_records.size() >= tl::numeric_limits::max(); - - if (zip64) - { - const uint64_t endOfCentralDirectoryRecord64Offset = m_sink.tell(); - - { - EndOfCentralDirectoryRecord64 header; - header.endOfCentralDirectorySize = sizeof(EndOfCentralDirectoryRecord64) - 12; - header.centralDirectoryRecordCountOnThisDisk = m_records.size(); - header.centralDirectoryRecordCount = m_records.size(); - header.centralDirectorySize = sizeOfCentralDirectoryRecords; - header.centralDirectoryOffset = centralDirectoryRecordsOffset; - m_sink.write({ reinterpret_cast(&header), sizeof(EndOfCentralDirectoryRecord64) }); - } - { - EndOfCentralDirectoryLocator64 header; - header.endOfCentralDirectoryRecordOffset = endOfCentralDirectoryRecord64Offset; - header.diskCount = 1; - m_sink.write({ reinterpret_cast(&header), sizeof(EndOfCentralDirectoryLocator64) }); - } - } - - EndOfCentralDirectoryRecord header; - header.centralDirectoryRecordCountOnThisDisk = zip64 ? static_cast(-1) : tl::narrow(m_records.size()); - header.centralDirectoryRecordCount = zip64 ? static_cast(-1) : tl::narrow(m_records.size()); - header.centralDirectorySize = zip64 ? static_cast(-1) : tl::narrow(sizeOfCentralDirectoryRecords); - header.centralDirectoryOffset = zip64 ? static_cast(-1) : tl::narrow(centralDirectoryRecordsOffset); - m_sink.write({ reinterpret_cast(&header), sizeof(EndOfCentralDirectoryRecord) }); + m_zipArchive = {}; } -////////////////////////////////////////////////////////////////////////// - -inline uint64_t ZipWriter::computePadding(uint64_t offset, const LocalFileHeader& header) const -{ - const uint64_t dataOffset = offset + sizeof(LocalFileHeader) + header.filenameLength + header.extraFieldLength; - const uint64_t m = dataOffset % m_fileDataAlignment; - if (m == 0) - return 0; - - return m_fileDataAlignment - m; -} ////////////////////////////////////////////////////////////////////////// }