Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2022-06-23 13:43:16 +0300
committerKornel <kornel@geekhood.net>2022-06-23 13:43:16 +0300
commitec44a8a0700a8b2444b07f576be332f756754323 (patch)
tree0b19ee3b63dd53aacca6990451022aee54d0aa69 /CPP/7zip/Archive
parentc3529a41f527101f05e9e834a19205ee33a3b097 (diff)
Diffstat (limited to 'CPP/7zip/Archive')
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7z.dsp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7z.dsw0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zCompressionMode.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zCompressionMode.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zDecode.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zDecode.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zEncode.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zEncode.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zExtract.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zFolderInStream.cpp123
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zFolderInStream.h31
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zHandler.cpp2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zHandler.h5
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zHandlerOut.cpp39
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zHeader.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zHeader.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zIn.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zIn.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zItem.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zOut.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zOut.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zProperties.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zProperties.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zRegister.cpp10
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zSpecStream.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zSpecStream.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zUpdate.cpp141
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/7zUpdate.h14
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/StdAfx.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/makefile0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/7z/resource.rc0
-rwxr-xr-xCPP/7zip/Archive/ApfsHandler.cpp3546
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ApmHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ArHandler.cpp14
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Archive.def0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Archive2.def0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ArchiveExports.cpp1
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ArjHandler.cpp10
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Base64Handler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Bz2Handler.cpp100
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabBlockInStream.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabBlockInStream.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabHandler.cpp10
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabHeader.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabHeader.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabIn.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabIn.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabItem.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/CabRegister.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Cab/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Chm/ChmHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Chm/ChmHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Chm/ChmIn.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Chm/ChmIn.h11
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Chm/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ComHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/CoderMixer2.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/CoderMixer2.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/DummyOutStream.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/DummyOutStream.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/FindSignature.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/FindSignature.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/HandlerOut.cpp77
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/HandlerOut.h26
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/InStreamWithCRC.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/InStreamWithCRC.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/ItemNameUtils.cpp23
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/ItemNameUtils.h2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/MultiStream.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/MultiStream.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/OutStreamWithCRC.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/OutStreamWithCRC.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/OutStreamWithSha1.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/OutStreamWithSha1.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/ParseProperties.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/ParseProperties.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Common/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/CpioHandler.cpp6
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/CramfsHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/DeflateProps.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/DeflateProps.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/DllExports.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/DllExports2.cpp18
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/DmgHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ElfHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ExtHandler.cpp51
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/FatHandler.cpp15
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/FlvHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/GptHandler.cpp75
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/GzHandler.cpp217
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/HandlerCont.cpp55
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/HandlerCont.h12
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/HfsHandler.cpp21
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/IArchive.h89
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/7z.icobin4710 -> 4710 bytes
-rwxr-xr-xCPP/7zip/Archive/Icons/apfs.icobin0 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/arj.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/bz2.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/cab.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/cpio.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/deb.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/dmg.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/fat.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/gz.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/hfs.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/iso.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/lzh.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/lzma.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/ntfs.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/rar.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/rpm.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/split.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/squashfs.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/tar.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/vhd.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/wim.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/xar.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/xz.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/z.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Icons/zip.icobin3638 -> 3638 bytes
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/IhexHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoHandler.cpp24
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoHeader.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoHeader.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoIn.cpp2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoIn.h15
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoItem.h13
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/IsoRegister.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Iso/StdAfx.h0
-rwxr-xr-xCPP/7zip/Archive/LpHandler.cpp1173
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/LzhHandler.cpp15
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/LzmaHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/MachoHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/MbrHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/MslzHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/MubHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisDecode.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisDecode.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisIn.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisIn.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/NsisRegister.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Nsis/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/NtfsHandler.cpp7
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/PeHandler.cpp6
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/PpmdHandler.cpp2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/QcowHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/Rar5Handler.cpp44
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/Rar5Handler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/RarHandler.cpp41
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/RarHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/RarHeader.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/RarItem.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/RarVol.h17
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/StdAfx.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Rar/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/RpmHandler.cpp6
-rwxr-xr-xCPP/7zip/Archive/SparseHandler.cpp548
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/SplitHandler.cpp7
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/SquashfsHandler.cpp155
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/SwfHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarHandler.cpp445
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarHandler.h27
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarHandlerOut.cpp209
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarHeader.cpp77
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarHeader.h8
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarIn.cpp945
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarIn.h130
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarItem.h246
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarOut.cpp561
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarOut.h31
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarRegister.cpp16
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarUpdate.cpp406
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarUpdate.h39
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Udf/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Udf/UdfHandler.cpp20
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Udf/UdfHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Udf/UdfIn.cpp2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Udf/UdfIn.h2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/UefiHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/VdiHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/VhdHandler.cpp3
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/VhdxHandler.cpp28
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/VmdkHandler.cpp2
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/WimHandler.cpp3
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/WimHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/WimHandlerOut.cpp14
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/WimIn.cpp9
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/WimIn.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Wim/WimRegister.cpp21
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/XarHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/XzHandler.cpp43
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/XzHandler.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/ZHandler.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/StdAfx.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipAddCommon.cpp0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipAddCommon.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipCompressionMode.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipHandler.cpp178
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipHandler.h7
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipHandlerOut.cpp81
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipHeader.h9
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipIn.cpp23
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipIn.h0
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipItem.cpp68
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipItem.h5
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipOut.cpp86
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipOut.h9
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipRegister.cpp18
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipUpdate.cpp171
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Zip/ZipUpdate.h28
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/makefile0
219 files changed, 9666 insertions, 1123 deletions
diff --git a/CPP/7zip/Archive/7z/7z.dsp b/CPP/7zip/Archive/7z/7z.dsp
index ffd28721..ffd28721 100644..100755
--- a/CPP/7zip/Archive/7z/7z.dsp
+++ b/CPP/7zip/Archive/7z/7z.dsp
diff --git a/CPP/7zip/Archive/7z/7z.dsw b/CPP/7zip/Archive/7z/7z.dsw
index 702a86c7..702a86c7 100644..100755
--- a/CPP/7zip/Archive/7z/7z.dsw
+++ b/CPP/7zip/Archive/7z/7z.dsw
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
index 6774fc48..6774fc48 100644..100755
--- a/CPP/7zip/Archive/7z/7zCompressionMode.cpp
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h
index 9e846345..9e846345 100644..100755
--- a/CPP/7zip/Archive/7z/7zCompressionMode.h
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.h
diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp
index c27c8fbc..c27c8fbc 100644..100755
--- a/CPP/7zip/Archive/7z/7zDecode.cpp
+++ b/CPP/7zip/Archive/7z/7zDecode.cpp
diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h
index eeb146e3..eeb146e3 100644..100755
--- a/CPP/7zip/Archive/7z/7zDecode.h
+++ b/CPP/7zip/Archive/7z/7zDecode.h
diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp
index 83b0f18f..83b0f18f 100644..100755
--- a/CPP/7zip/Archive/7z/7zEncode.cpp
+++ b/CPP/7zip/Archive/7z/7zEncode.cpp
diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h
index 6ea7f276..6ea7f276 100644..100755
--- a/CPP/7zip/Archive/7z/7zEncode.h
+++ b/CPP/7zip/Archive/7z/7zEncode.h
diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp
index 8ca815d4..8ca815d4 100644..100755
--- a/CPP/7zip/Archive/7z/7zExtract.cpp
+++ b/CPP/7zip/Archive/7z/7zExtract.cpp
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
index a68edf4e..cf50e694 100644..100755
--- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -2,6 +2,8 @@
#include "StdAfx.h"
+#include "../../../Windows/TimeUtils.h"
+
#include "7zFolderInStream.h"
namespace NArchive {
@@ -13,17 +15,17 @@ void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
_updateCallback = updateCallback;
_indexes = indexes;
_numFiles = numFiles;
- _index = 0;
Processed.ClearAndReserve(numFiles);
CRCs.ClearAndReserve(numFiles);
Sizes.ClearAndReserve(numFiles);
-
- _pos = 0;
- _crc = CRC_INIT_VAL;
- _size_Defined = false;
- _size = 0;
+ if (Need_CTime) CTimes.ClearAndReserve(numFiles);
+ if (Need_ATime) ATimes.ClearAndReserve(numFiles);
+ if (Need_MTime) MTimes.ClearAndReserve(numFiles);
+ if (Need_Attrib) Attribs.ClearAndReserve(numFiles);
+ TimesDefined.ClearAndReserve(numFiles);
+
_stream.Release();
}
@@ -32,44 +34,101 @@ HRESULT CFolderInStream::OpenStream()
_pos = 0;
_crc = CRC_INIT_VAL;
_size_Defined = false;
+ _times_Defined = false;
_size = 0;
+ FILETIME_Clear(_cTime);
+ FILETIME_Clear(_aTime);
+ FILETIME_Clear(_mTime);
+ _attrib = 0;
- while (_index < _numFiles)
+ while (Processed.Size() < _numFiles)
{
CMyComPtr<ISequentialInStream> stream;
- HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);
- if (result != S_OK)
- {
- if (result != S_FALSE)
- return result;
- }
+ const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream);
+ if (result != S_OK && result != S_FALSE)
+ return result;
_stream = stream;
if (stream)
{
- CMyComPtr<IStreamGetSize> streamGetSize;
- stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
- if (streamGetSize)
{
- if (streamGetSize->GetSize(&_size) == S_OK)
- _size_Defined = true;
+ CMyComPtr<IStreamGetProps> getProps;
+ stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ if (getProps)
+ {
+ // access could be changed in first myx pass
+ if (getProps->GetProps(&_size,
+ Need_CTime ? &_cTime : NULL,
+ Need_ATime ? &_aTime : NULL,
+ Need_MTime ? &_mTime : NULL,
+ Need_Attrib ? &_attrib : NULL)
+ == S_OK)
+ {
+ _size_Defined = true;
+ _times_Defined = true;
+ }
+ return S_OK;
+ }
+ }
+ {
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ if (streamGetSize->GetSize(&_size) == S_OK)
+ _size_Defined = true;
+ }
+ return S_OK;
}
- return S_OK;
}
- _index++;
- RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
- AddFileInfo(result == S_OK);
+ RINOK(AddFileInfo(result == S_OK));
}
return S_OK;
}
-void CFolderInStream::AddFileInfo(bool isProcessed)
+static void AddFt(CRecordVector<UInt64> &vec, const FILETIME &ft)
{
- Processed.Add(isProcessed);
- Sizes.Add(_pos);
- CRCs.Add(CRC_GET_DIGEST(_crc));
+ vec.AddInReserved(FILETIME_To_UInt64(ft));
+}
+
+/*
+HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ UInt32 index, UInt64 size, const UInt32 *crc)
+{
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
+ if (crc)
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
+ }
+ return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK);
+}
+*/
+
+HRESULT CFolderInStream::AddFileInfo(bool isProcessed)
+{
+ // const UInt32 index = _indexes[Processed.Size()];
+ Processed.AddInReserved(isProcessed);
+ Sizes.AddInReserved(_pos);
+ const UInt32 crc = CRC_GET_DIGEST(_crc);
+ CRCs.AddInReserved(crc);
+ TimesDefined.AddInReserved(_times_Defined);
+ if (Need_CTime) AddFt(CTimes, _cTime);
+ if (Need_ATime) AddFt(ATimes, _aTime);
+ if (Need_MTime) AddFt(MTimes, _mTime);
+ if (Need_Attrib) Attribs.AddInReserved(_attrib);
+ /*
+ if (isProcessed && _reportArcProp)
+ RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc))
+ */
+ return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
@@ -95,18 +154,10 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
}
_stream.Release();
- _index++;
- AddFileInfo(true);
-
- _pos = 0;
- _crc = CRC_INIT_VAL;
- _size_Defined = false;
- _size = 0;
-
- RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ RINOK(AddFileInfo(true));
}
- if (_index >= _numFiles)
+ if (Processed.Size() >= _numFiles)
break;
RINOK(OpenStream());
}
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h
index 805db54e..f054e681 100644..100755
--- a/CPP/7zip/Archive/7z/7zFolderInStream.h
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -23,21 +23,37 @@ class CFolderInStream:
UInt64 _pos;
UInt32 _crc;
bool _size_Defined;
+ bool _times_Defined;
UInt64 _size;
+ FILETIME _cTime;
+ FILETIME _aTime;
+ FILETIME _mTime;
+ UInt32 _attrib;
- const UInt32 *_indexes;
unsigned _numFiles;
- unsigned _index;
+ const UInt32 *_indexes;
CMyComPtr<IArchiveUpdateCallback> _updateCallback;
HRESULT OpenStream();
- void AddFileInfo(bool isProcessed);
+ HRESULT AddFileInfo(bool isProcessed);
public:
CRecordVector<bool> Processed;
CRecordVector<UInt32> CRCs;
CRecordVector<UInt64> Sizes;
+ CRecordVector<UInt64> CTimes;
+ CRecordVector<UInt64> ATimes;
+ CRecordVector<UInt64> MTimes;
+ CRecordVector<UInt32> Attribs;
+ CRecordVector<bool> TimesDefined;
+
+ bool Need_CTime;
+ bool Need_ATime;
+ bool Need_MTime;
+ bool Need_Attrib;
+
+ // CMyComPtr<IArchiveUpdateCallbackArcProp> _reportArcProp;
MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
@@ -45,7 +61,7 @@ public:
void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);
- bool WasFinished() const { return _index == _numFiles; }
+ bool WasFinished() const { return Processed.Size() == _numFiles; }
UInt64 GetFullSize() const
{
@@ -54,6 +70,13 @@ public:
size += Sizes[i];
return size;
}
+
+ CFolderInStream():
+ Need_CTime(false),
+ Need_ATime(false),
+ Need_MTime(false),
+ Need_Attrib(false)
+ {}
};
}}
diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp
index 9e344c34..ca22f881 100644..100755
--- a/CPP/7zip/Archive/7z/7zHandler.cpp
+++ b/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -278,7 +278,7 @@ static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVe
{
UInt64 value;
if (v.GetItem(index, value))
- PropVarEm_Set_FileTime64(prop, value);
+ PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns);
}
bool CHandler::IsFolderEncrypted(CNum folderIndex) const
diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h
index cbc2d028..08bd6540 100644..100755
--- a/CPP/7zip/Archive/7z/7zHandler.h
+++ b/CPP/7zip/Archive/7z/7zHandler.h
@@ -49,9 +49,8 @@ public:
bool _encryptHeaders;
// bool _useParents; 9.26
- CBoolPair Write_CTime;
- CBoolPair Write_ATime;
- CBoolPair Write_MTime;
+ CHandlerTimeOptions TimeOptions;
+
CBoolPair Write_Attrib;
bool _useMultiThreadMixer;
diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
index 8f875ce4..bf4e7a69 100644..100755
--- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp
+++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -384,16 +384,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
CObjectVector<CUpdateItem> updateItems;
- bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
- bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
- bool need_MTime = (Write_MTime.Def ? Write_MTime.Val : true);
+ bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
+ bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
+ bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
if (db && !db->Files.IsEmpty())
{
- if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
- if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
- if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
+ if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
+ if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
+ if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
}
@@ -719,6 +719,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
int level = GetLevel();
CUpdateOptions options;
+ options.Need_CTime = need_CTime;
+ options.Need_ATime = need_ATime;
+ options.Need_MTime = need_MTime;
+ options.Need_Attrib = need_Attrib;
+
options.Method = &methodMode;
options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
@@ -817,9 +822,7 @@ void COutHandler::InitProps7z()
_encryptHeaders = false;
// _useParents = false;
- Write_CTime.Init();
- Write_ATime.Init();
- Write_MTime.Init();
+ TimeOptions.Init();
Write_Attrib.Init();
_useMultiThreadMixer = true;
@@ -954,10 +957,20 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
return S_OK;
}
- if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);
- if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);
- if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);
-
+ {
+ bool processed;
+ RINOK(TimeOptions.Parse(name, value, processed));
+ if (processed)
+ {
+ if ( TimeOptions.Prec != (UInt32)(Int32)-1
+ && TimeOptions.Prec != k_PropVar_TimePrec_0
+ && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
+ && TimeOptions.Prec != k_PropVar_TimePrec_100ns)
+ return E_INVALIDARG;
+ return S_OK;
+ }
+ }
+
if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
diff --git a/CPP/7zip/Archive/7z/7zHeader.cpp b/CPP/7zip/Archive/7z/7zHeader.cpp
index acff2fdd..acff2fdd 100644..100755
--- a/CPP/7zip/Archive/7z/7zHeader.cpp
+++ b/CPP/7zip/Archive/7z/7zHeader.cpp
diff --git a/CPP/7zip/Archive/7z/7zHeader.h b/CPP/7zip/Archive/7z/7zHeader.h
index e1bbc0aa..e1bbc0aa 100644..100755
--- a/CPP/7zip/Archive/7z/7zHeader.h
+++ b/CPP/7zip/Archive/7z/7zHeader.h
diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp
index 7134595c..7134595c 100644..100755
--- a/CPP/7zip/Archive/7z/7zIn.cpp
+++ b/CPP/7zip/Archive/7z/7zIn.cpp
diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h
index ffa1e4bc..ffa1e4bc 100644..100755
--- a/CPP/7zip/Archive/7z/7zIn.h
+++ b/CPP/7zip/Archive/7z/7zIn.h
diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h
index 0f9fdada..0f9fdada 100644..100755
--- a/CPP/7zip/Archive/7z/7zItem.h
+++ b/CPP/7zip/Archive/7z/7zItem.h
diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp
index 2786bf28..2786bf28 100644..100755
--- a/CPP/7zip/Archive/7z/7zOut.cpp
+++ b/CPP/7zip/Archive/7z/7zOut.cpp
diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h
index 1ebad56d..1ebad56d 100644..100755
--- a/CPP/7zip/Archive/7z/7zOut.h
+++ b/CPP/7zip/Archive/7z/7zOut.h
diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp
index 4cb5a5e6..4cb5a5e6 100644..100755
--- a/CPP/7zip/Archive/7z/7zProperties.cpp
+++ b/CPP/7zip/Archive/7z/7zProperties.cpp
diff --git a/CPP/7zip/Archive/7z/7zProperties.h b/CPP/7zip/Archive/7z/7zProperties.h
index 66181795..66181795 100644..100755
--- a/CPP/7zip/Archive/7z/7zProperties.h
+++ b/CPP/7zip/Archive/7z/7zProperties.h
diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp
index 389b5407..eac8b4f2 100644..100755
--- a/CPP/7zip/Archive/7z/7zRegister.cpp
+++ b/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -15,7 +15,13 @@ REGISTER_ARC_IO_DECREMENT_SIG(
"7z", "7z", NULL, 7,
k_Signature_Dec,
0,
- NArcInfoFlags::kFindSignature,
- NULL);
+ NArcInfoFlags::kFindSignature
+ | NArcInfoFlags::kCTime
+ | NArcInfoFlags::kATime
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows)
+ , NULL);
}}
diff --git a/CPP/7zip/Archive/7z/7zSpecStream.cpp b/CPP/7zip/Archive/7z/7zSpecStream.cpp
index 8e45d987..8e45d987 100644..100755
--- a/CPP/7zip/Archive/7z/7zSpecStream.cpp
+++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp
diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h
index 21155069..21155069 100644..100755
--- a/CPP/7zip/Archive/7z/7zSpecStream.h
+++ b/CPP/7zip/Archive/7z/7zSpecStream.h
diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp
index b641d93f..b6fd1924 100644..100755
--- a/CPP/7zip/Archive/7z/7zUpdate.cpp
+++ b/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -804,10 +804,20 @@ struct CAnalysis
bool ParseExe;
bool ParseAll;
+ /*
+ bool Need_ATime;
+ bool ATime_Defined;
+ FILETIME ATime;
+ */
+
CAnalysis():
ParseWav(true),
ParseExe(false),
ParseAll(false)
+ /*
+ , Need_ATime(false)
+ , ATime_Defined(false)
+ */
{}
HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode);
@@ -887,6 +897,18 @@ HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMo
HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);
if (result == S_OK && stream)
{
+ /*
+ if (Need_ATime)
+ {
+ // access time could be changed in analysis pass
+ CMyComPtr<IStreamGetProps> getProps;
+ stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ if (getProps)
+ if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK)
+ ATime_Defined = true;
+ }
+ */
+
size_t size = kAnalysisBufSize;
result = ReadStream(stream, Buffer, &size);
stream.Release();
@@ -1586,6 +1608,11 @@ HRESULT Update(
CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;
updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);
+ /*
+ CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
+ updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
+ */
+
// size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
/*
@@ -1756,6 +1783,7 @@ HRESULT Update(
{
CAnalysis analysis;
+ // analysis.Need_ATime = options.Need_ATime;
if (options.AnalysisLevel == 0)
{
analysis.ParseWav = false;
@@ -1790,7 +1818,15 @@ HRESULT Update(
CFilterMode2 fm;
if (useFilters)
{
+ // analysis.ATime_Defined = false;
RINOK(analysis.GetFilterGroup(i, ui, fm));
+ /*
+ if (analysis.ATime_Defined)
+ {
+ ui.ATime = FILETIME_To_UInt64(analysis.ATime);
+ ui.ATime_WasReadByAnalysis = true;
+ }
+ */
}
fm.Encrypted = method.PasswordIsDefined;
@@ -2374,13 +2410,33 @@ HRESULT Update(
RINOK(lps->SetCur());
+ /*
+ const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size();
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NUpdateNotifyOp::kAdd));
+ }
+ */
+
+
CFolderInStream *inStreamSpec = new CFolderInStream;
CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+
+ // inStreamSpec->_reportArcProp = reportArcProp;
+
+ inStreamSpec->Need_CTime = options.Need_CTime;
+ inStreamSpec->Need_ATime = options.Need_ATime;
+ inStreamSpec->Need_MTime = options.Need_MTime;
+ inStreamSpec->Need_Attrib = options.Need_Attrib;
+
inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
unsigned startPackIndex = newDatabase.PackSizes.Size();
UInt64 curFolderUnpackSize = totalSize;
- // curFolderUnpackSize = (UInt64)(Int64)-1;
+ // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug
RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
@@ -2393,8 +2449,11 @@ HRESULT Update(
if (!inStreamSpec->WasFinished())
return E_FAIL;
+ UInt64 packSize = 0;
+ // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex;
for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
- lps->OutSize += newDatabase.PackSizes[startPackIndex];
+ packSize += newDatabase.PackSizes[startPackIndex];
+ lps->OutSize += packSize;
lps->InSize += curFolderUnpackSize;
// for ()
@@ -2403,7 +2462,9 @@ HRESULT Update(
CNum numUnpackStreams = 0;
UInt64 skippedSize = 0;
-
+ UInt64 procSize = 0;
+ // unsigned numProcessedFiles = 0;
+
for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
{
const CUpdateItem &ui = updateItems[indices[i + subIndex]];
@@ -2429,14 +2490,16 @@ HRESULT Update(
*/
if (!inStreamSpec->Processed[subIndex])
{
+ // we don't add file here
skippedSize += ui.Size;
- continue;
- // file.Name += ".locked";
+ continue; // comment it for debug
+ // name += ".locked"; // for debug
}
file.Crc = inStreamSpec->CRCs[subIndex];
file.Size = inStreamSpec->Sizes[subIndex];
+ procSize += file.Size;
// if (file.Size >= 0) // test purposes
if (file.Size != 0)
{
@@ -2450,6 +2513,23 @@ HRESULT Update(
file.HasStream = false;
}
+ if (inStreamSpec->TimesDefined[subIndex])
+ {
+ if (inStreamSpec->Need_CTime)
+ { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; }
+ if (inStreamSpec->Need_ATime
+ // && !ui.ATime_WasReadByAnalysis
+ )
+ { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; }
+ if (inStreamSpec->Need_MTime)
+ { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; }
+ if (inStreamSpec->Need_Attrib)
+ {
+ file2.AttribDefined = true;
+ file2.Attrib = inStreamSpec->Attribs[subIndex];
+ }
+ }
+
/*
file.Parent = ui.ParentFolderIndex;
if (ui.TreeFolderIndex >= 0)
@@ -2457,9 +2537,22 @@ HRESULT Update(
if (totalSecureDataSize != 0)
newDatabase.SecureIDs.Add(ui.SecureIndex);
*/
+ /*
+ if (reportArcProp)
+ {
+ RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size,
+ file.CrcDefined ? &file.Crc : NULL))
+ }
+ */
+
+ // numProcessedFiles++;
newDatabase.AddFile(file, file2, name);
}
+ // it's optional check to ensure that sizes are correct
+ if (procSize != curFolderUnpackSize)
+ return E_FAIL;
+
// numUnpackStreams = 0 is very bad case for locked files
// v3.13 doesn't understand it.
newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
@@ -2470,6 +2563,44 @@ HRESULT Update(
complexity -= skippedSize;
RINOK(updateCallback->SetTotal(complexity));
}
+
+ /*
+ if (reportArcProp)
+ {
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop));
+ }
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK));
+ }
+ */
+ /*
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NUpdateNotifyOp::kOpFinished));
+ }
+ */
}
}
diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h
index 7c0f78a8..e6c48cae 100644..100755
--- a/CPP/7zip/Archive/7z/7zUpdate.h
+++ b/CPP/7zip/Archive/7z/7zUpdate.h
@@ -62,6 +62,8 @@ struct CUpdateItem
bool ATimeDefined;
bool MTimeDefined;
+ // bool ATime_WasReadByAnalysis;
+
// int SecureIndex; // 0 means (no_security)
bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
@@ -76,6 +78,7 @@ struct CUpdateItem
CTimeDefined(false),
ATimeDefined(false),
MTimeDefined(false)
+ // , ATime_WasReadByAnalysis(false)
// SecureIndex(0)
{}
void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
@@ -103,6 +106,11 @@ struct CUpdateOptions
bool RemoveSfxBlock;
bool MultiThreadMixer;
+ bool Need_CTime;
+ bool Need_ATime;
+ bool Need_MTime;
+ bool Need_Attrib;
+
CUpdateOptions():
Method(NULL),
HeaderMethod(NULL),
@@ -114,7 +122,11 @@ struct CUpdateOptions
SolidExtension(false),
UseTypeSorting(true),
RemoveSfxBlock(false),
- MultiThreadMixer(true)
+ MultiThreadMixer(true),
+ Need_CTime(false),
+ Need_ATime(false),
+ Need_MTime(false),
+ Need_Attrib(false)
{}
};
diff --git a/CPP/7zip/Archive/7z/StdAfx.cpp b/CPP/7zip/Archive/7z/StdAfx.cpp
index d0feea85..d0feea85 100644..100755
--- a/CPP/7zip/Archive/7z/StdAfx.cpp
+++ b/CPP/7zip/Archive/7z/StdAfx.cpp
diff --git a/CPP/7zip/Archive/7z/StdAfx.h b/CPP/7zip/Archive/7z/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/7z/StdAfx.h
+++ b/CPP/7zip/Archive/7z/StdAfx.h
diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile
index a3b077da..a3b077da 100644..100755
--- a/CPP/7zip/Archive/7z/makefile
+++ b/CPP/7zip/Archive/7z/makefile
diff --git a/CPP/7zip/Archive/7z/resource.rc b/CPP/7zip/Archive/7z/resource.rc
index f79dac08..f79dac08 100644..100755
--- a/CPP/7zip/Archive/7z/resource.rc
+++ b/CPP/7zip/Archive/7z/resource.rc
diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp
new file mode 100755
index 00000000..8312456b
--- /dev/null
+++ b/CPP/7zip/Archive/ApfsHandler.cpp
@@ -0,0 +1,3546 @@
+// ApfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariantConv.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files.
+#define APFS_SHOW_ALT_STREAMS
+
+#define VI_MINUS1 ((unsigned)(int)-1)
+#define IsViDef(x) ((int)(x) != -1)
+#define IsViNotDef(x) ((int)(x) == -1)
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+#define G64(_offs_, dest) dest = Get64(p + (_offs_));
+
+namespace NArchive {
+namespace NApfs {
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void ConvertByteToHex(unsigned val, char *s)
+{
+ unsigned t;
+ t = val >> 4;
+ s[0] = ValToHex(t);
+ t = val & 0xF;
+ s[1] = ValToHex(t);
+}
+
+struct CUuid
+{
+ Byte Data[16];
+
+ void SetHex_To_str(char *s) const
+ {
+ for (unsigned i = 0; i < 16; i++)
+ ConvertByteToHex(Data[i], s + i * 2);
+ s[32] = 0;
+ }
+
+ void AddHexToString(UString &dest) const
+ {
+ char temp[32 + 4];
+ SetHex_To_str(temp);
+ dest += temp;
+ }
+
+ void SetFrom(const Byte *p) { memcpy(Data, p, 16); }
+};
+
+
+typedef UInt64 oid_t;
+typedef UInt64 xid_t;
+typedef Int64 paddr_t;
+
+#define G64o G64
+#define G64x G64
+// #define G64a G64
+
+/*
+struct prange_t
+{
+ paddr_t start_paddr;
+ UInt64 block_count;
+
+ void Parse(const Byte *p)
+ {
+ G64a (0, start_paddr);
+ G64 (8, block_count);
+ }
+};
+*/
+
+#define OBJECT_TYPE_NX_SUPERBLOCK 0x1
+#define OBJECT_TYPE_BTREE 0x2
+#define OBJECT_TYPE_BTREE_NODE 0x3
+/*
+#define OBJECT_TYPE_SPACEMAN 0x5
+#define OBJECT_TYPE_SPACEMAN_CAB 0x6
+#define OBJECT_TYPE_SPACEMAN_CIB 0x7
+#define OBJECT_TYPE_SPACEMAN_BITMAP 0x8
+#define OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x9
+#define OBJECT_TYPE_EXTENT_LIST_TREE 0xa
+*/
+#define OBJECT_TYPE_OMAP 0xb
+/*
+#define OBJECT_TYPE_CHECKPOINT_MAP 0xc
+*/
+#define OBJECT_TYPE_FS 0xd
+#define OBJECT_TYPE_FSTREE 0xe
+/*
+#define OBJECT_TYPE_BLOCKREFTREE 0xf
+#define OBJECT_TYPE_SNAPMETATREE 0x10
+#define OBJECT_TYPE_NX_REAPER 0x11
+#define OBJECT_TYPE_NX_REAP_LIST 0x12
+#define OBJECT_TYPE_OMAP_SNAPSHOT 0x13
+#define OBJECT_TYPE_EFI_JUMPSTART 0x14
+#define OBJECT_TYPE_FUSION_MIDDLE_TREE 0x15
+#define OBJECT_TYPE_NX_FUSION_WBC 0x16
+#define OBJECT_TYPE_NX_FUSION_WBC_LIST 0x17
+#define OBJECT_TYPE_ER_STATE 0x18
+#define OBJECT_TYPE_GBITMAP 0x19
+#define OBJECT_TYPE_GBITMAP_TREE 0x1a
+#define OBJECT_TYPE_GBITMAP_BLOCK 0x1b
+#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x1c
+#define OBJECT_TYPE_SNAP_META_EXT 0x1d
+#define OBJECT_TYPE_INTEGRITY_META 0x1e
+#define OBJECT_TYPE_FEXT_TREE 0x1f
+#define OBJECT_TYPE_RESERVED_20 0x20
+
+#define OBJECT_TYPE_INVALID 0x0
+#define OBJECT_TYPE_TEST 0xff
+#define OBJECT_TYPE_CONTAINER_KEYBAG 'keys'
+#define OBJECT_TYPE_VOLUME_KEYBAG 'recs'
+#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey'
+
+#define OBJ_VIRTUAL 0x0
+#define OBJ_EPHEMERAL 0x80000000
+#define OBJ_PHYSICAL 0x40000000
+
+#define OBJ_NOHEADER 0x20000000
+#define OBJ_ENCRYPTED 0x10000000
+#define OBJ_NONPERSISTENT 0x08000000
+*/
+#define OBJECT_TYPE_MASK 0x0000ffff
+/*
+#define OBJECT_TYPE_FLAGS_MASK 0xffff0000
+#define OBJ_STORAGETYPE_MASK 0xc0000000
+#define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000
+*/
+
+// #define MAX_CKSUM_SIZE 8
+
+// obj_phys_t
+struct CPhys
+{
+ // Byte cksum[MAX_CKSUM_SIZE];
+ oid_t oid;
+ xid_t xid;
+ UInt32 type;
+ UInt32 subtype;
+
+ UInt32 GetType() const { return type & OBJECT_TYPE_MASK; }
+ void Parse(const Byte *p);
+};
+
+void CPhys::Parse(const Byte *p)
+{
+ // memcpy(cksum, p, MAX_CKSUM_SIZE);
+ G64o (8, oid);
+ G64x (0x10, xid);
+ G32 (0x18, type);
+ G32 (0x1C, subtype);
+}
+
+#define NX_MAX_FILE_SYSTEMS 100
+/*
+#define NX_EPH_INFO_COUNT 4
+#define NX_EPH_MIN_BLOCK_COUNT 8
+#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4
+#define NX_TX_MIN_CHECKPOINT_COUNT 4
+#define NX_EPH_INFO_VERSION_1 1
+*/
+
+/*
+typedef enum
+{
+ NX_CNTR_OBJ_CKSUM_SET = 0,
+ NX_CNTR_OBJ_CKSUM_FAIL = 1,
+ NX_NUM_COUNTERS = 32
+} counter_id_t;
+*/
+
+/* Incompatible volume feature flags */
+#define APFS_INCOMPAT_CASE_INSENSITIVE (1 << 0)
+/*
+#define APFS_INCOMPAT_DATALESS_SNAPS (1 << 1)
+#define APFS_INCOMPAT_ENC_ROLLED (1 << 2)
+*/
+#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE (1 << 3)
+/*
+#define APFS_INCOMPAT_INCOMPLETE_RESTORE (1 << 4)
+#define APFS_INCOMPAT_SEALED_VOLUME (1 << 5)
+#define APFS_INCOMPAT_RESERVED_40 (1 << 6)
+*/
+
+static const char * const g_APFS_INCOMPAT_Flags[] =
+{
+ "CASE_INSENSITIVE"
+ , "DATALESS_SNAPS"
+ , "ENC_ROLLED"
+ , "NORMALIZATION_INSENSITIVE"
+ , "INCOMPLETE_RESTORE"
+ , "SEALED_VOLUME"
+};
+
+/*
+#define APFS_SUPPORTED_INCOMPAT_MASK \
+ ( APFS_INCOMPAT_CASE_INSENSITIVE \
+ | APFS_INCOMPAT_DATALESS_SNAPS \
+ | APFS_INCOMPAT_ENC_ROLLED \
+ | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \
+ | APFS_INCOMPAT_INCOMPLETE_RESTORE \
+ | APFS_INCOMPAT_SEALED_VOLUME \
+ | APFS_INCOMPAT_RESERVED_40 \
+)
+*/
+
+// superblock_t
+struct CSuperBlock
+{
+ // CPhys o;
+ // UInt32 magic;
+ UInt32 block_size;
+ unsigned block_size_Log;
+ UInt64 block_count;
+ // UInt64 features;
+ // UInt64 readonly_compatible_features;
+ // UInt64 incompatible_features;
+ CUuid uuid;
+ /*
+ oid_t next_oid;
+ xid_t next_xid;
+ UInt32 xp_desc_blocks;
+ UInt32 xp_data_blocks;
+ paddr_t xp_desc_base;
+ paddr_t xp_data_base;
+ UInt32 xp_desc_next;
+ UInt32 xp_data_next;
+ UInt32 xp_desc_index;
+ UInt32 xp_desc_len;
+ UInt32 xp_data_index;
+ UInt32 xp_data_len;
+ oid_t spaceman_oid;
+ */
+ oid_t omap_oid;
+ // oid_t reaper_oid;
+ // UInt32 test_type;
+ UInt32 max_file_systems;
+ // oid_t fs_oid[NX_MAX_FILE_SYSTEMS];
+ /*
+ UInt64 counters[NX_NUM_COUNTERS]; // counter_id_t
+ prange_t blocked_out_prange;
+ oid_t evict_mapping_tree_oid;
+ UInt64 flags;
+ paddr_t efi_jumpstart;
+ CUuid fusion_uuid;
+ prange_t keylocker;
+ UInt64 ephemeral_info[NX_EPH_INFO_COUNT];
+ oid_t test_oid;
+ oid_t fusion_mt_oid;
+ oid_t fusion_wbc_oid;
+ prange_t fusion_wbc;
+ UInt64 newest_mounted_version;
+ prange_t mkb_locker;
+ */
+
+ bool Parse(const Byte *p);
+};
+
+struct CSuperBlock2
+{
+ oid_t fs_oid[NX_MAX_FILE_SYSTEMS];
+ void Parse(const Byte *p)
+ {
+ for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++)
+ {
+ G64o (0xb8 + i * 8, fs_oid[i]);
+ }
+ }
+};
+
+
+// we include one additional byte of next field (block_size)
+static const unsigned k_SignatureOffset = 32;
+static const Byte k_Signature[] = { 'N', 'X', 'S', 'B', 0 };
+
+// size must be 4 bytes aligned
+static UInt64 Fletcher64(const Byte *data, size_t size)
+{
+ const UInt32 kMax32 = 0xffffffff;
+ const UInt64 val = 0; // startVal
+ UInt64 a = val & kMax32;
+ UInt64 b = (val >> 32) & kMax32;
+ for (size_t i = 0; i < size; i += 4)
+ {
+ a += GetUi32(data + i);
+ b += a;
+ }
+ a %= kMax32;
+ b %= kMax32;
+ b = (UInt32)(kMax32 - ((a + b) % kMax32));
+ a = (UInt32)(kMax32 - ((a + b) % kMax32));
+ return (a << 32) | b;
+}
+
+static bool CheckFletcher64(const Byte *p, size_t size)
+{
+ const UInt64 calculated_checksum = Fletcher64(p + 8, size - 8);
+ const UInt64 stored_checksum = Get64(p);
+ return (stored_checksum == calculated_checksum);
+}
+
+
+static unsigned GetLogSize(UInt32 size)
+{
+ unsigned k;
+ for (k = 0; k < 32; k++)
+ if (((UInt32)1 << k) == size)
+ return k;
+ return k;
+}
+
+static const unsigned kApfsHeaderSize = 1 << 12;
+
+// #define OID_INVALID 0
+#define OID_NX_SUPERBLOCK 1
+// #define OID_RESERVED_COUNT 1024
+// This range of identifiers is reserved for physical, virtual, and ephemeral objects
+
+bool CSuperBlock::Parse(const Byte *p)
+{
+ CPhys o;
+ o.Parse(p);
+ if (o.oid != OID_NX_SUPERBLOCK)
+ return false;
+ if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK)
+ return false;
+ if (o.subtype != 0)
+ return false;
+ if (memcmp(p + k_SignatureOffset, k_Signature, 4) != 0)
+ return false;
+ if (!CheckFletcher64(p, kApfsHeaderSize))
+ return false;
+
+ G32 (0x24, block_size);
+ {
+ unsigned logSize = GetLogSize(block_size);
+ if (logSize < 12 || logSize > 16)
+ return false;
+ block_size_Log = logSize;
+ }
+
+ G64 (0x28, block_count);
+
+ static const UInt64 kArcSize_MAX = (UInt64)1 << 62;
+ if (block_count > (kArcSize_MAX >> block_size_Log))
+ return false;
+
+ // G64 (0x30, features);
+ // G64 (0x38, readonly_compatible_features);
+ // G64 (0x40, incompatible_features);
+ uuid.SetFrom(p + 0x48);
+ /*
+ G64o (0x58, next_oid);
+ G64x (0x60, next_xid);
+ G32 (0x68, xp_desc_blocks);
+ G32 (0x6c, xp_data_blocks);
+ G64a (0x70, xp_desc_base);
+ G64a (0x78, xp_data_base);
+ G32 (0x80, xp_desc_next);
+ G32 (0x84, xp_data_next);
+ G32 (0x88, xp_desc_index);
+ G32 (0x8c, xp_desc_len);
+ G32 (0x90, xp_data_index);
+ G32 (0x94, xp_data_len);
+ G64o (0x98, spaceman_oid);
+ */
+ G64o (0xa0, omap_oid);
+ // G64o (0xa8, reaper_oid);
+ // G32 (0xb0, test_type);
+ G32 (0xb4, max_file_systems);
+ if (max_file_systems > NX_MAX_FILE_SYSTEMS)
+ return false;
+ /*
+ {
+ for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++)
+ {
+ G64o (0xb8 + i * 8, fs_oid[i]);
+ }
+ }
+ */
+ /*
+ {
+ for (unsigned i = 0; i < NX_NUM_COUNTERS; i++)
+ {
+ G64 (0x3d8 + i * 8, counters[i]);
+ }
+ }
+ blocked_out_prange.Parse(p + 0x4d8);
+ G64o (0x4e8, evict_mapping_tree_oid);
+ #define NX_CRYPTO_SW 0x00000004LL
+ G64 (0x4f0, flags);
+ G64a (0x4f8, efi_jumpstart);
+ fusion_uuid.SetFrom(p + 0x500);
+ keylocker.Parse(p + 0x510);
+ {
+ for (unsigned i = 0; i < NX_EPH_INFO_COUNT; i++)
+ {
+ G64 (0x520 + i * 8, ephemeral_info[i]);
+ }
+ }
+ G64o (0x540, test_oid);
+ G64o (0x548, fusion_mt_oid);
+ G64o (0x550, fusion_wbc_oid);
+ fusion_wbc.Parse(p + 0x558);
+ G64 (0x568, newest_mounted_version); // decimal 1412141 001 000 000
+ mkb_locker.Parse(p + 0x570);
+ */
+
+ return true;
+}
+
+
+
+struct C_omap_phys
+{
+ // om_ prefix
+ // CPhys o;
+ /*
+ UInt32 flags;
+ UInt32 snap_count;
+ UInt32 tree_type;
+ UInt32 snapshot_tree_type;
+ */
+ oid_t tree_oid;
+ /*
+ oid_t snapshot_tree_oid;
+ xid_t most_recent_snap;
+ xid_t pending_revert_min;
+ xid_t pending_revert_max;
+ */
+ bool Parse(const Byte *p, size_t size, oid_t oid);
+};
+
+bool C_omap_phys::Parse(const Byte *p, size_t size, oid_t oid)
+{
+ CPhys o;
+ if (!CheckFletcher64(p, size))
+ return false;
+ o.Parse(p);
+ if (o.GetType() != OBJECT_TYPE_OMAP)
+ return false;
+ if (o.oid != oid)
+ return false;
+ /*
+ G32 (0x20, flags);
+ G32 (0x24, snap_count);
+ G32 (0x28, tree_type);
+ G32 (0x2C, snapshot_tree_type);
+ */
+ G64o (0x30, tree_oid);
+ /*
+ G64o (0x38, snapshot_tree_oid);
+ G64x (0x40, most_recent_snap);
+ G64x (0x48, pending_revert_min);
+ G64x (0x50, pending_revert_max);
+ */
+ return true;
+}
+
+
+// #define BTOFF_INVALID 0xffff
+/* This value is stored in the off field of nloc_t to indicate that
+there's no offset. For example, the last entry in a free
+list has no entry after it, so it uses this value for its off field. */
+
+// A location within a B-tree node
+struct nloc
+{
+ UInt16 off;
+ UInt16 len;
+
+ void Parse(const Byte *p)
+ {
+ G16 (0, off);
+ G16 (2, len);
+ }
+ UInt32 GetEnd() const { return (UInt32)off + len; }
+ bool CheckOverLimit(UInt32 limit)
+ {
+ return off < limit && len <= limit - off;
+ }
+};
+
+
+// The location, within a B-tree node, of a key and value
+struct kvloc
+{
+ nloc k;
+ nloc v;
+
+ void Parse(const Byte *p)
+ {
+ k.Parse(p);
+ v.Parse(p + 4);
+ }
+};
+
+
+// The location, within a B-tree node, of a fixed-size key and value
+struct kvoff
+{
+ UInt16 k;
+ UInt16 v;
+
+ void Parse(const Byte *p)
+ {
+ G16 (0, k);
+ G16 (2, v);
+ }
+};
+
+
+#define BTNODE_ROOT (1 << 0)
+#define BTNODE_LEAF (1 << 1)
+#define BTNODE_FIXED_KV_SIZE (1 << 2)
+/*
+#define BTNODE_HASHED (1 << 3)
+#define BTNODE_NOHEADER (1 << 4)
+#define BTNODE_CHECK_KOFF_INVAL (1 << 15)
+*/
+
+static const unsigned k_Toc_offset = 0x38;
+
+// btree_node_phys
+struct CBTreeNodePhys
+{
+ // btn_ prefix
+ CPhys o;
+ UInt16 flags;
+ UInt16 level; // the number of child levels below this node. 0 - for a leaf node, 1 for the immediate parent of a leaf node
+ UInt32 nkeys; // The number of keys stored in this node.
+ nloc table_space;
+ /*
+ nloc free_space;
+ nloc key_free_list;
+ nloc val_free_list;
+ */
+
+ bool Is_FIXED_KV_SIZE() const { return (flags & BTNODE_FIXED_KV_SIZE) != 0; }
+
+ bool Parse(const Byte *p, size_t size)
+ {
+ if (!CheckFletcher64(p, size))
+ return false;
+ o.Parse(p);
+ G16 (0x20, flags);
+ G16 (0x22, level);
+ G32 (0x24, nkeys);
+ table_space.Parse(p + 0x28);
+ /*
+ free_space.Parse(p + 0x2C);
+ key_free_list.Parse(p + 0x30);
+ val_free_list.Parse(p + 0x34);
+ */
+ return true;
+ }
+};
+
+/*
+#define BTREE_UINT64_KEYS (1 << 0)
+#define BTREE_SEQUENTIAL_INSERT (1 << 1)
+#define BTREE_ALLOW_GHOSTS (1 << 2)
+*/
+#define BTREE_EPHEMERAL (1 << 3)
+#define BTREE_PHYSICAL (1 << 4)
+/*
+#define BTREE_NONPERSISTENT (1 << 5)
+#define BTREE_KV_NONALIGNED (1 << 6)
+#define BTREE_HASHED (1 << 7)
+*/
+
+/*
+ BTREE_EPHEMERAL: The nodes in the B-tree use ephemeral object identifiers to link to child nodes
+ BTREE_PHYSICAL : The nodes in the B-tree use physical object identifiers to link to child nodes.
+ If neither flag is set, nodes in the B-tree use virtual object
+ identifiers to link to their child nodes.
+*/
+
+// Static information about a B-tree.
+struct btree_info_fixed
+{
+ UInt32 flags;
+ UInt32 node_size;
+ UInt32 key_size;
+ UInt32 val_size;
+
+ void Parse(const Byte *p)
+ {
+ G32 (0, flags);
+ G32 (4, node_size);
+ G32 (8, key_size);
+ G32 (12, val_size);
+ }
+};
+
+static const unsigned k_btree_info_Size = 0x28;
+
+struct btree_info
+{
+ btree_info_fixed fixed;
+ UInt32 longest_key;
+ UInt32 longest_val;
+ UInt64 key_count;
+ UInt64 node_count;
+
+ bool Is_EPHEMERAL() const { return (fixed.flags & BTREE_EPHEMERAL) != 0; }
+ bool Is_PHYSICAL() const { return (fixed.flags & BTREE_PHYSICAL) != 0; }
+
+ void Parse(const Byte *p)
+ {
+ fixed.Parse(p);
+ G32 (0x10, longest_key);
+ G32 (0x14, longest_val);
+ G64 (0x18, key_count);
+ G64 (0x20, node_count);
+ }
+};
+
+
+/*
+typedef UInt32 cp_key_class_t;
+typedef UInt32 cp_key_os_version_t;
+typedef UInt16 cp_key_revision_t;
+typedef UInt32 crypto_flags_t;
+
+struct wrapped_meta_crypto_state
+{
+ UInt16 major_version;
+ UInt16 minor_version;
+ crypto_flags_t cpflags;
+ cp_key_class_t persistent_class;
+ cp_key_os_version_t key_os_version;
+ cp_key_revision_t key_revision;
+ // UInt16 unused;
+
+ void Parse(const Byte *p)
+ {
+ G16 (0, major_version);
+ G16 (2, minor_version);
+ G32 (4, cpflags);
+ G32 (8, persistent_class);
+ G32 (12, key_os_version);
+ G16 (16, key_revision);
+ }
+};
+*/
+
+
+#define APFS_MODIFIED_NAMELEN 32
+#define sizeof__apfs_modified_by_t (APFS_MODIFIED_NAMELEN + 16);
+
+struct apfs_modified_by_t
+{
+ Byte id[APFS_MODIFIED_NAMELEN];
+ UInt64 timestamp;
+ xid_t last_xid;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(id, p, APFS_MODIFIED_NAMELEN);
+ p += APFS_MODIFIED_NAMELEN;
+ G64 (0, timestamp);
+ G64x (8, last_xid);
+ }
+};
+
+
+#define APFS_MAX_HIST 8
+#define APFS_VOLNAME_LEN 256
+
+struct CApfs
+{
+ // apfs_
+ CPhys o;
+ // UInt32 magic;
+ UInt32 fs_index; // e index of the object identifier for this volume's file system in the container's array of file systems.
+ // UInt64 features;
+ // UInt64 readonly_compatible_features;
+ UInt64 incompatible_features;
+ UInt64 unmount_time;
+ // UInt64 fs_reserve_block_count;
+ // UInt64 fs_quota_block_count;
+ UInt64 fs_alloc_count;
+ // wrapped_meta_crypto_state meta_crypto;
+ // UInt32 root_tree_type;
+ /* The type of the root file-system tree.
+ The value is typically OBJ_VIRTUAL | OBJECT_TYPE_BTREE,
+ with a subtype of OBJECT_TYPE_FSTREE */
+
+ // UInt32 extentref_tree_type;
+ // UInt32 snap_meta_tree_type;
+ oid_t omap_oid;
+ oid_t root_tree_oid;
+ /*
+ oid_t extentref_tree_oid;
+ oid_t snap_meta_tree_oid;
+ xid_t revert_to_xid;
+ oid_t revert_to_sblock_oid;
+ UInt64 next_obj_id;
+ */
+ UInt64 num_files;
+ UInt64 num_directories;
+ UInt64 num_symlinks;
+ UInt64 num_other_fsobjects;
+ UInt64 num_snapshots;
+ UInt64 total_blocks_alloced;
+ UInt64 total_blocks_freed;
+ CUuid vol_uuid;
+ UInt64 last_mod_time;
+ UInt64 fs_flags;
+ apfs_modified_by_t formatted_by;
+ apfs_modified_by_t modified_by[APFS_MAX_HIST];
+ Byte volname[APFS_VOLNAME_LEN];
+ /*
+ UInt32 next_doc_id;
+ UInt16 role; // APFS_VOL_ROLE_NONE APFS_VOL_ROLE_SYSTEM ....
+ UInt16 reserved;
+ xid_t root_to_xid;
+ oid_t er_state_oid;
+ UInt64 cloneinfo_id_epoch;
+ UInt64 cloneinfo_xid;
+ oid_t snap_meta_ext_oid;
+ CUuid volume_group_id;
+ oid_t integrity_meta_oid;
+ oid_t fext_tree_oid;
+ UInt32 fext_tree_type;
+ UInt32 reserved_type;
+ oid_t reserved_oid;
+ */
+
+ UInt64 GetTotalItems() const
+ {
+ return num_files + num_directories + num_symlinks + num_other_fsobjects;
+ }
+
+ bool IsHashedName() const
+ {
+ return
+ (incompatible_features & APFS_INCOMPAT_CASE_INSENSITIVE) != 0 ||
+ (incompatible_features & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) != 0;
+ }
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+
+bool CApfs::Parse(const Byte *p, size_t size)
+{
+ o.Parse(p);
+ if (Get32(p + 32) != 0x42535041) // { 'A', 'P', 'S', 'B' };
+ return false;
+ if (o.GetType() != OBJECT_TYPE_FS)
+ return false;
+ if (!CheckFletcher64(p, size))
+ return false;
+ // if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) return false;
+
+ G32 (0x24, fs_index);
+ // G64 (0x28, features);
+ // G64 (0x30, readonly_compatible_features);
+ G64 (0x38, incompatible_features);
+ G64 (0x40, unmount_time);
+ // G64 (0x48, fs_reserve_block_count);
+ // G64 (0x50, fs_quota_block_count);
+ G64 (0x58, fs_alloc_count);
+ // meta_crypto.Parse(p + 0x60);
+ // G32 (0x74, root_tree_type);
+ // G32 (0x78, extentref_tree_type);
+ // G32 (0x7C, snap_meta_tree_type);
+
+ G64o (0x80, omap_oid);
+ G64o (0x88, root_tree_oid);
+ /*
+ G64o (0x90, extentref_tree_oid);
+ G64o (0x98, snap_meta_tree_oid);
+ G64x (0xa0, revert_to_xid);
+ G64o (0xa8, revert_to_sblock_oid);
+ G64 (0xb0, next_obj_id);
+ */
+ G64 (0xb8, num_files);
+ G64 (0xc0, num_directories);
+ G64 (0xc8, num_symlinks);
+ G64 (0xd0, num_other_fsobjects);
+ G64 (0xd8, num_snapshots);
+ G64 (0xe0, total_blocks_alloced);
+ G64 (0xe8, total_blocks_freed);
+ vol_uuid.SetFrom(p + 0xf0);
+ G64 (0x100, last_mod_time);
+ G64 (0x108, fs_flags);
+ p += 0x110;
+ formatted_by.Parse(p);
+ p += sizeof__apfs_modified_by_t;
+ for (unsigned i = 0; i < APFS_MAX_HIST; i++)
+ {
+ modified_by[i].Parse(p);
+ p += sizeof__apfs_modified_by_t;
+ }
+ memcpy(volname, p, APFS_VOLNAME_LEN);
+ p += APFS_VOLNAME_LEN;
+ /*
+ G32 (0, next_doc_id);
+ G16 (4, role);
+ G16 (6, reserved);
+ G64x (8, root_to_xid);
+ G64o (0x10, er_state_oid);
+ G64 (0x18, cloneinfo_id_epoch);
+ G64 (0x20, cloneinfo_xid);
+ G64o (0x28, snap_meta_ext_oid);
+ volume_group_id.SetFrom(p + 0x30);
+ G64o (0x40, integrity_meta_oid);
+ G64o (0x48, fext_tree_oid);
+ G32 (0x50, fext_tree_type);
+ G32 (0x54, reserved_type);
+ G64o (0x58, reserved_oid);
+ */
+ return true;
+}
+
+
+#define OBJ_ID_MASK 0x0fffffffffffffff
+/*
+#define OBJ_TYPE_MASK 0xf000000000000000
+#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000
+*/
+#define OBJ_TYPE_SHIFT 60
+
+typedef enum
+{
+ APFS_TYPE_ANY = 0,
+ APFS_TYPE_SNAP_METADATA = 1,
+ APFS_TYPE_EXTENT = 2,
+ APFS_TYPE_INODE = 3,
+ APFS_TYPE_XATTR = 4,
+ APFS_TYPE_SIBLING_LINK = 5,
+ APFS_TYPE_DSTREAM_ID = 6,
+ APFS_TYPE_CRYPTO_STATE = 7,
+ APFS_TYPE_FILE_EXTENT = 8,
+ APFS_TYPE_DIR_REC = 9,
+ APFS_TYPE_DIR_STATS = 10,
+ APFS_TYPE_SNAP_NAME = 11,
+ APFS_TYPE_SIBLING_MAP = 12,
+ APFS_TYPE_FILE_INFO = 13,
+ APFS_TYPE_MAX_VALID = 13,
+ APFS_TYPE_MAX = 15,
+ APFS_TYPE_INVALID = 15
+} j_obj_types;
+
+
+struct j_key_t
+{
+ UInt64 obj_id_and_type;
+
+ void Parse(const Byte *p) { G64(0, obj_id_and_type); }
+ unsigned GetType() const { return (unsigned)(obj_id_and_type >> OBJ_TYPE_SHIFT); }
+ UInt64 GetID() const { return obj_id_and_type & OBJ_ID_MASK; }
+};
+
+
+
+#define J_DREC_LEN_MASK 0x000003ff
+/*
+#define J_DREC_HASH_MASK 0xfffff400
+#define J_DREC_HASH_SHIFT 10
+*/
+
+static const unsigned k_SizeOf_j_drec_val = 0x12;
+
+struct j_drec_val
+{
+ UInt64 file_id;
+ UInt64 date_added; /* The time that this directory entry was added to the directory.
+ It's not updated when modifying the directory entry for example,
+ by renaming a file without moving it to a different directory. */
+ UInt16 flags;
+
+ // bool IsFlags_File() const { return flags == MY_LIN_DT_REG; }
+ bool IsFlags_Unknown() const { return flags == MY_LIN_DT_UNKNOWN; }
+ bool IsFlags_Dir() const { return flags == MY_LIN_DT_DIR; }
+
+ // uint8_t xfields[];
+ void Parse(const Byte *p)
+ {
+ G64 (0, file_id);
+ G64 (8, date_added);
+ G16 (0x10, flags);
+ }
+};
+
+
+struct CItem
+{
+ // j_key_t hdr;
+ UInt64 ParentId;
+ AString Name;
+ j_drec_val Val;
+
+ unsigned ParentItemIndex;
+ unsigned RefIndex;
+ // unsigned iNode_Index;
+
+ CItem():
+ ParentItemIndex(VI_MINUS1),
+ RefIndex(VI_MINUS1)
+ // iNode_Index(VI_MINUS1)
+ {}
+};
+
+
+/*
+#define INVALID_INO_NUM 0
+#define ROOT_DIR_PARENT 1 // parent for "root" and "private-dir", there's no inode on disk with this inode number.
+*/
+#define ROOT_DIR_INO_NUM 2 // "root" - parent for all main files
+#define PRIV_DIR_INO_NUM 3 // "private-dir"
+/*
+#define SNAP_DIR_INO_NUM 6 // the directory where snapshot metadata is stored. Snapshot inodes are stored in the snapshot metedata tree.
+#define PURGEABLE_DIR_INO_NUM 7
+#define MIN_USER_INO_NUM 16
+
+#define UNIFIED_ID_SPACE_MARK 0x0800000000000000
+*/
+
+/*
+typedef enum
+{
+INODE_IS_APFS_PRIVATE = 0x00000001,
+INODE_MAINTAIN_DIR_STATS = 0x00000002,
+INODE_DIR_STATS_ORIGIN = 0x00000004,
+INODE_PROT_CLASS_EXPLICIT = 0x00000008,
+INODE_WAS_CLONED = 0x00000010,
+INODE_FLAG_UNUSED = 0x00000020,
+INODE_HAS_SECURITY_EA = 0x00000040,
+INODE_BEING_TRUNCATED = 0x00000080,
+INODE_HAS_FINDER_INFO = 0x00000100,
+INODE_IS_SPARSE = 0x00000200,
+INODE_WAS_EVER_CLONED = 0x00000400,
+INODE_ACTIVE_FILE_TRIMMED = 0x00000800,
+INODE_PINNED_TO_MAIN = 0x00001000,
+INODE_PINNED_TO_TIER2 = 0x00002000,
+INODE_HAS_RSRC_FORK = 0x00004000,
+INODE_NO_RSRC_FORK = 0x00008000,
+INODE_ALLOCATION_SPILLEDOVER = 0x00010000,
+INODE_FAST_PROMOTE = 0x00020000,
+INODE_HAS_UNCOMPRESSED_SIZE = 0x00040000,
+INODE_IS_PURGEABLE = 0x00080000,
+INODE_WANTS_TO_BE_PURGEABLE = 0x00100000,
+INODE_IS_SYNC_ROOT = 0x00200000,
+INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000,
+
+
+INODE_INHERITED_INTERNAL_FLAGS = \
+ ( INODE_MAINTAIN_DIR_STATS \
+ | INODE_SNAPSHOT_COW_EXEMPTION),
+
+INODE_CLONED_INTERNAL_FLAGS = \
+ ( INODE_HAS_RSRC_FORK \
+ | INODE_NO_RSRC_FORK \
+ | INODE_HAS_FINDER_INFO \
+ | INODE_SNAPSHOT_COW_EXEMPTION),
+}
+j_inode_flags;
+
+
+#define APFS_VALID_INTERNAL_INODE_FLAGS \
+( INODE_IS_APFS_PRIVATE \
+| INODE_MAINTAIN_DIR_STATS \
+| INODE_DIR_STATS_ORIGIN \
+| INODE_PROT_CLASS_EXPLICIT \
+| INODE_WAS_CLONED \
+| INODE_HAS_SECURITY_EA \
+| INODE_BEING_TRUNCATED \
+| INODE_HAS_FINDER_INFO \
+| INODE_IS_SPARSE \
+| INODE_WAS_EVER_CLONED \
+| INODE_ACTIVE_FILE_TRIMMED \
+| INODE_PINNED_TO_MAIN \
+| INODE_PINNED_TO_TIER2 \
+| INODE_HAS_RSRC_FORK \
+| INODE_NO_RSRC_FORK \
+| INODE_ALLOCATION_SPILLEDOVER \
+| INODE_FAST_PROMOTE \
+| INODE_HAS_UNCOMPRESSED_SIZE \
+| INODE_IS_PURGEABLE \
+| INODE_WANTS_TO_BE_PURGEABLE \
+| INODE_IS_SYNC_ROOT \
+| INODE_SNAPSHOT_COW_EXEMPTION)
+
+#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2)
+*/
+
+static const char * const g_INODE_Flags[] =
+{
+ "IS_APFS_PRIVATE"
+ , "MAINTAIN_DIR_STATS"
+ , "DIR_STATS_ORIGIN"
+ , "PROT_CLASS_EXPLICIT"
+ , "WAS_CLONED"
+ , "FLAG_UNUSED"
+ , "HAS_SECURITY_EA"
+ , "BEING_TRUNCATED"
+ , "HAS_FINDER_INFO"
+ , "IS_SPARSE"
+ , "WAS_EVER_CLONED"
+ , "ACTIVE_FILE_TRIMMED"
+ , "PINNED_TO_MAIN"
+ , "PINNED_TO_TIER2"
+ , "HAS_RSRC_FORK"
+ , "NO_RSRC_FORK"
+ , "ALLOCATION_SPILLEDOVER"
+ , "FAST_PROMOTE"
+ , "HAS_UNCOMPRESSED_SIZE"
+ , "IS_PURGEABLE"
+ , "WANTS_TO_BE_PURGEABLE"
+ , "IS_SYNC_ROOT"
+ , "SNAPSHOT_COW_EXEMPTION"
+};
+
+
+// bsd stat.h
+/*
+#define MY__UF_SETTABLE 0x0000ffff // mask of owner changeable flags
+#define MY__UF_NODUMP 0x00000001 // do not dump file
+#define MY__UF_IMMUTABLE 0x00000002 // file may not be changed
+#define MY__UF_APPEND 0x00000004 // writes to file may only append
+#define MY__UF_OPAQUE 0x00000008 // directory is opaque wrt. union
+#define MY__UF_NOUNLINK 0x00000010 // file entry may not be removed or renamed Not implement in MacOS
+#define MY__UF_COMPRESSED 0x00000020 // file entry is compressed
+#define MY__UF_TRACKED 0x00000040 // notify about file entry changes
+#define MY__UF_DATAVAULT 0x00000080 // entitlement required for reading and writing
+#define MY__UF_HIDDEN 0x00008000 // file entry is hidden
+
+#define MY__SF_SETTABLE 0xffff0000 // mask of superuser changeable flags
+#define MY__SF_ARCHIVED 0x00010000 // file is archived
+#define MY__SF_IMMUTABLE 0x00020000 // file may not be changed
+#define MY__SF_APPEND 0x00040000 // writes to file may only append
+#define MY__SF_RESTRICTED 0x00080000 // entitlement required for writing
+#define MY__SF_NOUNLINK 0x00100000 // file entry may not be removed, renamed or used as mount point
+#define MY__SF_SNAPSHOT 0x00200000 // snapshot inode
+Not implement in MacOS
+*/
+
+static const char * const g_INODE_BSD_Flags[] =
+{
+ "UF_NODUMP"
+ , "UF_IMMUTABLE"
+ , "UF_APPEND"
+ , "UF_OPAQUE"
+ , "UF_NOUNLINK"
+ , "UF_COMPRESSED"
+ , "UF_TRACKED"
+ , "UF_DATAVAULT"
+ , NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL
+ , "UF_HIDDEN"
+
+ , "SF_ARCHIVE"
+ , "SF_IMMUTABLE"
+ , "SF_APPEND"
+ , "SF_RESTRICTED"
+ , "SF_NOUNLINK"
+ , "SF_SNAPSHOT"
+};
+
+/*
+#define INO_EXT_TYPE_SNAP_XID 1
+#define INO_EXT_TYPE_DELTA_TREE_OID 2
+#define INO_EXT_TYPE_DOCUMENT_ID 3
+*/
+#define INO_EXT_TYPE_NAME 4
+/*
+#define INO_EXT_TYPE_PREV_FSIZE 5
+#define INO_EXT_TYPE_RESERVED_6 6
+#define INO_EXT_TYPE_FINDER_INFO 7
+*/
+#define INO_EXT_TYPE_DSTREAM 8
+/*
+#define INO_EXT_TYPE_RESERVED_9 9
+#define INO_EXT_TYPE_DIR_STATS_KEY 10
+#define INO_EXT_TYPE_FS_UUID 11
+#define INO_EXT_TYPE_RESERVED_12 12
+#define INO_EXT_TYPE_SPARSE_BYTES 13
+#define INO_EXT_TYPE_RDEV 14
+#define INO_EXT_TYPE_PURGEABLE_FLAGS 15
+#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16
+*/
+
+
+static const unsigned k_SizeOf_j_dstream = 8 * 5;
+
+struct j_dstream
+{
+ UInt64 size;
+ UInt64 alloced_size;
+ UInt64 default_crypto_id;
+ UInt64 total_bytes_written;
+ UInt64 total_bytes_read;
+
+ void Parse(const Byte *p)
+ {
+ G64 (0, size);
+ G64 (0x8, alloced_size);
+ G64 (0x10, default_crypto_id);
+ G64 (0x18, total_bytes_written);
+ G64 (0x20, total_bytes_read);
+ }
+};
+
+static const unsigned k_SizeOf_j_file_extent_val = 8 * 3;
+
+#define J_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffU
+// #define J_FILE_EXTENT_FLAG_MASK 0xff00000000000000U
+// #define J_FILE_EXTENT_FLAG_SHIFT 56
+
+#define EXTENT_GET_LEN(x) ((x) & J_FILE_EXTENT_LEN_MASK)
+
+struct j_file_extent_val
+{
+ UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t.
+ // There are currently no flags defined
+ UInt64 phys_block_num; // The physical block address that the extent starts at
+ // UInt64 crypto_id; // The encryption key or the encryption tweak used in this extent.
+
+ void Parse(const Byte *p)
+ {
+ G64 (0, len_and_flags);
+ G64 (0x8, phys_block_num);
+ // G64 (0x10, crypto_id);
+ }
+};
+
+
+struct CExtent
+{
+ UInt64 logical_offset;
+ UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t.
+ // There are currently no flags defined
+ UInt64 phys_block_num; // The physical block address that the extent starts at
+};
+
+
+typedef UInt32 MY__uid_t;
+typedef UInt32 MY__gid_t;
+typedef UInt16 MY__mode_t;
+
+
+typedef enum
+{
+ XATTR_DATA_STREAM = 1 << 0,
+ XATTR_DATA_EMBEDDED = 1 << 1,
+ XATTR_FILE_SYSTEM_OWNED = 1 << 2,
+ XATTR_RESERVED_8 = 1 << 3
+} j_xattr_flags;
+
+
+struct CAttr
+{
+ AString Name;
+ UInt32 flags;
+ CByteBuffer Data;
+
+ j_dstream dstream;
+ bool dstream_defined;
+ UInt64 Id;
+
+ bool Is_dstream_OK_for_SymLink() const
+ {
+ return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0;
+ }
+
+ CAttr():
+ dstream_defined(false)
+ {}
+
+ bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; }
+ bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; }
+};
+
+
+// j_inode_val_t
+struct CNode
+{
+ unsigned ItemIndex; // index to CItem. We set it only if Node is directory.
+ unsigned NumCalcedLinks; // Num links to that node
+ // unsigned NumItems; // Num Items in that node
+
+ UInt64 parent_id; // The identifier of the file system record for the parent directory.
+ UInt64 private_id;
+ UInt64 create_time;
+ UInt64 mod_time;
+ UInt64 change_time;
+ UInt64 access_time;
+ UInt64 internal_flags;
+ union
+ {
+ UInt32 nchildren; /* The number of directory entries.
+ is valid only if the inode is a directory */
+ UInt32 nlink; /* The number of hard links whose target is this inode.
+ is valid only if the inode isn't a directory.
+ Inodes with multiple hard links (nlink > 1)
+ - The parent_id field refers to the parent directory of the primary link.
+ - The name field contains the name of the primary link.
+ - The INO_EXT_TYPE_NAME extended field contains the name of this link.
+ */
+ };
+ // cp_key_class_t default_protection_class;
+ UInt32 write_generation_counter;
+ UInt32 bsd_flags;
+ MY__uid_t owner;
+ MY__gid_t group;
+ MY__mode_t mode;
+ UInt16 pad1;
+ // UInt64 uncompressed_size;
+
+ j_dstream dstream;
+ AString PrimaryName;
+ bool dstream_defined;
+ bool refcnt_defined;
+ UInt32 refcnt; // j_dstream_id_val_t
+ CRecordVector<CExtent> Extents;
+ CObjectVector<CAttr> Attrs;
+ unsigned SymLinkIndex; // index in Attrs
+
+ CNode():
+ ItemIndex(VI_MINUS1),
+ NumCalcedLinks(0),
+ // NumItems(0),
+ dstream_defined(false),
+ refcnt_defined(false),
+ SymLinkIndex(VI_MINUS1)
+ {}
+
+ bool IsDir() const { return MY_LIN_S_ISDIR(mode); }
+ bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); }
+ unsigned Get_Type_From_mode() const { return mode >> 12; }
+
+ bool GetSize(unsigned attrIndex, UInt64 &size) const
+ {
+ if (IsViNotDef(attrIndex))
+ {
+ if (dstream_defined)
+ {
+ size = dstream.size;
+ return true;
+ }
+ if (!IsSymLink())
+ return false;
+ attrIndex = SymLinkIndex;
+ if (IsViNotDef(attrIndex))
+ return false;
+ }
+ const CAttr &attr = Attrs[(unsigned)attrIndex];
+ if (attr.dstream_defined)
+ size = attr.dstream.size;
+ else
+ size = attr.Data.Size();
+ return true;
+ }
+
+ bool GetPackSize(unsigned attrIndex, UInt64 &size) const
+ {
+ if (IsViNotDef(attrIndex))
+ {
+ if (dstream_defined)
+ {
+ size = dstream.alloced_size;
+ return true;
+ }
+ if (!IsSymLink())
+ return false;
+ attrIndex = SymLinkIndex;
+ if (IsViNotDef(attrIndex))
+ return false;
+ }
+ const CAttr &attr = Attrs[(unsigned)attrIndex];
+ if (attr.dstream_defined)
+ size = attr.dstream.alloced_size;
+ else
+ size = attr.Data.Size();
+ return true;
+ }
+
+ void Parse(const Byte *p);
+};
+
+
+// it's used for Attr streams
+struct CSmallNode
+{
+ CRecordVector<CExtent> Extents;
+ // UInt32 NumLinks;
+ // CSmallNode(): NumLinks(0) {};
+};
+
+static const unsigned k_SizeOf_j_inode_val = 0x5c;
+
+void CNode::Parse(const Byte *p)
+{
+ G64 (0, parent_id);
+ G64 (0x8, private_id);
+ G64 (0x10, create_time);
+ G64 (0x18, mod_time);
+ G64 (0x20, change_time);
+ G64 (0x28, access_time);
+ G64 (0x30, internal_flags);
+ {
+ G32(0x38, nchildren);
+ // G32(0x38, nlink);
+ }
+ // G32(0x3c, default_protection_class);
+ G32(0x40, write_generation_counter);
+ G32(0x44, bsd_flags);
+ G32(0x48, owner);
+ G32(0x4c, group);
+ G16(0x50, mode);
+ // G16(0x52, pad1);
+ // G64 (0x54, uncompressed_size);
+}
+
+
+struct CRef
+{
+ unsigned ItemIndex;
+ unsigned NodeIndex;
+ unsigned ParentRefIndex;
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ unsigned AttrIndex;
+ bool IsAltStream() const { return IsViDef(AttrIndex); }
+ unsigned GetAttrIndex() const { return AttrIndex; };
+ #else
+ unsigned GetAttrIndex() const { return VI_MINUS1; };
+ #endif
+};
+
+
+struct CRef2
+{
+ unsigned VolIndex;
+ unsigned RefIndex;
+};
+
+
+struct CVol
+{
+ CObjectVector<CNode> Nodes;
+ CRecordVector<UInt64> NodeIDs;
+ CObjectVector<CItem> Items;
+ CRecordVector<CRef> Refs;
+
+ CObjectVector<CSmallNode> SmallNodes;
+ CRecordVector<UInt64> SmallNodeIDs;
+
+ unsigned StartRef2Index; // ref2_Index for Refs[0] item
+ unsigned RootRef2Index; // ref2_Index of virtual root folder (Volume1)
+ CApfs apfs;
+ bool NodeNotFound;
+ bool ThereAreUnlinkedNodes;
+ bool WrongInodeLink;
+ bool UnsupportedFeature;
+
+ unsigned NumItems_In_PrivateDir;
+ unsigned NumAltStreams;
+
+ UString RootName;
+
+ bool ThereAreErrors() const
+ {
+ return NodeNotFound || ThereAreUnlinkedNodes || WrongInodeLink;
+ }
+
+ void AddComment(UString &s) const;
+
+ HRESULT FillRefs();
+
+ CVol():
+ StartRef2Index(0),
+ RootRef2Index(VI_MINUS1),
+ NodeNotFound(false),
+ ThereAreUnlinkedNodes(false),
+ WrongInodeLink(false),
+ UnsupportedFeature(false),
+ NumItems_In_PrivateDir(0),
+ NumAltStreams(0)
+ {}
+};
+
+
+static void ApfsTimeToFileTime(UInt64 apfsTime, FILETIME &ft, UInt32 &ns100)
+{
+ const UInt64 s = apfsTime / 1000000000;
+ const UInt32 ns = (UInt32)(apfsTime % 1000000000);
+ ns100 = (ns % 100);
+ const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(s) + ns / 100;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+static void AddComment_Name(UString &s, const char *name)
+{
+ s += name;
+ s += ": ";
+}
+
+/*
+static void AddComment_Bool(UString &s, const char *name, bool val)
+{
+ AddComment_Name(s, name);
+ s += val ? "+" : "-";
+ s.Add_LF();
+}
+*/
+
+static void AddComment_UInt64(UString &s, const char *name, UInt64 v)
+{
+ AddComment_Name(s, name);
+ s.Add_UInt64(v);
+ s.Add_LF();
+}
+
+
+static void AddComment_Time(UString &s, const char *name, UInt64 v)
+{
+ AddComment_Name(s, name);
+
+ FILETIME ft;
+ UInt32 ns100;
+ ApfsTimeToFileTime(v, ft, ns100);
+ char temp[64];
+ ConvertUtcFileTimeToString2(ft, ns100, temp
+ // , kTimestampPrintLevel_SEC);
+ , kTimestampPrintLevel_NS);
+ s += temp;
+ s.Add_LF();
+}
+
+
+static void AddComment_modified_by_t(UString &s, const char *name, const apfs_modified_by_t &v)
+{
+ AddComment_Name(s, name);
+ AString s2;
+ s2.SetFrom_CalcLen((const char *)v.id, sizeof(v.id));
+ s += s2;
+ s.Add_LF();
+ s += " ";
+ AddComment_Time(s, "timestamp", v.timestamp);
+ s += " ";
+ AddComment_UInt64(s, "last_xid", v.last_xid);
+}
+
+
+static void AddVolInternalName_toString(UString &s, const CApfs &apfs)
+{
+ AString temp;
+ temp.SetFrom_CalcLen((const char *)apfs.volname, sizeof(apfs.volname));
+ UString unicode;
+ ConvertUTF8ToUnicode(temp, unicode);
+ s += unicode;
+}
+
+
+void CVol::AddComment(UString &s) const
+{
+ AddComment_UInt64(s, "fs_index", apfs.fs_index);
+ {
+ AddComment_Name(s, "volume_name");
+ AddVolInternalName_toString(s, apfs);
+ s.Add_LF();
+ }
+ AddComment_Name(s, "vol_uuid");
+ apfs.vol_uuid.AddHexToString(s);
+ s.Add_LF();
+
+ AddComment_Name(s, "incompatible_features");
+ s += FlagsToString(g_APFS_INCOMPAT_Flags,
+ ARRAY_SIZE(g_APFS_INCOMPAT_Flags),
+ (UInt32)apfs.incompatible_features);
+ s.Add_LF();
+
+ // AddComment_UInt64(s, "reserve_block_count", apfs.fs_reserve_block_count, false);
+ // AddComment_UInt64(s, "quota_block_count", apfs.fs_quota_block_count);
+ AddComment_UInt64(s, "fs_alloc_count", apfs.fs_alloc_count);
+
+ AddComment_UInt64(s, "num_files", apfs.num_files);
+ AddComment_UInt64(s, "num_directories", apfs.num_directories);
+ AddComment_UInt64(s, "num_symlinks", apfs.num_symlinks);
+ AddComment_UInt64(s, "num_other_fsobjects", apfs.num_other_fsobjects);
+
+ AddComment_UInt64(s, "Num_Attr_Streams", NumAltStreams);
+
+ AddComment_UInt64(s, "num_snapshots", apfs.num_snapshots);
+ AddComment_UInt64(s, "total_blocks_alloced", apfs.total_blocks_alloced);
+ AddComment_UInt64(s, "total_blocks_freed", apfs.total_blocks_freed);
+
+ AddComment_Time(s, "unmounted", apfs.unmount_time);
+ AddComment_Time(s, "last_modified", apfs.last_mod_time);
+ AddComment_modified_by_t(s, "formatted_by", apfs.formatted_by);
+ for (unsigned i = 0; i < ARRAY_SIZE(apfs.modified_by); i++)
+ {
+ const apfs_modified_by_t &v = apfs.modified_by[i];
+ if (v.last_xid == 0 && v.timestamp == 0 && v.id[0] == 0)
+ continue;
+ AString name ("modified_by[");
+ name.Add_UInt32(i);
+ name += ']';
+ AddComment_modified_by_t(s, name.Ptr(), v);
+ }
+}
+
+
+
+struct CKeyValPair
+{
+ CByteBuffer Key;
+ CByteBuffer Val;
+ // unsigned ValPos; // for alognment
+};
+
+
+struct omap_key
+{
+ oid_t oid; // The object identifier
+ xid_t xid; // The transaction identifier
+ void Parse(const Byte *p)
+ {
+ G64o (0, oid);
+ G64x (8, xid);
+ }
+};
+
+/*
+#define OMAP_VAL_DELETED (1 << 0)
+#define OMAP_VAL_SAVED (1 << 1)
+#define OMAP_VAL_ENCRYPTED (1 << 2)
+#define OMAP_VAL_NOHEADER (1 << 3)
+#define OMAP_VAL_CRYPTO_GENERATION (1 << 4)
+*/
+
+struct omap_val
+{
+ UInt32 flags;
+ UInt32 size;
+ paddr_t paddr;
+
+ void Parse(const Byte *p)
+ {
+ G32 (0, flags);
+ G32 (4, size);
+ G64 (8, paddr);
+ }
+};
+
+
+struct CObjectMap
+{
+ CRecordVector<UInt64> Keys;
+ CRecordVector<omap_val> Vals;
+
+ bool Parse(const CObjectVector<CKeyValPair> &pairs);
+ int FindKey(UInt64 id) const { return Keys.FindInSorted(id); }
+};
+
+bool CObjectMap::Parse(const CObjectVector<CKeyValPair> &pairs)
+{
+ omap_key prev;
+ prev.oid = 0;
+ prev.xid = 0;
+ FOR_VECTOR (i, pairs)
+ {
+ const CKeyValPair &pair = pairs[i];
+ if (pair.Key.Size() != 16 || pair.Val.Size() != 16)
+ return false;
+ omap_key key;
+ key.Parse(pair.Key);
+ omap_val val;
+ val.Parse(pair.Val);
+ /* Object map B-trees are sorted by object identifier and then by transaction identifier
+ but it's possible to have identical Ids in map ?
+ do we need to look transaction id ?
+ and search key with largest transaction id? */
+ if (key.oid <= prev.oid)
+ return false;
+ prev = key;
+ Keys.Add(key.oid);
+ Vals.Add(val);
+ }
+ return true;
+}
+
+
+struct CMap
+{
+ CObjectVector<CKeyValPair> Pairs;
+
+ CObjectMap Omap;
+ btree_info bti;
+ UInt64 NumNodes;
+
+ // we use thnese options to check:
+ UInt32 Subtype;
+ bool IsPhysical;
+
+ bool CheckAtFinish() const
+ {
+ return NumNodes == bti.node_count && Pairs.Size() == bti.key_count;
+ }
+
+ CMap():
+ NumNodes(0),
+ Subtype(0),
+ IsPhysical(true)
+ {}
+};
+
+
+
+struct CDatabase
+{
+ CRecordVector<CRef2> Refs2;
+ CObjectVector<CVol> Vols;
+
+ bool HeadersError;
+ bool ThereAreAltStreams;
+ bool UnsupportedFeature;
+
+ CSuperBlock sb;
+
+ IInStream *OpenInStream;
+ IArchiveOpenCallback *OpenCallback;
+ UInt64 ProgressVal_Cur;
+ UInt64 ProgressVal_Prev;
+ UInt64 ProgressVal_NumFilesTotal;
+ CObjectVector<CByteBuffer> Buffers;
+
+ UInt64 GetSize(const UInt32 index) const;
+
+ void Clear()
+ {
+ HeadersError = false;
+ UnsupportedFeature = false;
+ ThereAreAltStreams = false;
+
+ ProgressVal_Cur = 0;
+ ProgressVal_Prev = 0;
+ ProgressVal_NumFilesTotal = 0;
+
+ Vols.Clear();
+ Refs2.Clear();
+ Buffers.Clear();
+ }
+
+ HRESULT SeekReadBlock_FALSE(UInt64 oid, void *data);
+ void GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const;
+ HRESULT ReadMap(UInt64 oid, CMap &map, unsigned recurseLevel);
+ HRESULT ReadObjectMap(UInt64 oid, CObjectMap &map);
+ HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid);
+ HRESULT Open2();
+
+ HRESULT GetStream2(
+ IInStream *apfsInStream,
+ const CRecordVector<CExtent> *extents, UInt64 rem,
+ ISequentialInStream **stream);
+};
+
+
+HRESULT CDatabase::SeekReadBlock_FALSE(UInt64 oid, void *data)
+{
+ if (OpenCallback)
+ {
+ if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22))
+ {
+ RINOK(OpenCallback->SetCompleted(NULL, &ProgressVal_Cur));
+ ProgressVal_Prev = ProgressVal_Cur;
+ }
+ ProgressVal_Cur += sb.block_size;
+ }
+ if (oid == 0 || oid >= sb.block_count)
+ return S_FALSE;
+ RINOK(OpenInStream->Seek(oid << sb.block_size_Log, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(OpenInStream, data, sb.block_size);
+}
+
+
+
+API_FUNC_static_IsArc IsArc_APFS(const Byte *p, size_t size)
+{
+ if (size < kApfsHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ CSuperBlock sb;
+ if (!sb.Parse(p))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+
+
+HRESULT CDatabase::ReadMap(UInt64 oid, CMap &map, unsigned recurseLevel)
+{
+ // is it allowed to use big number of levels ?
+ if (recurseLevel > (1 << 10))
+ return S_FALSE;
+
+ const UInt32 blockSize = sb.block_size;
+ if (Buffers.Size() <= recurseLevel)
+ {
+ Buffers.AddNew();
+ if (Buffers.Size() <= recurseLevel)
+ throw 123;
+ Buffers.Back().Alloc(blockSize);
+ }
+ const Byte *buf;
+ {
+ CByteBuffer &buf2 = Buffers[recurseLevel];
+ RINOK(SeekReadBlock_FALSE(oid, buf2));
+ buf = buf2;
+ }
+
+ CBTreeNodePhys bt;
+ if (!bt.Parse(buf, blockSize))
+ return S_FALSE;
+
+ map.NumNodes++;
+
+ /* Specification: All values are stored in leaf nodes, which
+ makes these B+ trees, and the values in nonleaf nodes are object
+ identifiers of child nodes.
+
+ The entries in the table of contents are sorted by key. The comparison function used for sorting depends on the keys type
+ - Object map B-trees are sorted by object identifier and then by transaction identifier.
+ - Free queue B-trees are sorted by transaction identifier and then by physical address.
+ - File-system records are sorted according to the rules listed in File-System Objects.
+ */
+
+ if (bt.o.subtype != map.Subtype)
+ return S_FALSE;
+
+ unsigned endLimit = blockSize;
+
+ if (recurseLevel == 0)
+ {
+ if (bt.o.GetType() != OBJECT_TYPE_BTREE)
+ return S_FALSE;
+ if ((bt.flags & BTNODE_ROOT) == 0)
+ return S_FALSE;
+ endLimit -= k_btree_info_Size;
+ map.bti.Parse(buf + endLimit);
+ btree_info &bti = map.bti;
+ if (bti.fixed.key_size >= blockSize)
+ return S_FALSE;
+ if (bti.Is_EPHEMERAL() &&
+ bti.Is_PHYSICAL())
+ return S_FALSE;
+ if (bti.Is_PHYSICAL() != map.IsPhysical)
+ return S_FALSE;
+ // we don't allow volumes with big number of Keys
+ const UInt32 kNumItemsMax = k_VectorSizeMax;
+ if (map.bti.node_count > kNumItemsMax)
+ return S_FALSE;
+ if (map.bti.key_count > kNumItemsMax)
+ return S_FALSE;
+ }
+ else
+ {
+ if (bt.o.GetType() != OBJECT_TYPE_BTREE_NODE)
+ return S_FALSE;
+ if ((bt.flags & BTNODE_ROOT) != 0)
+ return S_FALSE;
+ if (map.NumNodes > map.bti.node_count
+ || map.Pairs.Size() > map.bti.key_count)
+ return S_FALSE;
+ }
+
+ const bool isLeaf = (bt.flags & BTNODE_LEAF) != 0;
+
+ if (isLeaf)
+ {
+ if (bt.level != 0)
+ return S_FALSE;
+ }
+ else
+ {
+ if (bt.level == 0)
+ return S_FALSE;
+ }
+
+ if (!bt.table_space.CheckOverLimit(endLimit - k_Toc_offset))
+ return S_FALSE;
+
+ const unsigned tableEnd = k_Toc_offset + bt.table_space.GetEnd();
+ const unsigned keyValRange = endLimit - tableEnd;
+ const unsigned tocEntrySize = bt.Is_FIXED_KV_SIZE() ? 4 : 8;
+ if (bt.table_space.len / tocEntrySize < bt.nkeys)
+ return S_FALSE;
+
+ for (unsigned i = 0; i < bt.nkeys; i++)
+ {
+ const Byte *p = buf + k_Toc_offset + bt.table_space.off + i * tocEntrySize;
+ if (bt.Is_FIXED_KV_SIZE())
+ {
+ kvoff a;
+ a.Parse(p);
+ if (a.k + map.bti.fixed.key_size > keyValRange
+ || a.v > keyValRange)
+ return S_FALSE;
+ {
+ CKeyValPair pair;
+
+ const Byte *p2 = buf + k_Toc_offset + bt.table_space.len;
+ p2 += a.k;
+ pair.Key.CopyFrom(p2, map.bti.fixed.key_size);
+
+ p2 = buf + endLimit;
+ p2 -= a.v;
+ if (isLeaf)
+ {
+ if (a.v < map.bti.fixed.val_size)
+ return S_FALSE;
+ pair.Val.CopyFrom(p2, map.bti.fixed.val_size);
+ // pair.ValPos = endLimit - a.v;
+ map.Pairs.Add(pair);
+ continue;
+ }
+ {
+ if (a.v < 8)
+ return S_FALSE;
+ // value is only 64-bit for non leaf.
+ const oid_t oidNext = Get64(p2);
+ if (map.bti.Is_PHYSICAL())
+ {
+ RINOK(ReadMap(oidNext, map, recurseLevel + 1));
+ continue;
+ }
+ else
+ {
+ // fixme
+ return S_FALSE;
+ }
+ }
+ }
+ }
+ else
+ {
+ kvloc a;
+ a.Parse(p);
+ if (!a.k.CheckOverLimit(keyValRange)
+ || a.v.off > keyValRange
+ || a.v.len > a.v.off)
+ return S_FALSE;
+ {
+ CKeyValPair pair;
+ const Byte *p2 = buf + k_Toc_offset + bt.table_space.len;
+ p2 += a.k.off;
+ pair.Key.CopyFrom(p2, a.k.len);
+
+ p2 = buf + endLimit;
+ p2 -= a.v.off;
+ if (isLeaf)
+ {
+ pair.Val.CopyFrom(p2, a.v.len);
+ // pair.ValPos = endLimit - a.v.off;
+ map.Pairs.Add(pair);
+ continue;
+ }
+ {
+ if (a.v.off < 8 || a.v.len != 8)
+ return S_FALSE;
+ // value is only 64-bit for non leaf.
+ const oid_t oidNext = Get64(p2);
+
+ if (map.bti.Is_PHYSICAL())
+ {
+ return S_FALSE;
+ // the code was not tested:
+ // RINOK(ReadMap(oidNext, map, recurseLevel + 1));
+ // continue;
+ }
+ else
+ {
+ const int index = map.Omap.FindKey(oidNext);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = map.Omap.Vals[(unsigned)index];
+ if (ov.size != blockSize) // change it : it must be multiple of
+ return S_FALSE;
+ RINOK(ReadMap(ov.paddr, map, recurseLevel + 1));
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ if (recurseLevel == 0)
+ if (!map.CheckAtFinish())
+ return S_FALSE;
+ return S_OK;
+}
+
+
+
+HRESULT CDatabase::ReadObjectMap(UInt64 oid, CObjectMap &omap)
+{
+ CByteBuffer buf;
+ const size_t blockSize = sb.block_size;
+ buf.Alloc(blockSize);
+ RINOK(SeekReadBlock_FALSE(oid, buf));
+ C_omap_phys op;
+ if (!op.Parse(buf, blockSize, oid))
+ return S_FALSE;
+ CMap map;
+ map.Subtype = OBJECT_TYPE_OMAP;
+ map.IsPhysical = true;
+ RINOK(ReadMap(op.tree_oid, map, 0));
+ if (!omap.Parse(map.Pairs))
+ return S_FALSE;
+ return S_OK;
+}
+
+
+
+HRESULT CDatabase::Open2()
+{
+ Clear();
+ CSuperBlock2 sb2;
+ {
+ Byte buf[kApfsHeaderSize];
+ RINOK(ReadStream_FALSE(OpenInStream, buf, kApfsHeaderSize));
+ if (!sb.Parse(buf))
+ return S_FALSE;
+ sb2.Parse(buf);
+ }
+
+ {
+ CObjectMap omap;
+ RINOK(ReadObjectMap(sb.omap_oid, omap));
+ unsigned numRefs = 0;
+ for (unsigned i = 0; i < sb.max_file_systems; i++)
+ {
+ const oid_t oid = sb2.fs_oid[i];
+ if (oid == 0)
+ continue;
+ // for (unsigned k = 0; k < 1; k++) // for debug
+ RINOK(OpenVolume(omap, oid));
+ const unsigned a = Vols.Back().Refs.Size();
+ numRefs += a;
+ if (numRefs < a)
+ return S_FALSE; // overflow
+ }
+ }
+
+ const bool needVolumePrefix = (Vols.Size() > 1);
+ // const bool needVolumePrefix = true; // for debug
+ {
+ unsigned numRefs = 0;
+ FOR_VECTOR (i, Vols)
+ {
+ const unsigned a = Vols[i].Refs.Size();
+ numRefs += a;
+ if (numRefs < a)
+ return S_FALSE; // overflow
+ }
+ numRefs += Vols.Size();
+ if (numRefs < Vols.Size())
+ return S_FALSE; // overflow
+ Refs2.Reserve(numRefs);
+ }
+ {
+ FOR_VECTOR (i, Vols)
+ {
+ CVol &vol = Vols[i];
+
+ CRef2 ref2;
+ ref2.VolIndex = i;
+
+ if (needVolumePrefix)
+ {
+ vol.RootName = "Volume";
+ vol.RootName.Add_UInt32(1 + (UInt32)i);
+ vol.RootRef2Index = Refs2.Size();
+ ref2.RefIndex = VI_MINUS1;
+ Refs2.Add(ref2);
+ }
+
+ vol.StartRef2Index = Refs2.Size();
+ const unsigned numItems = vol.Refs.Size();
+ for (unsigned k = 0; k < numItems; k++)
+ {
+ ref2.RefIndex = k;
+ Refs2.Add(ref2);
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
+{
+ const size_t blockSize = sb.block_size;
+ CByteBuffer buf;
+ {
+ const int index = omap.FindKey(fs_oid);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = omap.Vals[(unsigned)index];
+ if (ov.size != blockSize) // change it : it must be multiple of
+ return S_FALSE;
+ buf.Alloc(blockSize);
+ RINOK(SeekReadBlock_FALSE(ov.paddr, buf));
+ }
+
+ CVol &vol = Vols.AddNew();
+ CApfs &apfs = vol.apfs;
+
+ if (!apfs.Parse(buf, blockSize))
+ return S_FALSE;
+
+ /* For each volume, read the root file system tree's virtual object
+ identifier from the apfs_root_tree_oid field,
+ and then look it up in the volume object map indicated
+ by the omap_oid field. */
+
+ CMap map;
+ {
+ ReadObjectMap(apfs.omap_oid, map.Omap);
+ const int index = map.Omap.FindKey(apfs.root_tree_oid);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = map.Omap.Vals[(unsigned)index];
+ if (ov.size != blockSize) // change it : it must be multiple of
+ return S_FALSE;
+ map.Subtype = OBJECT_TYPE_FSTREE;
+ map.IsPhysical = false;
+ RINOK(ReadMap(ov.paddr, map, 0));
+ }
+
+ bool NeedReadSymLink = false;
+
+ {
+ const bool isHashed = apfs.IsHashedName();
+ UInt64 prevId = 1;
+
+ {
+ const UInt64 numApfsItems = vol.apfs.GetTotalItems()
+ + 2; // we will have 2 additional hidden directories: root and private-dir
+ const UInt64 numApfsItems_Reserve = numApfsItems
+ + 16; // we reserve 16 for some possible unexpected items
+ if (numApfsItems_Reserve < map.Pairs.Size())
+ {
+ vol.Items.ClearAndReserve((unsigned)numApfsItems_Reserve);
+ vol.Nodes.ClearAndReserve((unsigned)numApfsItems_Reserve);
+ vol.NodeIDs.ClearAndReserve((unsigned)numApfsItems_Reserve);
+ }
+ if (OpenCallback)
+ {
+ const UInt64 numFiles = ProgressVal_NumFilesTotal + numApfsItems;
+ RINOK(OpenCallback->SetTotal(&numFiles, NULL));
+ }
+ }
+
+ FOR_VECTOR (i, map.Pairs)
+ {
+ if (OpenCallback && (i & 0xffff) == 1)
+ {
+ const UInt64 numFiles = ProgressVal_NumFilesTotal +
+ (vol.Items.Size() + vol.Nodes.Size()) / 2;
+ RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur));
+ }
+
+ const CKeyValPair &pair = map.Pairs[i];
+ j_key_t jkey;
+ if (pair.Key.Size() < 8)
+ return S_FALSE;
+ const Byte *p = pair.Key;
+ jkey.Parse(p);
+ const unsigned type = jkey.GetType();
+ const UInt64 id = jkey.GetID();
+ if (id < prevId)
+ return S_FALSE; // IDs must be sorted
+ prevId = id;
+
+ PRF(printf("\n%6d: id=%6d type = %2d", i, (unsigned)id, type));
+
+ if (type == APFS_TYPE_INODE)
+ {
+ PRF(printf (" INODE"));
+ if (pair.Key.Size() != 8 ||
+ pair.Val.Size() < k_SizeOf_j_inode_val)
+ return S_FALSE;
+
+ CNode inode;
+ inode.Parse(pair.Val);
+
+ if (inode.private_id != id)
+ {
+ /* private_id : The unique identifier used by this file's data stream.
+ This identifier appears in the owning_obj_id field of j_phys_ext_val_t
+ records that describe the extents where the data is stored.
+ For an inode that doesn't have data, the value of this
+ field is the file-system object's identifier.
+ */
+ // APFS_TYPE_EXTENT allow to link physical address extents.
+ // we don't support case (private_id != id)
+ UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+ const UInt32 extraSize = (UInt32)pair.Val.Size() - k_SizeOf_j_inode_val;
+ if (extraSize != 0)
+ {
+ if (extraSize < 4)
+ return S_FALSE;
+ /*
+ struct xf_blob
+ {
+ uint16_t xf_num_exts;
+ uint16_t xf_used_data;
+ uint8_t xf_data[];
+ };
+ */
+ const Byte *p2 = pair.Val + k_SizeOf_j_inode_val;
+ const UInt32 xf_num_exts = Get16(p2);
+ const UInt32 xf_used_data = Get16(p2 + 2);
+ UInt32 offset = 4 + (UInt32)xf_num_exts * 4;
+ if (offset + xf_used_data != extraSize)
+ return S_FALSE;
+ for (unsigned k = 0; k < xf_num_exts; k++)
+ {
+ // struct x_field
+ const Byte *p3 = p2 + 4 + k * 4;
+ const Byte x_type = p3[0];
+ // const Byte x_flags = p3[1];
+ const UInt32 x_size = Get16(p3 + 2);
+ const UInt32 x_size_ceil = (x_size + 7) & ~(UInt32)7;
+ if (offset + x_size_ceil > extraSize)
+ return S_FALSE;
+ const Byte *p4 = p2 + offset;
+ if (x_type == INO_EXT_TYPE_NAME)
+ {
+ if (x_size < 2)
+ return S_FALSE;
+ inode.PrimaryName.SetFrom_CalcLen((const char *)p4, x_size);
+ PRF(printf(" PrimaryName = %s", inode.PrimaryName.Ptr()));
+ if (inode.PrimaryName.Len() != x_size - 1)
+ HeadersError = true;
+ // return S_FALSE;
+ }
+ else if (x_type == INO_EXT_TYPE_DSTREAM)
+ {
+ if (x_size != k_SizeOf_j_dstream)
+ return S_FALSE;
+ if (inode.dstream_defined)
+ return S_FALSE;
+ inode.dstream.Parse(p4);
+ inode.dstream_defined = true;
+ }
+ else
+ {
+ // UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+ offset += x_size_ceil;
+ }
+ if (offset != extraSize)
+ return S_FALSE;
+ }
+
+ if (!vol.NodeIDs.IsEmpty())
+ if (id <= vol.NodeIDs.Back())
+ return S_FALSE;
+ vol.Nodes.Add(inode);
+ vol.NodeIDs.Add(id);
+ continue;
+ }
+
+ if (type == APFS_TYPE_XATTR)
+ {
+ PRF(printf(" XATTR"));
+
+ /*
+ struct j_xattr_key
+ {
+ j_key_t hdr;
+ uint16_t name_len;
+ uint8_t name[0];
+ }
+ */
+
+ UInt32 len;
+ unsigned nameOffset;
+ {
+ nameOffset = 8 + 2;
+ if (pair.Key.Size() < nameOffset + 1)
+ return S_FALSE;
+ len = Get16(p + 8);
+ }
+ if (nameOffset + len != pair.Key.Size())
+ return S_FALSE;
+
+ CAttr attr;
+ attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
+ if (attr.Name.Len() != len - 1)
+ return S_FALSE;
+
+ PRF(printf(" name=%s", attr.Name.Ptr()));
+
+ const unsigned k_SizeOf_j_xattr_val = 4;
+ if (pair.Val.Size() < k_SizeOf_j_xattr_val)
+ return S_FALSE;
+ /*
+ struct j_xattr_val
+ {
+ uint16_t flags;
+ uint16_t xdata_len;
+ uint8_t xdata[0];
+ }
+ */
+ attr.flags = Get16(pair.Val);
+ const UInt32 xdata_len = Get16(pair.Val + 2);
+
+ PRF(printf(" flags=%x xdata_len = %d",
+ (unsigned)attr.flags,
+ (unsigned)xdata_len));
+
+ const Byte *p4 = pair.Val + 4;
+
+ if (k_SizeOf_j_xattr_val + xdata_len != pair.Val.Size())
+ return S_FALSE;
+ if (attr.Is_EMBEDDED())
+ attr.Data.CopyFrom(p4, xdata_len);
+ else if (attr.Is_STREAM())
+ {
+ // why (attr.flags == 0x11) here? (0x11 is undocummented flag)
+ if (k_SizeOf_j_xattr_val + 8 + k_SizeOf_j_dstream != pair.Val.Size())
+ return S_FALSE;
+ attr.Id = Get64(p4);
+ attr.dstream.Parse(p4 + 8);
+ attr.dstream_defined = true;
+ PRF(printf(" streamID=%d", (unsigned)attr.Id));
+ }
+ else
+ {
+ // unknown attribute
+ // UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+
+ if (vol.NodeIDs.IsEmpty() ||
+ vol.NodeIDs.Back() != id)
+ {
+ return S_FALSE;
+ // UnsupportedFeature = true;
+ // continue;
+ }
+ CNode &inode = vol.Nodes.Back();
+ if (attr.Name.IsEqualTo("com.apple.fs.symlink"))
+ {
+ inode.SymLinkIndex = inode.Attrs.Size();
+ if (attr.Is_dstream_OK_for_SymLink())
+ NeedReadSymLink = true;
+ }
+ else
+ vol.NumAltStreams++;
+ inode.Attrs.Add(attr);
+ continue;
+ }
+
+ if (type == APFS_TYPE_DSTREAM_ID)
+ {
+ PRF(printf(" DSTREAM_ID"));
+ if (pair.Key.Size() != 8)
+ return S_FALSE;
+ // j_dstream_id_val_t
+ if (pair.Val.Size() != 4)
+ return S_FALSE;
+ const UInt32 refcnt = Get32(pair.Val);
+
+ // The data stream record can be deleted when its reference count reaches zero.
+ PRF(printf(" refcnt = %8d", (unsigned)refcnt));
+
+ if (vol.NodeIDs.IsEmpty())
+ return S_FALSE;
+
+ if (vol.NodeIDs.Back() != id)
+ {
+ // is it possible ?
+ // continue;
+ return S_FALSE;
+ }
+
+ CNode &inode = vol.Nodes.Back();
+
+ if (inode.refcnt_defined)
+ return S_FALSE;
+
+ inode.refcnt = refcnt;
+ inode.refcnt_defined = true;
+ if (inode.refcnt != (UInt32)inode.nlink)
+ {
+ // is it possible ?
+ // return S_FALSE;
+ }
+ continue;
+ }
+
+ if (type == APFS_TYPE_FILE_EXTENT)
+ {
+ PRF(printf(" FILE_EXTENT"));
+ /*
+ struct j_file_extent_key
+ {
+ j_key_t hdr;
+ uint64_t logical_addr;
+ }
+ */
+ if (pair.Key.Size() != 16)
+ return S_FALSE;
+ // The offset within the file's data, in bytes, for the data stored in this extent
+ const UInt64 logical_addr = Get64(p + 8);
+
+ j_file_extent_val eval;
+ if (pair.Val.Size() != k_SizeOf_j_file_extent_val)
+ return S_FALSE;
+ eval.Parse(pair.Val);
+
+ if (logical_addr != 0)
+ {
+ PRF(printf(" logical_addr = %d", (unsigned)logical_addr));
+ }
+ PRF(printf(" len = %8d pos = %8d",
+ (unsigned)eval.len_and_flags,
+ (unsigned)eval.phys_block_num
+ ));
+
+ CExtent ext;
+ ext.logical_offset = logical_addr;
+ ext.len_and_flags = eval.len_and_flags;
+ ext.phys_block_num = eval.phys_block_num;
+
+ if (vol.NodeIDs.IsEmpty())
+ return S_FALSE;
+ if (vol.NodeIDs.Back() != id)
+ {
+ // extents for Attributs;
+ if (vol.SmallNodeIDs.IsEmpty() ||
+ vol.SmallNodeIDs.Back() != id)
+ {
+ vol.SmallNodeIDs.Add(id);
+ vol.SmallNodes.AddNew();
+ }
+ vol.SmallNodes.Back().Extents.Add(ext);
+ continue;
+ // return S_FALSE;
+ }
+
+ CNode &inode = vol.Nodes.Back();
+ inode.Extents.Add(ext);
+ continue;
+ }
+
+ if (type == APFS_TYPE_DIR_REC)
+ {
+ UInt32 len;
+ unsigned nameOffset;
+
+ if (isHashed)
+ {
+ /*
+ struct j_drec_hashed_key
+ {
+ j_key_t hdr;
+ UInt32 name_len_and_hash;
+ uint8_t name[0];
+ }
+ */
+ nameOffset = 8 + 4;
+ if (pair.Key.Size() < nameOffset + 1)
+ return S_FALSE;
+ const UInt32 name_len_and_hash = Get32(p + 8);
+ len = name_len_and_hash & J_DREC_LEN_MASK;
+ }
+ else
+ {
+ /*
+ struct j_drec_key
+ {
+ j_key_t hdr;
+ UInt16 name_len; // The length of the name, including the final null character
+ uint8_t name[0]; // The name, represented as a null-terminated UTF-8 string
+ }
+ */
+ nameOffset = 8 + 2;
+ if (pair.Key.Size() < nameOffset + 1)
+ return S_FALSE;
+ len = Get16(p + 8);
+ }
+ if (nameOffset + len != pair.Key.Size())
+ return S_FALSE;
+ CItem item;
+ item.ParentId = id;
+ item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
+ if (item.Name.Len() != len - 1)
+ return S_FALSE;
+
+ if (pair.Val.Size() < k_SizeOf_j_drec_val)
+ return S_FALSE;
+
+ item.Val.Parse(pair.Val);
+
+ if (pair.Val.Size() > k_SizeOf_j_drec_val)
+ {
+ // fixme: parse extra fields;
+ // UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+
+ vol.Items.Add(item);
+
+ /*
+ if (!vol.NodeIDs.IsEmpty() && vol.NodeIDs.Back() == id)
+ vol.Nodes.Back().NumItems++;
+ */
+ if (id == PRIV_DIR_INO_NUM)
+ vol.NumItems_In_PrivateDir++;
+
+ PRF(printf(" next=%6d flags=%2x %s",
+ (unsigned)item.Val.file_id,
+ (unsigned)item.Val.flags,
+ item.Name.Ptr()));
+ continue;
+ }
+
+ UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+ ProgressVal_NumFilesTotal += vol.Items.Size();
+ }
+
+ if (NeedReadSymLink)
+ {
+ /* we read external streams for SymLinks to CAttr.Data
+ So we can get SymLink for GetProperty(kpidSymLink) later */
+ FOR_VECTOR (i, vol.Nodes)
+ {
+ CNode &node = vol.Nodes[i];
+ if (IsViNotDef(node.SymLinkIndex))
+ continue;
+ CAttr &attr = node.Attrs[(unsigned)node.SymLinkIndex];
+ // FOR_VECTOR (k, node.Attrs) { CAttr &attr = node.Attrs[(unsigned)k]; // for debug
+ if (attr.Data.Size() != 0
+ || !attr.Is_dstream_OK_for_SymLink())
+ continue;
+ const UInt32 size = (UInt32)attr.dstream.size;
+ const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
+ if (idIndex == -1)
+ continue;
+ CMyComPtr<ISequentialInStream> inStream;
+ const HRESULT res = GetStream2(
+ OpenInStream,
+ &vol.SmallNodes[(unsigned)idIndex].Extents,
+ size, &inStream);
+ if (res == S_OK && inStream)
+ {
+ CByteBuffer buf2;
+ buf2.Alloc(size);
+ if (ReadStream_FAIL(inStream, buf2, size) == S_OK)
+ attr.Data = buf2;
+ }
+ }
+ }
+
+ const HRESULT res = vol.FillRefs();
+
+ if (vol.ThereAreErrors())
+ HeadersError = true;
+ if (vol.UnsupportedFeature)
+ UnsupportedFeature = true;
+ if (vol.NumAltStreams != 0)
+ ThereAreAltStreams = true;
+
+ return res;
+}
+
+
+
+HRESULT CVol::FillRefs()
+{
+ {
+ // we fill Refs[*]
+ // we
+ // and set Nodes[*].ItemIndex for Nodes that are dictories;
+ FOR_VECTOR (i, Items)
+ {
+ CItem &item = Items[i];
+ const UInt64 id = item.Val.file_id;
+ // if (item.Id == ROOT_DIR_PARENT) continue;
+ /* for two root folders items
+ we don't set Node.ItemIndex; */
+ // so nodes
+ if (id == ROOT_DIR_INO_NUM)
+ continue;
+ if (id == PRIV_DIR_INO_NUM)
+ if (NumItems_In_PrivateDir == 0) // if (inode.NumItems == 0)
+ continue;
+
+ CRef ref;
+ ref.ItemIndex = i;
+ // ref.NodeIndex = VI_MINUS1;
+ ref.ParentRefIndex = VI_MINUS1;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ ref.AttrIndex = VI_MINUS1;
+ #endif
+ const int index = NodeIDs.FindInSorted(id);
+ // const int index = -1; // for debug
+ ref.NodeIndex = (unsigned)index;
+ item.RefIndex = Refs.Size();
+ Refs.Add(ref);
+
+ if (index == -1)
+ {
+ NodeNotFound = true;
+ continue;
+ // return S_FALSE;
+ }
+
+ // item.iNode_Index = index;
+ CNode &inode = Nodes[(unsigned)index];
+ if (!item.Val.IsFlags_Unknown()
+ && inode.Get_Type_From_mode() != item.Val.flags)
+ {
+ Refs.Back().NodeIndex = VI_MINUS1;
+ WrongInodeLink = true;
+ continue;
+ // return S_FALSE;
+ }
+
+ const bool isDir = inode.IsDir();
+ if (isDir)
+ {
+ if (IsViDef(inode.ItemIndex))
+ {
+ // hard links to dirs are not supported
+ Refs.Back().NodeIndex = VI_MINUS1;
+ WrongInodeLink = true;
+ continue;
+ }
+ inode.ItemIndex = i;
+ }
+ inode.NumCalcedLinks++;
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!isDir)
+ {
+ // we use alt streams only for files
+ const unsigned numAttrs = inode.Attrs.Size();
+ if (numAttrs != 0)
+ {
+ ref.ParentRefIndex = item.RefIndex;
+ for (unsigned k = 0; k < numAttrs; k++)
+ {
+ if (k == inode.SymLinkIndex)
+ continue;
+ ref.AttrIndex = k;
+ Refs.Add(ref);
+ /*
+ const CAttr &attr = inode.Attrs[k];
+ if (attr.dstream_defined)
+ {
+ const int idIndex = SmallNodeIDs.FindInSorted(attr.Id);
+ if (idIndex != -1)
+ SmallNodes[(unsigned)idIndex].NumLinks++; // for debug
+ }
+ */
+ }
+ }
+ }
+ #endif
+ }
+ }
+
+
+ {
+ // fill ghost nodes
+ CRef ref;
+ ref.ItemIndex = VI_MINUS1;
+ ref.ParentRefIndex = VI_MINUS1;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ ref.AttrIndex = VI_MINUS1;
+ #endif
+ FOR_VECTOR (i, Nodes)
+ {
+ if (Nodes[i].NumCalcedLinks != 0)
+ continue;
+ const UInt64 id = NodeIDs[i];
+ if (id == ROOT_DIR_INO_NUM ||
+ id == PRIV_DIR_INO_NUM)
+ continue;
+ ThereAreUnlinkedNodes = true;
+ ref.NodeIndex = i;
+ Refs.Add(ref);
+ }
+ }
+
+ /* if want to create Refs for ghost data streams,
+ we need additional CRef::SmallNodeIndex field */
+
+ {
+ /* all Nodes[*].ItemIndex were already filled for directory Nodes,
+ except of "root" and "private-dir" Nodes. */
+
+ // now we fill Items[*].ParentItemIndex and Refs[*].ParentRefIndex
+
+ UInt64 prev_ID = (UInt64)(Int64)-1;
+ unsigned prev_ParentItemIndex = VI_MINUS1;
+
+ FOR_VECTOR (i, Items)
+ {
+ CItem &item = Items[i];
+ const UInt64 id = item.ParentId; // it's id of parent NODE
+ if (id != prev_ID)
+ {
+ prev_ID = id;
+ prev_ParentItemIndex = VI_MINUS1;
+ const int index = NodeIDs.FindInSorted(id);
+ if (index == -1)
+ continue;
+ prev_ParentItemIndex = Nodes[(unsigned)index].ItemIndex;
+ }
+
+ if (IsViNotDef(prev_ParentItemIndex))
+ continue;
+ item.ParentItemIndex = prev_ParentItemIndex;
+ if (IsViNotDef(item.RefIndex))
+ {
+ // RefIndex is not set for 2 Items (root folders)
+ // but there is no node for them usually
+ continue;
+ }
+ CRef &ref = Refs[item.RefIndex];
+
+ /*
+ // it's optional check that parent_id is set correclty
+ if (IsViDef(ref.NodeIndex))
+ {
+ const CNode &node = Nodes[ref.NodeIndex];
+ if (node.IsDir() && node.parent_id != id)
+ return S_FALSE;
+ }
+ */
+
+ /*
+ if (id == ROOT_DIR_INO_NUM)
+ {
+ // ItemIndex in Node for ROOT_DIR_INO_NUM was not set bofere
+ // probably unused now.
+ ref.ParentRefIndex = VI_MINUS1;
+ }
+ else
+ */
+ ref.ParentRefIndex = Items[prev_ParentItemIndex].RefIndex;
+ }
+ }
+
+ {
+ // check for loops
+ const unsigned numItems = Items.Size();
+ if (numItems + 1 == 0)
+ return S_FALSE;
+ CUIntArr arr;
+ arr.Alloc(numItems);
+ {
+ for (unsigned i = 0; i < numItems; i++)
+ arr[i] = 0;
+ }
+ for (unsigned i = 0; i < numItems;)
+ {
+ unsigned k = i++;
+ for (;;)
+ {
+ const unsigned a = arr[k];
+ if (a != 0)
+ {
+ if (a == i)
+ return S_FALSE;
+ break;
+ }
+ arr[k] = i;
+ k = Items[k].ParentItemIndex;
+ if (IsViNotDef(k))
+ break;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+class CHandler:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ public CDatabase
+{
+ CMyComPtr<IInStream> _stream;
+public:
+ MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ INTERFACE_IArchiveGetRawProps(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ OpenInStream = inStream;
+ OpenCallback = callback;
+ RINOK(Open2());
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ Clear();
+ return S_OK;
+}
+
+
+enum
+{
+ kpidBytesWritten = kpidUserDefined,
+ kpidBytesRead,
+ kpidPrimeName,
+ kpidParentINode,
+ kpidAddTime,
+ kpidGeneration,
+ kpidBsdFlags
+};
+
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR },
+ { NULL, kpidSize, VT_UI8 },
+ { NULL, kpidPackSize, VT_UI8 },
+ { NULL, kpidPosixAttrib, VT_UI4 },
+ { NULL, kpidMTime, VT_FILETIME },
+ { NULL, kpidCTime, VT_FILETIME },
+ { NULL, kpidATime, VT_FILETIME },
+ { NULL, kpidChangeTime, VT_FILETIME },
+ { "Added Time", kpidAddTime, VT_FILETIME },
+ { NULL, kpidINode, VT_UI8 },
+ { NULL, kpidLinks, VT_UI4 },
+ { NULL, kpidSymLink, VT_BSTR },
+ { NULL, kpidUserId, VT_UI4 },
+ { NULL, kpidGroupId, VT_UI4 },
+ #ifdef APFS_SHOW_ALT_STREAMS
+ { NULL, kpidIsAltStream, VT_BOOL },
+ #endif
+ { "Parent iNode", kpidParentINode, VT_UI8 },
+ { "Primary Name", kpidPrimeName, VT_BSTR },
+ { "Generation", kpidGeneration, VT_UI4 },
+ { "Written Size", kpidBytesWritten, VT_UI8 },
+ { "Read Size", kpidBytesRead, VT_UI8 },
+ { "BSD Flags", kpidBsdFlags, VT_UI4 }
+};
+
+
+static const Byte kArcProps[] =
+{
+ kpidName,
+ kpidId,
+ kpidClusterSize,
+ kpidCTime,
+ kpidMTime,
+ kpidComment
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps
+
+
+static void ApfsTimeToProp(UInt64 hfsTime, NWindows::NCOM::CPropVariant &prop)
+{
+ if (hfsTime == 0)
+ return;
+ FILETIME ft;
+ UInt32 ns100;
+ ApfsTimeToFileTime(hfsTime, ft, ns100);
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
+}
+
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CApfs *apfs = NULL;
+ if (Vols.Size() == 1)
+ apfs = &Vols[0].apfs;
+ switch (propID)
+ {
+ case kpidPhySize:
+ prop = (UInt64)sb.block_count << sb.block_size_Log;
+ break;
+ case kpidClusterSize: prop = (UInt32)(sb.block_size); break;
+ case kpidMTime:
+ if (apfs)
+ ApfsTimeToProp(apfs->modified_by[0].timestamp, prop);
+ break;
+ case kpidCTime:
+ if (apfs)
+ ApfsTimeToProp(apfs->formatted_by.timestamp, prop);
+ break;
+ case kpidIsTree: prop = true; break;
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ case kpidWarningFlags:
+ {
+ UInt32 flags = 0;
+ if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+
+ case kpidName:
+ {
+ if (apfs)
+ {
+ UString s;
+ AddVolInternalName_toString(s, *apfs);
+ s += ".apfs";
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidId:
+ {
+ char s[32 + 4];
+ sb.uuid.SetHex_To_str(s);
+ prop = s;
+ break;
+ }
+
+ case kpidComment:
+ {
+ UString s;
+ {
+ AddComment_UInt64(s, "block_size", sb.block_size);
+
+ FOR_VECTOR (i, Vols)
+ {
+ if (Vols.Size() > 1)
+ {
+ if (i != 0)
+ {
+ s += "----";
+ s.Add_LF();
+ }
+ AddComment_UInt64(s, "Volume", i + 1);
+ }
+ Vols[i].AddComment(s);
+ }
+ }
+ prop = s;
+ break;
+ }
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ case kpidIsAltStream:
+ prop = ThereAreAltStreams;
+ // prop = false; // for debug
+ break;
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
+{
+ *name = NULL;
+ *propID = 0;
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)
+{
+ *parentType = NParentType::kDir;
+
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ UInt32 parentIndex = (UInt32)(Int32)-1;
+ *parentType = NParentType::kDir;
+
+ if (IsViDef(ref2.RefIndex))
+ {
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (ref.IsAltStream())
+ *parentType = NParentType::kAltStream;
+ #endif
+ if (IsViDef(ref.ParentRefIndex))
+ parentIndex = (UInt32)(ref.ParentRefIndex + vol.StartRef2Index);
+ else if (index != vol.RootRef2Index && IsViDef(vol.RootRef2Index))
+ parentIndex = (UInt32)vol.RootRef2Index;
+ }
+
+ *parent = parentIndex;
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ UNUSED_VAR(index);
+ UNUSED_VAR(propID);
+ return S_OK;
+}
+
+
+static void Utf8Name_to_InterName(const AString &src, UString &dest)
+{
+ ConvertUTF8ToUnicode(src, dest);
+ NItemName::NormalizeSlashes_in_FileName_for_OsPath(dest);
+}
+
+
+static void AddNodeName(UString &s, const CNode &inode, UInt64 id)
+{
+ s += "node";
+ s.Add_UInt64(id);
+ if (!inode.PrimaryName.IsEmpty())
+ {
+ s += '.';
+ UString s2;
+ Utf8Name_to_InterName(inode.PrimaryName, s2);
+ s += s2;
+ }
+}
+
+
+void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const
+{
+ const unsigned kNumLevelsMax = (1 << 10);
+ const unsigned kLenMax = (1 << 12);
+ UString s;
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+
+ if (IsViDef(ref2.RefIndex))
+ {
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ unsigned cur = ref.ItemIndex;
+ if (IsViNotDef(cur))
+ {
+ if (inode)
+ AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]);
+ }
+ else
+ {
+ for (unsigned i = 0;; i++)
+ {
+ if (i >= kNumLevelsMax || s.Len() > kLenMax)
+ {
+ s.Insert(0, UString("[LONG_PATH]"));
+ break;
+ }
+ const CItem &item = vol.Items[(unsigned)cur];
+ UString s2;
+ Utf8Name_to_InterName(item.Name, s2);
+ // s2 += "a\\b"; // for debug
+ s.Insert(0, s2);
+ cur = item.ParentItemIndex;
+ if (IsViNotDef(cur))
+ break;
+ // ParentItemIndex was not set for sch items
+ // if (item.ParentId == ROOT_DIR_INO_NUM) break;
+ s.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ }
+ }
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (IsViDef(ref.AttrIndex) && inode)
+ {
+ s += ':';
+ UString s2;
+ Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2);
+ // s2 += "a\\b"; // for debug
+ s += s2;
+ }
+ #endif
+ }
+
+ if (!vol.RootName.IsEmpty())
+ {
+ if (IsViDef(ref2.RefIndex))
+ s.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ s.Insert(0, vol.RootName);
+ }
+
+ path = s;
+}
+
+
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+
+ if (IsViNotDef(ref2.RefIndex))
+ {
+ switch (propID)
+ {
+ case kpidName:
+ case kpidPath:
+ GetItemPath(index, NULL, prop);
+ break;
+ case kpidIsDir:
+ prop = true;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+
+ const CItem *item = NULL;
+ if (IsViDef(ref.ItemIndex))
+ item = &vol.Items[ref.ItemIndex];
+
+ const CNode *inode = NULL;
+ if (IsViDef(ref.NodeIndex))
+ inode = &vol.Nodes[ref.NodeIndex];
+
+ switch (propID)
+ {
+ case kpidPath:
+ GetItemPath(index, inode, prop);
+ break;
+ case kpidPrimeName:
+ {
+ if (inode
+ #ifdef APFS_SHOW_ALT_STREAMS
+ && !ref.IsAltStream()
+ #endif
+ && !inode->PrimaryName.IsEmpty())
+ {
+ UString s;
+ ConvertUTF8ToUnicode(inode->PrimaryName, s);
+ /*
+ // for debug:
+ if (inode.PrimaryName != item.Name) throw 123456;
+ */
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidName:
+ {
+ UString s;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (ref.IsAltStream())
+ {
+ // if (inode)
+ {
+ const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex];
+ ConvertUTF8ToUnicode(attr.Name, s);
+ }
+ }
+ else
+ #endif
+ {
+ if (item)
+ ConvertUTF8ToUnicode(item->Name, s);
+ else if (inode)
+ AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]);
+ else
+ break;
+ }
+ // s += "s/1bs\\2"; // for debug:
+ prop = s;
+ break;
+ }
+
+ case kpidSymLink:
+ if (inode)
+ {
+ if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex))
+ {
+ const CByteBuffer &buf = inode->Attrs[(unsigned)inode->SymLinkIndex].Data;
+ if (buf.Size() != 0)
+ {
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const Byte *)buf, (unsigned)buf.Size());
+ if (s.Len() == buf.Size() - 1)
+ {
+ UString u;
+ ConvertUTF8ToUnicode(s, u);
+ prop = u;
+ }
+ }
+ }
+ }
+ break;
+
+ case kpidSize:
+ if (inode)
+ {
+ UInt64 size;
+ if (inode->GetSize(ref.GetAttrIndex(), size))
+ prop = size;
+ }
+ break;
+
+ case kpidPackSize:
+ if (inode)
+ {
+ UInt64 size;
+ if (inode->GetPackSize(ref.GetAttrIndex(), size))
+ prop = size;
+ }
+ break;
+
+ case kpidIsDir:
+ {
+ bool isDir = false;
+ if (inode)
+ isDir = inode->IsDir();
+ else if (item)
+ isDir = item->Val.IsFlags_Dir();
+ prop = isDir;
+ break;
+ }
+
+ case kpidPosixAttrib:
+ {
+ if (inode)
+ {
+ UInt32 mode = inode->mode;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (ref.IsAltStream())
+ {
+ mode &= 0666; // we disable execution
+ mode |= MY_LIN_S_IFREG;
+ }
+ #endif
+ prop = (UInt32)mode;
+ }
+ else if (item && !item->Val.IsFlags_Unknown())
+ prop = (UInt32)(item->Val.flags << 12);
+ break;
+ }
+
+ case kpidCTime: if (inode) ApfsTimeToProp(inode->create_time, prop); break;
+ case kpidMTime: if (inode) ApfsTimeToProp(inode->mod_time, prop); break;
+ case kpidATime: if (inode) ApfsTimeToProp(inode->access_time, prop); break;
+ case kpidChangeTime: if (inode) ApfsTimeToProp(inode->change_time, prop); break;
+ case kpidAddTime: if (item) ApfsTimeToProp(item->Val.date_added, prop); break;
+
+ case kpidBytesWritten:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode && inode->dstream_defined)
+ prop = inode->dstream.total_bytes_written;
+ break;
+ case kpidBytesRead:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode && inode->dstream_defined)
+ prop = inode->dstream.total_bytes_read;
+ break;
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ case kpidIsAltStream:
+ prop = ref.IsAltStream();
+ break;
+ #endif
+
+ case kpidCharacts:
+ if (inode)
+ {
+ FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop);
+ }
+ break;
+
+ case kpidBsdFlags:
+ if (inode)
+ {
+ FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop);
+ }
+ break;
+
+ case kpidGeneration:
+ if (inode)
+ prop = inode->write_generation_counter;
+ break;
+
+ case kpidUserId:
+ if (inode)
+ prop = (UInt32)inode->owner;
+ break;
+
+ case kpidGroupId:
+ if (inode)
+ prop = (UInt32)inode->group;
+ break;
+
+ case kpidLinks:
+ if (inode && !inode->IsDir())
+ prop = (UInt32)inode->nlink;
+ break;
+
+ case kpidINode:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ // here we can disable iNode for alt stream.
+ // if (!ref.IsAltStream())
+ #endif
+ if (IsViDef(ref.NodeIndex))
+ prop = (UInt32)vol.NodeIDs[ref.NodeIndex];
+ break;
+
+ case kpidParentINode:
+ if (inode)
+ prop = (UInt32)inode->parent_id;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+UInt64 CDatabase::GetSize(const UInt32 index) const
+{
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ if (IsViNotDef(ref2.RefIndex))
+ return 0;
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ if (IsViNotDef(ref.NodeIndex))
+ return 0;
+ const CNode &inode = vol.Nodes[ref.NodeIndex];
+ UInt64 size;
+ if (inode.GetSize(ref.GetAttrIndex(), size))
+ return size;
+ return 0;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = Refs2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+
+ {
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ totalSize += GetSize(index);
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+ }
+
+ UInt64 currentTotalSize = 0, currentItemSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = currentTotalSize;
+ lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+
+ currentItemSize = GetSize(index);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (IsViNotDef(ref2.RefIndex))
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ bool isDir = false;
+ if (IsViDef(ref.NodeIndex))
+ isDir = vol.Nodes[ref.NodeIndex].IsDir();
+ else if (IsViDef(ref.ItemIndex))
+ isDir =
+ #ifdef APFS_SHOW_ALT_STREAMS
+ !ref.IsAltStream() &&
+ #endif
+ vol.Items[ref.ItemIndex].Val.IsFlags_Dir();
+
+ if (isDir)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ int opRes = NExtract::NOperationResult::kDataError;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ if (GetStream(index, &inStream) == S_OK && inStream)
+ {
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ opRes = NExtract::NOperationResult::kDataError;
+ if (copyCoderSpec->TotalSize == currentItemSize)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (copyCoderSpec->TotalSize < currentItemSize)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = Refs2.Size();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ *stream = NULL;
+
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ if (IsViNotDef(ref2.RefIndex))
+ return S_FALSE;
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ if (IsViNotDef(ref.NodeIndex))
+ return S_FALSE;
+ const CNode &inode = vol.Nodes[ref.NodeIndex];
+
+ const CRecordVector<CExtent> *extents;
+ UInt64 rem = 0;
+
+ unsigned attrIndex = ref.GetAttrIndex();
+
+ if (IsViNotDef(attrIndex)
+ && !inode.dstream_defined
+ && inode.IsSymLink())
+ {
+ attrIndex = inode.SymLinkIndex;
+ if (IsViNotDef(attrIndex))
+ return S_FALSE;
+ }
+
+ if (IsViDef(attrIndex))
+ {
+ const CAttr &attr = inode.Attrs[(unsigned)attrIndex];
+ if (!attr.dstream_defined)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
+ if (idIndex == -1)
+ return S_FALSE;
+ extents = &vol.SmallNodes[(unsigned)idIndex].Extents;
+ rem = attr.dstream.size;
+ }
+ else
+ {
+ if (IsViDef(ref.ItemIndex))
+ if (vol.Items[ref.ItemIndex].Val.IsFlags_Dir())
+ return S_FALSE;
+ if (inode.IsDir())
+ return S_FALSE;
+ if (inode.dstream_defined)
+ rem = inode.dstream.size;
+ extents = &inode.Extents;
+ }
+ return GetStream2(_stream, extents, rem, stream);
+}
+
+
+
+HRESULT CDatabase::GetStream2(
+ IInStream *apfsInStream,
+ const CRecordVector<CExtent> *extents, UInt64 rem,
+ ISequentialInStream **stream)
+{
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ UInt64 virt = 0;
+ FOR_VECTOR (i, *extents)
+ {
+ const CExtent &e = (*extents)[i];
+ if (virt != e.logical_offset)
+ return S_FALSE;
+ const UInt64 len = EXTENT_GET_LEN(e.len_and_flags);
+ if (len == 0)
+ {
+ return S_FALSE;
+ // continue;
+ }
+ if (rem == 0)
+ return S_FALSE;
+ UInt64 cur = len;
+ if (cur > rem)
+ cur = rem;
+ CSeekExtent se;
+ se.Phy = (UInt64)e.phys_block_num << sb.block_size_Log;
+ se.Virt = virt;
+ virt += cur;
+ rem -= cur;
+ extentStreamSpec->Extents.Add(se);
+ if (rem == 0)
+ if (i != extents->Size() - 1)
+ return S_FALSE;
+ }
+
+ if (rem != 0)
+ return S_FALSE;
+
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virt;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Stream = apfsInStream;
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+
+REGISTER_ARC_I(
+ "APFS", "apfs img", NULL, 0xc3,
+ k_Signature,
+ k_SignatureOffset,
+ 0,
+ IsArc_APFS)
+
+}}
diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp
index 73e5fcb6..73e5fcb6 100644..100755
--- a/CPP/7zip/Archive/ApmHandler.cpp
+++ b/CPP/7zip/Archive/ApmHandler.cpp
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp
index 0bea8b4e..6cd72bb3 100644..100755
--- a/CPP/7zip/Archive/ArHandler.cpp
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -322,8 +322,8 @@ static const Byte kProps[] =
kpidSize,
kpidMTime,
kpidPosixAttrib,
- kpidUser,
- kpidGroup
+ kpidUserId,
+ kpidGroupId
};
IMP_IInArchive_Props
@@ -734,15 +734,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime:
{
if (item.MTime != 0)
- {
- FILETIME fileTime;
- NTime::UnixTimeToFileTime(item.MTime, fileTime);
- prop = fileTime;
- }
+ PropVariant_SetFrom_UnixTime(prop, item.MTime);
break;
}
- case kpidUser: if (item.User != 0) prop = item.User; break;
- case kpidGroup: if (item.Group != 0) prop = item.Group; break;
+ case kpidUserId: if (item.User != 0) prop = item.User; break;
+ case kpidGroupId: if (item.Group != 0) prop = item.Group; break;
case kpidPosixAttrib:
if (item.TextFileIndex < 0)
prop = item.Mode;
diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def
index 145516d7..145516d7 100644..100755
--- a/CPP/7zip/Archive/Archive.def
+++ b/CPP/7zip/Archive/Archive.def
diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def
index c7582742..c7582742 100644..100755
--- a/CPP/7zip/Archive/Archive2.def
+++ b/CPP/7zip/Archive/Archive2.def
diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp
index 6549b3d2..8a441bc2 100644..100755
--- a/CPP/7zip/Archive/ArchiveExports.cpp
+++ b/CPP/7zip/Archive/ArchiveExports.cpp
@@ -115,6 +115,7 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value
case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break;
case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break;
case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break;
+ case NArchive::NHandlerPropID::kTimeFlags: prop = (UInt32)arc.TimeFlags; break;
case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break;
// case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break;
diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp
index 0e353dca..125b9c20 100644..100755
--- a/CPP/7zip/Archive/ArjHandler.cpp
+++ b/CPP/7zip/Archive/ArjHandler.cpp
@@ -682,15 +682,7 @@ static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
{
if (dosTime == 0)
return;
- FILETIME localFileTime, utc;
- if (NTime::DosTimeToFileTime(dosTime, localFileTime))
- {
- if (!LocalFileTimeToFileTime(&localFileTime, &utc))
- utc.dwHighDateTime = utc.dwLowDateTime = 0;
- }
- else
- utc.dwHighDateTime = utc.dwLowDateTime = 0;
- prop = utc;
+ PropVariant_SetFrom_DosTime(prop, dosTime);
}
static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)
diff --git a/CPP/7zip/Archive/Base64Handler.cpp b/CPP/7zip/Archive/Base64Handler.cpp
index 63b4552e..63b4552e 100644..100755
--- a/CPP/7zip/Archive/Base64Handler.cpp
+++ b/CPP/7zip/Archive/Base64Handler.cpp
diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp
index b0c2f750..c89a53c5 100644..100755
--- a/CPP/7zip/Archive/Bz2Handler.cpp
+++ b/CPP/7zip/Archive/Bz2Handler.cpp
@@ -305,29 +305,91 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
+/*
+static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
+}
+
+static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
+}
+
+static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ const UInt64 *unpackSize,
+ const UInt64 *numBlocks)
+{
+ NCOM::CPropVariant sizeProp;
+ if (unpackSize)
+ {
+ sizeProp = *unpackSize;
+ RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
+ }
+
+ if (unpackSize)
+ {
+ RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
+ }
+ if (numBlocks)
+ {
+ NCOM::CPropVariant prop;
+ prop = *numBlocks;
+ RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop));
+ }
+ return S_OK;
+}
+*/
static HRESULT UpdateArchive(
UInt64 unpackSize,
ISequentialOutStream *outStream,
const CProps &props,
- IArchiveUpdateCallback *updateCallback)
+ IArchiveUpdateCallback *updateCallback
+ // , ArchiveUpdateCallbackArcProp *reportArcProp
+ )
{
- RINOK(updateCallback->SetTotal(unpackSize));
- CMyComPtr<ISequentialInStream> fileInStream;
- RINOK(updateCallback->GetStream(0, &fileInStream));
- CLocalProgress *localProgressSpec = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
- localProgressSpec->Init(updateCallback, true);
- NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
- CMyComPtr<ICompressCoder> encoder = encoderSpec;
- RINOK(props.SetCoderProps(encoderSpec, NULL));
- RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+ if (!fileInStream)
+ return S_FALSE;
+ {
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ UInt64 size;
+ if (streamGetSize->GetSize(&size) == S_OK)
+ unpackSize = size;
+ }
+ }
+ RINOK(updateCallback->SetTotal(unpackSize));
+ CLocalProgress *localProgressSpec = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
+ localProgressSpec->Init(updateCallback, true);
+ {
+ NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+ RINOK(props.SetCoderProps(encoderSpec, NULL));
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
+ /*
+ if (reportArcProp)
+ {
+ unpackSize = encoderSpec->GetInProcessedSize();
+ RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks));
+ }
+ */
+ }
+ }
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
-STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{
- *type = NFileTimeType::kUnix;
+ *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
+ // *timeType = NFileTimeType::kUnix;
return S_OK;
}
@@ -345,6 +407,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_FAIL;
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+ /*
+ CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
+ updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
+ */
+
if (IntToBool(newProps))
{
{
@@ -396,6 +463,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return NCompress::CopyStream(_stream, outStream, progress);
+ // return ReportArcProps(reportArcProp, NULL, NULL);
+
COM_TRY_END
}
@@ -410,7 +479,8 @@ REGISTER_ARC_IO(
"bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
k_Signature,
0,
- NArcInfoFlags::kKeepName,
- IsArc_BZip2)
+ NArcInfoFlags::kKeepName
+ , 0
+ , IsArc_BZip2)
}}
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
index c193434f..c193434f 100644..100755
--- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h
index af89abb6..af89abb6 100644..100755
--- a/CPP/7zip/Archive/Cab/CabBlockInStream.h
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
index fafd7aa0..804c921a 100644..100755
--- a/CPP/7zip/Archive/Cab/CabHandler.cpp
+++ b/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -295,15 +295,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime:
{
- FILETIME localFileTime, utcFileTime;
- if (NTime::DosTimeToFileTime(item.Time, localFileTime))
- {
- if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
- utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
- }
- else
- utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
- prop = utcFileTime;
+ PropVariant_SetFrom_DosTime(prop, item.Time);
break;
}
diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h
index 6f44b875..6f44b875 100644..100755
--- a/CPP/7zip/Archive/Cab/CabHandler.h
+++ b/CPP/7zip/Archive/Cab/CabHandler.h
diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp
index 370a2f1e..370a2f1e 100644..100755
--- a/CPP/7zip/Archive/Cab/CabHeader.cpp
+++ b/CPP/7zip/Archive/Cab/CabHeader.cpp
diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h
index 2f2bd109..2f2bd109 100644..100755
--- a/CPP/7zip/Archive/Cab/CabHeader.h
+++ b/CPP/7zip/Archive/Cab/CabHeader.h
diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp
index e11ce9d0..e11ce9d0 100644..100755
--- a/CPP/7zip/Archive/Cab/CabIn.cpp
+++ b/CPP/7zip/Archive/Cab/CabIn.cpp
diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h
index 39586d12..39586d12 100644..100755
--- a/CPP/7zip/Archive/Cab/CabIn.h
+++ b/CPP/7zip/Archive/Cab/CabIn.h
diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h
index 9a912d5e..9a912d5e 100644..100755
--- a/CPP/7zip/Archive/Cab/CabItem.h
+++ b/CPP/7zip/Archive/Cab/CabItem.h
diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp
index 0b5cc93a..0b5cc93a 100644..100755
--- a/CPP/7zip/Archive/Cab/CabRegister.cpp
+++ b/CPP/7zip/Archive/Cab/CabRegister.cpp
diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Cab/StdAfx.h
+++ b/CPP/7zip/Archive/Cab/StdAfx.h
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp
index 03e7ddd2..03e7ddd2 100644..100755
--- a/CPP/7zip/Archive/Chm/ChmHandler.cpp
+++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.h b/CPP/7zip/Archive/Chm/ChmHandler.h
index 884f391b..884f391b 100644..100755
--- a/CPP/7zip/Archive/Chm/ChmHandler.h
+++ b/CPP/7zip/Archive/Chm/ChmHandler.h
diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp
index f4916b68..f4916b68 100644..100755
--- a/CPP/7zip/Archive/Chm/ChmIn.cpp
+++ b/CPP/7zip/Archive/Chm/ChmIn.cpp
diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h
index f7b75d81..7cba0c71 100644..100755
--- a/CPP/7zip/Archive/Chm/ChmIn.h
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -84,6 +84,11 @@ struct CResetTable
// unsigned BlockSizeBits;
CRecordVector<UInt64> ResetOffsets;
+ CResetTable():
+ UncompressedSize(0),
+ CompressedSize(0)
+ {}
+
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
{
if (blockIndex >= ResetOffsets.Size())
@@ -118,6 +123,12 @@ struct CLzxInfo
CResetTable ResetTable;
+ CLzxInfo():
+ Version(0),
+ ResetIntervalBits(0),
+ CacheSize(0)
+ {}
+
unsigned GetNumDictBits() const
{
if (Version == 2 || Version == 3)
diff --git a/CPP/7zip/Archive/Chm/StdAfx.h b/CPP/7zip/Archive/Chm/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Chm/StdAfx.h
+++ b/CPP/7zip/Archive/Chm/StdAfx.h
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
index a1f643b7..a1f643b7 100644..100755
--- a/CPP/7zip/Archive/ComHandler.cpp
+++ b/CPP/7zip/Archive/ComHandler.cpp
diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp
index c8b67bd4..c8b67bd4 100644..100755
--- a/CPP/7zip/Archive/Common/CoderMixer2.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp
diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h
index f099ac3e..f099ac3e 100644..100755
--- a/CPP/7zip/Archive/Common/CoderMixer2.h
+++ b/CPP/7zip/Archive/Common/CoderMixer2.h
diff --git a/CPP/7zip/Archive/Common/DummyOutStream.cpp b/CPP/7zip/Archive/Common/DummyOutStream.cpp
index 7c4f5487..7c4f5487 100644..100755
--- a/CPP/7zip/Archive/Common/DummyOutStream.cpp
+++ b/CPP/7zip/Archive/Common/DummyOutStream.cpp
diff --git a/CPP/7zip/Archive/Common/DummyOutStream.h b/CPP/7zip/Archive/Common/DummyOutStream.h
index b5a51fc0..b5a51fc0 100644..100755
--- a/CPP/7zip/Archive/Common/DummyOutStream.h
+++ b/CPP/7zip/Archive/Common/DummyOutStream.h
diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp
index fc952fa8..fc952fa8 100644..100755
--- a/CPP/7zip/Archive/Common/FindSignature.cpp
+++ b/CPP/7zip/Archive/Common/FindSignature.cpp
diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h
index c359b9ed..c359b9ed 100644..100755
--- a/CPP/7zip/Archive/Common/FindSignature.h
+++ b/CPP/7zip/Archive/Common/FindSignature.h
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 89012204..1b9a93eb 100644..100755
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -240,34 +240,42 @@ void CSingleMethodProps::Init()
}
+HRESULT CSingleMethodProps::SetProperty(const wchar_t *name2, const PROPVARIANT &value)
+{
+ // processed = false;
+ UString name = name2;
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ if (name.IsPrefixedBy_Ascii_NoCase("x"))
+ {
+ UInt32 a = 9;
+ RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
+ _level = a;
+ AddProp_Level(a);
+ // processed = true;
+ return S_OK;
+ }
+ {
+ HRESULT hres;
+ if (SetCommonProperty(name, value, hres))
+ {
+ // processed = true;
+ return S_OK;
+ }
+ }
+ RINOK(ParseMethodFromPROPVARIANT(name, value));
+ return S_OK;
+}
+
+
HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
Init();
for (UInt32 i = 0; i < numProps; i++)
{
- UString name = names[i];
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
- const PROPVARIANT &value = values[i];
- if (name[0] == L'x')
- {
- UInt32 a = 9;
- RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
- _level = a;
- AddProp_Level(a);
- continue;
- }
- {
- HRESULT hres;
- if (SetCommonProperty(name, value, hres))
- {
- RINOK(hres)
- continue;
- }
- }
- RINOK(ParseMethodFromPROPVARIANT(names[i], value));
+ RINOK(SetProperty(names[i], values[i]));
}
return S_OK;
@@ -275,4 +283,29 @@ HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PR
#endif
+
+static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
+{
+ RINOK(PROPVARIANT_to_bool(prop, dest.Val));
+ dest.Def = true;
+ return S_OK;
+}
+
+HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed)
+{
+ processed = true;
+ if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); }
+ if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); }
+ if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); }
+ if (name.IsPrefixedBy_Ascii_NoCase("tp"))
+ {
+ UInt32 v = 0;
+ RINOK(ParsePropToUInt32(name.Ptr(2), prop, v));
+ Prec = v;
+ return S_OK;
+ }
+ processed = false;
+ return S_OK;
+}
+
}
diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h
index b3d07e9e..41ee189d 100644..100755
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -16,6 +16,7 @@ class CCommonMethodProps
protected:
void InitCommon()
{
+ // _Write_MTime = true;
#ifndef _7ZIP_ST
_numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
_numThreads_WasForced = false;
@@ -118,11 +119,36 @@ public:
CSingleMethodProps() { InitSingle(); }
int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values);
HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
};
#endif
+struct CHandlerTimeOptions
+{
+ CBoolPair Write_MTime;
+ CBoolPair Write_ATime;
+ CBoolPair Write_CTime;
+ UInt32 Prec;
+
+ void Init()
+ {
+ Write_MTime.Init();
+ Write_MTime.Val = true;
+ Write_ATime.Init();
+ Write_CTime.Init();
+ Prec = (UInt32)(Int32)-1;
+ }
+
+ CHandlerTimeOptions()
+ {
+ Init();
+ }
+
+ HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed);
+};
+
}
#endif
diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
index a2d68832..a2d68832 100644..100755
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h
index 31b761e4..31b761e4 100644..100755
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
index 905a863d..8caf1d14 100644..100755
--- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -79,6 +79,29 @@ void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool
}
+void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *name, unsigned len)
+{
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = name[i];
+ if (c == L'/')
+ c = L'_';
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ else if (c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
+ #endif
+ else
+ continue;
+ name[i] = c;
+ }
+}
+
+void NormalizeSlashes_in_FileName_for_OsPath(UString &name)
+{
+ NormalizeSlashes_in_FileName_for_OsPath(name.GetBuf(), name.Len());
+}
+
+
bool HasTailSlash(const AString &name, UINT
#if defined(_WIN32) && !defined(UNDER_CE)
codePage
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h
index 6a4d6c71..3f5f4e8a 100644..100755
--- a/CPP/7zip/Archive/Common/ItemNameUtils.h
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -14,6 +14,8 @@ UString GetOsPath(const UString &name);
UString GetOsPath_Remove_TailSlash(const UString &name);
void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false);
+void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len);
+void NormalizeSlashes_in_FileName_for_OsPath(UString &name);
bool HasTailSlash(const AString &name, UINT codePage);
diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp
index 162fc928..162fc928 100644..100755
--- a/CPP/7zip/Archive/Common/MultiStream.cpp
+++ b/CPP/7zip/Archive/Common/MultiStream.cpp
diff --git a/CPP/7zip/Archive/Common/MultiStream.h b/CPP/7zip/Archive/Common/MultiStream.h
index c10cd455..c10cd455 100644..100755
--- a/CPP/7zip/Archive/Common/MultiStream.h
+++ b/CPP/7zip/Archive/Common/MultiStream.h
diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
index f955c225..f955c225 100644..100755
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
index 09b899bb..09b899bb 100644..100755
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
index ac26edf7..ac26edf7 100644..100755
--- a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
index 5a7bfef3..5a7bfef3 100644..100755
--- a/CPP/7zip/Archive/Common/OutStreamWithSha1.h
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
diff --git a/CPP/7zip/Archive/Common/ParseProperties.cpp b/CPP/7zip/Archive/Common/ParseProperties.cpp
index 63e4f3ef..63e4f3ef 100644..100755
--- a/CPP/7zip/Archive/Common/ParseProperties.cpp
+++ b/CPP/7zip/Archive/Common/ParseProperties.cpp
diff --git a/CPP/7zip/Archive/Common/ParseProperties.h b/CPP/7zip/Archive/Common/ParseProperties.h
index 1038a8c0..1038a8c0 100644..100755
--- a/CPP/7zip/Archive/Common/ParseProperties.h
+++ b/CPP/7zip/Archive/Common/ParseProperties.h
diff --git a/CPP/7zip/Archive/Common/StdAfx.h b/CPP/7zip/Archive/Common/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Common/StdAfx.h
+++ b/CPP/7zip/Archive/Common/StdAfx.h
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index ffdab16c..b7e7564f 100644..100755
--- a/CPP/7zip/Archive/CpioHandler.cpp
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -652,11 +652,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime:
{
if (item.MTime != 0)
- {
- FILETIME utc;
- NTime::UnixTimeToFileTime(item.MTime, utc);
- prop = utc;
- }
+ PropVariant_SetFrom_UnixTime(prop, item.MTime);
break;
}
case kpidPosixAttrib: prop = item.Mode; break;
diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp
index 0f123321..0f123321 100644..100755
--- a/CPP/7zip/Archive/CramfsHandler.cpp
+++ b/CPP/7zip/Archive/CramfsHandler.cpp
diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp
index ca3dc6f5..ca3dc6f5 100644..100755
--- a/CPP/7zip/Archive/DeflateProps.cpp
+++ b/CPP/7zip/Archive/DeflateProps.cpp
diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h
index 9fd2c2e9..9fd2c2e9 100644..100755
--- a/CPP/7zip/Archive/DeflateProps.h
+++ b/CPP/7zip/Archive/DeflateProps.h
diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp
index 7aee235e..7aee235e 100644..100755
--- a/CPP/7zip/Archive/DllExports.cpp
+++ b/CPP/7zip/Archive/DllExports.cpp
diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp
index 967a7cbf..1f714861 100644..100755
--- a/CPP/7zip/Archive/DllExports2.cpp
+++ b/CPP/7zip/Archive/DllExports2.cpp
@@ -125,6 +125,24 @@ STDAPI SetCaseSensitive(Int32 caseSensitive)
return S_OK;
}
+/*
+UInt32 g_ClientVersion;
+STDAPI SetClientVersion(UInt32 version);
+STDAPI SetClientVersion(UInt32 version)
+{
+ g_ClientVersion = version;
+ return S_OK;
+}
+*/
+
+/*
+STDAPI SetProperty(Int32 id, const PROPVARIANT *value);
+STDAPI SetProperty(Int32 id, const PROPVARIANT *value)
+{
+ return S_OK;
+}
+*/
+
#ifdef EXTERNAL_CODECS
CExternalCodecs g_ExternalCodecs;
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp
index 1f2ca264..1f2ca264 100644..100755
--- a/CPP/7zip/Archive/DmgHandler.cpp
+++ b/CPP/7zip/Archive/DmgHandler.cpp
diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp
index efcde95d..efcde95d 100644..100755
--- a/CPP/7zip/Archive/ElfHandler.cpp
+++ b/CPP/7zip/Archive/ElfHandler.cpp
diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp
index 6c095d9a..01e12edc 100644..100755
--- a/CPP/7zip/Archive/ExtHandler.cpp
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -343,6 +343,8 @@ struct CHeader
bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; }
bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; }
+ UInt64 GetPhySize() const { return NumBlocks << BlockBits; }
+
bool Parse(const Byte *p);
};
@@ -638,7 +640,7 @@ struct CNode
CExtTime MTime;
CExtTime ATime;
CExtTime CTime;
- // CExtTime InodeChangeTime;
+ CExtTime ChangeTime;
// CExtTime DTime;
UInt64 NumBlocks;
@@ -674,14 +676,14 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
ATime.Extra = 0;
CTime.Extra = 0;
CTime.Val = 0;
- // InodeChangeTime.Extra = 0;
+ ChangeTime.Extra = 0;
// DTime.Extra = 0;
LE_16 (0x00, Mode);
LE_16 (0x02, Uid);
LE_32 (0x04, FileSize);
LE_32 (0x08, ATime.Val);
- // LE_32 (0x0C, InodeChangeTime.Val);
+ LE_32 (0x0C, ChangeTime.Val);
LE_32 (0x10, MTime.Val);
// LE_32 (0x14, DTime.Val);
LE_16 (0x18, Gid);
@@ -742,7 +744,7 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
{
// UInt16 checksumUpper;
// LE_16 (0x82, checksumUpper);
- // LE_32 (0x84, InodeChangeTime.Extra);
+ LE_32 (0x84, ChangeTime.Extra);
LE_32 (0x88, MTime.Extra);
LE_32 (0x8C, ATime.Extra);
LE_32 (0x90, CTime.Val);
@@ -1148,7 +1150,7 @@ HRESULT CHandler::Open2(IInStream *inStream)
}
_isArc = true;
- _phySize = _h.NumBlocks << _h.BlockBits;
+ _phySize = _h.GetPhySize();
if (_openCallback)
{
@@ -1744,8 +1746,8 @@ static const UInt32 kProps[] =
kpidLinks,
kpidSymLink,
kpidCharacts,
- kpidUser,
- kpidGroup
+ kpidUserId,
+ kpidGroupId
};
@@ -1792,11 +1794,7 @@ static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVa
static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop)
{
if (val != 0)
- {
- FILETIME ft;
- NTime::UnixTimeToFileTime(val, ft);
- prop = ft;
- }
+ PropVariant_SetFrom_UnixTime(prop, val);
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
@@ -1988,15 +1986,19 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
return;
FILETIME ft;
+ unsigned low100ns = 0;
// if (t.Extra != 0)
{
// 1901-2446 :
Int64 v = (Int64)(Int32)t.Val;
v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp
- UInt64 ft64 = NTime::UnixTime64ToFileTime64(v);
+ UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v);
const UInt32 ns = (t.Extra >> 2);
if (ns < 1000000000)
+ {
ft64 += ns / 100;
+ low100ns = (unsigned)(ns % 100);
+ }
ft.dwLowDateTime = (DWORD)ft64;
ft.dwHighDateTime = (DWORD)(ft64 >> 32);
}
@@ -2011,7 +2013,7 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
// NTime::UnixTimeToFileTime(t.Val, ft); // for
}
*/
- prop = ft;
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns);
}
@@ -2103,10 +2105,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidCTime: ExtTimeToProp(node.CTime, prop); break;
case kpidATime: ExtTimeToProp(node.ATime, prop); break;
// case kpidDTime: ExtTimeToProp(node.DTime, prop); break;
- // case kpidChangeTime: ExtTimeToProp(node.InodeChangeTime, prop); break;
-
- case kpidUser: prop = (UInt32)node.Uid; break;
- case kpidGroup: prop = (UInt32)node.Gid; break;
+ case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break;
+ case kpidUserId: prop = (UInt32)node.Uid; break;
+ case kpidGroupId: prop = (UInt32)node.Gid; break;
case kpidLinks: prop = node.NumLinks; break;
case kpidINode: prop = (UInt32)item.Node; break;
case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break;
@@ -2827,17 +2828,29 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
}
-API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size)
+API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
+API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize)
{
+ if (phySize)
+ *phySize = 0;
if (size < kHeaderSize)
return k_IsArc_Res_NEED_MORE;
CHeader h;
if (!h.Parse(p + kHeaderDataOffset))
return k_IsArc_Res_NO;
+ if (phySize)
+ *phySize = h.GetPhySize();
return k_IsArc_Res_YES;
}
+
+
+API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
+API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size)
+{
+ return IsArc_Ext_PhySize(p, size, NULL);
}
+
static const Byte k_Signature[] = { 0x53, 0xEF };
REGISTER_ARC_I(
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index 1cbc8508..826b4fd1 100644..100755
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -111,14 +111,14 @@ static int GetLog(UInt32 num)
static const UInt32 kHeaderSize = 512;
-API_FUNC_static_IsArc IsArc_Fat(const Byte *p, size_t size)
+API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
+API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
{
if (size < kHeaderSize)
return k_IsArc_Res_NEED_MORE;
CHeader h;
return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO;
}
-}
bool CHeader::Parse(const Byte *p)
{
@@ -846,17 +846,18 @@ static const CStatProp kArcProps[] =
IMP_IInArchive_Props
IMP_IInArchive_ArcProps_WITH_NAME
+
static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
{
FILETIME localFileTime, utc;
- if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime))
+ if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
if (LocalFileTimeToFileTime(&localFileTime, &utc))
{
UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
t64 += ms10 * 100000;
utc.dwLowDateTime = (DWORD)t64;
utc.dwHighDateTime = (DWORD)(t64 >> 32);
- prop = utc;
+ prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2);
}
}
@@ -892,7 +893,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidPhySize: prop = PhySize; break;
case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
case kpidHeadersSize: prop = GetHeadersSize(); break;
- case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break;
+ case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break;
case kpidShortComment:
case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
@@ -920,9 +921,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPath: prop = GetItemPath(index); break;
case kpidShortName: prop = item.GetShortName(); break;
case kpidIsDir: prop = item.IsDir(); break;
- case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break;
+ case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
- case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break;
+ case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break;
case kpidAttrib: prop = (UInt32)item.Attrib; break;
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp
index 97a7c268..97a7c268 100644..100755
--- a/CPP/7zip/Archive/FlvHandler.cpp
+++ b/CPP/7zip/Archive/FlvHandler.cpp
diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp
index 2b3a673b..0d2caa3d 100644..100755
--- a/CPP/7zip/Archive/GptHandler.cpp
+++ b/CPP/7zip/Archive/GptHandler.cpp
@@ -23,6 +23,11 @@
using namespace NWindows;
namespace NArchive {
+
+namespace NFat {
+API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
+}
+
namespace NGpt {
#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }
@@ -51,6 +56,7 @@ struct CPartition
UInt64 FirstLba;
UInt64 LastLba;
UInt64 Flags;
+ const char *Ext; // detected later
Byte Name[kNameLen * 2];
bool IsUnused() const
@@ -73,6 +79,7 @@ struct CPartition
LastLba = Get64(p + 40);
Flags = Get64(p + 48);
memcpy(Name, p + 56, kNameLen * 2);
+ Ext = NULL;
}
};
@@ -252,6 +259,28 @@ HRESULT CHandler::Open2(IInStream *stream)
return S_OK;
}
+
+
+static const unsigned k_Ntfs_Fat_HeaderSize = 512;
+
+static const Byte k_NtfsSignature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
+
+static bool IsNtfs(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+ if (memcmp(p + 3, k_NtfsSignature, ARRAY_SIZE(k_NtfsSignature)) != 0)
+ return false;
+ switch (p[0])
+ {
+ case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
+ case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
+ default: return false;
+ }
+ return true;
+}
+
+
STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * /* openArchiveCallback */)
@@ -260,6 +289,42 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
Close();
RINOK(Open2(stream));
_stream = stream;
+
+ FOR_VECTOR (fileIndex, _items)
+ {
+ CPartition &item = _items[fileIndex];
+ const int typeIndex = FindPartType(item.Type);
+ if (typeIndex < 0)
+ continue;
+ const CPartType &t = kPartTypes[(unsigned)typeIndex];
+ if (t.Ext)
+ {
+ item.Ext = t.Ext;
+ continue;
+ }
+ if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows"))
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ if (GetStream(fileIndex, &inStream) == S_OK && inStream)
+ {
+ Byte temp[k_Ntfs_Fat_HeaderSize];
+ if (ReadStream_FAIL(inStream, temp, k_Ntfs_Fat_HeaderSize) == S_OK)
+ {
+ if (IsNtfs(temp))
+ {
+ item.Ext = "ntfs";
+ continue;
+ }
+ if (NFat::IsArc_Fat(temp, k_Ntfs_Fat_HeaderSize) == k_IsArc_Res_YES)
+ {
+ item.Ext = "fat";
+ continue;
+ }
+ }
+ }
+ }
+ }
+
return S_OK;
COM_TRY_END
}
@@ -355,13 +420,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
{
s += '.';
- const char *ext = NULL;
- int typeIndex = FindPartType(item.Type);
- if (typeIndex >= 0)
- ext = kPartTypes[(unsigned)typeIndex].Ext;
- if (!ext)
- ext = "img";
- s += ext;
+ s += (item.Ext ? item.Ext : "img");
}
prop = s;
break;
@@ -375,7 +434,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
char s[48];
const char *res;
- int typeIndex = FindPartType(item.Type);
+ const int typeIndex = FindPartType(item.Type);
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
res = kPartTypes[(unsigned)typeIndex].Type;
else
diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp
index 0054840d..35e642ec 100644..100755
--- a/CPP/7zip/Archive/GzHandler.cpp
+++ b/CPP/7zip/Archive/GzHandler.cpp
@@ -475,6 +475,7 @@ class CHandler:
NDecoder::CCOMCoder *_decoderSpec;
CSingleMethodProps _props;
+ CHandlerTimeOptions _timeOptions;
public:
MY_UNKNOWN_IMP4(
@@ -487,8 +488,15 @@ public:
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
- CHandler()
+ CHandler():
+ _isArc(false),
+ _decoderSpec(NULL)
+ {}
+
+ void CreateDecoder()
{
+ if (_decoder)
+ return;
_decoderSpec = new NDecoder::CCOMCoder;
_decoder = _decoderSpec;
}
@@ -528,7 +536,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidErrorFlags:
{
UInt32 v = 0;
- if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
prop = v;
@@ -567,12 +575,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
break;
// case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
case kpidMTime:
+ // gzip specification: MTIME = 0 means no time stamp is available.
if (_item.Time != 0)
- {
- FILETIME utc;
- NTime::UnixTimeToFileTime(_item.Time, utc);
- prop = utc;
- }
+ PropVariant_SetFrom_UnixTime(prop, _item.Time);
+ break;
+ case kpidTimeType:
+ if (_item.Time != 0)
+ prop = (UInt32)NFileTimeType::kUnix;
break;
case kpidSize:
{
@@ -644,6 +653,7 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
try
{
Close();
+ CreateDecoder();
_decoderSpec->SetInStream(stream);
_decoderSpec->InitInStream(true);
RINOK(_item.ReadHeader(_decoderSpec));
@@ -672,7 +682,8 @@ STDMETHODIMP CHandler::Close()
_headerSize = 0;
_stream.Release();
- _decoderSpec->ReleaseInStream();
+ if (_decoder)
+ _decoderSpec->ReleaseInStream();
return S_OK;
}
@@ -699,6 +710,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
extractCallback->PrepareOperation(askMode);
+ CreateDecoder();
+
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->SetStream(realOutStream);
@@ -873,21 +886,99 @@ static const Byte kHostOS =
NHostOS::kUnix;
#endif
+
+/*
+static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
+}
+
+static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
+}
+
+static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ const CItem &item,
+ bool needTime,
+ bool needCrc,
+ const UInt64 *unpackSize)
+{
+ NCOM::CPropVariant timeProp;
+ NCOM::CPropVariant sizeProp;
+ if (needTime)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(item.Time, ft);
+ timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
+ }
+ if (unpackSize)
+ {
+ sizeProp = *unpackSize;
+ RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
+ }
+ if (needCrc)
+ {
+ NCOM::CPropVariant prop;
+ prop = item.Crc;
+ RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop));
+ }
+ {
+ RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp));
+ }
+
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
+
+ if (unpackSize)
+ {
+ RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
+ }
+ {
+ RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp));
+ }
+ return S_OK;
+}
+*/
+
static HRESULT UpdateArchive(
ISequentialOutStream *outStream,
UInt64 unpackSize,
CItem &item,
const CSingleMethodProps &props,
- IArchiveUpdateCallback *updateCallback)
+ const CHandlerTimeOptions &timeOptions,
+ IArchiveUpdateCallback *updateCallback
+ // , IArchiveUpdateCallbackArcProp *reportArcProp
+ )
{
- UInt64 complexity = 0;
- RINOK(updateCallback->SetTotal(unpackSize));
- RINOK(updateCallback->SetCompleted(&complexity));
-
+ UInt64 unpackSizeReal;
+ {
CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream));
+ if (!fileInStream)
+ return S_FALSE;
+
+ {
+ CMyComPtr<IStreamGetProps> getProps;
+ fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ if (getProps)
+ {
+ FILETIME mTime;
+ UInt64 size;
+ if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK)
+ {
+ unpackSize = size;
+ if (timeOptions.Write_MTime.Val)
+ NTime::FileTime_To_UnixTime(mTime, item.Time);
+ }
+ }
+ }
+
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(unpackSize));
+ RINOK(updateCallback->SetCompleted(&complexity));
+
CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
inStreamSpec->SetStream(fileInStream);
@@ -911,14 +1002,50 @@ static HRESULT UpdateArchive(
RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
item.Crc = inStreamSpec->GetCRC();
- item.Size32 = (UInt32)inStreamSpec->GetSize();
+ unpackSizeReal = inStreamSpec->GetSize();
+ item.Size32 = (UInt32)unpackSizeReal;
RINOK(item.WriteFooter(outStream));
+ }
+ /*
+ if (reportArcProp)
+ {
+ RINOK(ReportArcProps(reportArcProp,
+ item,
+ props._Write_MTime, // item.Time != 0,
+ true, // writeCrc
+ &unpackSizeReal));
+ }
+ */
return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
}
+
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{
- *timeType = NFileTimeType::kUnix;
+ /*
+ if (_item.Time != 0)
+ {
+ we set NFileTimeType::kUnix in precision,
+ and we return NFileTimeType::kUnix in kpidTimeType
+ so GetFileTimeType() value is not used in any version of 7-zip.
+ }
+ else // (_item.Time == 0)
+ {
+ kpidMTime and kpidTimeType are not defined
+ before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList();
+ 22.00 : GetFileTimeType() value is not used
+ }
+ */
+
+ UInt32 t;
+ t = NFileTimeType::kUnix;
+ if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val)
+ {
+ t = GET_FileTimeType_NotDefined_for_GetFileTimeType;
+ // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21
+ // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21
+ }
+ *timeType = t;
return S_OK;
}
@@ -936,6 +1063,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_FAIL;
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+ /*
+ CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
+ updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
+ */
+
CItem newItem;
if (!IntToBool(newProps))
@@ -945,11 +1077,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
{
newItem.HostOS = kHostOS;
+ if (_timeOptions.Write_MTime.Val)
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
if (prop.vt == VT_FILETIME)
- NTime::FileTimeToUnixTime(prop.filetime, newItem.Time);
+ NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time);
else if (prop.vt == VT_EMPTY)
newItem.Time = 0;
else
@@ -990,7 +1123,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_INVALIDARG;
size = prop.uhVal.QuadPart;
}
- return UpdateArchive(outStream, size, newItem, _props, updateCallback);
+ return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback);
}
if (indexInArchive != 0)
@@ -1022,6 +1155,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
RINOK(_stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL));
+ /*
+ if (reportArcProp)
+ ReportArcProps(reportArcProp, newItem,
+ _props._Write_MTime,
+ false, // writeCrc
+ NULL); // unpacksize
+ */
+
return NCompress::CopyStream(_stream, outStream, progress);
COM_TRY_END
@@ -1029,16 +1170,48 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
- return _props.SetProperties(names, values, numProps);
+ _timeOptions.Init();
+ _props.Init();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &value = values[i];
+ {
+ bool processed = false;
+ RINOK(_timeOptions.Parse(name, value, processed));
+ if (processed)
+ {
+ if (_timeOptions.Write_CTime.Val ||
+ _timeOptions.Write_ATime.Val)
+ return E_INVALIDARG;
+ if ( _timeOptions.Prec != (UInt32)(Int32)-1
+ && _timeOptions.Prec != k_PropVar_TimePrec_0
+ && _timeOptions.Prec != k_PropVar_TimePrec_Unix
+ && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec
+ && _timeOptions.Prec != k_PropVar_TimePrec_Base)
+ return E_INVALIDARG;
+ continue;
+ }
+ }
+ RINOK(_props.SetProperty(name, value));
+ }
+ return S_OK;
}
static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 };
REGISTER_ARC_IO(
"gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF,
- k_Signature,
- 0,
- NArcInfoFlags::kKeepName,
- IsArc_Gz)
+ k_Signature, 0,
+ NArcInfoFlags::kKeepName
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
+ , IsArc_Gz)
}}
diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp
index 6f196de8..3cbfdacd 100644..100755
--- a/CPP/7zip/Archive/HandlerCont.cpp
+++ b/CPP/7zip/Archive/HandlerCont.cpp
@@ -14,6 +14,10 @@
namespace NArchive {
+namespace NExt {
+API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
+}
+
STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
@@ -132,11 +136,12 @@ STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosit
}
static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
-
+// static const Byte k_Ext_Signature[] = { 0x53, 0xEF };
+// static const unsigned k_Ext_Signature_offset = 0x438;
static const char *GetImgExt(ISequentialInStream *stream)
{
- const size_t kHeaderSize = 1 << 10;
+ const size_t kHeaderSize = 1 << 11;
Byte buf[kHeaderSize];
if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
{
@@ -146,6 +151,8 @@ static const char *GetImgExt(ISequentialInStream *stream)
return "gpt";
return "mbr";
}
+ if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES)
+ return "ext";
}
return NULL;
}
@@ -208,6 +215,33 @@ STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
+
+class CHandlerImgProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CHandlerImg &Handler;
+ CMyComPtr<ICompressProgressInfo> _ratioProgress;
+
+ CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {}
+
+ // MY_UNKNOWN_IMP1(ICompressProgressInfo)
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+
+STDMETHODIMP CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ UInt64 inSize2;
+ if (Handler.Get_PackSizeProcessed(inSize2))
+ inSize = &inSize2;
+ return _ratioProgress->SetRatioInfo(inSize, outSize);
+}
+
+
STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
@@ -227,10 +261,6 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode));
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, false);
-
int opRes = NExtract::NOperationResult::kDataError;
ClearStreamVars();
@@ -242,6 +272,19 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
if (hres == S_OK && inStream)
{
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ if (Init_PackSizeProcessed())
+ {
+ CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
+ CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
+ imgProgressSpec->_ratioProgress = progress;
+ progress.Release();
+ progress = imgProgress;
+ }
+
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h
index 0b92d190..3c645929 100644..100755
--- a/CPP/7zip/Archive/HandlerCont.h
+++ b/CPP/7zip/Archive/HandlerCont.h
@@ -94,7 +94,19 @@ protected:
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
virtual void CloseAtError();
+
+ // returns (true), if Get_PackSizeProcessed() is required in Extract()
+ virtual bool Init_PackSizeProcessed()
+ {
+ return false;
+ }
public:
+ virtual bool Get_PackSizeProcessed(UInt64 &size)
+ {
+ size = 0;
+ return false;
+ }
+
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
INTERFACE_IInArchive_Img(PURE)
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
index b70a291f..f0a85f1a 100644..100755
--- a/CPP/7zip/Archive/HfsHandler.cpp
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -240,7 +240,7 @@ struct CItem
UInt32 ID;
UInt32 CTime;
UInt32 MTime;
- // UInt32 AttrMTime;
+ UInt32 AttrMTime;
UInt32 ATime;
// UInt32 BackupDate;
@@ -1000,7 +1000,7 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
item.CTime = Get32(r + 0xC);
item.MTime = Get32(r + 0x10);
- // item.AttrMTime = Get32(r + 0x14);
+ item.AttrMTime = Get32(r + 0x14);
item.ATime = Get32(r + 0x18);
// item.BackupDate = Get32(r + 0x1C);
@@ -1404,6 +1404,7 @@ static const Byte kProps[] =
kpidCTime,
kpidMTime,
kpidATime,
+ kpidChangeTime,
kpidPosixAttrib
};
@@ -1421,9 +1422,11 @@ IMP_IInArchive_ArcProps
static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
{
+ if (hfsTime == 0)
+ return;
FILETIME ft;
HfsTimeToFileTime(hfsTime, ft);
- prop = ft;
+ prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
@@ -1447,10 +1450,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidMTime: HfsTimeToProp(Header.MTime, prop); break;
case kpidCTime:
{
- FILETIME localFt, ft;
- HfsTimeToFileTime(Header.CTime, localFt);
- if (LocalFileTimeToFileTime(&localFt, &ft))
- prop = ft;
+ if (Header.CTime != 0)
+ {
+ FILETIME localFt, ft;
+ HfsTimeToFileTime(Header.CTime, localFt);
+ if (LocalFileTimeToFileTime(&localFt, &ft))
+ prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
+ }
break;
}
case kpidIsTree: prop = true; break;
@@ -1578,6 +1584,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
case kpidATime: HfsTimeToProp(item.ATime, prop); break;
+ case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break;
case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break;
}
diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h
index 6df76d26..9551dfaf 100644..100755
--- a/CPP/7zip/Archive/IArchive.h
+++ b/CPP/7zip/Archive/IArchive.h
@@ -38,9 +38,11 @@ namespace NFileTimeType
{
enum EEnum
{
- kWindows,
+ kNotDefined = -1,
+ kWindows = 0,
kUnix,
- kDOS
+ kDOS,
+ k1ns
};
}
@@ -60,8 +62,31 @@ namespace NArcInfoFlags
const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches
const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums)
+ const UInt32 kCTime = 1 << 14;
+ const UInt32 kCTime_Default = 1 << 15;
+ const UInt32 kATime = 1 << 16;
+ const UInt32 kATime_Default = 1 << 17;
+ const UInt32 kMTime = 1 << 18;
+ const UInt32 kMTime_Default = 1 << 19;
+ // const UInt32 kTTime_Reserved = 1 << 20;
+ // const UInt32 kTTime_Reserved_Default = 1 << 21;
}
+namespace NArcInfoTimeFlags
+{
+ const unsigned kTime_Prec_Mask_bit_index = 0;
+ const unsigned kTime_Prec_Mask_num_bits = 26;
+
+ const unsigned kTime_Prec_Default_bit_index = 27;
+ const unsigned kTime_Prec_Default_num_bits = 5;
+}
+
+#define TIME_PREC_TO_ARC_FLAGS_MASK(x) \
+ ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (x)))
+
+#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(x) \
+ ((UInt32)(x) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index)
+
namespace NArchive
{
namespace NHandlerPropID
@@ -79,8 +104,8 @@ namespace NArchive
kSignatureOffset, // VT_UI4
kAltStreams, // VT_BOOL
kNtSecure, // VT_BOOL
- kFlags // VT_UI4
- // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR)
+ kFlags, // VT_UI4
+ kTimeFlags // VT_UI4
};
}
@@ -123,6 +148,7 @@ namespace NArchive
kInArcIndex,
kBlockIndex,
kOutArcIndex
+ // kArcProp
};
}
@@ -133,7 +159,8 @@ namespace NArchive
enum
{
kOK = 0
- // , kError
+ // kError = 1,
+ // kError_FileChanged
};
}
}
@@ -461,9 +488,10 @@ namespace NUpdateNotifyOp
kSkip,
kDelete,
kHeader,
- kHashRead
-
- // kNumDefined
+ kHashRead,
+ kInFileChanged
+ // , kOpFinished
+ // , kNumDefined
};
};
@@ -493,6 +521,20 @@ ARCHIVE_INTERFACE(IArchiveGetDiskProperty, 0x84)
};
/*
+#define INTERFACE_IArchiveUpdateCallbackArcProp(x) \
+ STDMETHOD(ReportProp)(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x; \
+ STDMETHOD(ReportRawProp)(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x; \
+ STDMETHOD(ReportFinished)(UInt32 indexType, UInt32 index, Int32 opRes) x; \
+ STDMETHOD(DoNeedArcProp)(PROPID propID, Int32 *answer) x; \
+
+
+ARCHIVE_INTERFACE(IArchiveUpdateCallbackArcProp, 0x85)
+{
+ INTERFACE_IArchiveUpdateCallbackArcProp(PURE);
+};
+*/
+
+/*
UpdateItems()
-------------
@@ -636,9 +678,40 @@ extern "C"
typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
typedef HRESULT (WINAPI *Func_SetLargePageMode)();
+ // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version);
typedef IOutArchive * (*Func_CreateOutArchive)();
typedef IInArchive * (*Func_CreateInArchive)();
}
+
+/*
+ if there is no time in archive, external MTime of archive
+ will be used instead of _item.Time from archive.
+ For 7-zip before 22.00 we need to return some supported value.
+ But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00.
+ So we return highest precision value supported by old 7-Zip.
+ new 7-Zip 22.00 doesn't use that value in usual cases.
+*/
+
+
+#define DECLARE_AND_SET_CLIENT_VERSION_VAR
+#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
+ NFileTimeType::kWindows
+
+/*
+extern UInt32 g_ClientVersion;
+
+#define GET_CLIENT_VERSION(major, minor) \
+ ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor)))
+
+#define DECLARE_AND_SET_CLIENT_VERSION_VAR \
+ UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR);
+
+#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
+ ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \
+ (UInt32)(Int32)NFileTimeType::kNotDefined : \
+ NFileTimeType::kWindows))
+*/
+
#endif
diff --git a/CPP/7zip/Archive/Icons/7z.ico b/CPP/7zip/Archive/Icons/7z.ico
index 319753a1..319753a1 100644..100755
--- a/CPP/7zip/Archive/Icons/7z.ico
+++ b/CPP/7zip/Archive/Icons/7z.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/apfs.ico b/CPP/7zip/Archive/Icons/apfs.ico
new file mode 100755
index 00000000..124eb76c
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/apfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/arj.ico b/CPP/7zip/Archive/Icons/arj.ico
index c0f8b141..c0f8b141 100644..100755
--- a/CPP/7zip/Archive/Icons/arj.ico
+++ b/CPP/7zip/Archive/Icons/arj.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/bz2.ico b/CPP/7zip/Archive/Icons/bz2.ico
index f22abebc..f22abebc 100644..100755
--- a/CPP/7zip/Archive/Icons/bz2.ico
+++ b/CPP/7zip/Archive/Icons/bz2.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cab.ico b/CPP/7zip/Archive/Icons/cab.ico
index c96c0f01..c96c0f01 100644..100755
--- a/CPP/7zip/Archive/Icons/cab.ico
+++ b/CPP/7zip/Archive/Icons/cab.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cpio.ico b/CPP/7zip/Archive/Icons/cpio.ico
index 9abaabc7..9abaabc7 100644..100755
--- a/CPP/7zip/Archive/Icons/cpio.ico
+++ b/CPP/7zip/Archive/Icons/cpio.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/deb.ico b/CPP/7zip/Archive/Icons/deb.ico
index 97a08654..97a08654 100644..100755
--- a/CPP/7zip/Archive/Icons/deb.ico
+++ b/CPP/7zip/Archive/Icons/deb.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/dmg.ico b/CPP/7zip/Archive/Icons/dmg.ico
index 7d63b09f..7d63b09f 100644..100755
--- a/CPP/7zip/Archive/Icons/dmg.ico
+++ b/CPP/7zip/Archive/Icons/dmg.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/fat.ico b/CPP/7zip/Archive/Icons/fat.ico
index 7503d933..7503d933 100644..100755
--- a/CPP/7zip/Archive/Icons/fat.ico
+++ b/CPP/7zip/Archive/Icons/fat.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/gz.ico b/CPP/7zip/Archive/Icons/gz.ico
index d402a698..d402a698 100644..100755
--- a/CPP/7zip/Archive/Icons/gz.ico
+++ b/CPP/7zip/Archive/Icons/gz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/hfs.ico b/CPP/7zip/Archive/Icons/hfs.ico
index bf2c1986..bf2c1986 100644..100755
--- a/CPP/7zip/Archive/Icons/hfs.ico
+++ b/CPP/7zip/Archive/Icons/hfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/iso.ico b/CPP/7zip/Archive/Icons/iso.ico
index b3e3ac2f..b3e3ac2f 100644..100755
--- a/CPP/7zip/Archive/Icons/iso.ico
+++ b/CPP/7zip/Archive/Icons/iso.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzh.ico b/CPP/7zip/Archive/Icons/lzh.ico
index 84dab49c..84dab49c 100644..100755
--- a/CPP/7zip/Archive/Icons/lzh.ico
+++ b/CPP/7zip/Archive/Icons/lzh.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzma.ico b/CPP/7zip/Archive/Icons/lzma.ico
index 2de2c249..2de2c249 100644..100755
--- a/CPP/7zip/Archive/Icons/lzma.ico
+++ b/CPP/7zip/Archive/Icons/lzma.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/ntfs.ico b/CPP/7zip/Archive/Icons/ntfs.ico
index 6b2aeb00..6b2aeb00 100644..100755
--- a/CPP/7zip/Archive/Icons/ntfs.ico
+++ b/CPP/7zip/Archive/Icons/ntfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rar.ico b/CPP/7zip/Archive/Icons/rar.ico
index 2918d294..2918d294 100644..100755
--- a/CPP/7zip/Archive/Icons/rar.ico
+++ b/CPP/7zip/Archive/Icons/rar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rpm.ico b/CPP/7zip/Archive/Icons/rpm.ico
index cdeb8d1b..cdeb8d1b 100644..100755
--- a/CPP/7zip/Archive/Icons/rpm.ico
+++ b/CPP/7zip/Archive/Icons/rpm.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/split.ico b/CPP/7zip/Archive/Icons/split.ico
index 65723ff3..65723ff3 100644..100755
--- a/CPP/7zip/Archive/Icons/split.ico
+++ b/CPP/7zip/Archive/Icons/split.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico
index b802d942..b802d942 100644..100755
--- a/CPP/7zip/Archive/Icons/squashfs.ico
+++ b/CPP/7zip/Archive/Icons/squashfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/tar.ico b/CPP/7zip/Archive/Icons/tar.ico
index 6835885b..6835885b 100644..100755
--- a/CPP/7zip/Archive/Icons/tar.ico
+++ b/CPP/7zip/Archive/Icons/tar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/vhd.ico b/CPP/7zip/Archive/Icons/vhd.ico
index 33bed3c9..33bed3c9 100644..100755
--- a/CPP/7zip/Archive/Icons/vhd.ico
+++ b/CPP/7zip/Archive/Icons/vhd.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/wim.ico b/CPP/7zip/Archive/Icons/wim.ico
index 887975e6..887975e6 100644..100755
--- a/CPP/7zip/Archive/Icons/wim.ico
+++ b/CPP/7zip/Archive/Icons/wim.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xar.ico b/CPP/7zip/Archive/Icons/xar.ico
index 281aa7dc..281aa7dc 100644..100755
--- a/CPP/7zip/Archive/Icons/xar.ico
+++ b/CPP/7zip/Archive/Icons/xar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xz.ico b/CPP/7zip/Archive/Icons/xz.ico
index bc07a7eb..bc07a7eb 100644..100755
--- a/CPP/7zip/Archive/Icons/xz.ico
+++ b/CPP/7zip/Archive/Icons/xz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/z.ico b/CPP/7zip/Archive/Icons/z.ico
index 2db53583..2db53583 100644..100755
--- a/CPP/7zip/Archive/Icons/z.ico
+++ b/CPP/7zip/Archive/Icons/z.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/zip.ico b/CPP/7zip/Archive/Icons/zip.ico
index 2af46066..2af46066 100644..100755
--- a/CPP/7zip/Archive/Icons/zip.ico
+++ b/CPP/7zip/Archive/Icons/zip.ico
Binary files differ
diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp
index 05453ee6..05453ee6 100644..100755
--- a/CPP/7zip/Archive/IhexHandler.cpp
+++ b/CPP/7zip/Archive/IhexHandler.cpp
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp
index 87f4aa3b..8588a7c5 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoHandler.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -6,9 +6,6 @@
#include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h"
-#include "../../../Windows/PropVariant.h"
-#include "../../../Windows/TimeUtils.h"
-
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
@@ -34,8 +31,8 @@ static const Byte kProps[] =
// kpidCTime,
// kpidATime,
kpidPosixAttrib,
- // kpidUser,
- // kpidGroup,
+ // kpidUserId,
+ // kpidGroupId,
// kpidLinks,
kpidSymLink
};
@@ -127,8 +124,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = s;
break;
}
- case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; }
- case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; }
+ case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
+ case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
}
}
@@ -242,8 +239,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPosixAttrib:
/*
case kpidLinks:
- case kpidUser:
- case kpidGroup:
+ case kpidUserId:
+ case kpidGroupId:
*/
{
if (_archive.IsSusp)
@@ -254,8 +251,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPosixAttrib: t = k_Px_Mode; break;
/*
case kpidLinks: t = k_Px_Links; break;
- case kpidUser: t = k_Px_User; break;
- case kpidGroup: t = k_Px_Group; break;
+ case kpidUserId: t = k_Px_User; break;
+ case kpidGroupId: t = k_Px_Group; break;
*/
}
UInt32 v;
@@ -276,9 +273,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
// case kpidCTime:
// case kpidATime:
{
- FILETIME utc;
- if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc))
- prop = utc;
+ // if
+ item.DateTime.GetFileTime(prop);
/*
else
{
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.h b/CPP/7zip/Archive/Iso/IsoHandler.h
index 1923784d..1923784d 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoHandler.h
+++ b/CPP/7zip/Archive/Iso/IsoHandler.h
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp
index 3b59060a..3b59060a 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoHeader.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h
index e6a4d327..e6a4d327 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoHeader.h
+++ b/CPP/7zip/Archive/Iso/IsoHeader.h
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
index 211b3eea..67802359 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoIn.cpp
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -587,6 +587,8 @@ HRESULT CInArchive::Open2()
for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
if (VolDescs[MainVolDescIndex].IsJoliet())
break;
+ /* FIXME: some volume can contain Rock Ridge, that is better than
+ Joliet volume. So we need some way to detect such case */
// MainVolDescIndex = 0; // to read primary volume
const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
if (vd.LogicalBlockSize != kBlockSize)
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
index 347f9e9b..a705b06a 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoIn.h
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -127,17 +127,18 @@ struct CDateTime
bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
- bool GetFileTime(FILETIME &ft) const
+ bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
{
- UInt64 value;
- bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
+ UInt64 v;
+ const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v);
if (res)
{
- value -= (Int64)((Int32)GmtOffset * 15 * 60);
- value *= 10000000;
+ v -= (Int64)((Int32)GmtOffset * 15 * 60);
+ v *= 10000000;
+ if (Hundredths < 100)
+ v += (UInt32)Hundredths * 100000;
+ prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2);
}
- ft.dwLowDateTime = (DWORD)value;
- ft.dwHighDateTime = (DWORD)(value >> 32);
return res;
}
};
diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h
index a42ae039..8c2a7253 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoItem.h
+++ b/CPP/7zip/Archive/Iso/IsoItem.h
@@ -25,17 +25,16 @@ struct CRecordingDateTime
Byte Second;
signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
- bool GetFileTime(FILETIME &ft) const
+ bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
{
- UInt64 value;
- bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value);
+ UInt64 v;
+ const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v);
if (res)
{
- value -= (Int64)((Int32)GmtOffset * 15 * 60);
- value *= 10000000;
+ v -= (Int64)((Int32)GmtOffset * 15 * 60);
+ v *= 10000000;
+ prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base);
}
- ft.dwLowDateTime = (DWORD)value;
- ft.dwHighDateTime = (DWORD)(value >> 32);
return res;
}
};
diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp
index 0205238d..0205238d 100644..100755
--- a/CPP/7zip/Archive/Iso/IsoRegister.cpp
+++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp
diff --git a/CPP/7zip/Archive/Iso/StdAfx.h b/CPP/7zip/Archive/Iso/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Iso/StdAfx.h
+++ b/CPP/7zip/Archive/Iso/StdAfx.h
diff --git a/CPP/7zip/Archive/LpHandler.cpp b/CPP/7zip/Archive/LpHandler.cpp
new file mode 100755
index 00000000..b2720f4b
--- /dev/null
+++ b/CPP/7zip/Archive/LpHandler.cpp
@@ -0,0 +1,1173 @@
+// LpHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Sha256.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+#define G64(_offs_, dest) dest = Get64(p + (_offs_));
+
+using namespace NWindows;
+
+namespace NArchive {
+
+namespace NExt {
+API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
+}
+
+namespace NLp {
+
+/*
+Android 10+ use Android's Dynamic Partitions to allow the
+different read-only system partitions (e.g. system, vendor, product)
+to share the same pool of storage space (as LVM in Linux).
+Name for partition: "super" (for GPT) or "super.img" (for file).
+Dynamic Partition Tools: lpmake
+All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.):
+boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+*/
+
+#define LP_METADATA_MAJOR_VERSION 10
+// #define LP_METADATA_MINOR_VERSION_MIN 0
+// #define LP_METADATA_MINOR_VERSION_MAX 2
+
+// #define LP_SECTOR_SIZE 512
+static const unsigned kSectorSizeLog = 9;
+
+/* Amount of space reserved at the start of every super partition to avoid
+ * creating an accidental boot sector. */
+#define LP_PARTITION_RESERVED_BYTES 4096
+#define LP_METADATA_GEOMETRY_SIZE 4096
+#define LP_METADATA_HEADER_MAGIC 0x414C5030
+
+#define SIGNATURE { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 }
+static const unsigned k_SignatureSize = 8;
+static const Byte k_Signature[k_SignatureSize] = SIGNATURE;
+
+// The length (36) is the same as the maximum length of a GPT partition name.
+static const unsigned kNameLen = 36;
+
+static void AddName36ToString(AString &s, const char *name, bool strictConvert)
+{
+ for (unsigned i = 0; i < kNameLen; i++)
+ {
+ char c = name[i];
+ if (c == 0)
+ return;
+ if (strictConvert && c < 32)
+ c = '_';
+ s += c;
+ }
+}
+
+
+static const unsigned k_Geometry_Size = 0x34;
+
+// LpMetadataGeometry
+struct CGeometry
+{
+ // UInt32 magic;
+ // UInt32 struct_size;
+ // Byte checksum[32]; /* SHA256 checksum of this struct, with this field set to 0. */
+
+ /* Maximum amount of space a single copy of the metadata can use,
+ a multiple of LP_SECTOR_SIZE. */
+ UInt32 metadata_max_size;
+
+ /* Number of copies of the metadata to keep.
+ For Non-A/B: 1, For A/B: 2, for A/B/C: 3.
+ A backup copy of each slot is kept */
+ UInt32 metadata_slot_count;
+
+ /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */
+ UInt32 logical_block_size;
+
+ bool Parse(const Byte *p)
+ {
+ G32 (40, metadata_max_size);
+ G32 (44, metadata_slot_count);
+ G32 (48, logical_block_size);
+ if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20))
+ return false;
+ if (metadata_max_size == 0)
+ return false;
+ if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0)
+ return false;
+ return true;
+ }
+
+ UInt64 GetTotalMetadataSize() const
+ {
+ // there are 2 copies of GEOMETRY and METADATA slots
+ return LP_PARTITION_RESERVED_BYTES +
+ LP_METADATA_GEOMETRY_SIZE * 2 +
+ ((UInt64)metadata_max_size * metadata_slot_count) * 2;
+ }
+};
+
+
+
+// LpMetadataTableDescriptor
+struct CDescriptor
+{
+ UInt32 offset; /* Location of the table, relative to end of the metadata header. */
+ UInt32 num_entries; /* Number of entries in the table. */
+ UInt32 entry_size; /* Size of each entry in the table, in bytes. */
+
+ void Parse(const Byte *p)
+ {
+ G32 (0, offset);
+ G32 (4, num_entries);
+ G32 (8, entry_size);
+ }
+
+ bool CheckLimits(UInt32 limit) const
+ {
+ if (entry_size == 0)
+ return false;
+ const UInt32 size = num_entries * entry_size;
+ if (size / entry_size != num_entries)
+ return false;
+ if (offset > limit || limit - offset < size)
+ return false;
+ return true;
+ }
+};
+
+
+// #define LP_PARTITION_ATTR_NONE 0x0
+// #define LP_PARTITION_ATTR_READONLY (1 << 0)
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the partition name needs a slot suffix applied. The slot suffix is
+ * determined by the metadata slot number (0 = _a, 1 = _b).
+ */
+// #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
+
+/* This flag is applied automatically when using MetadataBuilder::NewForUpdate.
+ * It signals that the partition was created (or modified) for a snapshot-based
+ * update. If this flag is not present, the partition was likely flashed via
+ * fastboot.
+ */
+// #define LP_PARTITION_ATTR_UPDATED (1 << 2)
+
+/* This flag marks a partition as disabled. It should not be used or mapped. */
+// #define LP_PARTITION_ATTR_DISABLED (1 << 3)
+
+static const char * const g_PartitionAttr[] =
+{
+ "READONLY"
+ , "SLOT_SUFFIXED"
+ , "UPDATED"
+ , "DISABLED"
+};
+
+static unsigned const k_MetaPartition_Size = 52;
+
+// LpMetadataPartition
+struct CPartition
+{
+ /* ASCII characters: alphanumeric or _. at least one ASCII character,
+ (name) must be unique across all partition names. */
+ char name[kNameLen];
+
+ UInt32 attributes; /* (LP_PARTITION_ATTR_*). */
+
+ /* Index of the first extent owned by this partition. The extent will
+ * start at logical sector 0. Gaps between extents are not allowed. */
+ UInt32 first_extent_index;
+
+ /* Number of extents in the partition. Every partition must have at least one extent. */
+ UInt32 num_extents;
+
+ /* Group this partition belongs to. */
+ UInt32 group_index;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(name, p, kNameLen);
+ G32 (36, attributes);
+ G32 (40, first_extent_index);
+ G32 (44, num_extents);
+ G32 (48, group_index);
+ }
+
+ // calced properties:
+ UInt32 MethodsMask;
+ UInt64 NumSectors;
+ UInt64 NumSectors_Pack;
+ const char *Ext;
+
+ UInt64 GetSize() const { return NumSectors << kSectorSizeLog; }
+ UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; }
+
+ CPartition():
+ MethodsMask(0),
+ NumSectors(0),
+ NumSectors_Pack(0),
+ Ext(NULL)
+ {}
+};
+
+
+
+
+#define LP_TARGET_TYPE_LINEAR 0
+/* This extent is a dm-zero target. The index is ignored and must be 0. */
+#define LP_TARGET_TYPE_ZERO 1
+
+static const char * const g_Methods[] =
+{
+ "RAW" // "LINEAR"
+ , "ZERO"
+};
+
+static unsigned const k_MetaExtent_Size = 24;
+
+// LpMetadataExtent
+struct CExtent
+{
+ UInt64 num_sectors; /* Length in 512-byte sectors. */
+ UInt32 target_type; /* Target type for device-mapper (LP_TARGET_TYPE_*). */
+
+ /* for LINEAR: The sector on the physical partition that this extent maps onto.
+ for ZERO: must be 0. */
+ UInt64 target_data;
+
+ /* for LINEAR: index into the block devices table.
+ for ZERO: must be 0. */
+ UInt32 target_source;
+
+ bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; }
+
+ void Parse(const Byte *p)
+ {
+ G64 (0, num_sectors);
+ G32 (8, target_type);
+ G64 (12, target_data);
+ G32 (20, target_source);
+ }
+};
+
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. If set, the group needs a slot suffix to be interpreted
+ * correctly. The suffix is automatically applied by ReadMetadata().
+ */
+// #define LP_GROUP_SLOT_SUFFIXED (1 << 0)
+static unsigned const k_Group_Size = 48;
+
+// LpMetadataPartitionGroup
+struct CGroup
+{
+ char name[kNameLen];
+ UInt32 flags; /* (LP_GROUP_*). */
+ UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */
+
+ void Parse(const Byte *p)
+ {
+ memcpy(name, p, kNameLen);
+ G32 (36, flags);
+ G64 (40, maximum_size);
+ }
+};
+
+
+
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the block device needs a slot suffix applied before being used with
+ * IPartitionOpener. The slot suffix is determined by the metadata slot number
+ * (0 = _a, 1 = _b).
+ */
+// #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
+
+static unsigned const k_Device_Size = 64;
+
+/* This struct defines an entry in the block_devices table. There must be at
+ * least one device, and the first device must represent the partition holding
+ * the super metadata.
+ */
+// LpMetadataBlockDevice
+struct CDevice
+{
+ /* 0: First usable sector for allocating logical partitions. this will be
+ * the first sector after the initial geometry blocks, followed by the
+ * space consumed by metadata_max_size*metadata_slot_count*2.
+ */
+ UInt64 first_logical_sector;
+
+ /* 8: Alignment for defining partitions or partition extents. For example,
+ * an alignment of 1MiB will require that all partitions have a size evenly
+ * divisible by 1MiB, and that the smallest unit the partition can grow by
+ * is 1MiB.
+ *
+ * Alignment is normally determined at runtime when growing or adding
+ * partitions. If for some reason the alignment cannot be determined, then
+ * this predefined alignment in the geometry is used instead. By default
+ * it is set to 1MiB.
+ */
+ UInt32 alignment;
+
+ /* 12: Alignment offset for "stacked" devices. For example, if the "super"
+ * partition itself is not aligned within the parent block device's
+ * partition table, then we adjust for this in deciding where to place
+ * |first_logical_sector|.
+ *
+ * Similar to |alignment|, this will be derived from the operating system.
+ * If it cannot be determined, it is assumed to be 0.
+ */
+ UInt32 alignment_offset;
+
+ /* 16: Block device size, as specified when the metadata was created. This
+ * can be used to verify the geometry against a target device.
+ */
+ UInt64 size;
+
+ /* 24: Partition name in the GPT*/
+ char partition_name[kNameLen];
+
+ /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
+ UInt32 flags;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(partition_name, p + 24, kNameLen);
+ G64 (0, first_logical_sector);
+ G32 (8, alignment);
+ G32 (12, alignment_offset);
+ G64 (16, size);
+ G32 (60, flags);
+ }
+};
+
+
+/* This device uses Virtual A/B. Note that on retrofit devices, the expanded
+ * header may not be present.
+ */
+// #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1
+
+static const char * const g_Header_Flags[] =
+{
+ "VIRTUAL_AB"
+};
+
+
+static const unsigned k_LpMetadataHeader10_size = 128;
+static const unsigned k_LpMetadataHeader12_size = 256;
+
+struct LpMetadataHeader
+{
+ /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */
+ UInt32 magic;
+
+ /* 4: Version number required to read this metadata. If the version is not
+ * equal to the library version, the metadata should be considered
+ * incompatible.
+ */
+ UInt16 major_version;
+
+ /* 6: Minor version. A library supporting newer features should be able to
+ * read metadata with an older minor version. However, an older library
+ * should not support reading metadata if its minor version is higher.
+ */
+ UInt16 minor_version;
+
+ /* 8: The size of this header struct. */
+ UInt32 header_size;
+
+ /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as
+ * if this field were set to 0.
+ */
+ // Byte header_checksum[32];
+
+ /* 44: The total size of all tables. This size is contiguous; tables may not
+ * have gaps in between, and they immediately follow the header.
+ */
+ UInt32 tables_size;
+
+ /* 48: SHA256 checksum of all table contents. */
+ Byte tables_checksum[32];
+
+ /* 80: Partition table descriptor. */
+ CDescriptor partitions;
+ /* 92: Extent table descriptor. */
+ CDescriptor extents;
+ /* 104: Updateable group descriptor. */
+ CDescriptor groups;
+ /* 116: Block device table. */
+ CDescriptor block_devices;
+
+ /* Everything past here is header version 1.2+, and is only included if
+ * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
+ * zero these additional fields.
+ */
+
+ /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are
+ * independent of the version number and intended to be informational only.
+ * New flags can be added without bumping the version.
+ */
+ // UInt32 flags;
+
+ /* 132: Reserved (zero), pad to 256 bytes. */
+ // Byte reserved[124];
+
+ void Parse128(const Byte *p)
+ {
+ G32 (0, magic);
+ G16 (4, major_version);
+ G16 (6, minor_version);
+ G32 (8, header_size)
+ // Byte header_checksum[32];
+ G32 (44, tables_size)
+ memcpy (tables_checksum, p + 48, 32);
+ partitions.Parse(p + 80);
+ extents.Parse(p + 92);
+ groups.Parse(p + 104);
+ block_devices.Parse(p + 116);
+ /* Everything past here is header version 1.2+, and is only included if
+ * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
+ * zero these additional fields.
+ */
+ }
+};
+
+
+static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum)
+{
+ CSha256 sha;
+ Sha256_Init(&sha);
+ Sha256_Update(&sha, data, size);
+ Byte calced[32];
+ Sha256_Final(&sha, calced);
+ return memcmp(checksum, calced, 32) == 0;
+}
+
+static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset)
+{
+ Byte checksum[32];
+ Byte *shaData = &data[hashOffset];
+ memcpy(checksum, shaData, 32);
+ memset(shaData, 0, 32);
+ return CheckSha256(data, size, checksum);
+}
+
+
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CRecordVector<CPartition> _items;
+ CRecordVector<CExtent> Extents;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _totalSize;
+ // UInt64 _usedSize;
+ // UInt64 _headersSize;
+
+ CGeometry geom;
+ UInt16 Major_version;
+ UInt16 Minor_version;
+ UInt32 Flags;
+
+ Int32 _mainFileIndex;
+ UInt32 MethodsMask;
+ bool _headerWarning;
+ AString GroupsString;
+ AString DevicesString;
+ AString DeviceArcName;
+
+ HRESULT Open2(IInStream *stream);
+
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+
+static void AddComment_UInt64(AString &s, const char *name, UInt64 val)
+{
+ s.Add_Space();
+ s += name;
+ s += '=';
+ s.Add_UInt64(val);
+}
+
+
+static bool IsBufZero(const Byte *data, size_t size)
+{
+ for (size_t i = 0; i < size; i += 4)
+ if (*(const UInt32 *)(const void *)(data + i) != 0)
+ return false;
+ return true;
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ RINOK(stream->Seek(LP_PARTITION_RESERVED_BYTES, STREAM_SEEK_SET, NULL));
+ {
+ Byte buf[k_Geometry_Size];
+ RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size));
+ if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
+ return S_FALSE;
+ if (!geom.Parse(buf))
+ return S_FALSE;
+ if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8))
+ return S_FALSE;
+ }
+
+ CByteBuffer buffer;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2);
+ {
+ // buffer.Size() >= LP_PARTITION_RESERVED_BYTES
+ RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES));
+ if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES))
+ {
+ _headerWarning = true;
+ // return S_FALSE;
+ }
+ }
+
+ RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2));
+ // we check that 2 copies of GEOMETRY are identical:
+ if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0
+ || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size))
+ {
+ _headerWarning = true;
+ // return S_FALSE;
+ }
+
+ RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size));
+ LpMetadataHeader header;
+ header.Parse128(buffer);
+ if (header.magic != LP_METADATA_HEADER_MAGIC ||
+ header.major_version != LP_METADATA_MAJOR_VERSION ||
+ header.header_size < k_LpMetadataHeader10_size)
+ return S_FALSE;
+ Flags = 0;
+ if (header.header_size > k_LpMetadataHeader10_size)
+ {
+ if (header.header_size != k_LpMetadataHeader12_size)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size,
+ header.header_size - k_LpMetadataHeader10_size));
+ Flags = Get32(buffer + k_LpMetadataHeader10_size);
+ }
+ Major_version = header.major_version;
+ Minor_version = header.minor_version;
+
+ if (!CheckSha256_csOffset(buffer, header.header_size, 12))
+ return S_FALSE;
+
+ if (geom.metadata_max_size < header.tables_size ||
+ geom.metadata_max_size - header.tables_size < header.header_size)
+ return S_FALSE;
+
+ buffer.AllocAtLeast(header.tables_size);
+ RINOK(ReadStream_FALSE(stream, buffer, header.tables_size));
+
+ const UInt64 totalMetaSize = geom.GetTotalMetadataSize();
+ // _headersSize = _totalSize;
+ _totalSize = totalMetaSize;
+
+ if (!CheckSha256(buffer, header.tables_size, header.tables_checksum))
+ return S_FALSE;
+
+ {
+ const CDescriptor &d = header.partitions;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_MetaPartition_Size)
+ return S_FALSE;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CPartition part;
+ part.Parse(buffer + d.offset + i * d.entry_size);
+ const UInt32 extLimit = part.first_extent_index + part.num_extents;
+ if (extLimit < part.first_extent_index ||
+ extLimit > header.extents.num_entries ||
+ part.group_index >= header.groups.num_entries)
+ return S_FALSE;
+ _items.Add(part);
+ }
+ }
+ {
+ const CDescriptor &d = header.extents;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_MetaExtent_Size)
+ return S_FALSE;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CExtent e;
+ e.Parse(buffer + d.offset + i * d.entry_size);
+ // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE;
+ if (e.IsRAW())
+ {
+ if (e.target_source >= header.block_devices.num_entries)
+ return S_FALSE;
+ const UInt64 endSector = e.target_data + e.num_sectors;
+ const UInt64 endOffset = endSector << kSectorSizeLog;
+ if (_totalSize < endOffset)
+ _totalSize = endOffset;
+ }
+ MethodsMask |= (UInt32)1 << e.target_type;
+ Extents.Add(e);
+ }
+ }
+
+ // _usedSize = _totalSize;
+ {
+ const CDescriptor &d = header.groups;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_Group_Size)
+ return S_FALSE;
+ AString s;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CGroup g;
+ g.Parse(buffer + d.offset + i * d.entry_size);
+ if (_totalSize < g.maximum_size)
+ _totalSize = g.maximum_size;
+ s += " ";
+ AddName36ToString(s, g.name, true);
+ AddComment_UInt64(s, "maximum_size", g.maximum_size);
+ AddComment_UInt64(s, "flags", g.flags);
+ s.Add_LF();
+ }
+ GroupsString = s;
+ }
+
+ {
+ const CDescriptor &d = header.block_devices;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_Device_Size)
+ return S_FALSE;
+ AString s;
+ // CRecordVector<CDevice> devices;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CDevice v;
+ v.Parse(buffer + d.offset + i * d.entry_size);
+ // if (i == 0)
+ {
+ // it's super_device is first device;
+ if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog))
+ return S_FALSE;
+ }
+ if (_totalSize < v.size)
+ _totalSize = v.size;
+ s += " ";
+ if (i == 0)
+ AddName36ToString(DeviceArcName, v.partition_name, true);
+ // devices.Add(v);
+ AddName36ToString(s, v.partition_name, true);
+ AddComment_UInt64(s, "size", v.size);
+ AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector);
+ AddComment_UInt64(s, "alignment", v.alignment);
+ AddComment_UInt64(s, "alignment_offset", v.alignment_offset);
+ AddComment_UInt64(s, "flags", v.flags);
+ s.Add_LF();
+ }
+ DevicesString = s;
+ }
+
+ {
+ FOR_VECTOR (i, _items)
+ {
+ CPartition &part = _items[i];
+ if (part.first_extent_index > Extents.Size() ||
+ part.num_extents > Extents.Size() - part.first_extent_index)
+ return S_FALSE;
+
+ UInt64 numSectors = 0;
+ UInt64 numSectors_Pack = 0;
+ UInt32 methods = 0;
+ for (UInt32 k = 0; k < part.num_extents; k++)
+ {
+ const CExtent &e = Extents[part.first_extent_index + k];
+ numSectors += e.num_sectors;
+ if (e.IsRAW())
+ numSectors_Pack += e.num_sectors;
+ methods |= (UInt32)1 << e.target_type;
+ }
+ part.NumSectors = numSectors;
+ part.NumSectors_Pack = numSectors_Pack;
+ part.MethodsMask = methods;
+ }
+ }
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(stream));
+ _stream = stream;
+
+ int mainFileIndex = -1;
+ unsigned numNonEmptyParts = 0;
+
+ FOR_VECTOR (fileIndex, _items)
+ {
+ CPartition &item = _items[fileIndex];
+ if (item.NumSectors != 0)
+ {
+ mainFileIndex = fileIndex;
+ numNonEmptyParts++;
+ CMyComPtr<ISequentialInStream> parseStream;
+ if (GetStream(fileIndex, &parseStream) == S_OK && parseStream)
+ {
+ const size_t kParseSize = 1 << 11;
+ Byte buf[kParseSize];
+ if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK)
+ {
+ UInt64 extSize;
+ if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES)
+ if (extSize == item.GetSize())
+ item.Ext = "ext";
+ }
+ }
+ }
+ }
+ if (numNonEmptyParts == 1)
+ _mainFileIndex = mainFileIndex;
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::Close()
+{
+ _totalSize = 0;
+ // _usedSize = 0;
+ // _headersSize = 0;
+ _items.Clear();
+ Extents.Clear();
+ _stream.Release();
+ _mainFileIndex = -1;
+ _headerWarning = false;
+ MethodsMask = 0;
+ GroupsString.Empty();
+ DevicesString.Empty();
+ DeviceArcName.Empty();
+ return S_OK;
+}
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCharacts,
+ kpidMethod,
+ kpidNumBlocks,
+ kpidOffset
+};
+
+static const Byte kArcProps[] =
+{
+ kpidUnpackVer,
+ kpidMethod,
+ kpidClusterSize,
+ // kpidHeadersSize,
+ // kpidFreeSpace,
+ kpidName,
+ kpidComment
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile:
+ {
+ if (_mainFileIndex >= 0)
+ prop = (UInt32)_mainFileIndex;
+ break;
+ }
+ case kpidPhySize: prop = _totalSize; break;
+
+ // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break;
+ // case kpidHeadersSize: prop = _headersSize; break;
+
+ case kpidMethod:
+ {
+ const UInt32 m = MethodsMask;
+ if (m != 0)
+ {
+ FLAGS_TO_PROP(g_Methods, m, prop);
+ }
+ break;
+ }
+
+ case kpidUnpackVer:
+ {
+ AString s;
+ s.Add_UInt32(Major_version);
+ s += '.';
+ s.Add_UInt32(Minor_version);
+ prop = s;
+ break;
+ }
+
+ case kpidClusterSize:
+ prop = geom.logical_block_size;
+ break;
+
+ case kpidComment:
+ {
+ AString s;
+
+ s += "metadata_slot_count: ";
+ s.Add_UInt32(geom.metadata_slot_count);
+ s.Add_LF();
+
+ s += "metadata_max_size: ";
+ s.Add_UInt32(geom.metadata_max_size);
+ s.Add_LF();
+
+ if (Flags != 0)
+ {
+ s += "flags: ";
+ s += FlagsToString(g_Header_Flags, ARRAY_SIZE(g_Header_Flags), Flags);
+ s.Add_LF();
+ }
+
+ if (!GroupsString.IsEmpty())
+ {
+ s += "Groups:";
+ s.Add_LF();
+ s += GroupsString;
+ }
+
+ if (!DevicesString.IsEmpty())
+ {
+ s += "BlockDevices:";
+ s.Add_LF();
+ s += DevicesString;
+ }
+
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidName:
+ if (!DeviceArcName.IsEmpty())
+ prop = DeviceArcName + ".lpimg";
+ break;
+
+ case kpidWarningFlags:
+ if (_headerWarning)
+ {
+ UInt32 v = kpv_ErrorFlags_HeadersError;
+ prop = v;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CPartition &item = _items[index];
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString s;
+ AddName36ToString(s, item.name, false);
+ if (s.IsEmpty())
+ s.Add_UInt32(index);
+ if (item.num_extents != 0)
+ {
+ s += '.';
+ s += (item.Ext ? item.Ext : "img");
+ }
+ prop = s;
+ break;
+ }
+
+ case kpidSize: prop = item.GetSize(); break;
+ case kpidPackSize: prop = item.GetPackSize(); break;
+ case kpidNumBlocks: prop = item.num_extents; break;
+ case kpidMethod:
+ {
+ const UInt32 m = item.MethodsMask;
+ if (m != 0)
+ {
+ FLAGS_TO_PROP(g_Methods, m, prop);
+ }
+ break;
+ }
+ case kpidOffset:
+ if (item.num_extents != 0)
+ if (item.first_extent_index < Extents.Size())
+ prop = Extents[item.first_extent_index].target_data << kSectorSizeLog;
+ break;
+
+ case kpidCharacts:
+ {
+ AString s;
+ s += "group:";
+ s.Add_UInt32(item.group_index);
+ s.Add_Space();
+ s += FlagsToString(g_PartitionAttr, ARRAY_SIZE(g_PartitionAttr), item.attributes);
+ prop = s;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+
+ const CPartition &item = _items[index];
+
+ if (item.first_extent_index > Extents.Size()
+ || item.num_extents > Extents.Size() - item.first_extent_index)
+ return S_FALSE;
+
+ if (item.num_extents == 0)
+ return CreateLimitedInStream(_stream, 0, 0, stream);
+
+ if (item.num_extents == 1)
+ {
+ const CExtent &e = Extents[item.first_extent_index];
+ if (e.IsRAW())
+ {
+ const UInt64 pos = e.target_data << kSectorSizeLog;
+ if ((pos >> kSectorSizeLog) != e.target_data)
+ return S_FALSE;
+ const UInt64 size = item.GetSize();
+ if (pos + size < pos)
+ return S_FALSE;
+ return CreateLimitedInStream(_stream, pos, size, stream);
+ }
+ }
+
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ // const unsigned kNumDebugExtents = 10;
+ extentStreamSpec->Extents.Reserve(item.num_extents + 1
+ // + kNumDebugExtents
+ );
+
+ UInt64 virt = 0;
+ for (UInt32 k = 0; k < item.num_extents; k++)
+ {
+ const CExtent &e = Extents[item.first_extent_index + k];
+
+ CSeekExtent se;
+ {
+ const UInt64 numSectors = e.num_sectors;
+ if (numSectors == 0)
+ {
+ continue;
+ // return S_FALSE;
+ }
+ const UInt64 numBytes = numSectors << kSectorSizeLog;
+ if ((numBytes >> kSectorSizeLog) != numSectors)
+ return S_FALSE;
+ if (numBytes >= ((UInt64)1 << 63) - virt)
+ return S_FALSE;
+
+ se.Virt = virt;
+ virt += numBytes;
+ }
+
+ const UInt64 phySector = e.target_data;
+ if (e.target_type == LP_TARGET_TYPE_ZERO)
+ {
+ if (phySector != 0)
+ return S_FALSE;
+ se.SetAs_ZeroFill();
+ }
+ else if (e.target_type == LP_TARGET_TYPE_LINEAR)
+ {
+ se.Phy = phySector << kSectorSizeLog;
+ if ((se.Phy >> kSectorSizeLog) != phySector)
+ return S_FALSE;
+ if (se.Phy >= ((UInt64)1 << 63))
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ extentStreamSpec->Extents.AddInReserved(se);
+
+ /*
+ {
+ // for debug
+ const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents;
+ for (unsigned i = 0; i < kNumDebugExtents; i++)
+ {
+ se.Phy += kAdd;
+ // se.Phy += (UInt64)1 << 63; // for debug
+ // se.Phy += 1; // for debug
+ se.Virt += kAdd;
+ extentStreamSpec->Extents.AddInReserved(se);
+ }
+ }
+ */
+ }
+
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virt;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Stream = _stream;
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ totalSize += _items[index].GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+
+ const UInt64 size = _items[index].GetSize();
+ totalSize += size;
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ CMyComPtr<ISequentialInStream> inStream;
+ const HRESULT hres = GetStream(index, &inStream);
+ int opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ if (hres != S_FALSE)
+ {
+ if (hres != S_OK)
+ return hres;
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ opRes = NExtract::NOperationResult::kDataError;
+ if (copyCoderSpec->TotalSize == size)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (copyCoderSpec->TotalSize < size)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+REGISTER_ARC_I(
+ "LP", "lpimg img", NULL, 0xc1,
+ k_Signature,
+ LP_PARTITION_RESERVED_BYTES,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp
index e1984d28..6711da60 100644..100755
--- a/CPP/7zip/Archive/LzhHandler.cpp
+++ b/CPP/7zip/Archive/LzhHandler.cpp
@@ -487,22 +487,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break;
case kpidMTime:
{
- FILETIME utc;
UInt32 unixTime;
if (item.GetUnixTime(unixTime))
- NTime::UnixTimeToFileTime(unixTime, utc);
+ PropVariant_SetFrom_UnixTime(prop, unixTime);
else
- {
- FILETIME localFileTime;
- if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
- {
- if (!LocalFileTimeToFileTime(&localFileTime, &utc))
- utc.dwHighDateTime = utc.dwLowDateTime = 0;
- }
- else
- utc.dwHighDateTime = utc.dwLowDateTime = 0;
- }
- prop = utc;
+ PropVariant_SetFrom_DosTime(prop, item.ModifiedTime);
break;
}
// case kpidAttrib: prop = (UInt32)item.Attributes; break;
diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp
index ba547c83..ba547c83 100644..100755
--- a/CPP/7zip/Archive/LzmaHandler.cpp
+++ b/CPP/7zip/Archive/LzmaHandler.cpp
diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp
index bc8ba223..bc8ba223 100644..100755
--- a/CPP/7zip/Archive/MachoHandler.cpp
+++ b/CPP/7zip/Archive/MachoHandler.cpp
diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp
index 026696f3..026696f3 100644..100755
--- a/CPP/7zip/Archive/MbrHandler.cpp
+++ b/CPP/7zip/Archive/MbrHandler.cpp
diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp
index 6f9057a6..6f9057a6 100644..100755
--- a/CPP/7zip/Archive/MslzHandler.cpp
+++ b/CPP/7zip/Archive/MslzHandler.cpp
diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp
index c790265d..c790265d 100644..100755
--- a/CPP/7zip/Archive/MubHandler.cpp
+++ b/CPP/7zip/Archive/MubHandler.cpp
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
index e2822184..e2822184 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h
index 2153d785..2153d785 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisDecode.h
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.h
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
index aa0a9175..aa0a9175 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.h b/CPP/7zip/Archive/Nsis/NsisHandler.h
index 1eb8b731..1eb8b731 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisHandler.h
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.h
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp
index 4e2d7a9d..4e2d7a9d 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisIn.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h
index 1d92e12f..1d92e12f 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisIn.h
+++ b/CPP/7zip/Archive/Nsis/NsisIn.h
diff --git a/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
index 7230c3c2..7230c3c2 100644..100755
--- a/CPP/7zip/Archive/Nsis/NsisRegister.cpp
+++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Nsis/StdAfx.h
+++ b/CPP/7zip/Archive/Nsis/StdAfx.h
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index daa01fef..7d0c6f78 100644..100755
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -278,7 +278,7 @@ struct CSiAttr
{
UInt64 CTime;
UInt64 MTime;
- // UInt64 ThisRecMTime;
+ UInt64 ThisRecMTime;
UInt64 ATime;
UInt32 Attrib;
@@ -300,7 +300,7 @@ bool CSiAttr::Parse(const Byte *p, unsigned size)
return false;
G64(p + 0x00, CTime);
G64(p + 0x08, MTime);
- // G64(p + 0x10, ThisRecMTime);
+ G64(p + 0x10, ThisRecMTime);
G64(p + 0x18, ATime);
G32(p + 0x20, Attrib);
SecurityId = 0;
@@ -2301,6 +2301,7 @@ static const Byte kProps[] =
kpidMTime,
kpidCTime,
kpidATime,
+ kpidChangeTime,
kpidAttrib,
kpidLinks,
kpidINode,
@@ -2577,7 +2578,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break;
- // case kpidRecMTime: if (fn) NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break;
+ case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break;
/*
case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break;
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
index ee265571..34a38acf 100644..100755
--- a/CPP/7zip/Archive/PeHandler.cpp
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -885,11 +885,7 @@ IMP_IInArchive_ArcProps_WITH_NAME
static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
{
if (unixTime != 0)
- {
- FILETIME ft;
- NTime::UnixTimeToFileTime(unixTime, ft);
- prop = ft;
- }
+ PropVariant_SetFrom_UnixTime(prop, unixTime);
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp
index 05a07e53..101bfd98 100644..100755
--- a/CPP/7zip/Archive/PpmdHandler.cpp
+++ b/CPP/7zip/Archive/PpmdHandler.cpp
@@ -174,7 +174,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
{
// time can be in Unix format ???
FILETIME utc;
- if (NTime::DosTimeToFileTime(_item.Time, utc))
+ if (NTime::DosTime_To_FileTime(_item.Time, utc))
prop = utc;
break;
}
diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp
index 4a795eca..4a795eca 100644..100755
--- a/CPP/7zip/Archive/QcowHandler.cpp
+++ b/CPP/7zip/Archive/QcowHandler.cpp
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
index bb8a2edb..563695f8 100644..100755
--- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -1591,14 +1591,14 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop)
{
unsigned size;
- int offset = item.FindExtra(NExtraID::kTime, size);
+ const int offset = item.FindExtra(NExtraID::kTime, size);
if (offset < 0)
return;
const Byte *p = item.Extra + (unsigned)offset;
UInt64 flags;
{
- unsigned num = ReadVarInt(p, size, &flags);
+ const unsigned num = ReadVarInt(p, size, &flags);
if (num == 0)
return;
p += num;
@@ -1610,8 +1610,8 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
unsigned numStamps = 0;
unsigned curStamp = 0;
- unsigned i;
- for (i = 0; i < 3; i++)
+
+ for (unsigned i = 0; i < 3; i++)
if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0)
{
if (i == stampIndex)
@@ -1620,20 +1620,28 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
}
FILETIME ft;
-
+
+ unsigned timePrec = 0;
+ unsigned ns100 = 0;
+
if ((flags & NTimeRecord::NFlags::kUnixTime) != 0)
{
curStamp *= 4;
if (curStamp + 4 > size)
return;
- const Byte *p2 = p + curStamp;
- UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2));
+ p += curStamp;
+ UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p));
numStamps *= 4;
+ timePrec = k_PropVar_TimePrec_Unix;
if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size)
{
- const UInt32 ns = Get32(p2 + numStamps) & 0x3FFFFFFF;
+ const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF;
if (ns < 1000000000)
+ {
val += ns / 100;
+ ns100 = (unsigned)(ns % 100);
+ timePrec = k_PropVar_TimePrec_1ns;
+ }
}
ft.dwLowDateTime = (DWORD)val;
ft.dwHighDateTime = (DWORD)(val >> 32);
@@ -1643,12 +1651,12 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
curStamp *= 8;
if (curStamp + 8 > size)
return;
- const Byte *p2 = p + curStamp;
- ft.dwLowDateTime = Get32(p2);
- ft.dwHighDateTime = Get32(p2 + 4);
+ p += curStamp;
+ ft.dwLowDateTime = Get32(p);
+ ft.dwHighDateTime = Get32(p + 4);
}
- prop = ft;
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100);
}
@@ -1715,21 +1723,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop);
if (prop.vt == VT_EMPTY && item.Has_UnixMTime())
- {
- FILETIME ft;
- NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft);
- prop = ft;
- }
+ PropVariant_SetFrom_UnixTime(prop, item.UnixMTime);
if (prop.vt == VT_EMPTY && ref.Parent >= 0)
{
const CItem &baseItem = _items[_refs[ref.Parent].Item];
TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop);
if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime())
- {
- FILETIME ft;
- NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft);
- prop = ft;
- }
+ PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime);
}
break;
}
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h
index 3b3b940a..3b3b940a 100644..100755
--- a/CPP/7zip/Archive/Rar/Rar5Handler.h
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.h
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index 7491c50b..ecadf853 100644..100755
--- a/CPP/7zip/Archive/Rar/RarHandler.cpp
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -360,7 +360,7 @@ void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item)
static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
{
rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
- unsigned numDigits = (mask & 3);
+ const unsigned numDigits = (mask & 3);
rarTime.SubTime[0] =
rarTime.SubTime[1] =
rarTime.SubTime[2] = 0;
@@ -405,8 +405,8 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
item.MTime.LowSecond = 0;
item.MTime.SubTime[0] =
- item.MTime.SubTime[1] =
- item.MTime.SubTime[2] = 0;
+ item.MTime.SubTime[1] =
+ item.MTime.SubTime[2] = 0;
p += kFileHeaderSize;
size -= kFileHeaderSize;
@@ -941,31 +941,32 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
+static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &ft)
{
- if (!NTime::DosTimeToFileTime(rarTime.DosTime, result))
+ if (!NTime::DosTime_To_FileTime(rarTime.DosTime, ft))
return false;
- UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
- value += (UInt64)rarTime.LowSecond * 10000000;
- value += ((UInt64)rarTime.SubTime[2] << 16) +
- ((UInt64)rarTime.SubTime[1] << 8) +
- ((UInt64)rarTime.SubTime[0]);
- result.dwLowDateTime = (DWORD)value;
- result.dwHighDateTime = DWORD(value >> 32);
+ UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ v += (UInt32)rarTime.LowSecond * 10000000;
+ v +=
+ ((UInt32)rarTime.SubTime[2] << 16) +
+ ((UInt32)rarTime.SubTime[1] << 8) +
+ ((UInt32)rarTime.SubTime[0]);
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
return true;
}
static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop)
{
- FILETIME localFileTime, utcFileTime;
- if (RarTimeToFileTime(rarTime, localFileTime))
- {
- if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
- utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
- }
+ FILETIME localFileTime, utc;
+ if (RarTimeToFileTime(rarTime, localFileTime)
+ && LocalFileTimeToFileTime(&localFileTime, &utc))
+ prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
+ /*
else
- utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
- prop = utcFileTime;
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
+ */
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h
index a62b60cd..a62b60cd 100644..100755
--- a/CPP/7zip/Archive/Rar/RarHandler.h
+++ b/CPP/7zip/Archive/Rar/RarHandler.h
diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h
index 30c53ec9..30c53ec9 100644..100755
--- a/CPP/7zip/Archive/Rar/RarHeader.h
+++ b/CPP/7zip/Archive/Rar/RarHeader.h
diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h
index 10e21c57..10e21c57 100644..100755
--- a/CPP/7zip/Archive/Rar/RarItem.h
+++ b/CPP/7zip/Archive/Rar/RarItem.h
diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h
index 96264330..2f5bbd37 100644..100755
--- a/CPP/7zip/Archive/Rar/RarVol.h
+++ b/CPP/7zip/Archive/Rar/RarVol.h
@@ -52,7 +52,7 @@ public:
ext.IsEqualTo_Ascii_NoCase("r01"))
{
_changed = ext;
- _before = name.Left(dotPos + 1);
+ _before.SetFrom(name.Ptr(), dotPos + 1);
return true;
}
}
@@ -60,16 +60,23 @@ public:
if (newStyle)
{
- unsigned i = base.Len();
+ unsigned k = base.Len();
+
+ for (; k != 0; k--)
+ if (IsDigit(base[k - 1]))
+ break;
+
+ unsigned i = k;
for (; i != 0; i--)
if (!IsDigit(base[i - 1]))
break;
- if (i != base.Len())
+ if (i != k)
{
- _before = base.Left(i);
- _changed = base.Ptr(i);
+ _before.SetFrom(base.Ptr(), i);
+ _changed.SetFrom(base.Ptr(i), k - i);
+ _after.Insert(0, base.Ptr(k));
return true;
}
}
diff --git a/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp
index d0feea85..d0feea85 100644..100755
--- a/CPP/7zip/Archive/Rar/StdAfx.cpp
+++ b/CPP/7zip/Archive/Rar/StdAfx.cpp
diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Rar/StdAfx.h
+++ b/CPP/7zip/Archive/Rar/StdAfx.h
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
index e0ec28ce..366f8efb 100644..100755
--- a/CPP/7zip/Archive/RpmHandler.cpp
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -215,11 +215,7 @@ class CHandler: public CHandlerCont
void SetTime(NCOM::CPropVariant &prop) const
{
if (_time_Defined && _buildTime != 0)
- {
- FILETIME ft;
- NTime::UnixTimeToFileTime(_buildTime, ft);
- prop = ft;
- }
+ PropVariant_SetFrom_UnixTime(prop, _buildTime);
}
void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const
diff --git a/CPP/7zip/Archive/SparseHandler.cpp b/CPP/7zip/Archive/SparseHandler.cpp
new file mode 100755
index 00000000..47e3ed8d
--- /dev/null
+++ b/CPP/7zip/Archive/SparseHandler.cpp
@@ -0,0 +1,548 @@
+// SparseHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSparse {
+
+// libsparse and simg2img
+
+struct CHeader
+{
+ // UInt32 magic; /* 0xed26ff3a */
+ // UInt16 major_version; /* (0x1) - reject images with higher major versions */
+ // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */
+ UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */
+ UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
+ UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */
+ UInt32 NumBlocks; /* total blocks in the non-sparse output image */
+ UInt32 NumChunks; /* total chunks in the sparse input image */
+ // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */
+
+ void Parse(const Byte *p)
+ {
+ // G16 (4, major_version);
+ // G16 (6, minor_version);
+ G16 (8, file_hdr_sz);
+ G16 (10, chunk_hdr_sz);
+ G32 (12, BlockSize);
+ G32 (16, NumBlocks);
+ G32 (20, NumChunks);
+ // G32 (24, image_checksum);
+ }
+};
+
+// #define SPARSE_HEADER_MAGIC 0xed26ff3a
+
+#define CHUNK_TYPE_RAW 0xCAC1
+#define CHUNK_TYPE_FILL 0xCAC2
+#define CHUNK_TYPE_DONT_CARE 0xCAC3
+#define CHUNK_TYPE_CRC32 0xCAC4
+
+#define MY__CHUNK_TYPE_FILL 0
+#define MY__CHUNK_TYPE_DONT_CARE 1
+#define MY__CHUNK_TYPE_RAW__START 2
+
+static const char * const g_Methods[] =
+{
+ "RAW"
+ , "FILL"
+ , "SPARSE" // "DONT_CARE"
+ , "CRC32"
+};
+
+static const unsigned kFillSize = 4;
+
+struct CChunk
+{
+ UInt32 VirtBlock;
+ Byte Fill [kFillSize];
+ UInt64 PhyOffset;
+};
+
+static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 };
+
+
+class CHandler: public CHandlerImg
+{
+ CRecordVector<CChunk> Chunks;
+ UInt64 _virtSize_fromChunks;
+ unsigned _blockSizeLog;
+ UInt32 _chunkIndexPrev;
+
+ UInt64 _packSizeProcessed;
+ UInt64 _phySize;
+ UInt32 _methodFlags;
+ bool _isArc;
+ bool _headersError;
+ bool _unexpectedEnd;
+ // bool _unsupported;
+ UInt32 NumChunks; // from header
+
+ HRESULT Seek2(UInt64 offset)
+ {
+ _posInArc = offset;
+ return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ }
+
+ void InitSeekPositions()
+ {
+ /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()).
+ So we must reset these variables before first call of Read() */
+ Reset_VirtPos();
+ Reset_PosInArc();
+ _chunkIndexPrev = 0;
+ _packSizeProcessed = 0;
+ }
+
+ // virtual functions
+ bool Init_PackSizeProcessed()
+ {
+ _packSizeProcessed = 0;
+ return true;
+ }
+ bool Get_PackSizeProcessed(UInt64 &size)
+ {
+ size = _packSizeProcessed;
+ return true;
+ }
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback);
+ HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed);
+
+public:
+ INTERFACE_IInArchive_Img(;)
+
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidClusterSize,
+ kpidNumBlocks,
+ kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break;
+ case kpidNumBlocks: prop = (UInt32)NumChunks; break;
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+
+ case kpidMethod:
+ {
+ FLAGS_TO_PROP(g_Methods, _methodFlags, prop);
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_headersError) v |= kpv_ErrorFlags_HeadersError;
+ if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (!Stream && v == 0 && _isArc)
+ v = kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = _size; break;
+ case kpidPackSize: prop = _phySize; break;
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+static unsigned GetLogSize(UInt32 size)
+{
+ unsigned k;
+ for (k = 0; k < 32; k++)
+ if (((UInt32)1 << k) == size)
+ return k;
+ return k;
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
+{
+ const unsigned kHeaderSize = 28;
+ const unsigned kChunkHeaderSize = 12;
+ CHeader h;
+ {
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
+ if (memcmp(buf, k_Signature, 6) != 0)
+ return S_FALSE;
+ h.Parse(buf);
+ }
+
+ if (h.file_hdr_sz != kHeaderSize ||
+ h.chunk_hdr_sz != kChunkHeaderSize)
+ return S_FALSE;
+
+ NumChunks = h.NumChunks;
+
+ const unsigned logSize = GetLogSize(h.BlockSize);
+ if (logSize < 2 || logSize >= 32)
+ return S_FALSE;
+ _blockSizeLog = logSize;
+
+ _size = (UInt64)h.NumBlocks << logSize;
+
+ if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit
+ return S_FALSE;
+
+ _isArc = true;
+ Chunks.Reserve(h.NumChunks + 1);
+ UInt64 offset = kHeaderSize;
+ UInt32 virtBlock = 0;
+ UInt32 i;
+
+ for (i = 0; i < h.NumChunks; i++)
+ {
+ {
+ const UInt32 mask = ((UInt32)1 << 16) - 1;
+ if ((i & mask) == mask && openCallback)
+ {
+ RINOK(openCallback->SetCompleted(NULL, &offset));
+ }
+ }
+ Byte buf[kChunkHeaderSize];
+ {
+ size_t processed = kChunkHeaderSize;
+ RINOK(ReadStream(stream, buf, &processed));
+ if (kChunkHeaderSize != processed)
+ {
+ offset += kChunkHeaderSize;
+ break;
+ }
+ }
+ const UInt32 type = Get32(&buf[0]);
+ const UInt32 numBlocks = Get32(&buf[4]);
+ UInt32 size = Get32(&buf[8]);
+
+ if (type < CHUNK_TYPE_RAW ||
+ type > CHUNK_TYPE_CRC32)
+ return S_FALSE;
+ if (size < kChunkHeaderSize)
+ return S_FALSE;
+ CChunk c;
+ c.PhyOffset = offset + kChunkHeaderSize;
+ c.VirtBlock = virtBlock;
+ offset += size;
+ size -= kChunkHeaderSize;
+ _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW));
+
+ if (numBlocks > h.NumBlocks - virtBlock)
+ return S_FALSE;
+
+ if (type == CHUNK_TYPE_CRC32)
+ {
+ // crc chunk must be last chunk (i == h.NumChunks -1);
+ if (size != kFillSize || numBlocks != 0)
+ return S_FALSE;
+ {
+ size_t processed = kFillSize;
+ RINOK(ReadStream(stream, c.Fill, &processed));
+ if (kFillSize != processed)
+ break;
+ }
+ continue;
+ }
+ // else
+ {
+ if (numBlocks == 0)
+ return S_FALSE;
+
+ if (type == CHUNK_TYPE_DONT_CARE)
+ {
+ if (size != 0)
+ return S_FALSE;
+ c.PhyOffset = MY__CHUNK_TYPE_DONT_CARE;
+ }
+ else if (type == CHUNK_TYPE_FILL)
+ {
+ if (size != kFillSize)
+ return S_FALSE;
+ c.PhyOffset = MY__CHUNK_TYPE_FILL;
+ size_t processed = kFillSize;
+ RINOK(ReadStream(stream, c.Fill, &processed));
+ if (kFillSize != processed)
+ break;
+ }
+ else if (type == CHUNK_TYPE_RAW)
+ {
+ /* Here we require (size == virtSize).
+ Probably original decoder also requires it.
+ But maybe size of last chunk can be non-aligned with blockSize ? */
+ const UInt32 virtSize = (numBlocks << _blockSizeLog);
+ if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog))
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ virtBlock += numBlocks;
+ Chunks.AddInReserved(c);
+ if (type == CHUNK_TYPE_RAW)
+ RINOK(stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ }
+ }
+
+ if (i != h.NumChunks)
+ _unexpectedEnd = true;
+ else if (virtBlock != h.NumBlocks)
+ _headersError = true;
+
+ _phySize = offset;
+
+ {
+ CChunk c;
+ c.VirtBlock = virtBlock;
+ c.PhyOffset = offset;
+ Chunks.AddInReserved(c);
+ }
+ _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog;
+
+ Stream = stream;
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Close()
+{
+ Chunks.Clear();
+ _isArc = false;
+ _virtSize_fromChunks = 0;
+ // _unsupported = false;
+ _headersError = false;
+ _unexpectedEnd = false;
+ _phySize = 0;
+ _methodFlags = 0;
+
+ _chunkIndexPrev = 0;
+ _packSizeProcessed = 0;
+
+ // CHandlerImg:
+ Clear_HandlerImg_Vars();
+ Stream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ if (Chunks.Size() < 1)
+ return S_FALSE;
+ if (Chunks.Size() < 2 && _virtSize_fromChunks != 0)
+ return S_FALSE;
+ // if (_unsupported) return S_FALSE;
+ InitSeekPositions();
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+
+HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed)
+{
+ processed = 0;
+ if (offset > _phySize || offset + size > _phySize)
+ {
+ // we don't expect these cases, if (_phySize) was set correctly.
+ return S_FALSE;
+ }
+ if (offset != _posInArc)
+ {
+ const HRESULT res = Seek2(offset);
+ if (res != S_OK)
+ {
+ Reset_PosInArc(); // we don't trust seek_pos in case of error
+ return res;
+ }
+ }
+ {
+ size_t size2 = size;
+ const HRESULT res = ReadStream(Stream, data, &size2);
+ processed = (UInt32)size2;
+ _packSizeProcessed += size2;
+ _posInArc += size2;
+ if (res != S_OK)
+ Reset_PosInArc(); // we don't trust seek_pos in case of reading error
+ return res;
+ }
+}
+
+
+STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug
+ if (_virtPos >= _virtSize_fromChunks)
+ return S_OK;
+ {
+ const UInt64 rem = _virtSize_fromChunks - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ }
+
+ UInt32 chunkIndex = _chunkIndexPrev;
+ if (chunkIndex + 1 >= Chunks.Size())
+ return S_FALSE;
+ {
+ const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog);
+ if (blockIndex < Chunks[chunkIndex ].VirtBlock ||
+ blockIndex >= Chunks[chunkIndex + 1].VirtBlock)
+ {
+ unsigned left = 0, right = Chunks.Size() - 1;
+ for (;;)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ if (mid == left)
+ break;
+ if (blockIndex < Chunks[mid].VirtBlock)
+ right = mid;
+ else
+ left = mid;
+ }
+ chunkIndex = left;
+ _chunkIndexPrev = chunkIndex;
+ }
+ }
+
+ const CChunk &c = Chunks[chunkIndex];
+ const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog);
+ {
+ const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock;
+ const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ const UInt64 phyOffset = c.PhyOffset;
+
+ if (phyOffset >= MY__CHUNK_TYPE_RAW__START)
+ {
+ UInt32 processed = 0;
+ const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed);
+ if (processedSize)
+ *processedSize = processed;
+ _virtPos += processed;
+ return res;
+ }
+
+ unsigned b = 0;
+
+ if (phyOffset == MY__CHUNK_TYPE_FILL)
+ {
+ const Byte b0 = c.Fill [0];
+ const Byte b1 = c.Fill [1];
+ const Byte b2 = c.Fill [2];
+ const Byte b3 = c.Fill [3];
+ if (b0 != b1 ||
+ b0 != b2 ||
+ b0 != b3)
+ {
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ Byte *dest = (Byte *)data;
+ while (size >= 4)
+ {
+ dest[0] = b0;
+ dest[1] = b1;
+ dest[2] = b2;
+ dest[3] = b3;
+ dest += 4;
+ size -= 4;
+ }
+ if (size > 0) dest[0] = b0;
+ if (size > 1) dest[1] = b1;
+ if (size > 2) dest[2] = b2;
+ return S_OK;
+ }
+ b = b0;
+ }
+ else if (phyOffset != MY__CHUNK_TYPE_DONT_CARE)
+ return S_FALSE;
+
+ memset(data, b, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+REGISTER_ARC_I(
+ "Sparse", "simg img", NULL, 0xc2,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp
index 6705aee0..6bddfb83 100644..100755
--- a/CPP/7zip/Archive/SplitHandler.cpp
+++ b/CPP/7zip/Archive/SplitHandler.cpp
@@ -162,7 +162,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
numLetters++;
}
}
- else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01"))
+ else if (ext2.Len() >= 2 && (
+ StringsAreEqual_Ascii(ext2.RightPtr(2), "01")
+ || StringsAreEqual_Ascii(ext2.RightPtr(2), "00")
+ ))
{
while (numLetters < ext2.Len())
{
@@ -170,7 +173,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break;
numLetters++;
}
- if (numLetters != ext.Len())
+ if (numLetters != ext2.Len())
return S_FALSE;
}
else
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp
index 74bc8fb8..fe271bc3 100644..100755
--- a/CPP/7zip/Archive/SquashfsHandler.cpp
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -76,7 +76,7 @@ static const char * const k_Methods[] =
, "XZ"
};
-static const UInt32 kMetadataBlockSizeLog = 13;
+static const unsigned kMetadataBlockSizeLog = 13;
static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
enum
@@ -408,7 +408,7 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
{
- bool be = _h.be;
+ const bool be = _h.be;
if (size < 4)
return 0;
{
@@ -541,7 +541,7 @@ UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
{
- bool be = _h.be;
+ const bool be = _h.be;
if (size < 12)
return 0;
@@ -843,8 +843,8 @@ class CHandler:
CData _inodesData;
CData _dirs;
CRecordVector<CFrag> _frags;
- // CByteBuffer _uids;
- // CByteBuffer _gids;
+ CByteBuffer _uids;
+ CByteBuffer _gids;
CHeader _h;
bool _noPropsLZMA;
bool _needCheckLzma;
@@ -891,14 +891,20 @@ class CHandler:
_cachedUnpackBlockSize = 0;
}
+ HRESULT Seek2(UInt64 offset)
+ {
+ return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ }
+
HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
UInt32 inSize, UInt32 outSizeMax);
HRESULT ReadMetadataBlock(UInt32 &packSize);
+ HRESULT ReadMetadataBlock2();
HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
HRESULT ScanInodes(UInt64 ptr);
- // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
+ HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
HRESULT Open2(IInStream *inStream);
AString GetPath(int index) const;
bool GetPackSize(int index, UInt64 &res, bool fillOffsets);
@@ -938,9 +944,9 @@ static const Byte kProps[] =
kpidSize,
kpidPackSize,
kpidMTime,
- kpidPosixAttrib
- // kpidUser,
- // kpidGroup,
+ kpidPosixAttrib,
+ kpidUserId,
+ kpidGroupId
// kpidLinks,
// kpidOffset
};
@@ -1280,14 +1286,14 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool
HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
{
Byte temp[3];
- unsigned offset = _h.NeedCheckData() ? 3 : 2;
+ const unsigned offset = _h.NeedCheckData() ? 3 : 2;
if (offset > packSize)
return S_FALSE;
RINOK(ReadStream_FALSE(_stream, temp, offset));
// if (NeedCheckData && Major < 4) checkByte must be = 0xFF
- bool be = _h.be;
+ const bool be = _h.be;
UInt32 size = Get16(temp);
- bool isCompressed = ((size & kNotCompressedBit16) == 0);
+ const bool isCompressed = ((size & kNotCompressedBit16) == 0);
if (size != kNotCompressedBit16)
size &= ~kNotCompressedBit16;
@@ -1311,12 +1317,20 @@ HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
return S_OK;
}
+
+HRESULT CHandler::ReadMetadataBlock2()
+{
+ _dynOutStreamSpec->Init();
+ UInt32 packSize = kMetadataBlockSize + 3; // check it
+ return ReadMetadataBlock(packSize);
+}
+
HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end)
{
if (end < start || end - start >= ((UInt64)1 << 32))
return S_FALSE;
const UInt32 size = (UInt32)(end - start);
- RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL));
+ RINOK(Seek2(start));
_dynOutStreamSpec->Init();
UInt32 packPos = 0;
while (packPos != size)
@@ -1395,7 +1409,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
CRecordVector<CTempItem> tempItems;
while (rem != 0)
{
- bool be = _h.be;
+ const bool be = _h.be;
UInt32 count;
CTempItem tempItem;
if (_h.Major <= 2)
@@ -1519,15 +1533,15 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
return S_OK;
}
-/*
HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids)
{
- size_t size = num * 4;
- ids.SetCapacity(size);
- RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL));
+ const size_t size = (size_t)num * 4;
+ ids.Alloc(size);
+ if (num == 0)
+ return S_OK;
+ RINOK(Seek2(start));
return ReadStream_FALSE(_stream, ids, size);
}
-*/
HRESULT CHandler::Open2(IInStream *inStream)
{
@@ -1560,24 +1574,22 @@ HRESULT CHandler::Open2(IInStream *inStream)
if (_h.NumFrags > kNumFilesMax)
return S_FALSE;
_frags.ClearAndReserve(_h.NumFrags);
- unsigned bigFrag = (_h.Major > 2);
+ const unsigned bigFrag = (_h.Major > 2);
- unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
- UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
- size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
+ const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
+ const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
+ const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
CByteBuffer data(numBlocksBytes);
- RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL));
+ RINOK(Seek2(_h.FragTable));
RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
- bool be = _h.be;
+ const bool be = _h.be;
for (UInt32 i = 0; i < numBlocks; i++)
{
- UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
- RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
- _dynOutStreamSpec->Init();
- UInt32 packSize = kMetadataBlockSize + 3;
- RINOK(ReadMetadataBlock(packSize));
- UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
+ const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
+ RINOK(Seek2(offset));
+ RINOK(ReadMetadataBlock2());
+ const UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
if (unpackSize != kMetadataBlockSize)
if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
return S_FALSE;
@@ -1605,8 +1617,6 @@ HRESULT CHandler::Open2(IInStream *inStream)
return S_FALSE;
}
- // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL));
-
RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable));
RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable));
@@ -1655,7 +1665,6 @@ HRESULT CHandler::Open2(IInStream *inStream)
int rootNodeIndex;
RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex));
- /*
if (_h.Major < 4)
{
RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids));
@@ -1663,33 +1672,34 @@ HRESULT CHandler::Open2(IInStream *inStream)
}
else
{
- UInt32 size = _h.NumIDs * 4;
- _uids.SetCapacity(size);
+ const UInt32 size = (UInt32)_h.NumIDs * 4;
+ _uids.Alloc(size);
- UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
- UInt32 numBlocksBytes = numBlocks << 3;
+ const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
+ const UInt32 numBlocksBytes = numBlocks << 3;
CByteBuffer data;
- data.SetCapacity(numBlocksBytes);
- RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL));
+ data.Alloc(numBlocksBytes);
+ RINOK(Seek2(_h.UidTable));
RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
for (UInt32 i = 0; i < numBlocks; i++)
{
- UInt64 offset = GetUi64(data + i * 8);
- UInt32 unpackSize, packSize;
- RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
- RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
+ const UInt64 offset = GetUi64(data + i * 8);
+ RINOK(Seek2(offset));
+ // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
+ RINOK(ReadMetadataBlock2());
+ const size_t unpackSize = _dynOutStreamSpec->GetSize();
if (unpackSize != kMetadataBlockSize)
if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1)))
return S_FALSE;
+ memcpy(_uids + kMetadataBlockSize * i, _dynOutStreamSpec->GetBuffer(), unpackSize);
}
}
- */
{
const UInt32 alignSize = 1 << 12;
Byte buf[alignSize];
- RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL));
+ RINOK(Seek2(_h.Size));
UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
_sizeCalculated = _h.Size;
if (rem != 0)
@@ -1710,7 +1720,7 @@ AString CHandler::GetPath(int index) const
{
unsigned len = 0;
int indexMem = index;
- bool be = _h.be;
+ const bool be = _h.be;
do
{
const CItem &item = _items[index];
@@ -1804,9 +1814,9 @@ bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
totalPack = 0;
const CItem &item = _items[index];
const CNode &node = _nodes[item.Node];
- UInt32 ptr = _nodesPos[item.Node];
+ const UInt32 ptr = _nodesPos[item.Node];
const Byte *p = _inodesData.Data + ptr;
- bool be = _h.be;
+ const bool be = _h.be;
UInt32 type = node.Type;
UInt32 offset;
@@ -1936,11 +1946,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidBigEndian: prop = _h.be; break;
case kpidCTime:
if (_h.CTime != 0)
- {
- FILETIME ft;
- NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft);
- prop = ft;
- }
+ PropVariant_SetFrom_UnixTime(prop, _h.CTime);
break;
case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
// case kpidNumBlocks: prop = _h.NumFrags; break;
@@ -1979,8 +1985,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
NWindows::NCOM::CPropVariant prop;
const CItem &item = _items[index];
const CNode &node = _nodes[item.Node];
- bool isDir = node.IsDir();
- bool be = _h.be;
+ const bool isDir = node.IsDir();
+ const bool be = _h.be;
switch (propID)
{
@@ -2031,9 +2037,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (offset != 0)
{
const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
- FILETIME ft;
- NWindows::NTime::UnixTimeToFileTime(Get32(p), ft);
- prop = ft;
+ PropVariant_SetFrom_UnixTime(prop, Get32(p));
}
break;
}
@@ -2043,31 +2047,38 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
break;
}
- /*
- case kpidUser:
+ case kpidUserId:
{
- UInt32 offset = node.Uid * 4;
+ const UInt32 offset = (UInt32)node.Uid * 4;
if (offset < _uids.Size())
prop = (UInt32)Get32(_uids + offset);
break;
}
- case kpidGroup:
+ case kpidGroupId:
{
- if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex())
+ if (_h.Major < 4)
{
- UInt32 offset = node.Uid * 4;
- if (offset < _uids.Size())
- prop = (UInt32)Get32(_uids + offset);
+ if (node.Gid == _h.GetSpecGuidIndex())
+ {
+ const UInt32 offset = (UInt32)node.Uid * 4;
+ if (offset < _uids.Size())
+ prop = (UInt32)Get32(_uids + offset);
+ }
+ else
+ {
+ const UInt32 offset = (UInt32)node.Gid * 4;
+ if (offset < _gids.Size())
+ prop = (UInt32)Get32(_gids + offset);
+ }
}
else
{
- UInt32 offset = node.Gid * 4;
- if (offset < _gids.Size())
- prop = (UInt32)Get32(_gids + offset);
+ const UInt32 offset = (UInt32)node.Gid * 4;
+ if (offset < _uids.Size())
+ prop = (UInt32)Get32(_uids + offset);
}
break;
}
- */
/*
case kpidLinks:
if (_h.Major >= 3 && node.Type != kType_FILE)
@@ -2128,7 +2139,7 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
packBlockSize != _cachedPackBlockSize)
{
ClearCache();
- RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL));
+ RINOK(Seek2(blockOffset));
_limitedInStreamSpec->Init(packBlockSize);
if (compressed)
diff --git a/CPP/7zip/Archive/StdAfx.h b/CPP/7zip/Archive/StdAfx.h
index 1cbd7fea..1cbd7fea 100644..100755
--- a/CPP/7zip/Archive/StdAfx.h
+++ b/CPP/7zip/Archive/StdAfx.h
diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp
index a5ff1877..a5ff1877 100644..100755
--- a/CPP/7zip/Archive/SwfHandler.cpp
+++ b/CPP/7zip/Archive/SwfHandler.cpp
diff --git a/CPP/7zip/Archive/Tar/StdAfx.h b/CPP/7zip/Archive/Tar/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Tar/StdAfx.h
+++ b/CPP/7zip/Archive/Tar/StdAfx.h
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
index 2f23dd85..bd04bd7d 100644..100755
--- a/CPP/7zip/Archive/Tar/TarHandler.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -36,22 +36,34 @@ static const Byte kProps[] =
kpidSize,
kpidPackSize,
kpidMTime,
+ kpidCTime,
+ kpidATime,
kpidPosixAttrib,
kpidUser,
kpidGroup,
+ kpidUserId,
+ kpidGroupId,
kpidSymLink,
kpidHardLink,
- kpidCharacts
- // kpidLinkType
+ kpidCharacts,
+ kpidComment
+ , kpidDeviceMajor
+ , kpidDeviceMinor
+ // , kpidDevice
+ // , kpidHeadersSize // for debug
+ // , kpidOffset // for debug
};
static const Byte kArcProps[] =
{
kpidHeadersSize,
kpidCodePage,
- kpidCharacts
+ kpidCharacts,
+ kpidComment
};
+static const char *k_Characts_Prefix = "PREFIX";
+
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
@@ -60,14 +72,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
NCOM::CPropVariant prop;
switch (propID)
{
- case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
- case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
+ case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break;
+ case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break;
case kpidErrorFlags:
{
UInt32 flags = 0;
if (!_isArc)
flags |= kpv_ErrorFlags_IsNotArc;
- else switch (_error)
+ else switch (_arc._error)
{
case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
@@ -82,7 +94,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidWarningFlags:
{
- if (_warning)
+ if (_arc._is_Warning)
prop = kpv_ErrorFlags_HeadersError;
break;
}
@@ -107,37 +119,38 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidCharacts:
{
- prop = _encodingCharacts.GetCharactsString();
+ AString s;
+ if (_arc._are_Gnu) s.Add_OptSpaced("GNU");
+ if (_arc._are_Posix) s.Add_OptSpaced("POSIX");
+ if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM");
+ if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix);
+ if (_arc._are_LongName) s.Add_OptSpaced("LongName");
+ if (_arc._are_LongLink) s.Add_OptSpaced("LongLink");
+ if (_arc._are_Pax) s.Add_OptSpaced("PAX");
+ if (_arc._are_pax_path) s.Add_OptSpaced("path");
+ if (_arc._are_pax_link) s.Add_OptSpaced("linkpath");
+ if (_arc._are_mtime) s.Add_OptSpaced("mtime");
+ if (_arc._are_atime) s.Add_OptSpaced("atime");
+ if (_arc._are_ctime) s.Add_OptSpaced("ctime");
+ if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR");
+ s.Add_OptSpaced(_encodingCharacts.GetCharactsString());
+ prop = s;
break;
}
- }
- prop.Detach(value);
- return S_OK;
-}
-HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
-{
- item.HeaderPos = _phySize;
- EErrorType error;
- HRESULT res = ReadItem(stream, filled, item, error);
- if (error == k_ErrorType_Warning)
- _warning = true;
- else if (error != k_ErrorType_OK)
- _error = error;
- RINOK(res);
- if (filled)
- {
- /*
- if (item.IsSparse())
- _isSparse = true;
- */
- if (item.IsPaxExtendedHeader())
- _thereIsPaxExtendedHeader = true;
- if (item.IsThereWarning())
- _warning = true;
+ case kpidComment:
+ {
+ if (_arc.PaxGlobal_Defined)
+ {
+ AString s;
+ _arc.PaxGlobal.Print_To_String(s);
+ if (!s.IsEmpty())
+ prop = s;
+ }
+ break;
+ }
}
- _phySize += item.HeaderSize;
- _headersSize += item.HeaderSize;
+ prop.Detach(value);
return S_OK;
}
@@ -199,16 +212,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
}
- _phySizeDefined = true;
+ _arc._phySize_Defined = true;
// bool utf8_OK = true;
+ _arc.SeqStream = stream;
+ _arc.InStream = stream;
+ _arc.OpenCallback = callback;
+
+ CItemEx item;
for (;;)
{
- CItemEx item;
- bool filled;
- RINOK(ReadItem2(stream, filled, item));
- if (!filled)
+ _arc.NumFiles = _items.Size();
+ RINOK(_arc.ReadItem(item));
+ if (!_arc.filled)
break;
_isArc = true;
@@ -228,10 +245,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
_items.Add(item);
- RINOK(stream->Seek((Int64)item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
- if (_phySize > endPos)
+ RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize));
+ if (_arc._phySize > endPos)
{
- _error = k_ErrorType_UnexpectedEnd;
+ _arc._error = k_ErrorType_UnexpectedEnd;
break;
}
/*
@@ -241,6 +258,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break;
}
*/
+ /*
if (callback)
{
if (_items.Size() == 1)
@@ -249,10 +267,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
if ((_items.Size() & 0x3FF) == 0)
{
- UInt64 numFiles = _items.Size();
+ const UInt64 numFiles = _items.Size();
RINOK(callback->SetCompleted(&numFiles, &_phySize));
}
}
+ */
}
/*
@@ -266,7 +285,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
if (_items.Size() == 0)
{
- if (_error != k_ErrorType_OK)
+ if (_arc._error != k_ErrorType_OK)
{
_isArc = false;
return S_FALSE;
@@ -294,6 +313,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)
{
COM_TRY_BEGIN
+ // for (int i = 0; i < 10; i++) // for debug
{
Close();
RINOK(Open2(stream, openArchiveCallback));
@@ -314,16 +334,11 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close()
{
_isArc = false;
- _warning = false;
- _error = k_ErrorType_OK;
- _phySizeDefined = false;
- _phySize = 0;
- _headersSize = 0;
+ _arc.Clear();
+
_curIndex = 0;
_latestIsRead = false;
- // _isSparse = false;
- _thereIsPaxExtendedHeader = false;
_encodingCharacts.Clear();
_items.Clear();
_seqStream.Release();
@@ -351,12 +366,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
{
if (_latestIsRead)
{
- UInt64 packSize = _latestItem.GetPackSizeAligned();
+ const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
- _phySize += copyCoderSpec->TotalSize;
+ _arc._phySize += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != packSize)
{
- _error = k_ErrorType_UnexpectedEnd;
+ _arc._error = k_ErrorType_UnexpectedEnd;
return S_FALSE;
}
_latestIsRead = false;
@@ -364,11 +379,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
}
else
{
- bool filled;
- RINOK(ReadItem2(_seqStream, filled, _latestItem));
- if (!filled)
+ _arc.SeqStream = _seqStream;
+ _arc.InStream = NULL;
+ RINOK(_arc.ReadItem(_latestItem));
+ if (!_arc.filled)
{
- _phySizeDefined = true;
+ _arc._phySize_Defined = true;
return E_INVALIDARG;
}
_latestIsRead = true;
@@ -390,6 +406,69 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant
prop = dest;
}
+
+static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop)
+{
+ UInt64 v;
+ if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v))
+ return;
+ if (pt.Ns != 0)
+ v += pt.Ns / 100;
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft,
+ k_PropVar_TimePrec_Base + pt.NumDigits, pt.Ns % 100);
+}
+
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void AddByteToHex2(unsigned val, AString &s)
+{
+ unsigned t;
+ t = val >> 4;
+ s += ValToHex(t);
+ t = val & 0xF;
+ s += ValToHex(t);
+}
+
+static void AddSpecCharToString(const char c, AString &s)
+{
+ if ((Byte)c <= 0x20 || (Byte)c > 127)
+ {
+ s += '[';
+ AddByteToHex2((Byte)(c), s);
+ s += ']';
+ }
+ else
+ s += c;
+}
+
+static void AddSpecUInt64(AString &s, const char *name, UInt64 v)
+{
+ if (v != 0)
+ {
+ s.Add_OptSpaced(name);
+ if (v > 1)
+ {
+ s += ':';
+ s.Add_UInt64(v);
+ }
+ }
+}
+
+static void AddSpecBools(AString &s, const char *name, bool b1, bool b2)
+{
+ if (b1)
+ {
+ s.Add_OptSpaced(name);
+ if (b2)
+ s += '*';
+ }
+}
+
+
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
@@ -413,49 +492,189 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
case kpidIsDir: prop = item->IsDir(); break;
- case kpidSize: prop = item->GetUnpackSize(); break;
- case kpidPackSize: prop = item->GetPackSizeAligned(); break;
+ case kpidSize: prop = item->Get_UnpackSize(); break;
+ case kpidPackSize: prop = item->Get_PackSize_Aligned(); break;
case kpidMTime:
- if (item->MTime != 0)
+ {
+ /*
+ // for debug:
+ PropVariant_SetFrom_UnixTime(prop, 1 << 30);
+ prop.wReserved1 = k_PropVar_TimePrec_Base + 1;
+ prop.wReserved2 = 12;
+ break;
+ */
+
+ if (item->PaxTimes.MTime.IsDefined())
+ PaxTimeToProp(item->PaxTimes.MTime, prop);
+ else
+ // if (item->MTime != 0)
{
+ // we allow (item->MTime == 0)
FILETIME ft;
- if (NTime::UnixTime64ToFileTime(item->MTime, ft))
- prop = ft;
+ if (NTime::UnixTime64_To_FileTime(item->MTime, ft))
+ {
+ unsigned prec = k_PropVar_TimePrec_Unix;
+ if (item->MTime_IsBin)
+ {
+ /* we report here that it's Int64-UnixTime
+ instead of basic UInt32-UnixTime range */
+ prec = k_PropVar_TimePrec_Base;
+ }
+ prop.SetAsTimeFrom_FT_Prec(ft, prec);
+ }
}
break;
+ }
+ case kpidATime:
+ if (item->PaxTimes.ATime.IsDefined())
+ PaxTimeToProp(item->PaxTimes.ATime, prop);
+ break;
+ case kpidCTime:
+ if (item->PaxTimes.CTime.IsDefined())
+ PaxTimeToProp(item->PaxTimes.CTime, prop);
+ break;
case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break;
- case kpidUser: TarStringToUnicode(item->User, prop); break;
- case kpidGroup: TarStringToUnicode(item->Group, prop); break;
- case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
- case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
- // case kpidLinkType: prop = (int)item->LinkFlag; break;
+
+ case kpidUser:
+ if (!item->User.IsEmpty())
+ TarStringToUnicode(item->User, prop);
+ break;
+ case kpidGroup:
+ if (!item->Group.IsEmpty())
+ TarStringToUnicode(item->Group, prop);
+ break;
+
+ case kpidUserId:
+ // if (item->UID != 0)
+ prop = (UInt32)item->UID;
+ break;
+ case kpidGroupId:
+ // if (item->GID != 0)
+ prop = (UInt32)item->GID;
+ break;
+
+ case kpidDeviceMajor:
+ if (item->DeviceMajor_Defined)
+ // if (item->DeviceMajor != 0)
+ prop = (UInt32)item->DeviceMajor;
+ break;
+
+ case kpidDeviceMinor:
+ if (item->DeviceMinor_Defined)
+ // if (item->DeviceMinor != 0)
+ prop = (UInt32)item->DeviceMinor;
+ break;
+ /*
+ case kpidDevice:
+ if (item->DeviceMajor_Defined)
+ if (item->DeviceMinor_Defined)
+ prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor);
+ break;
+ */
+
+ case kpidSymLink:
+ if (item->Is_SymLink())
+ if (!item->LinkName.IsEmpty())
+ TarStringToUnicode(item->LinkName, prop);
+ break;
+ case kpidHardLink:
+ if (item->Is_HardLink())
+ if (!item->LinkName.IsEmpty())
+ TarStringToUnicode(item->LinkName, prop);
+ break;
+
case kpidCharacts:
{
- AString s = item->EncodingCharacts.GetCharactsString();
- if (item->IsThereWarning())
+ AString s;
{
s.Add_Space_if_NotEmpty();
- s += "HEADER_ERROR";
+ AddSpecCharToString(item->LinkFlag, s);
}
- prop = s;
+ if (item->IsMagic_GNU())
+ s.Add_OptSpaced("GNU");
+ else if (item->IsMagic_Posix_ustar_00())
+ s.Add_OptSpaced("POSIX");
+ else
+ {
+ s.Add_Space_if_NotEmpty();
+ for (unsigned i = 0; i < sizeof(item->Magic); i++)
+ AddSpecCharToString(item->Magic[i], s);
+ }
+
+ if (item->IsSignedChecksum)
+ s.Add_OptSpaced("SignedChecksum");
+
+ if (item->Prefix_WasUsed)
+ s.Add_OptSpaced(k_Characts_Prefix);
+
+ s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString());
+
+ // AddSpecUInt64(s, "LongName", item->Num_LongName_Records);
+ // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records);
+ AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2);
+ AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2);
+
+ if (item->MTime_IsBin)
+ s.Add_OptSpaced("bin_mtime");
+ if (item->PackSize_IsBin)
+ s.Add_OptSpaced("bin_psize");
+ if (item->Size_IsBin)
+ s.Add_OptSpaced("bin_size");
+
+ AddSpecUInt64(s, "PAX", item->Num_Pax_Records);
+
+ if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime");
+ if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime");
+ if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime");
+
+ if (item->pax_path_WasUsed)
+ s.Add_OptSpaced("pax_path");
+ if (item->pax_link_WasUsed)
+ s.Add_OptSpaced("pax_linkpath");
+ if (item->pax_size_WasUsed)
+ s.Add_OptSpaced("pax_size");
+
+ if (item->IsThereWarning())
+ s.Add_OptSpaced("WARNING");
+ if (item->HeaderError)
+ s.Add_OptSpaced("ERROR");
+ if (item->Pax_Error)
+ s.Add_OptSpaced("PAX_error");
+ if (!item->PaxExtra.RawLines.IsEmpty())
+ s.Add_OptSpaced("PAX_unsupported_line");
+ if (item->Pax_Overflow)
+ s.Add_OptSpaced("PAX_overflow");
+ if (!s.IsEmpty())
+ prop = s;
break;
}
+ case kpidComment:
+ {
+ AString s;
+ item->PaxExtra.Print_To_String(s);
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug
+ // case kpidOffset: prop = item->HeaderPos; break; // for debug
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
+
HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
ISequentialInStream *stream = _seqStream;
- bool seqMode = (_stream == NULL);
+ const bool seqMode = (_stream == NULL);
if (!seqMode)
stream = _stream;
- bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (_stream && numItems == 0)
@@ -463,7 +682,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
- totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
+ totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
extractCallback->SetTotal(totalSize);
UInt64 totalPackSize;
@@ -503,9 +722,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
item = &_items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
- UInt64 unpackSize = item->GetUnpackSize();
+ const UInt64 unpackSize = item->Get_UnpackSize();
totalSize += unpackSize;
- totalPackSize += item->GetPackSizeAligned();
+ totalPackSize += item->Get_PackSize_Aligned();
if (item->IsDir())
{
RINOK(extractCallback->PrepareOperation(askMode));
@@ -539,7 +758,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 opRes = NExtract::NOperationResult::kOK;
CMyComPtr<ISequentialInStream> inStream2;
- if (!item->IsSparse())
+ if (!item->Is_Sparse())
inStream2 = inStream;
else
{
@@ -549,7 +768,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
{
- if (item->IsSymLink())
+ if (item->Is_SymLink())
{
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
}
@@ -557,9 +776,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
if (!seqMode)
{
- RINOK(_stream->Seek((Int64)item->GetDataPosition(), STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek((Int64)item->Get_DataPos(), STREAM_SEEK_SET, NULL));
}
- streamSpec->Init(item->GetPackSizeAligned());
+ streamSpec->Init(item->Get_PackSize_Aligned());
RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
}
if (outStreamSpec->GetRem() != 0)
@@ -628,7 +847,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
unsigned left = 0, right = item.SparseBlocks.Size();
for (;;)
{
- unsigned mid = (left + right) / 2;
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
if (mid == left)
break;
if (_virtPos < item.SparseBlocks[mid].Offset)
@@ -648,7 +867,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
UInt64 phyPos = PhyOffsets[left] + relat;
if (_needStartSeek || _phyPos != phyPos)
{
- RINOK(Handler->_stream->Seek((Int64)(item.GetDataPosition() + phyPos), STREAM_SEEK_SET, NULL));
+ RINOK(Handler->_stream->Seek((Int64)(item.Get_DataPos() + phyPos), STREAM_SEEK_SET, NULL));
_needStartSeek = false;
_phyPos = phyPos;
}
@@ -698,7 +917,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
const CItemEx &item = _items[index];
- if (item.IsSparse())
+ if (item.Is_Sparse())
{
CSparseStream *streamSpec = new CSparseStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
@@ -718,24 +937,30 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
return S_OK;
}
- if (item.IsSymLink())
+ if (item.Is_SymLink())
{
Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream);
return S_OK;
}
- return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream);
+ return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream);
COM_TRY_END
}
+
void CHandler::Init()
{
_forceCodePage = false;
_curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
- _thereIsPaxExtendedHeader = false;
+ _posixMode = false;
+ _posixMode_WasForced = false;
+ // TimeOptions.Clear();
+ _handlerTimeOptions.Init();
+ // _handlerTimeOptions.Write_MTime.Val = true; // it's default already
}
+
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
Init();
@@ -768,8 +993,54 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
else if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
{
}
+ else if (name.IsEqualTo("m"))
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ const UString s = prop.bstrVal;
+ if (s.IsEqualTo_Ascii_NoCase("pax") ||
+ s.IsEqualTo_Ascii_NoCase("posix"))
+ _posixMode = true;
+ else if (s.IsEqualTo_Ascii_NoCase("gnu"))
+ _posixMode = false;
+ else
+ return E_INVALIDARG;
+ _posixMode_WasForced = true;
+ }
else
+ {
+ /*
+ if (name.IsPrefixedBy_Ascii_NoCase("td"))
+ {
+ name.Delete(0, 3);
+ if (prop.vt == VT_EMPTY)
+ {
+ if (name.IsEqualTo_Ascii_NoCase("n"))
+ {
+ // TimeOptions.UseNativeDigits = true;
+ }
+ else if (name.IsEqualTo_Ascii_NoCase("r"))
+ {
+ // TimeOptions.RemoveZeroDigits = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else
+ {
+ UInt32 numTimeDigits = 0;
+ RINOK(ParsePropToUInt32(name, prop, numTimeDigits));
+ TimeOptions.NumDigits_WasForced = true;
+ TimeOptions.NumDigits = numTimeDigits;
+ }
+ }
+ */
+ bool processed = false;
+ RINOK(_handlerTimeOptions.Parse(name, prop, processed));
+ if (processed)
+ continue;
return E_INVALIDARG;
+ }
}
return S_OK;
}
diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h
index 4834c2a7..44a99809 100644..100755
--- a/CPP/7zip/Archive/Tar/TarHandler.h
+++ b/CPP/7zip/Archive/Tar/TarHandler.h
@@ -9,7 +9,7 @@
#include "../../Compress/CopyCoder.h"
-#include "../IArchive.h"
+#include "../Common/HandlerOut.h"
#include "TarIn.h"
@@ -29,31 +29,26 @@ public:
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
private:
- UInt32 _curIndex;
- bool _latestIsRead;
- CItemEx _latestItem;
-
- UInt64 _phySize;
- UInt64 _headersSize;
- bool _phySizeDefined;
- EErrorType _error;
- bool _warning;
bool _isArc;
-
- // bool _isSparse;
- bool _thereIsPaxExtendedHeader;
-
+ bool _posixMode_WasForced;
+ bool _posixMode;
bool _forceCodePage;
UInt32 _specifiedCodePage;
UInt32 _curCodePage;
UInt32 _openCodePage;
-
+ // CTimeOptions TimeOptions;
+ CHandlerTimeOptions _handlerTimeOptions;
CEncodingCharacts _encodingCharacts;
+ UInt32 _curIndex;
+ bool _latestIsRead;
+ CItemEx _latestItem;
+
+ CArchive _arc;
+
NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder;
- HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
HRESULT SkipTo(UInt32 index);
void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const;
diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
index 5ddb4b24..53255e4c 100644..100755
--- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -2,15 +2,16 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../Common/ComTry.h"
-#include "../../../Common/Defs.h"
#include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h"
-#include "../../../Common/UTFConvert.h"
-#include "../../../Windows/PropVariant.h"
#include "../../../Windows/TimeUtils.h"
+#include "../Common/ItemNameUtils.h"
+
#include "TarHandler.h"
#include "TarUpdate.h"
@@ -21,10 +22,35 @@ namespace NTar {
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
{
- *type = NFileTimeType::kUnix;
+ UInt32 t = NFileTimeType::kUnix;
+ const UInt32 prec = _handlerTimeOptions.Prec;
+ if (prec != (UInt32)(Int32)-1)
+ {
+ t = NFileTimeType::kWindows;
+ if (prec == k_PropVar_TimePrec_0 ||
+ prec == k_PropVar_TimePrec_100ns)
+ t = NFileTimeType::kWindows;
+ else if (prec == k_PropVar_TimePrec_HighPrec)
+ t = k_PropVar_TimePrec_1ns;
+ else if (prec >= k_PropVar_TimePrec_Base)
+ t = prec;
+ }
+ // 7-Zip before 22.00 fails, if unknown typeType.
+ *type = t;
return S_OK;
}
+
+void Get_AString_From_UString(const UString &s, AString &res,
+ UINT codePage, unsigned utfFlags)
+{
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
+ else
+ UnicodeStringToMultiByte2(res, s, codePage);
+}
+
+
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
UINT codePage, unsigned utfFlags, bool convertSlash)
{
@@ -36,14 +62,7 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
UString s = prop.bstrVal;
if (convertSlash)
NItemName::ReplaceSlashes_OsToUnix(s);
-
- if (codePage == CP_UTF8)
- {
- ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
- // if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG;
- }
- else
- UnicodeStringToMultiByte2(res, s, codePage);
+ Get_AString_From_UString(s, res, codePage, utfFlags);
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
@@ -70,12 +89,106 @@ static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
}
+static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback,
+ CPaxTime &pt)
+{
+ pt.Clear();
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pid, &prop));
+ return Prop_To_PaxTime(prop, pt);
+}
+
+
+/*
+static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
+ UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidDevice, &prop));
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ {
+ const UInt64 v = prop.uhVal.QuadPart;
+ majo = MY_dev_major(v);
+ mino = MY_dev_minor(v);
+ majo_defined = true;
+ mino_defined = true;
+ }
+ return S_OK;
+}
+*/
+
+static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
+ UInt32 pid, UInt32 &id, bool &defined)
+{
+ defined = false;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pid, &prop));
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ defined = true;
+ return S_OK;
+ }
+ return E_INVALIDARG;
+}
+
+
+static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i,
+ UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
+ UINT codePage, unsigned utfFlags)
+{
+ // printf("\ncallback->GetProperty(i, pidId, &prop))\n");
+
+ bool isSet = false;
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pidId, &prop));
+ if (prop.vt == VT_UI4)
+ {
+ isSet = true;
+ id = prop.ulVal;
+ // printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id);
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pidName, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ const UString s = prop.bstrVal;
+ Get_AString_From_UString(s, name, codePage, utfFlags);
+ if (!isSet)
+ id = 0;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+
+
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
- if ((_stream && (_error != k_ErrorType_OK || _warning /* || _isSparse */)) || _seqStream)
+ if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning
+ /* || _isSparse */
+ )) || _seqStream)
return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems;
const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
@@ -131,25 +244,30 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
ui.Mode = prop.ulVal;
// 21.07 : we clear high file type bits as GNU TAR.
- ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
+ // we will clear it later
+ // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
}
- {
- NCOM::CPropVariant prop;
- RINOK(callback->GetProperty(i, kpidMTime, &prop));
- if (prop.vt == VT_EMPTY)
- ui.MTime = 0;
- else if (prop.vt != VT_FILETIME)
- return E_INVALIDARG;
- else
- ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
- }
-
+ if (_handlerTimeOptions.Write_MTime.Val)
+ RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime))
+ if (_handlerTimeOptions.Write_ATime.Val)
+ RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime))
+ if (_handlerTimeOptions.Write_CTime.Val)
+ RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime))
+
RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true));
if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
ui.Name += '/';
- RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage, utfFlags, false));
- RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage, utfFlags, false));
+ // ui.Name += '/'; // for debug
+
+ if (_posixMode)
+ {
+ RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined));
+ RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined));
+ }
+
+ RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags));
+ RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags));
}
if (IntToBool(newData))
@@ -169,13 +287,44 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
updateItems.Add(ui);
}
- if (_thereIsPaxExtendedHeader)
+ if (_arc._are_Pax_Items)
{
- // we restore original order of files, if there is pax header block
+ // we restore original order of files, if there are pax items
updateItems.Sort(CompareUpdateItems, NULL);
}
+
+ CUpdateOptions options;
+
+ options.CodePage = codePage;
+ options.UtfFlags = utfFlags;
+ options.PosixMode = _posixMode;
+
+ options.Write_MTime = _handlerTimeOptions.Write_MTime;
+ options.Write_ATime = _handlerTimeOptions.Write_ATime;
+ options.Write_CTime = _handlerTimeOptions.Write_CTime;
- return UpdateArchive(_stream, outStream, _items, updateItems, codePage, utfFlags, callback);
+ // options.TimeOptions = TimeOptions;
+
+ const UInt32 prec = _handlerTimeOptions.Prec;
+ if (prec != (UInt32)(Int32)-1)
+ {
+ unsigned numDigits = 0;
+ if (prec == 0)
+ numDigits = 7;
+ else if (prec == k_PropVar_TimePrec_HighPrec
+ || prec >= k_PropVar_TimePrec_1ns)
+ numDigits = 9;
+ else if (prec >= k_PropVar_TimePrec_Base)
+ numDigits = prec - k_PropVar_TimePrec_Base;
+ options.TimeOptions.NumDigitsMax = numDigits;
+ // options.TimeOptions.RemoveZeroMode =
+ // k_PaxTimeMode_DontRemoveZero; // pure for debug
+ // k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code
+ // k_PaxTimeMode_RemoveZero_Always; // original pax code
+ }
+
+ return UpdateArchive(_stream, outStream, _items, updateItems,
+ options, callback);
COM_TRY_END
}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp
index 9c16c895..f1efddb5 100644..100755
--- a/CPP/7zip/Archive/Tar/TarHeader.cpp
+++ b/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -18,9 +18,82 @@ namespace NFileHeader {
// const char * const kGNUTar = "GNUtar "; // 7 chars and a null
// const char * const kEmpty = "\0\0\0\0\0\0\0\0";
// 7-Zip used kUsTar_00 before 21.07:
- // const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
+ const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
// GNU TAR uses such header:
- const char kUsTar_GNU[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ;
+ const char k_GNU_ustar__[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ;
}
+/*
+pre-POSIX.1-1988 (i.e. v7) tar header:
+-----
+Link indicator:
+'0' or 0 : Normal file
+'1' : Hard link
+'2' : Symbolic link
+Some pre-POSIX.1-1988 tar implementations indicated a directory by having
+a trailing slash (/) in the name.
+
+Numeric values : octal with leading zeroes.
+For historical reasons, a final NUL or space character should also be used.
+Thus only 11 octal digits can be stored from 12 bytes field.
+
+2001 star : introduced a base-256 coding that is indicated by
+setting the high-order bit of the leftmost byte of a numeric field.
+GNU-tar and BSD-tar followed this idea.
+
+versions of tar from before the first POSIX standard from 1988
+pad the values with spaces instead of zeroes.
+
+UStar
+-----
+UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988.
+ 257 signature: "ustar", 0, "00"
+ 265 32 Owner user name
+ 297 32 Owner group name
+ 329 8 Device major number
+ 337 8 Device minor number
+ 345 155 Filename prefix
+
+POSIX.1-2001/pax
+----
+format is known as extended tar format or pax format
+vendor-tagged vendor-specific enhancements.
+tags Defined by the POSIX standard:
+ atime, mtime, path, linkpath, uname, gname, size, uid, gid, ...
+
+
+PAX EXTENSION
+-----------
+Hard links
+A further difference from the ustar header block is that data blocks
+for files of typeflag 1 (hard link) may be included,
+which means that the size field may be greater than zero.
+Archives created by pax -o linkdata shall include these data
+blocks with the hard links.
+*
+
+compatiblity
+------------
+ 7-Zip 16.03 supports "PaxHeader/"
+ 7-Zip 20.01 supports "PaxHeaders.X/" with optional "./"
+ 7-Zip 21.02 supports "@PaxHeader" with optional "./" "./"
+
+ GNU tar --format=posix uses "PaxHeaders/" in folder of file
+
+
+GNU TAR format
+==============
+v7 - Unix V7
+oldgnu - GNU tar <=1.12 : writes zero in last character in name
+gnu - GNU tar 1.13 : doesn't write zero in last character in name
+ as 7-zip 21.07
+ustar - POSIX.1-1988
+posix (pax) - POSIX.1-2001
+
+ gnu tar:
+ if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) {
+ major_t devmajor = major (st->stat.st_rdev);
+ minor_t devminor = minor (st->stat.st_rdev); }
+*/
+
}}}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h
index b0f0ec34..1af30935 100644..100755
--- a/CPP/7zip/Archive/Tar/TarHeader.h
+++ b/CPP/7zip/Archive/Tar/TarHeader.h
@@ -59,6 +59,9 @@ namespace NFileHeader
const char kGnu_LongName = 'L';
const char kSparse = 'S';
const char kLabel = 'V';
+ const char kPax = 'x'; // Extended header with meta data for the next file in the archive (POSIX.1-2001)
+ const char kPax_2 = 'X';
+ const char kGlobal = 'g'; // Global extended header with meta data (POSIX.1-2001)
const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
data: list of files created by the --incremental (-G) option
Each file name is preceded by either
@@ -66,6 +69,7 @@ namespace NFileHeader
- 'N' (file is a directory, or is not stored in the archive.)
Each file name is terminated by a null + an additional null after
the last file name. */
+ // 'A'-'Z' Vendor specific extensions (POSIX.1-1988)
}
extern const char * const kLongLink; // = "././@LongLink";
@@ -76,8 +80,8 @@ namespace NFileHeader
// extern const char * const kUsTar; // = "ustar"; // 5 chars
// extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null
// extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0"
- // extern const char kUsTar_00[8];
- extern const char kUsTar_GNU[8];
+ extern const char k_Posix_ustar_00[8];
+ extern const char k_GNU_ustar__[8];
}
}
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
index 58399d0c..4fd8c5b1 100644..100755
--- a/CPP/7zip/Archive/Tar/TarIn.cpp
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -12,6 +12,45 @@
#include "TarIn.h"
+#define NUM_UNROLL_BYTES (8 * 4)
+
+MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size);
+MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+
+ for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--)
+ if (*p++ != 0)
+ return true;
+
+ if (size >= NUM_UNROLL_BYTES)
+ {
+ const Byte *lim = p + size;
+ size &= (NUM_UNROLL_BYTES - 1);
+ lim -= size;
+ do
+ {
+ if (*(const UInt64 *)(const void *)(p ) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p ) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true;
+ p += NUM_UNROLL_BYTES;
+ }
+ while (p != lim);
+ }
+
+ for (; size != 0; size--)
+ if (*p++ != 0)
+ return true;
+
+ return false;
+}
+
+
namespace NArchive {
namespace NTar {
@@ -41,10 +80,11 @@ static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, boo
return (*end == ' ' || *end == 0);
}
-static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, bool allowEmpty = false)
+static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false)
{
+ const unsigned kSize = 8;
UInt64 res64;
- if (!OctalToNumber(srcString, size, res64, allowEmpty))
+ if (!OctalToNumber(srcString, kSize, res64, allowEmpty))
return false;
res = (UInt32)res64;
return (res64 <= 0xFFFFFFFF);
@@ -52,68 +92,61 @@ static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, b
#define RIF(x) { if (!(x)) return S_OK; }
-/*
-static bool IsEmptyData(const char *buf, size_t size)
-{
- for (unsigned i = 0; i < size; i++)
- if (buf[i] != 0)
- return false;
- return true;
-}
-*/
-
-static bool IsRecordLast(const char *buf)
-{
- for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
- if (buf[i] != 0)
- return false;
- return true;
-}
-
static void ReadString(const char *s, unsigned size, AString &result)
{
result.SetFrom_CalcLen(s, size);
}
-static bool ParseInt64(const char *p, Int64 &val)
+static bool ParseInt64(const char *p, Int64 &val, bool &isBin)
{
- UInt32 h = GetBe32(p);
+ const UInt32 h = GetBe32(p);
val = (Int64)GetBe64(p + 4);
+ isBin = true;
if (h == (UInt32)1 << 31)
return ((val >> 63) & 1) == 0;
if (h == (UInt32)(Int32)-1)
return ((val >> 63) & 1) != 0;
- UInt64 uv;
- bool res = OctalToNumber(p, 12, uv);
- val = (Int64)uv;
+ isBin = false;
+ UInt64 u;
+ const bool res = OctalToNumber(p, 12, u);
+ val = (Int64)u;
return res;
}
-static bool ParseInt64_MTime(const char *p, Int64 &val)
+static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin)
{
// rare case tar : ZEROs in Docker-Windows TARs
// rare case tar : spaces
+ isBin = false;
if (GetUi32(p) != 0)
for (unsigned i = 0; i < 12; i++)
if (p[i] != ' ')
- return ParseInt64(p, val);
+ return ParseInt64(p, val, isBin);
val = 0;
return true;
}
-static bool ParseSize(const char *p, UInt64 &val)
+static bool ParseSize(const char *p, UInt64 &val, bool &isBin)
{
if (GetBe32(p) == (UInt32)1 << 31)
{
// GNU extension
+ isBin = true;
val = GetBe64(p + 4);
return ((val >> 63) & 1) == 0;
}
+ isBin = false;
return OctalToNumber(p, 12, val,
true // 20.03: allow empty size for 'V' Label entry
);
}
+static bool ParseSize(const char *p, UInt64 &val)
+{
+ bool isBin;
+ return ParseSize(p, val, isBin);
+}
+
#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; }
API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
@@ -126,26 +159,27 @@ API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
UInt32 mode;
// we allow empty Mode value for LongName prefix items
- CHECK(OctalToNumber32(p, 8, mode, true)); p += 8;
+ CHECK(OctalToNumber32(p, mode, true)); p += 8;
- // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0;
+ // if (!OctalToNumber32(p, item.UID)) item.UID = 0;
p += 8;
- // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0;
+ // if (!OctalToNumber32(p, item.GID)) item.GID = 0;
p += 8;
UInt64 packSize;
Int64 time;
UInt32 checkSum;
- CHECK(ParseSize(p, packSize)); p += 12;
- CHECK(ParseInt64_MTime(p, time)); p += 12;
- CHECK(OctalToNumber32(p, 8, checkSum));
+ bool isBin;
+ CHECK(ParseSize(p, packSize, isBin)); p += 12;
+ CHECK(ParseInt64_MTime(p, time, isBin)); p += 12;
+ CHECK(OctalToNumber32(p, checkSum));
return k_IsArc_Res_YES;
}
-static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
+
+HRESULT CArchive::GetNextItemReal(CItemEx &item)
{
char buf[NFileHeader::kRecordSize];
- char *p = buf;
error = k_ErrorType_OK;
filled = false;
@@ -154,7 +188,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
for (;;)
{
size_t processedSize = NFileHeader::kRecordSize;
- RINOK(ReadStream(stream, buf, &processedSize));
+ RINOK(ReadStream(SeqStream, buf, &processedSize));
if (processedSize == 0)
{
if (!thereAreEmptyRecords)
@@ -180,10 +214,14 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
- if (!IsRecordLast(buf))
+ if (IsBufNonZero(buf, NFileHeader::kRecordSize))
break;
item.HeaderSize += NFileHeader::kRecordSize;
thereAreEmptyRecords = true;
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0));
+ }
}
if (thereAreEmptyRecords)
{
@@ -191,52 +229,69 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
+ char *p = buf;
+
error = k_ErrorType_Corrupted;
- ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
- item.NameCouldBeReduced =
+
+ // ReadString(p, NFileHeader::kNameSize, item.Name);
+ p += NFileHeader::kNameSize;
+
+ /*
+ item.Name_CouldBeReduced =
(item.Name.Len() == NFileHeader::kNameSize ||
item.Name.Len() == NFileHeader::kNameSize - 1);
+ */
// we allow empty Mode value for LongName prefix items
- RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8;
+ RIF(OctalToNumber32(p, item.Mode, true)); p += 8;
- if (!OctalToNumber32(p, 8, item.UID)) { item.UID = 0; } p += 8;
- if (!OctalToNumber32(p, 8, item.GID)) { item.GID = 0; } p += 8;
+ if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8;
+ if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8;
- RIF(ParseSize(p, item.PackSize));
+ RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin));
item.Size = item.PackSize;
+ item.Size_IsBin = item.PackSize_IsBin;
p += 12;
- RIF(ParseInt64_MTime(p, item.MTime)); p += 12;
+ RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)); p += 12;
UInt32 checkSum;
- RIF(OctalToNumber32(p, 8, checkSum));
+ RIF(OctalToNumber32(p, checkSum));
memset(p, ' ', 8); p += 8;
item.LinkFlag = *p++;
ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
- item.LinkNameCouldBeReduced =
+
+ /*
+ item.LinkName_CouldBeReduced =
(item.LinkName.Len() == NFileHeader::kNameSize ||
item.LinkName.Len() == NFileHeader::kNameSize - 1);
+ */
memcpy(item.Magic, p, 8); p += 8;
ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
- item.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8;
- item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8;
+ item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)); } p += 8;
+ item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)); } p += 8;
- if (p[0] != 0)
+ if (p[0] != 0
+ && item.IsMagic_ustar_5chars()
+ && (item.LinkFlag != 'L' ))
{
- AString prefix;
- ReadString(p, NFileHeader::kPrefixSize, prefix);
- if (!prefix.IsEmpty()
- && item.IsUstarMagic()
- && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
- item.Name = prefix + '/' + item.Name;
+ item.Prefix_WasUsed = true;
+ ReadString(p, NFileHeader::kPrefixSize, item.Name);
+ item.Name += '/';
+ unsigned i;
+ for (i = 0; i < NFileHeader::kNameSize; i++)
+ if (buf[i] == 0)
+ break;
+ item.Name.AddFrom(buf, i);
}
-
+ else
+ ReadString(buf, NFileHeader::kNameSize, item.Name);
+
p += NFileHeader::kPrefixSize;
if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink)
@@ -255,22 +310,25 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
/*
TAR standard requires sum of unsigned byte values.
- But some TAR programs use sum of signed byte values.
+ But some old TAR programs use sum of signed byte values.
So we check both values.
*/
- UInt32 checkSumReal = 0;
- Int32 checkSumReal_Signed = 0;
- for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ // for (int y = 0; y < 100; y++) // for debug
{
- char c = buf[i];
- checkSumReal_Signed += (signed char)c;
- checkSumReal += (Byte)buf[i];
- }
-
- if (checkSumReal != checkSum)
- {
- if ((UInt32)checkSumReal_Signed != checkSum)
- return S_OK;
+ UInt32 sum0 = 0;
+ {
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ sum0 += (Byte)buf[i];
+ }
+ if (sum0 != checkSum)
+ {
+ Int32 sum = 0;
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ sum += (signed char)buf[i];
+ if ((UInt32)sum != checkSum)
+ return S_OK;
+ item.IsSignedChecksum = true;
+ }
}
item.HeaderSize += NFileHeader::kRecordSize;
@@ -280,7 +338,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
Byte isExtended = (Byte)buf[482];
if (isExtended != 0 && isExtended != 1)
return S_OK;
- RIF(ParseSize(buf + 483, item.Size));
+ RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin));
UInt64 min = 0;
for (unsigned i = 0; i < 4; i++)
{
@@ -309,7 +367,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
while (isExtended != 0)
{
size_t processedSize = NFileHeader::kRecordSize;
- RINOK(ReadStream(stream, buf, &processedSize));
+ RINOK(ReadStream(SeqStream, buf, &processedSize));
if (processedSize != NFileHeader::kRecordSize)
{
error = k_ErrorType_UnexpectedEnd;
@@ -317,6 +375,12 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
}
item.HeaderSize += NFileHeader::kRecordSize;
+
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0));
+ }
+
isExtended = (Byte)buf[21 * 24];
if (isExtended != 0 && isExtended != 1)
return S_OK;
@@ -346,172 +410,711 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
+ if (item.PackSize >= (UInt64)1 << 63)
+ return S_OK;
+
filled = true;
error = k_ErrorType_OK;
return S_OK;
}
-static HRESULT ReadDataToString(ISequentialInStream *stream, CItemEx &item, AString &s, EErrorType &error)
+HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset)
{
- const unsigned packSize = (unsigned)item.GetPackSizeAligned();
- size_t processedSize = packSize;
- HRESULT res = ReadStream(stream, s.GetBuf(packSize), &processedSize);
- item.HeaderSize += (unsigned)processedSize;
- s.ReleaseBuf_CalcLen((unsigned)item.PackSize);
- RINOK(res);
- if (processedSize != packSize)
- error = k_ErrorType_UnexpectedEnd;
+ const UInt64 pos = item.Get_DataPos() + posOffset;
+ if (NumFiles - NumFiles_Prev < (1 << 16)
+ // && NumRecords - NumRecords_Prev < (1 << 16)
+ && pos - Pos_Prev < ((UInt32)1 << 28))
+ return S_OK;
+ {
+ Pos_Prev = pos;
+ NumFiles_Prev = NumFiles;
+ // NumRecords_Prev = NumRecords;
+ // Sleep(100); // for debug
+ return OpenCallback->SetCompleted(&NumFiles, &pos);
+ }
+}
+
+
+HRESULT CArchive::ReadDataToBuffer(const CItemEx &item,
+ CTempBuffer &tb, size_t stringLimit)
+{
+ tb.Init();
+ UInt64 packSize = item.Get_PackSize_Aligned();
+ if (packSize == 0)
+ return S_OK;
+
+ UInt64 pos;
+
+ {
+ size_t size = stringLimit;
+ if (size > packSize)
+ size = (size_t)packSize;
+ tb.Buffer.AllocAtLeast(size);
+ size_t processedSize = size;
+ const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize);
+ pos = processedSize;
+ if (processedSize != size)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return res;
+ }
+ RINOK(res);
+
+ packSize -= size;
+
+ size_t i;
+ const Byte *p = tb.Buffer;
+ for (i = 0; i < size; i++)
+ if (p[i] == 0)
+ break;
+ if (i >= item.PackSize)
+ tb.StringSize_IsConfirmed = true;
+ if (i > item.PackSize)
+ {
+ tb.StringSize = (size_t)item.PackSize;
+ tb.IsNonZeroTail = true;
+ }
+ else
+ {
+ tb.StringSize = i;
+ if (i != size)
+ {
+ tb.StringSize_IsConfirmed = true;
+ if (IsBufNonZero(p + i, size - i))
+ tb.IsNonZeroTail = true;
+ }
+ }
+
+ if (packSize == 0)
+ return S_OK;
+ }
+
+ if (InStream)
+ {
+ RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL));
+ return S_OK;
+ }
+ const unsigned kBufSize = 1 << 15;
+ Buffer.AllocAtLeast(kBufSize);
+
+ do
+ {
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, pos));
+ }
+
+ unsigned size = kBufSize;
+ if (size > packSize)
+ size = (unsigned)packSize;
+ size_t processedSize = size;
+ const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize);
+ if (processedSize != size)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return res;
+ }
+ if (!tb.IsNonZeroTail)
+ {
+ if (IsBufNonZero(Buffer, size))
+ tb.IsNonZeroTail = true;
+ }
+ packSize -= size;
+ pos += size;
+ }
+ while (packSize != 0);
return S_OK;
}
+
-static bool ParsePaxLongName(const AString &src, AString &dest)
+
+struct CPaxInfo: public CPaxTimes
{
- dest.Empty();
- for (unsigned pos = 0;;)
+ bool DoubleTagError;
+ bool TagParsingError;
+ bool UnknownLines_Overflow;
+ bool Size_Defined;
+ bool UID_Defined;
+ bool GID_Defined;
+ bool Path_Defined;
+ bool Link_Defined;
+ bool User_Defined;
+ bool Group_Defined;
+
+ UInt64 Size;
+ UInt32 UID;
+ UInt32 GID;
+
+ AString Path;
+ AString Link;
+ AString User;
+ AString Group;
+ AString UnknownLines;
+
+ bool ParseID(const AString &val, bool &defined, UInt32 &res)
{
- if (pos >= src.Len())
+ if (defined)
+ DoubleTagError = true;
+ if (val.IsEmpty())
return false;
- const char *start = src.Ptr(pos);
- const char *end;
- const UInt32 lineLen = ConvertStringToUInt32(start, &end);
- if (end == start)
+ const char *end2;
+ res = ConvertStringToUInt32(val.Ptr(), &end2);
+ if (*end2 != 0)
return false;
- if (*end != ' ')
+ defined = true;
+ return true;
+ }
+
+ bool ParsePax(const CTempBuffer &tb, bool isFile);
+};
+
+
+static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError)
+{
+ if (pt.IsDefined())
+ doubleTagError = true;
+ pt.Clear();
+ const char *s = src.Ptr();
+ bool isNegative = false;
+ if (*s == '-')
+ {
+ isNegative = true;
+ s++;
+ }
+ const char *end;
+ {
+ UInt64 sec = ConvertStringToUInt64(s, &end);
+ if (s == end)
return false;
- if (lineLen > src.Len() - pos)
+ if (sec >= ((UInt64)1 << 63))
return false;
- unsigned offset = (unsigned)(end - start) + 1;
- if (lineLen < offset)
+ if (isNegative)
+ sec = -(Int64)sec;
+ pt.Sec = sec;
+ }
+ if (*end == 0)
+ {
+ pt.Ns = 0;
+ pt.NumDigits = 0;
+ return true;
+ }
+ if (*end != '.')
+ return false;
+ s = end + 1;
+
+ UInt32 ns = 0;
+ unsigned i;
+ const unsigned kNsDigits = 9;
+ for (i = 0;; i++)
+ {
+ const char c = s[i];
+ if (c == 0)
+ break;
+ if (c < '0' || c > '9')
return false;
- if (IsString1PrefixedByString2(src.Ptr(pos + offset), "path="))
+ // we ignore digits after 9 digits as GNU TAR
+ if (i < kNsDigits)
+ {
+ ns *= 10;
+ ns += c - '0';
+ }
+ }
+ pt.NumDigits = (i < kNsDigits ? i : kNsDigits);
+ while (i < kNsDigits)
+ {
+ ns *= 10;
+ i++;
+ }
+ if (isNegative && ns != 0)
+ {
+ pt.Sec--;
+ ns = (UInt32)1000 * 1000 * 1000 - ns;
+ }
+ pt.Ns = ns;
+ return true;
+}
+
+
+bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile)
+{
+ DoubleTagError = false;
+ TagParsingError = false;
+ UnknownLines_Overflow = false;
+ Size_Defined = false;
+ UID_Defined = false;
+ GID_Defined = false;
+ Path_Defined = false;
+ Link_Defined = false;
+ User_Defined = false;
+ Group_Defined = false;
+
+ // CPaxTimes::Clear();
+
+ const char *s = (const char *)(const void *)(const Byte *)tb.Buffer;
+ size_t rem = tb.StringSize;
+
+ Clear();
+
+ AString name, val;
+
+ while (rem != 0)
+ {
+ unsigned i;
+ for (i = 0;; i++)
{
- offset += 5; // "path="
- dest = src.Mid(pos + offset, lineLen - offset);
- if (dest.IsEmpty())
+ if (i > 24 || i >= rem) // we use limitation for size of (size) field
return false;
- if (dest.Back() != '\n')
+ if (s[i] == ' ')
+ break;
+ }
+ if (i == 0)
+ return false;
+ const char *end;
+ const UInt32 size = ConvertStringToUInt32(s, &end);
+ const unsigned offset = (unsigned)(end - s) + 1;
+ if (size > rem
+ || size <= offset + 1
+ || offset != i + 1
+ || s[size - 1] != '\n')
+ return false;
+
+ for (i = offset; i < size; i++)
+ if (s[i] == 0)
return false;
- dest.DeleteBack();
- return true;
+
+ for (i = offset; i < size - 1; i++)
+ if (s[i] == '=')
+ break;
+ if (i == size - 1)
+ return false;
+
+ name.SetFrom(s + offset, i - offset);
+ val.SetFrom(s + i + 1, size - 1 - (i + 1));
+
+ bool parsed = false;
+ if (isFile)
+ {
+ bool isDetectedName = true;
+ // only lower case (name) is supported
+ if (name.IsEqualTo("path"))
+ {
+ if (Path_Defined)
+ DoubleTagError = true;
+ Path = val;
+ Path_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("linkpath"))
+ {
+ if (Link_Defined)
+ DoubleTagError = true;
+ Link = val;
+ Link_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("uname"))
+ {
+ if (User_Defined)
+ DoubleTagError = true;
+ User = val;
+ User_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("gname"))
+ {
+ if (Group_Defined)
+ DoubleTagError = true;
+ Group = val;
+ Group_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("uid"))
+ {
+ parsed = ParseID(val, UID_Defined, UID);
+ }
+ else if (name.IsEqualTo("gid"))
+ {
+ parsed = ParseID(val, GID_Defined, GID);
+ }
+ else if (name.IsEqualTo("size"))
+ {
+ if (Size_Defined)
+ DoubleTagError = true;
+ Size_Defined = false;
+ if (!val.IsEmpty())
+ {
+ const char *end2;
+ Size = ConvertStringToUInt64(val.Ptr(), &end2);
+ if (*end2 == 0)
+ {
+ Size_Defined = true;
+ parsed = true;
+ }
+ }
+ }
+ else if (name.IsEqualTo("mtime"))
+ { parsed = ParsePaxTime(val, MTime, DoubleTagError); }
+ else if (name.IsEqualTo("atime"))
+ { parsed = ParsePaxTime(val, ATime, DoubleTagError); }
+ else if (name.IsEqualTo("ctime"))
+ { parsed = ParsePaxTime(val, CTime, DoubleTagError); }
+ else
+ isDetectedName = false;
+ if (isDetectedName && !parsed)
+ TagParsingError = true;
}
- pos += lineLen;
+ if (!parsed)
+ {
+ if (!UnknownLines_Overflow)
+ {
+ const unsigned addSize = size - offset;
+ if (UnknownLines.Len() + addSize < (1 << 16))
+ UnknownLines.AddFrom(s + offset, addSize);
+ else
+ UnknownLines_Overflow = true;
+ }
+ }
+
+ s += size;
+ rem -= size;
}
+ return true;
}
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
+
+HRESULT CArchive::ReadItem2(CItemEx &item)
{
+ // CItem
+
+ item.SparseBlocks.Clear();
+ item.PaxTimes.Clear();
+
+ // CItemEx
+
item.HeaderSize = 0;
+ item.Num_Pax_Records = 0;
- bool flagL = false;
- bool flagK = false;
- AString nameL;
- AString nameK;
- AString pax;
+ item.LongName_WasUsed = false;
+ item.LongName_WasUsed_2 = false;
+
+ item.LongLink_WasUsed = false;
+ item.LongLink_WasUsed_2 = false;
+
+ item.HeaderError = false;
+ item.IsSignedChecksum = false;
+ item.Prefix_WasUsed = false;
- for (;;)
+ item.Pax_Error = false;
+ item.Pax_Overflow = false;
+ item.pax_path_WasUsed = false;
+ item.pax_link_WasUsed = false;
+ item.pax_size_WasUsed = false;
+
+ item.PaxExtra.Clear();
+
+ item.EncodingCharacts.Clear();
+
+ // CArchive temp variable
+
+ NameBuf.Init();
+ LinkBuf.Init();
+ PaxBuf.Init();
+ PaxBuf_global.Init();
+
+ for (unsigned recordIndex = 0;; recordIndex++)
{
- RINOK(GetNextItemReal(stream, filled, item, error));
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0));
+ }
+
+ RINOK(GetNextItemReal(item));
+
+ // NumRecords++;
+
if (!filled)
{
- if (error == k_ErrorType_OK && (flagL || flagK))
+ if (error == k_ErrorType_OK)
+ if (item.LongName_WasUsed ||
+ item.LongLink_WasUsed ||
+ item.Num_Pax_Records != 0)
error = k_ErrorType_Corrupted;
- return S_OK;
}
if (error != k_ErrorType_OK)
return S_OK;
- if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name
- item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname
+ const char lf = item.LinkFlag;
+ if (lf == NFileHeader::NLinkFlag::kGnu_LongName ||
+ lf == NFileHeader::NLinkFlag::kGnu_LongLink)
{
- AString *name;
- if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName)
- { if (flagL) return S_OK; flagL = true; name = &nameL; }
- else
- { if (flagK) return S_OK; flagK = true; name = &nameK; }
-
+ // GNU tar ignores item.Name after LinkFlag test
+ // 22.00 : now we also ignore item.Name here
+ /*
if (item.Name != NFileHeader::kLongLink &&
item.Name != NFileHeader::kLongLink2)
+ {
+ break;
+ // return S_OK;
+ }
+ */
+
+ CTempBuffer *tb =
+ lf == NFileHeader::NLinkFlag::kGnu_LongName ?
+ &NameBuf :
+ &LinkBuf;
+
+ /*
+ if (item.PackSize > (1 << 29))
+ {
+ // break;
return S_OK;
- if (item.PackSize > (1 << 14))
- return S_OK;
+ }
+ */
- RINOK(ReadDataToString(stream, item, *name, error));
+ const unsigned kLongNameSizeMax = (unsigned)1 << 14;
+ RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax));
if (error != k_ErrorType_OK)
return S_OK;
+ if (lf == NFileHeader::NLinkFlag::kGnu_LongName)
+ {
+ item.LongName_WasUsed_2 =
+ item.LongName_WasUsed;
+ item.LongName_WasUsed = true;
+ }
+ else
+ {
+ item.LongLink_WasUsed_2 =
+ item.LongLink_WasUsed;
+ item.LongLink_WasUsed = true;
+ }
+
+ if (!tb->StringSize_IsConfirmed)
+ tb->StringSize = 0;
+ item.HeaderSize += item.Get_PackSize_Aligned();
+ if (tb->StringSize == 0 ||
+ tb->StringSize + 1 != item.PackSize)
+ item.HeaderError = true;
+ if (tb->IsNonZeroTail)
+ item.HeaderError = true;
continue;
}
- switch (item.LinkFlag)
+ if (lf == NFileHeader::NLinkFlag::kGlobal ||
+ lf == NFileHeader::NLinkFlag::kPax ||
+ lf == NFileHeader::NLinkFlag::kPax_2)
{
- case 'g':
- case 'x':
- case 'X':
+ // GNU tar ignores item.Name after LinkFlag test
+ // 22.00 : now we also ignore item.Name here
+ /*
+ if (item.PackSize > (UInt32)1 << 26)
{
- const char *s = item.Name.Ptr();
- if (IsString1PrefixedByString2(s, "./"))
- s += 2;
- if (IsString1PrefixedByString2(s, "./"))
- s += 2;
- if ( IsString1PrefixedByString2(s, "PaxHeader/")
- || IsString1PrefixedByString2(s, "PaxHeaders.X/")
- || IsString1PrefixedByString2(s, "PaxHeaders.4467/")
- || StringsAreEqual_Ascii(s, "@PaxHeader")
- )
- {
- RINOK(ReadDataToString(stream, item, pax, error));
- if (error != k_ErrorType_OK)
- return S_OK;
- continue;
- }
- break;
+ break; // we don't want big PaxBuf files
+ // return S_OK;
}
- case NFileHeader::NLinkFlag::kDumpDir:
+ */
+ const unsigned kParsingPaxSizeMax = (unsigned)1 << 26;
+
+ const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize);
+
+ CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf);
+
+ RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax));
+ if (error != k_ErrorType_OK)
+ return S_OK;
+
+ item.HeaderSize += item.Get_PackSize_Aligned();
+
+ if (tb->StringSize != item.PackSize
+ || tb->StringSize == 0
+ || tb->IsNonZeroTail)
+ item.Pax_Error = true;
+
+ item.Num_Pax_Records++;
+ if (lf != NFileHeader::NLinkFlag::kGlobal)
{
- break;
- // GNU Extensions to the Archive Format
+ item.PaxExtra.RecordPath = item.Name;
+ continue;
}
- case NFileHeader::NLinkFlag::kSparse:
+ // break; // for debug
{
- break;
- // GNU Extensions to the Archive Format
+ if (PaxGlobal_Defined)
+ _is_PaxGlobal_Error = true;
+ CPaxInfo paxInfo;
+ if (paxInfo.ParsePax(PaxBuf_global, false))
+ {
+ PaxGlobal.RawLines = paxInfo.UnknownLines;
+ PaxGlobal.RecordPath = item.Name;
+ PaxGlobal_Defined = true;
+ }
+ else
+ _is_PaxGlobal_Error = true;
+ if (isStartHeader)
+ {
+ // we skip global pax header info after parsing
+ item.HeaderPos += item.HeaderSize;
+ item.HeaderSize = 0;
+ }
}
- default:
- if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
- return S_OK;
+ continue;
}
- if (flagL)
+ /*
+ if (lf == NFileHeader::NLinkFlag::kDumpDir ||
+ lf == NFileHeader::NLinkFlag::kSparse)
{
- item.Name = nameL;
- item.NameCouldBeReduced = false;
+ // GNU Extensions to the Archive Format
+ break;
}
-
- if (flagK)
+ if (lf > '7' || (lf < '0' && lf != 0))
{
- item.LinkName = nameK;
- item.LinkNameCouldBeReduced = false;
+ break;
+ // return S_OK;
}
-
- error = k_ErrorType_OK;
-
- if (!pax.IsEmpty())
+ */
+ break;
+ }
+
+ // we still use name from main header, if long_name is bad
+ if (item.LongName_WasUsed && NameBuf.StringSize != 0)
+ {
+ NameBuf.CopyToString(item.Name);
+ // item.Name_CouldBeReduced = false;
+ }
+
+ if (item.LongLink_WasUsed)
+ {
+ // we use empty link, if long_link is bad
+ LinkBuf.CopyToString(item.LinkName);
+ // item.LinkName_CouldBeReduced = false;
+ }
+
+ error = k_ErrorType_OK;
+
+ if (PaxBuf.StringSize != 0)
+ {
+ CPaxInfo paxInfo;
+ if (!paxInfo.ParsePax(PaxBuf, true))
+ item.Pax_Error = true;
+ else
{
- AString name;
- if (ParsePaxLongName(pax, name))
- item.Name = name;
- else
+ if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty())
+ {
+ item.Name = paxInfo.Path;
+ item.pax_path_WasUsed = true;
+ }
+ if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty())
+ {
+ item.LinkName = paxInfo.Link;
+ item.pax_link_WasUsed = true;
+ }
+ if (paxInfo.User_Defined)
+ {
+ item.User = paxInfo.User;
+ // item.pax_uname_WasUsed = true;
+ }
+ if (paxInfo.Group_Defined)
+ {
+ item.Group = paxInfo.Group;
+ // item.pax_gname_WasUsed = true;
+ }
+ if (paxInfo.UID_Defined)
{
- // no "path" property is allowed in pax4467
- // error = k_ErrorType_Warning;
+ item.UID = (UInt32)paxInfo.UID;
}
- pax.Empty();
+ if (paxInfo.GID_Defined)
+ {
+ item.GID = (UInt32)paxInfo.GID;
+ }
+
+ if (paxInfo.Size_Defined)
+ {
+ const UInt64 piSize = paxInfo.Size;
+ // GNU TAR ignores (item.Size) in that case
+ if (item.Size != 0 && item.Size != piSize)
+ item.Pax_Error = true;
+ item.Size = piSize;
+ item.PackSize = piSize;
+ item.pax_size_WasUsed = true;
+ }
+
+ item.PaxTimes = paxInfo;
+ item.PaxExtra.RawLines = paxInfo.UnknownLines;
+ if (paxInfo.UnknownLines_Overflow)
+ item.Pax_Overflow = true;
+ if (paxInfo.TagParsingError)
+ item.Pax_Error = true;
+ if (paxInfo.DoubleTagError)
+ item.Pax_Error = true;
}
+ }
- return S_OK;
+ return S_OK;
+}
+
+
+
+HRESULT CArchive::ReadItem(CItemEx &item)
+{
+ item.HeaderPos = _phySize;
+
+ const HRESULT res = ReadItem2(item);
+
+ /*
+ if (error == k_ErrorType_Warning)
+ _is_Warning = true;
+ else
+ */
+
+ if (error != k_ErrorType_OK)
+ _error = error;
+
+ RINOK(res);
+
+ if (filled)
+ {
+ if (item.IsMagic_GNU())
+ _are_Gnu = true;
+ else if (item.IsMagic_Posix_ustar_00())
+ _are_Posix = true;
+
+ if (item.Num_Pax_Records != 0)
+ _are_Pax = true;
+
+ if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true;
+ if (item.PaxTimes.ATime.IsDefined()) _are_atime = true;
+ if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true;
+
+ if (item.pax_path_WasUsed)
+ _are_pax_path = true;
+ if (item.pax_link_WasUsed)
+ _are_pax_link = true;
+ if (item.LongName_WasUsed)
+ _are_LongName = true;
+ if (item.LongLink_WasUsed)
+ _are_LongLink = true;
+ if (item.Prefix_WasUsed)
+ _pathPrefix_WasUsed = true;
+ /*
+ if (item.IsSparse())
+ _isSparse = true;
+ */
+ if (item.Is_PaxExtendedHeader())
+ _are_Pax_Items = true;
+ if (item.IsThereWarning()
+ || item.HeaderError
+ || item.Pax_Error)
+ _is_Warning = true;
}
+
+ const UInt64 headerEnd = item.HeaderPos + item.HeaderSize;
+ // _headersSize += headerEnd - _phySize;
+ // we don't count skipped records
+ _headersSize += item.HeaderSize;
+ _phySize = headerEnd;
+ return S_OK;
}
}}
diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h
index 1c508bcc..e99599a4 100644..100755
--- a/CPP/7zip/Archive/Tar/TarIn.h
+++ b/CPP/7zip/Archive/Tar/TarIn.h
@@ -3,7 +3,7 @@
#ifndef __ARCHIVE_TAR_IN_H
#define __ARCHIVE_TAR_IN_H
-#include "../../IStream.h"
+#include "../IArchive.h"
#include "TarItem.h"
@@ -14,11 +14,133 @@ enum EErrorType
{
k_ErrorType_OK,
k_ErrorType_Corrupted,
- k_ErrorType_UnexpectedEnd,
- k_ErrorType_Warning
+ k_ErrorType_UnexpectedEnd
+ // , k_ErrorType_Warning
+};
+
+
+struct CTempBuffer
+{
+ CByteBuffer Buffer;
+ size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize)
+ bool IsNonZeroTail;
+ bool StringSize_IsConfirmed;
+
+ void CopyToString(AString &s)
+ {
+ s.Empty();
+ if (StringSize != 0)
+ s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize);
+ }
+
+ void Init()
+ {
+ StringSize = 0;
+ IsNonZeroTail = false;
+ StringSize_IsConfirmed = false;
+ }
+};
+
+
+class CArchive
+{
+public:
+ bool _phySize_Defined;
+ bool _is_Warning;
+ bool PaxGlobal_Defined;
+ bool _is_PaxGlobal_Error;
+ bool _are_Pax_Items;
+ bool _are_Gnu;
+ bool _are_Posix;
+ bool _are_Pax;
+ bool _are_mtime;
+ bool _are_atime;
+ bool _are_ctime;
+ bool _are_pax_path;
+ bool _are_pax_link;
+ bool _are_LongName;
+ bool _are_LongLink;
+ bool _pathPrefix_WasUsed;
+ // bool _isSparse;
+
+ // temp internal vars for ReadItem():
+ bool filled;
+private:
+ EErrorType error;
+
+public:
+ UInt64 _phySize;
+ UInt64 _headersSize;
+ EErrorType _error;
+
+ ISequentialInStream *SeqStream;
+ IInStream *InStream;
+ IArchiveOpenCallback *OpenCallback;
+ UInt64 NumFiles;
+ UInt64 NumFiles_Prev;
+ UInt64 Pos_Prev;
+ // UInt64 NumRecords;
+ // UInt64 NumRecords_Prev;
+
+ CPaxExtra PaxGlobal;
+
+ void Clear()
+ {
+ SeqStream = NULL;
+ InStream = NULL;
+ OpenCallback = NULL;
+ NumFiles = 0;
+ NumFiles_Prev = 0;
+ Pos_Prev = 0;
+ // NumRecords = 0;
+ // NumRecords_Prev = 0;
+
+ PaxGlobal.Clear();
+ PaxGlobal_Defined = false;
+ _is_PaxGlobal_Error = false;
+ _are_Pax_Items = false; // if there are final paxItems
+ _are_Gnu = false;
+ _are_Posix = false;
+ _are_Pax = false;
+ _are_mtime = false;
+ _are_atime = false;
+ _are_ctime = false;
+ _are_pax_path = false;
+ _are_pax_link = false;
+ _are_LongName = false;
+ _are_LongLink = false;
+ _pathPrefix_WasUsed = false;
+ // _isSparse = false;
+
+ _is_Warning = false;
+ _error = k_ErrorType_OK;
+
+ _phySize_Defined = false;
+ _phySize = 0;
+ _headersSize = 0;
+ }
+
+private:
+ CTempBuffer NameBuf;
+ CTempBuffer LinkBuf;
+ CTempBuffer PaxBuf;
+ CTempBuffer PaxBuf_global;
+
+ CByteBuffer Buffer;
+
+ HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit);
+ HRESULT Progress(const CItemEx &item, UInt64 posOffset);
+ HRESULT GetNextItemReal(CItemEx &item);
+ HRESULT ReadItem2(CItemEx &itemInfo);
+public:
+ CArchive()
+ {
+ // we will call Clear() in CHandler::Close().
+ // Clear(); // it's not required here
+ }
+ HRESULT ReadItem(CItemEx &itemInfo);
};
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h
index f947786f..738618f2 100644..100755
--- a/CPP/7zip/Archive/Tar/TarItem.h
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -6,8 +6,6 @@
#include "../../../Common/MyLinux.h"
#include "../../../Common/UTFConvert.h"
-#include "../Common/ItemNameUtils.h"
-
#include "TarHeader.h"
namespace NArchive {
@@ -19,50 +17,149 @@ struct CSparseBlock
UInt64 Size;
};
+
+enum EPaxTimeRemoveZeroMode
+{
+ k_PaxTimeMode_DontRemoveZero,
+ k_PaxTimeMode_RemoveZero_if_PureSecondOnly,
+ k_PaxTimeMode_RemoveZero_Always
+};
+
+struct CTimeOptions
+{
+ EPaxTimeRemoveZeroMode RemoveZeroMode;
+ unsigned NumDigitsMax;
+
+ void Init()
+ {
+ RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly;
+ NumDigitsMax = 0;
+ }
+ CTimeOptions() { Init(); }
+};
+
+
+struct CPaxTime
+{
+ Int32 NumDigits; // -1 means undefined
+ UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files.
+ Int64 Sec; // can be negative
+
+ Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; }
+
+ bool IsDefined() const { return NumDigits != -1; }
+ // bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); }
+
+ void Clear()
+ {
+ NumDigits = -1;
+ Ns = 0;
+ Sec = 0;
+ }
+ CPaxTime() { Clear(); }
+
+ /*
+ void ReducePrecison(int numDigits)
+ {
+ // we don't use this->NumDigits here
+ if (numDigits > 0)
+ {
+ if (numDigits >= 9)
+ return;
+ UInt32 r = 1;
+ for (unsigned i = numDigits; i < 9; i++)
+ r *= 10;
+ Ns /= r;
+ Ns *= r;
+ return;
+ }
+ Ns = 0;
+ if (numDigits == 0)
+ return;
+ UInt32 r;
+ if (numDigits == -1) r = 60;
+ else if (numDigits == -2) r = 60 * 60;
+ else if (numDigits == -3) r = 60 * 60 * 24;
+ else return;
+ Sec /= r;
+ Sec *= r;
+ }
+ */
+};
+
+
+struct CPaxTimes
+{
+ CPaxTime MTime;
+ CPaxTime ATime;
+ CPaxTime CTime;
+
+ void Clear()
+ {
+ MTime.Clear();
+ ATime.Clear();
+ CTime.Clear();
+ }
+
+ /*
+ void ReducePrecison(int numDigits)
+ {
+ MTime.ReducePrecison(numDigits);
+ CTime.ReducePrecison(numDigits);
+ ATime.ReducePrecison(numDigits);
+ }
+ */
+};
+
+
struct CItem
{
- AString Name;
UInt64 PackSize;
UInt64 Size;
Int64 MTime;
+ char LinkFlag;
+ bool DeviceMajor_Defined;
+ bool DeviceMinor_Defined;
+
UInt32 Mode;
UInt32 UID;
UInt32 GID;
UInt32 DeviceMajor;
UInt32 DeviceMinor;
+ AString Name;
AString LinkName;
AString User;
AString Group;
char Magic[8];
- char LinkFlag;
- bool DeviceMajorDefined;
- bool DeviceMinorDefined;
+
+ CPaxTimes PaxTimes;
CRecordVector<CSparseBlock> SparseBlocks;
- void SetDefaultWriteFields()
+ void SetMagic_Posix(bool posixMode)
{
- DeviceMajorDefined = false;
- DeviceMinorDefined = false;
- UID = 0;
- GID = 0;
- memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 8);
+ memcpy(Magic, posixMode ?
+ NFileHeader::NMagic::k_Posix_ustar_00 :
+ NFileHeader::NMagic::k_GNU_ustar__,
+ 8);
}
- bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
- bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
- bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
- UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; }
- bool IsPaxExtendedHeader() const
+ bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
+ bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
+ bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
+
+ UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; }
+
+ bool Is_PaxExtendedHeader() const
{
switch (LinkFlag)
{
- case 'g':
- case 'x':
- case 'X': // Check it
+ case NFileHeader::NLinkFlag::kPax:
+ case NFileHeader::NLinkFlag::kPax_2:
+ case NFileHeader::NLinkFlag::kGlobal:
return true;
}
return false;
@@ -72,6 +169,17 @@ struct CItem
{
return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag();
}
+
+ void Set_LinkFlag_for_File(UInt32 mode)
+ {
+ Byte lf = NFileHeader::NLinkFlag::kNormal;
+ if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter;
+ else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock;
+ else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO;
+ // else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory;
+ // else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink;
+ LinkFlag = lf;
+ }
UInt32 Get_FileTypeMode_from_LinkFlag() const
{
@@ -82,10 +190,10 @@ struct CItem
case NFileHeader::NLinkFlag::kDumpDir:
return MY_LIN_S_IFDIR;
*/
- case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
- case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
- case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
- case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
+ case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
+ case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
+ case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
+ case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
// case return MY_LIN_S_IFSOCK;
}
@@ -104,20 +212,41 @@ struct CItem
case NFileHeader::NLinkFlag::kOldNormal:
case NFileHeader::NLinkFlag::kNormal:
case NFileHeader::NLinkFlag::kSymLink:
- return NItemName::HasTailSlash(Name, CP_OEMCP);
+ if (Name.IsEmpty())
+ return false;
+ // GNU TAR uses last character as directory marker
+ // we also do it
+ return Name.Back() == '/';
+ // return NItemName::HasTailSlash(Name, CP_OEMCP);
}
return false;
}
- bool IsUstarMagic() const
+ bool IsMagic_ustar_5chars() const
+ {
+ for (unsigned i = 0; i < 5; i++)
+ if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
+ return false;
+ return true;
+ }
+
+ bool IsMagic_Posix_ustar_00() const
+ {
+ for (unsigned i = 0; i < 8; i++)
+ if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i])
+ return false;
+ return true;
+ }
+
+ bool IsMagic_GNU() const
{
- for (int i = 0; i < 5; i++)
- if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i])
+ for (unsigned i = 0; i < 8; i++)
+ if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
return false;
return true;
}
- UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
+ UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
bool IsThereWarning() const
{
@@ -163,18 +292,67 @@ struct CEncodingCharacts
};
+struct CPaxExtra
+{
+ AString RecordPath;
+ AString RawLines;
+
+ void Clear()
+ {
+ RecordPath.Empty();
+ RawLines.Empty();
+ }
+
+ void Print_To_String(AString &s) const
+ {
+ if (!RecordPath.IsEmpty())
+ {
+ s += RecordPath;
+ s.Add_LF();
+ }
+ if (!RawLines.IsEmpty())
+ s += RawLines;
+ }
+};
+
struct CItemEx: public CItem
{
+ bool HeaderError;
+
+ bool IsSignedChecksum;
+ bool Prefix_WasUsed;
+
+ bool Pax_Error;
+ bool Pax_Overflow;
+ bool pax_path_WasUsed;
+ bool pax_link_WasUsed;
+ bool pax_size_WasUsed;
+
+ bool MTime_IsBin;
+ bool PackSize_IsBin;
+ bool Size_IsBin;
+
+ bool LongName_WasUsed;
+ bool LongName_WasUsed_2;
+
+ bool LongLink_WasUsed;
+ bool LongLink_WasUsed_2;
+
+ // bool Name_CouldBeReduced;
+ // bool LinkName_CouldBeReduced;
+
UInt64 HeaderPos;
- unsigned HeaderSize;
- bool NameCouldBeReduced;
- bool LinkNameCouldBeReduced;
+ UInt64 HeaderSize;
+
+ UInt64 Num_Pax_Records;
+ CPaxExtra PaxExtra;
CEncodingCharacts EncodingCharacts;
- UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
- UInt64 GetFullSize() const { return HeaderSize + PackSize; }
+ UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; }
+ // UInt64 GetFullSize() const { return HeaderSize + PackSize; }
+ UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); }
};
}}
diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp
index 271b854a..f73c625b 100644..100755
--- a/CPP/7zip/Archive/Tar/TarOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -2,6 +2,10 @@
#include "StdAfx.h"
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/IntToString.h"
+
#include "../../Common/StreamUtils.h"
#include "TarOut.h"
@@ -9,23 +13,27 @@
namespace NArchive {
namespace NTar {
-HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
-{
- Pos += size;
- return WriteStream(m_Stream, data, size);
-}
+using namespace NFileHeader;
+
+// it's path prefix assigned by 7-Zip to show that file path was cut
+#define K_PREFIX_PATH_CUT "@PathCut"
+
+static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1;
-static bool WriteOctal_8(char *s, UInt32 val)
+static void WriteOctal_8(char *s, UInt32 val)
{
const unsigned kNumDigits = 8 - 1;
if (val >= ((UInt32)1 << (kNumDigits * 3)))
- return false;
+ {
+ val = 0;
+ // return false;
+ }
for (unsigned i = 0; i < kNumDigits; i++)
{
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
val >>= 3;
}
- return true;
+ // return true;
}
static void WriteBin_64bit(char *s, UInt64 val)
@@ -68,61 +76,93 @@ static void CopyString(char *dest, const AString &src, unsigned maxSize)
unsigned len = src.Len();
if (len == 0)
return;
- // 21.07: we don't require additional 0 character at the end
+ // 21.07: new gnu : we don't require additional 0 character at the end
+ // if (len >= maxSize)
if (len > maxSize)
{
len = maxSize;
- // return false;
+ /*
+ // oldgnu needs 0 character at the end
+ len = maxSize - 1;
+ dest[len] = 0;
+ */
}
memcpy(dest, src.Ptr(), len);
- // return true;
}
-#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
+// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; }
+#define RETURN_IF_NOT_TRUE(x) { x; }
#define COPY_STRING_CHECK(dest, src, size) \
CopyString(dest, src, size); dest += (size);
#define WRITE_OCTAL_8_CHECK(dest, src) \
- RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src));
+ RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src))
-HRESULT COutArchive::WriteHeaderReal(const CItem &item)
+HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax
+ // , bool zero_PackSize
+ // , bool zero_MTime
+ )
{
- char record[NFileHeader::kRecordSize];
- memset(record, 0, NFileHeader::kRecordSize);
+ /*
+ if (isPax) { we don't use Glob_Name and Prefix }
+ if (!isPax)
+ {
+ we use Glob_Name if it's not empty
+ we use Prefix if it's not empty
+ }
+ */
+ char record[kRecordSize];
+ memset(record, 0, kRecordSize);
char *cur = record;
- COPY_STRING_CHECK (cur, item.Name, NFileHeader::kNameSize);
+ COPY_STRING_CHECK (cur,
+ (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name,
+ kNameSize);
- WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8;
+ WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; // & k_7_oct_digits_Val_Max
WRITE_OCTAL_8_CHECK (cur, item.UID); cur += 8;
WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8;
- WriteOctal_12(cur, item.PackSize); cur += 12;
- WriteOctal_12_Signed(cur, item.MTime); cur += 12;
+ WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12;
+ WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12;
- memset(cur, ' ', 8); // checksum field
+ // we will use binary init for checksum instead of memset
+ // checksum field:
+ // memset(cur, ' ', 8);
cur += 8;
*cur++ = item.LinkFlag;
- COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize);
+ COPY_STRING_CHECK (cur, item.LinkName, kNameSize);
memcpy(cur, item.Magic, 8);
cur += 8;
- COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize);
- COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize);
+ COPY_STRING_CHECK (cur, item.User, kUserNameSize);
+ COPY_STRING_CHECK (cur, item.Group, kGroupNameSize);
- if (item.DeviceMajorDefined)
- WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor);
+ const bool needDevice = (IsPosixMode && !isPax);
+
+ if (item.DeviceMajor_Defined)
+ WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor)
+ else if (needDevice)
+ WRITE_OCTAL_8_CHECK (cur, 0)
cur += 8;
- if (item.DeviceMinorDefined)
- WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor);
+
+ if (item.DeviceMinor_Defined)
+ WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
+ else if (needDevice)
+ WRITE_OCTAL_8_CHECK (cur, 0)
cur += 8;
- if (item.IsSparse())
+ if (!isPax && !Prefix.IsEmpty())
+ {
+ COPY_STRING_CHECK (cur, Prefix, kPrefixSize);
+ }
+
+ if (item.Is_Sparse())
{
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
WriteOctal_12(record + 483, item.Size);
@@ -136,31 +176,31 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
}
{
- UInt32 checkSum = 0;
+ UInt32 sum = (unsigned)(' ') * 8; // we use binary init
{
- for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
- checkSum += (Byte)record[i];
+ for (unsigned i = 0; i < kRecordSize; i++)
+ sum += (Byte)record[i];
}
- /* we use GNU TAR scheme:
- checksum field is formatted differently from the
+ /* checksum field is formatted differently from the
other fields: it has [6] digits, a null, then a space. */
- // WRITE_OCTAL_8_CHECK(record + 148, checkSum);
+ // WRITE_OCTAL_8_CHECK(record + 148, sum);
const unsigned kNumDigits = 6;
for (unsigned i = 0; i < kNumDigits; i++)
{
- record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7));
- checkSum >>= 3;
+ record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7));
+ sum >>= 3;
}
- record[148 + 6] = 0;
+ // record[148 + 6] = 0; // we need it, if we use memset(' ') init
+ record[148 + 7] = ' '; // we need it, if we use binary init
}
- RINOK(WriteBytes(record, NFileHeader::kRecordSize));
+ RINOK(Write_Data(record, kRecordSize));
- if (item.IsSparse())
+ if (item.Is_Sparse())
{
for (unsigned i = 4; i < item.SparseBlocks.Size();)
{
- memset(record, 0, NFileHeader::kRecordSize);
+ memset(record, 0, kRecordSize);
for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
{
const CSparseBlock &sb = item.SparseBlocks[i];
@@ -169,7 +209,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
WriteOctal_12(p + 12, sb.Size);
}
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
- RINOK(WriteBytes(record, NFileHeader::kRecordSize));
+ RINOK(Write_Data(record, kRecordSize));
}
}
@@ -177,101 +217,426 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
}
-/* OLD_GNU_TAR: writes short name with zero at the end
- NEW_GNU_TAR: writes short name without zero at the end */
+static void AddPaxLine(AString &s, const char *name, const AString &val)
+{
+ // s.Add_LF(); // for debug
+ const unsigned len = 3 + (unsigned)strlen(name) + val.Len();
+ AString n;
+ for (unsigned numDigits = 1;; numDigits++)
+ {
+ n.Empty();
+ n.Add_UInt32(numDigits + len);
+ if (numDigits == n.Len())
+ break;
+ }
+ s += n;
+ s.Add_Space();
+ s += name;
+ s += '=';
+ s += val;
+ s.Add_LF();
+}
+
+
+static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt,
+ const CTimeOptions &options)
+{
+ unsigned numDigits = pt.NumDigits;
+ if (numDigits > options.NumDigitsMax)
+ numDigits = options.NumDigitsMax;
+
+ bool needNs = false;
+ UInt32 ns = 0;
+ if (numDigits != 0)
+ {
+ ns = pt.Ns;
+ // if (ns != 0) before reduction, we show all digits after digits reduction
+ needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero);
+ UInt32 d = 1;
+ for (unsigned k = numDigits; k < 9; k++)
+ d *= 10;
+ ns /= d;
+ ns *= d;
+ }
+
+ AString v;
+ {
+ Int64 sec = pt.Sec;
+ if (pt.Sec < 0)
+ {
+ sec = -sec;
+ v += '-';
+ if (ns != 0)
+ {
+ ns = 1000*1000*1000 - ns;
+ sec--;
+ }
+ }
+ v.Add_UInt64(sec);
+ }
+
+ if (needNs)
+ {
+ AString d;
+ d.Add_UInt32(ns);
+ while (d.Len() < 9)
+ d.InsertAtFront('0');
+ // here we have precision
+ while (d.Len() > (unsigned)numDigits)
+ d.DeleteBack();
+ // GNU TAR reduces '0' digits.
+ if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always)
+ while (!d.IsEmpty() && d.Back() == '0')
+ d.DeleteBack();
+
+ if (!d.IsEmpty())
+ {
+ v += '.';
+ v += d;
+ // v += "1234567009999"; // for debug
+ // for (int y = 0; y < 1000; y++) v += '8'; // for debug
+ }
+ }
+
+ AddPaxLine(s, name, v);
+}
+
+
+static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v)
+{
+ if (v > k_7_oct_digits_Val_Max)
+ {
+ AString s2;
+ s2.Add_UInt32(v);
+ AddPaxLine(s, name, s2);
+ }
+}
+
+
+/* OLD_GNU_TAR: writes name with zero at the end
+ NEW_GNU_TAR: can write name filled with all kNameSize characters */
static const unsigned kNameSize_Max =
- NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
- // NFileHeader::kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
+ kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
+ // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max)
+
HRESULT COutArchive::WriteHeader(const CItem &item)
{
- if (DOES_NAME_FIT_IN_FIELD(item.Name) &&
- DOES_NAME_FIT_IN_FIELD(item.LinkName))
- return WriteHeaderReal(item);
+ Glob_Name.Empty();
+ Prefix.Empty();
- // here we can get all fields from main (item) or create new empty item
- /*
- CItem mi;
- mi.SetDefaultWriteFields();
- */
-
- CItem mi = item;
- mi.LinkName.Empty();
- // SparseBlocks will be ignored by IsSparse()
- // mi.SparseBlocks.Clear();
+ unsigned namePos = 0;
+ bool needPathCut = false;
+ bool allowPrefix = false;
+
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name))
+ {
+ const char *s = item.Name;
+ const char *p = s + item.Name.Len() - 1;
+ for (; *p == '/' && p != s; p--)
+ {}
+ for (; p != s && p[-1] != '/'; p--)
+ {}
+ namePos = (unsigned)(p - s);
+ needPathCut = true;
+ }
- mi.Name = NFileHeader::kLongLink;
- // 21.07 : we set Mode and MTime props as in GNU TAR:
- mi.Mode = 0644; // octal
- mi.MTime = 0;
+ if (IsPosixMode)
+ {
+ AString s;
+
+ if (needPathCut)
+ {
+ const unsigned nameLen = item.Name.Len() - namePos;
+ if ( item.LinkFlag >= NLinkFlag::kNormal
+ && item.LinkFlag <= NLinkFlag::kDirectory
+ && namePos > 1
+ && nameLen != 0
+ // && IsPrefixAllowed
+ && item.IsMagic_Posix_ustar_00())
+ {
+ /* GNU TAR decoder supports prefix field, only if (magic)
+ signature matches 6-bytes "ustar\0".
+ so here we use prefix field only in posix mode with posix signature */
+
+ allowPrefix = true;
+ // allowPrefix = false; // for debug
+ if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max)
+ {
+ needPathCut = false;
+ /* we will set Prefix and Glob_Name later, for such conditions:
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */
+ }
+ }
- for (int i = 0; i < 2; i++)
+ if (needPathCut)
+ AddPaxLine(s, "path", item.Name);
+ }
+
+ // AddPaxLine(s, "testname", AString("testval")); // for debug
+
+ if (item.LinkName.Len() > kNameSize_Max)
+ AddPaxLine(s, "linkpath", item.LinkName);
+
+ const UInt64 kPaxSize_Limit = ((UInt64)1 << 33);
+ // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug
+ // bool zero_PackSize = false;
+ if (item.PackSize >= kPaxSize_Limit)
+ {
+ /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB
+ But old 7-Zip doesn't detect "size" property from pax header.
+ So we write real size (>= 8 GiB) to main record in binary format,
+ and old 7-Zip can decode size correctly */
+ // zero_PackSize = true;
+ AString v;
+ v.Add_UInt64(item.PackSize);
+ AddPaxLine(s, "size", v);
+ }
+
+ /* GNU TAR encoder can set "devmajor" / "devminor" attributes,
+ but GNU TAR decoder doesn't parse "devmajor" / "devminor" */
+ if (item.DeviceMajor_Defined)
+ AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor);
+ if (item.DeviceMinor_Defined)
+ AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor);
+
+ AddPax_UInt32_ifBig(s, "uid", item.UID);
+ AddPax_UInt32_ifBig(s, "gid", item.GID);
+
+ const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33);
+ const bool zero_MTime = (
+ item.MTime < 0 ||
+ item.MTime >= (Int64)kPax_MTime_Limit);
+
+ const CPaxTime &mtime = item.PaxTimes.MTime;
+ if (mtime.IsDefined())
+ {
+ bool needPax = false;
+ if (zero_MTime)
+ needPax = true;
+ else if (TimeOptions.NumDigitsMax > 0)
+ if (mtime.Ns != 0 ||
+ (mtime.NumDigits != 0 &&
+ TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero))
+ needPax = true;
+ if (needPax)
+ AddPaxTime(s, "mtime", mtime, TimeOptions);
+ }
+
+ if (item.PaxTimes.ATime.IsDefined())
+ AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions);
+ if (item.PaxTimes.CTime.IsDefined())
+ AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions);
+
+ if (item.User.Len() > kUserNameSize)
+ AddPaxLine(s, "uname", item.User);
+ if (item.Group.Len() > kGroupNameSize)
+ AddPaxLine(s, "gname", item.Group);
+
+ /*
+ // for debug
+ AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a);
+ */
+
+ const unsigned paxSize = s.Len();
+ if (paxSize != 0)
+ {
+ CItem mi = item;
+ mi.LinkName.Empty();
+ // SparseBlocks will be ignored by Is_Sparse()
+ // mi.SparseBlocks.Clear();
+ // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder
+
+ // GNU TAR writes empty for these fields;
+ mi.User.Empty();
+ mi.Group.Empty();
+ mi.UID = 0;
+ mi.GID = 0;
+
+ mi.DeviceMajor_Defined = false;
+ mi.DeviceMinor_Defined = false;
+
+ mi.Name = "PaxHeader/@PaxHeader";
+ mi.Mode = 0644; // octal
+ if (zero_MTime)
+ mi.MTime = 0;
+ mi.LinkFlag = NLinkFlag::kPax;
+ // mi.LinkFlag = 'Z'; // for debug
+ mi.PackSize = paxSize;
+ // for (unsigned y = 0; y < 1; y++) { // for debug
+ RINOK(WriteHeaderReal(mi, true)); // isPax
+ RINOK(Write_Data_And_Residual(s, paxSize));
+ // } // for debug
+ /*
+ we can send (zero_MTime) for compatibility with gnu tar output.
+ we can send (zero_MTime = false) for better compatibility with old 7-Zip
+ */
+ // return WriteHeaderReal(item);
+ /*
+ false, // isPax
+ false, // zero_PackSize
+ false); // zero_MTime
+ */
+ }
+ }
+ else // !PosixMode
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name) ||
+ !DOES_NAME_FIT_IN_FIELD(item.LinkName))
{
- const AString *name;
- // We suppose that GNU TAR also writes item for long link before item for LongName?
- if (i == 0)
+ // here we can get all fields from main (item) or create new empty item
+ /*
+ CItem mi;
+ mi.SetDefaultWriteFields();
+ */
+ CItem mi = item;
+ mi.LinkName.Empty();
+ // SparseBlocks will be ignored by Is_Sparse()
+ // mi.SparseBlocks.Clear();
+ mi.Name = kLongLink;
+ // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug
+ // 21.07 : we set Mode and MTime props as in GNU TAR:
+ mi.Mode = 0644; // octal
+ mi.MTime = 0;
+
+ mi.User.Empty();
+ mi.Group.Empty();
+ /*
+ gnu tar sets "root" for such items:
+ uid_to_uname (0, &uname);
+ gid_to_gname (0, &gname);
+ */
+ /*
+ mi.User = "root";
+ mi.Group = "root";
+ */
+ mi.UID = 0;
+ mi.GID = 0;
+ mi.DeviceMajor_Defined = false;
+ mi.DeviceMinor_Defined = false;
+
+
+ for (unsigned i = 0; i < 2; i++)
{
- mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
- name = &item.LinkName;
+ const AString *name;
+ // We suppose that GNU TAR also writes item for long link before item for LongName?
+ if (i == 0)
+ {
+ mi.LinkFlag = NLinkFlag::kGnu_LongLink;
+ name = &item.LinkName;
+ }
+ else
+ {
+ mi.LinkFlag = NLinkFlag::kGnu_LongName;
+ name = &item.Name;
+ }
+ if (DOES_NAME_FIT_IN_FIELD(*name))
+ continue;
+ // GNU TAR writes null character after NAME to file. We do same here:
+ const unsigned nameStreamSize = name->Len() + 1;
+ mi.PackSize = nameStreamSize;
+ // for (unsigned y = 0; y < 3; y++) { // for debug
+ RINOK(WriteHeaderReal(mi));
+ RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize));
+ // }
+
+ // for debug
+ /*
+ const unsigned kSize = (1 << 29) + 16;
+ CByteBuffer buf;
+ buf.Alloc(kSize);
+ memset(buf, 0, kSize);
+ memcpy(buf, name->Ptr(), name->Len());
+ const unsigned nameStreamSize = kSize;
+ mi.PackSize = nameStreamSize;
+ // for (unsigned y = 0; y < 3; y++) { // for debug
+ RINOK(WriteHeaderReal(mi));
+ RINOK(WriteBytes(buf, nameStreamSize));
+ RINOK(FillDataResidual(nameStreamSize));
+ */
}
+ }
+
+ // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR
+
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name))
+ {
+ const unsigned nameLen = item.Name.Len() - namePos;
+ if (!needPathCut)
+ Prefix.SetFrom(item.Name, namePos - 1);
else
{
- mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
- name = &item.Name;
+ Glob_Name = K_PREFIX_PATH_CUT "/_pc_";
+
+ if (namePos == 0)
+ Glob_Name += "root";
+ else
+ {
+ Glob_Name += "crc32/";
+ char temp[12];
+ ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp);
+ Glob_Name += temp;
+ }
+
+ if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max)
+ Glob_Name.Add_Slash();
+ else
+ {
+ Prefix = Glob_Name;
+ Glob_Name.Empty();
+ }
}
- if (DOES_NAME_FIT_IN_FIELD(*name))
- continue;
- // GNU TAR writes null character after NAME to file. We do same here:
- const unsigned nameStreamSize = name->Len() + 1;
- mi.PackSize = nameStreamSize;
- RINOK(WriteHeaderReal(mi));
- RINOK(WriteBytes(name->Ptr(), nameStreamSize));
- RINOK(FillDataResidual(nameStreamSize));
+ Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen);
}
- // 21.07: WriteHeaderReal() writes short part of (Name) and (LinkName).
return WriteHeaderReal(item);
- /*
- mi = item;
- if (!DOES_NAME_FIT_IN_FIELD(mi.Name))
- mi.Name.SetFrom(item.Name, kNameSize_Max);
- if (!DOES_NAME_FIT_IN_FIELD(mi.LinkName))
- mi.LinkName.SetFrom(item.LinkName, kNameSize_Max);
- return WriteHeaderReal(mi);
- */
}
-HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
+
+HRESULT COutArchive::Write_Data(const void *data, unsigned size)
{
- unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
- if (lastRecordSize == 0)
+ Pos += size;
+ return WriteStream(Stream, data, size);
+}
+
+HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize)
+{
+ const unsigned v = ((unsigned)dataSize & (kRecordSize - 1));
+ if (v == 0)
return S_OK;
- unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
- Byte buf[NFileHeader::kRecordSize];
+ const unsigned rem = kRecordSize - v;
+ Byte buf[kRecordSize];
memset(buf, 0, rem);
- return WriteBytes(buf, rem);
+ return Write_Data(buf, rem);
+}
+
+
+HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size)
+{
+ RINOK(Write_Data(data, size));
+ return Write_AfterDataResidual(size);
}
+
HRESULT COutArchive::WriteFinishHeader()
{
- Byte record[NFileHeader::kRecordSize];
- memset(record, 0, NFileHeader::kRecordSize);
+ Byte record[kRecordSize];
+ memset(record, 0, kRecordSize);
const unsigned kNumFinishRecords = 2;
/* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB)
we also can use cluster alignment:
- const unsigned numBlocks = (unsigned)(Pos / NFileHeader::kRecordSize) + kNumFinishRecords;
+ const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords;
const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB
const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1));
*/
for (unsigned i = 0; i < kNumFinishRecords; i++)
{
- RINOK(WriteBytes(record, NFileHeader::kRecordSize));
+ RINOK(Write_Data(record, kRecordSize));
}
return S_OK;
}
diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h
index ee9b965e..34af20ac 100644..100755
--- a/CPP/7zip/Archive/Tar/TarOut.h
+++ b/CPP/7zip/Archive/Tar/TarOut.h
@@ -14,21 +14,38 @@ namespace NTar {
class COutArchive
{
- CMyComPtr<ISequentialOutStream> m_Stream;
+ CMyComPtr<ISequentialOutStream> Stream;
+
+ AString Glob_Name;
+ AString Prefix;
+
+ HRESULT WriteHeaderReal(const CItem &item, bool isPax = false
+ // , bool zero_PackSize = false
+ // , bool zero_MTime = false
+ );
+
+ HRESULT Write_Data(const void *data, unsigned size);
+ HRESULT Write_Data_And_Residual(const void *data, unsigned size);
- HRESULT WriteBytes(const void *data, unsigned size);
- HRESULT WriteHeaderReal(const CItem &item);
public:
UInt64 Pos;
-
+ bool IsPosixMode;
+ // bool IsPrefixAllowed; // it's used only if (IsPosixMode == true)
+ CTimeOptions TimeOptions;
+
void Create(ISequentialOutStream *outStream)
{
- m_Stream = outStream;
+ Stream = outStream;
}
-
HRESULT WriteHeader(const CItem &item);
- HRESULT FillDataResidual(UInt64 dataSize);
+ HRESULT Write_AfterDataResidual(UInt64 dataSize);
HRESULT WriteFinishHeader();
+
+ COutArchive():
+ Pos(0),
+ IsPosixMode(false)
+ // , IsPrefixAllowed(true)
+ {}
};
}}
diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp
index 5014f04d..a78c3766 100644..100755
--- a/CPP/7zip/Archive/Tar/TarRegister.cpp
+++ b/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -15,9 +15,17 @@ REGISTER_ARC_IO(
"tar", "tar ova", 0, 0xEE,
k_Signature,
NFileHeader::kUstarMagic_Offset,
- NArcInfoFlags::kStartOpen |
- NArcInfoFlags::kSymLinks |
- NArcInfoFlags::kHardLinks,
- IsArc_Tar)
+ NArcInfoFlags::kStartOpen
+ | NArcInfoFlags::kSymLinks
+ | NArcInfoFlags::kHardLinks
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ // | NArcInfoTimeFlags::kCTime
+ // | NArcInfoTimeFlags::kATime
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
+ , IsArc_Tar)
}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp
index 295e16bb..caa0a822 100644..100755
--- a/CPP/7zip/Archive/Tar/TarUpdate.cpp
+++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -2,6 +2,8 @@
#include "StdAfx.h"
+// #include <stdio.h>
+
#include "../../../Windows/TimeUtils.h"
#include "../../Common/LimitedStreams.h"
@@ -15,18 +17,161 @@
namespace NArchive {
namespace NTar {
+static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt)
+{
+ UInt32 ns;
+ pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns);
+ pt.Ns = ns * 100;
+ pt.NumDigits = 7;
+}
+
+
+HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt)
+{
+ pt.Clear();
+ if (prop.vt == VT_EMPTY)
+ {
+ // pt.Sec = 0;
+ return S_OK;
+ }
+ if (prop.vt != VT_FILETIME)
+ return E_INVALIDARG;
+ {
+ UInt32 ns;
+ pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns);
+ ns *= 100;
+ pt.NumDigits = 7;
+ const unsigned prec = prop.wReserved1;
+ if (prec >= k_PropVar_TimePrec_Base)
+ {
+ pt.NumDigits = prec - k_PropVar_TimePrec_Base;
+ if (prop.wReserved2 < 100)
+ ns += prop.wReserved2;
+ }
+ pt.Ns = ns;
+ return S_OK;
+ }
+}
+
+
+static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt)
+{
+ pt.Clear();
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pid, &prop));
+ return Prop_To_PaxTime(prop, pt);
+}
+
+
+static HRESULT GetUser(IStreamGetProp *getProp,
+ UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
+ UINT codePage, unsigned utfFlags)
+{
+ // printf("\nGetUser\n");
+ // we keep old values, if both GetProperty() return VT_EMPTY
+ // we clear old values, if any of GetProperty() returns non-VT_EMPTY;
+ bool isSet = false;
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pidId, &prop));
+ if (prop.vt == VT_UI4)
+ {
+ isSet = true;
+ id = prop.ulVal;
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pidName, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ const UString s = prop.bstrVal;
+ Get_AString_From_UString(s, name, codePage, utfFlags);
+ // printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr());
+ if (!isSet)
+ id = 0;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+
+/*
+static HRESULT GetDevice(IStreamGetProp *getProp,
+ UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(kpidDevice, &prop));
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ {
+ printf("\nTarUpdate.cpp :: GetDevice()\n");
+ const UInt64 v = prop.uhVal.QuadPart;
+ majo = MY_dev_major(v);
+ mino = MY_dev_minor(v);
+ majo_defined = true;
+ mino_defined = true;
+ }
+ return S_OK;
+}
+*/
+
+static HRESULT GetDevice(IStreamGetProp *getProp,
+ UInt32 pid, UInt32 &id, bool &defined)
+{
+ defined = false;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pid, &prop));
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ defined = true;
+ return S_OK;
+ }
+ return E_INVALIDARG;
+}
+
+
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
- UINT codePage, unsigned utfFlags,
+ const CUpdateOptions &options,
IArchiveUpdateCallback *updateCallback)
{
COutArchive outArchive;
outArchive.Create(outStream);
outArchive.Pos = 0;
+ outArchive.IsPosixMode = options.PosixMode;
+ outArchive.TimeOptions = options.TimeOptions;
CMyComPtr<IOutStream> outSeekStream;
outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
+ if (outSeekStream)
+ {
+ /*
+ // for debug
+ Byte buf[1 << 14];
+ memset (buf, 0, sizeof(buf));
+ RINOK(outStream->Write(buf, sizeof(buf), NULL));
+ */
+ // we need real outArchive.Pos, if outSeekStream->SetSize() will be used.
+ RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos));
+ }
+
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
@@ -40,7 +185,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.NewData)
complexity += ui.Size;
else
- complexity += inputItems[(unsigned)ui.IndexInArc].GetFullSize();
+ complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned();
}
RINOK(updateCallback->SetTotal(complexity));
@@ -58,21 +203,31 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
complexity = 0;
- for (i = 0; i < updateItems.Size(); i++)
+ // const int kNumReduceDigits = -1; // for debug
+
+ for (i = 0;; i++)
{
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
+ if (i == updateItems.Size())
+ return outArchive.WriteFinishHeader();
+
const CUpdateItem &ui = updateItems[i];
CItem item;
if (ui.NewProps)
{
- item.SetDefaultWriteFields();
- item.Mode = ui.Mode;
+ item.SetMagic_Posix(options.PosixMode);
item.Name = ui.Name;
item.User = ui.User;
item.Group = ui.Group;
+ item.UID = ui.UID;
+ item.GID = ui.GID;
+ item.DeviceMajor = ui.DeviceMajor;
+ item.DeviceMinor = ui.DeviceMinor;
+ item.DeviceMajor_Defined = ui.DeviceMajor_Defined;
+ item.DeviceMinor_Defined = ui.DeviceMinor_Defined;
if (ui.IsDir)
{
@@ -81,11 +236,15 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
else
{
- item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
item.PackSize = ui.Size;
+ item.Set_LinkFlag_for_File(ui.Mode);
}
-
- item.MTime = ui.MTime;
+
+ // 22.00
+ item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT;
+ item.PaxTimes = ui.PaxTimes;
+ // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
+ item.MTime = ui.PaxTimes.MTime.GetSec();
}
else
item = inputItems[(unsigned)ui.IndexInArc];
@@ -93,7 +252,8 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
AString symLink;
if (ui.NewData || ui.NewProps)
{
- RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, utfFlags, true));
+ RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink,
+ options.CodePage, options.UtfFlags, true));
if (!symLink.IsEmpty())
{
item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
@@ -120,7 +280,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
else
{
- HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
if (res == S_FALSE)
needWrite = false;
@@ -128,31 +288,105 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
{
RINOK(res);
- if (fileInStream)
+ if (!fileInStream)
+ {
+ item.PackSize = 0;
+ item.Size = 0;
+ }
+ else
{
CMyComPtr<IStreamGetProps> getProps;
- fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
- if (getProps)
+ CMyComPtr<IStreamGetProp> getProp;
+ fileInStream->QueryInterface(IID_IStreamGetProp, (void **)&getProp);
+ if (getProp)
+ {
+ if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime))
+ if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime))
+ if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime))
+
+ if (options.PosixMode)
+ {
+ /*
+ RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor,
+ item.DeviceMajor_Defined, item.DeviceMinor_Defined));
+ */
+ bool defined = false;
+ UInt32 val = 0;
+ RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined));
+ if (defined)
+ {
+ item.DeviceMajor = val;
+ item.DeviceMajor_Defined = true;
+ item.DeviceMinor = 0;
+ item.DeviceMinor_Defined = false;
+ RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined));
+ }
+ }
+
+ RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags));
+ RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags));
+
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(kpidPosixAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ item.Mode =
+ MY_LIN_S_IRWXO
+ | MY_LIN_S_IRWXG
+ | MY_LIN_S_IRWXU
+ | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ item.Mode = prop.ulVal;
+ // 21.07 : we clear high file type bits as GNU TAR.
+ item.Set_LinkFlag_for_File(item.Mode);
+ item.Mode &= ~(UInt32)MY_LIN_S_IFMT;
+ }
+
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ const UInt64 size = prop.uhVal.QuadPart;
+ item.PackSize = size;
+ item.Size = size;
+ }
+ /*
+ printf("\nNum digits = %d %d\n",
+ (int)item.PaxTimes.MTime.NumDigits,
+ (int)item.PaxTimes.MTime.Ns);
+ */
+ }
+ else
{
- FILETIME mTime;
- UInt64 size2;
- if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
+ fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ if (getProps)
{
- item.PackSize = size2;
- item.Size = size2;
- item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
+ FILETIME mTime, aTime, cTime;
+ UInt64 size2;
+ if (getProps->GetProps(&size2,
+ options.Write_CTime.Val ? &cTime : NULL,
+ options.Write_ATime.Val ? &aTime : NULL,
+ options.Write_MTime.Val ? &mTime : NULL,
+ NULL) == S_OK)
+ {
+ item.PackSize = size2;
+ item.Size = size2;
+ if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime);
+ if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime);
+ if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime);
+ }
}
}
}
- else
- {
- item.PackSize = 0;
- item.Size = 0;
- }
{
+ // we must request kpidHardLink after updateCallback->GetStream()
AString hardLink;
- RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, utfFlags, true));
+ RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink,
+ options.CodePage, options.UtfFlags, true));
if (!hardLink.IsEmpty())
{
item.LinkFlag = NFileHeader::NLinkFlag::kHardLink;
@@ -165,37 +399,98 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
}
+ // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
+
+ if (ui.NewProps)
+ item.MTime = item.PaxTimes.MTime.GetSec();
+
if (needWrite)
{
- UInt64 fileHeaderStartPos = outArchive.Pos;
+ const UInt64 headerPos = outArchive.Pos;
+ // item.PackSize = ((UInt64)1 << 33); // for debug
RINOK(outArchive.WriteHeader(item));
if (fileInStream)
{
- RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
- outArchive.Pos += copyCoderSpec->TotalSize;
- if (copyCoderSpec->TotalSize != item.PackSize)
+ for (unsigned numPasses = 0;; numPasses++)
{
+ /* we support 2 attempts to write header:
+ pass-0: main pass:
+ pass-1: additional pass, if size_of_file and size_of_header are changed */
+ if (numPasses >= 2)
+ {
+ // opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged;
+ // break;
+ return E_FAIL;
+ }
+
+ const UInt64 dataPos = outArchive.Pos;
+ RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
+ outArchive.Pos += copyCoderSpec->TotalSize;
+ RINOK(outArchive.Write_AfterDataResidual(copyCoderSpec->TotalSize));
+
+ // if (numPasses >= 10) // for debug
+ if (copyCoderSpec->TotalSize == item.PackSize)
+ break;
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient,
+ NUpdateNotifyOp::kInFileChanged))
+ }
+
if (!outSeekStream)
return E_FAIL;
- UInt64 backOffset = outArchive.Pos - fileHeaderStartPos;
- RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL));
- outArchive.Pos = fileHeaderStartPos;
+ const UInt64 nextPos = outArchive.Pos;
+ RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL));
+ outArchive.Pos = headerPos;
item.PackSize = copyCoderSpec->TotalSize;
+
RINOK(outArchive.WriteHeader(item));
- RINOK(outSeekStream->Seek((Int64)item.PackSize, STREAM_SEEK_CUR, NULL));
- outArchive.Pos += item.PackSize;
+
+ // if (numPasses >= 10) // for debug
+ if (outArchive.Pos == dataPos)
+ {
+ const UInt64 alignedSize = nextPos - dataPos;
+ if (alignedSize != 0)
+ {
+ RINOK(outSeekStream->Seek(alignedSize, STREAM_SEEK_CUR, NULL));
+ outArchive.Pos += alignedSize;
+ }
+ break;
+ }
+
+ // size of header was changed.
+ // we remove data after header and try new attempt, if required
+ CMyComPtr<IInStream> fileSeekStream;
+ fileInStream->QueryInterface(IID_IInStream, (void **)&fileSeekStream);
+ if (!fileSeekStream)
+ return E_FAIL;
+ RINOK(fileSeekStream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(outSeekStream->SetSize(outArchive.Pos));
+ if (item.PackSize == 0)
+ break;
}
- RINOK(outArchive.FillDataResidual(item.PackSize));
}
}
complexity += item.PackSize;
+ fileInStream.Release();
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
else
{
+ // (ui.NewData == false)
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
+ NUpdateNotifyOp::kReplicate))
+ }
+
const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc];
- UInt64 size;
+ UInt64 size, pos;
if (ui.NewProps)
{
@@ -216,44 +511,37 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
item.PackSize = existItem.PackSize;
}
- item.DeviceMajorDefined = existItem.DeviceMajorDefined;
- item.DeviceMinorDefined = existItem.DeviceMinorDefined;
+ item.DeviceMajor_Defined = existItem.DeviceMajor_Defined;
+ item.DeviceMinor_Defined = existItem.DeviceMinor_Defined;
item.DeviceMajor = existItem.DeviceMajor;
item.DeviceMinor = existItem.DeviceMinor;
item.UID = existItem.UID;
item.GID = existItem.GID;
RINOK(outArchive.WriteHeader(item));
- RINOK(inStream->Seek((Int64)existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
- size = existItem.PackSize;
+ size = existItem.Get_PackSize_Aligned();
+ pos = existItem.Get_DataPos();
}
else
{
- RINOK(inStream->Seek((Int64)existItem.HeaderPos, STREAM_SEEK_SET, NULL));
- size = existItem.GetFullSize();
+ size = existItem.Get_FullSize_Aligned();
+ pos = existItem.HeaderPos;
}
-
- streamSpec->Init(size);
- if (opCallback)
+ if (size != 0)
{
- RINOK(opCallback->ReportOperation(
- NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
- NUpdateNotifyOp::kReplicate))
+ RINOK(inStream->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(size);
+ // 22.00 : we copy Residual data from old archive to new archive instead of zeroing
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != size)
+ return E_FAIL;
+ outArchive.Pos += size;
+ // RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize));
+ complexity += size;
}
-
- RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
- if (copyCoderSpec->TotalSize != size)
- return E_FAIL;
- outArchive.Pos += size;
- RINOK(outArchive.FillDataResidual(existItem.PackSize));
- complexity += size;
}
}
-
- lps->InSize = lps->OutSize = complexity;
- RINOK(lps->SetCur());
- return outArchive.WriteFinishHeader();
}
}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h
index 1e3d0217..ca0976dd 100644..100755
--- a/CPP/7zip/Archive/Tar/TarUpdate.h
+++ b/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -15,27 +15,60 @@ struct CUpdateItem
int IndexInArc;
unsigned IndexInClient;
UInt64 Size;
- Int64 MTime;
+ // Int64 MTime;
UInt32 Mode;
bool NewData;
bool NewProps;
bool IsDir;
+ bool DeviceMajor_Defined;
+ bool DeviceMinor_Defined;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 DeviceMajor;
+ UInt32 DeviceMinor;
AString Name;
AString User;
AString Group;
- CUpdateItem(): Size(0), IsDir(false) {}
+ CPaxTimes PaxTimes;
+
+ CUpdateItem():
+ Size(0),
+ IsDir(false),
+ DeviceMajor_Defined(false),
+ DeviceMinor_Defined(false),
+ UID(0),
+ GID(0)
+ {}
+};
+
+
+struct CUpdateOptions
+{
+ UINT CodePage;
+ unsigned UtfFlags;
+ bool PosixMode;
+ CBoolPair Write_MTime;
+ CBoolPair Write_ATime;
+ CBoolPair Write_CTime;
+ CTimeOptions TimeOptions;
};
+
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
- UINT codePage, unsigned utfFlags,
+ const CUpdateOptions &options,
IArchiveUpdateCallback *updateCallback);
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
UINT codePage, unsigned utfFlags, bool convertSlash);
+HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt);
+
+void Get_AString_From_UString(const UString &s, AString &res,
+ UINT codePage, unsigned utfFlags);
+
}}
#endif
diff --git a/CPP/7zip/Archive/Udf/StdAfx.h b/CPP/7zip/Archive/Udf/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Udf/StdAfx.h
+++ b/CPP/7zip/Archive/Udf/StdAfx.h
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
index 74ec0beb..2232c64a 100644..100755
--- a/CPP/7zip/Archive/Udf/UdfHandler.cpp
+++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -27,11 +27,17 @@ static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop
return;
if (t.IsLocal())
numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60);
- FILETIME ft;
- UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10;
- ft.dwLowDateTime = (UInt32)v;
- ft.dwHighDateTime = (UInt32)(v >> 32);
- prop = ft;
+ const UInt32 m0 = d[9];
+ const UInt32 m1 = d[10];
+ const UInt32 m2 = d[11];
+ unsigned numDigits = 0;
+ UInt64 v = numSecs * 10000000;
+ if (m0 < 100 && m1 < 100 && m2 < 100)
+ {
+ v += m0 * 100000 + m1 * 1000 + m2 * 10;
+ numDigits = 6;
+ }
+ prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits);
}
static const Byte kProps[] =
@@ -41,7 +47,8 @@ static const Byte kProps[] =
kpidSize,
kpidPackSize,
kpidMTime,
- kpidATime
+ kpidATime,
+ kpidChangeTime
};
static const Byte kArcProps[] =
@@ -205,6 +212,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
+ case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
}
}
prop.Detach(value);
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h
index da44b232..da44b232 100644..100755
--- a/CPP/7zip/Archive/Udf/UdfHandler.h
+++ b/CPP/7zip/Archive/Udf/UdfHandler.h
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index 04d9228f..d2d2b20a 100644..100755
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -333,7 +333,7 @@ void CItem::Parse(const Byte *p)
NumLogBlockRecorded = Get64(p + 64);
ATime.Parse(p + 72);
MTime.Parse(p + 84);
- // AttrtTime.Parse(p + 96);
+ AttribTime.Parse(p + 96);
// CheckPoint = Get32(p + 108);
// ExtendedAttrIcb.Parse(p + 112);
// ImplId.Parse(p + 128);
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
index c26f6099..4e7dfa11 100644..100755
--- a/CPP/7zip/Archive/Udf/UdfIn.h
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -243,7 +243,7 @@ struct CItem
UInt64 NumLogBlockRecorded;
CTime ATime;
CTime MTime;
- // CTime AttrtTime;
+ CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of.
// UInt32 CheckPoint;
// CLongAllocDesc ExtendedAttrIcb;
// CRegId ImplId;
diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp
index 67fe795a..67fe795a 100644..100755
--- a/CPP/7zip/Archive/UefiHandler.cpp
+++ b/CPP/7zip/Archive/UefiHandler.cpp
diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp
index 7641cdc9..7641cdc9 100644..100755
--- a/CPP/7zip/Archive/VdiHandler.cpp
+++ b/CPP/7zip/Archive/VdiHandler.cpp
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
index 8b9af45a..60bc3d30 100644..100755
--- a/CPP/7zip/Archive/VhdHandler.cpp
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -921,7 +921,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
CLimitedInStream *streamSpec = new CLimitedInStream;
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
streamSpec->SetStream(Stream);
- streamSpec->InitAndSeek(0, Footer.CurrentSize);
+ // fixme : check (startOffset = 0)
+ streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize);
RINOK(streamSpec->SeekToStart());
*stream = streamTemp.Detach();
return S_OK;
diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp
index e1e4692d..0fc83ace 100644..100755
--- a/CPP/7zip/Archive/VhdxHandler.cpp
+++ b/CPP/7zip/Archive/VhdxHandler.cpp
@@ -171,6 +171,20 @@ struct CHeader
UInt64 LogOffset;
CGuid Guids[3];
+ bool IsEqualTo(const CHeader &h) const
+ {
+ if (SequenceNumber != h.SequenceNumber)
+ return false;
+ if (LogLength != h.LogLength)
+ return false;
+ if (LogOffset != h.LogOffset)
+ return false;
+ for (unsigned i = 0; i < 3; i++)
+ if (!Guids[i].IsEqualTo(h.Guids[i]))
+ return false;
+ return true;
+ };
+
bool Parse(Byte *p);
};
@@ -1174,7 +1188,18 @@ HRESULT CHandler::Open3()
unsigned mainIndex;
if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1;
- else return S_FALSE;
+ else
+ {
+ /* Disk2vhd v2.02 can create image with 2 full copies of headers.
+ It's violation of VHDX specification:
+ "A header is current if it is the only valid header
+ or if it is valid and its SequenceNumber field is
+ greater than the other header's SequenceNumber".
+ but we support such Disk2vhd archives. */
+ if (!headers[0].IsEqualTo(headers[1]))
+ return S_FALSE;
+ mainIndex = 0;
+ }
const CHeader &h = headers[mainIndex];
Header = h;
@@ -1567,6 +1592,7 @@ static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
void CHandler::AddComment(UString &s) const
{
+ AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
AddComment_UInt64(s, "PhysicalSize", _phySize);
if (!_errorMessage.IsEmpty())
diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp
index fb5bb1f8..40f56131 100644..100755
--- a/CPP/7zip/Archive/VmdkHandler.cpp
+++ b/CPP/7zip/Archive/VmdkHandler.cpp
@@ -138,7 +138,7 @@ static bool Str_to_ValName(const AString &s, AString &name, AString &val)
int eq = s.Find('=');
if (eq < 0 || (qu >= 0 && eq > qu))
return false;
- name = s.Left(eq);
+ name.SetFrom(s.Ptr(), eq);
name.Trim();
val = s.Ptr(eq + 1);
val.Trim();
diff --git a/CPP/7zip/Archive/Wim/StdAfx.h b/CPP/7zip/Archive/Wim/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Wim/StdAfx.h
+++ b/CPP/7zip/Archive/Wim/StdAfx.h
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
index 9e39d028..3b394557 100644..100755
--- a/CPP/7zip/Archive/Wim/WimHandler.cpp
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -355,6 +355,7 @@ static void GetFileTime(const Byte *p, NCOM::CPropVariant &prop)
prop.vt = VT_FILETIME;
prop.filetime.dwLowDateTime = Get32(p);
prop.filetime.dwHighDateTime = Get32(p + 4);
+ prop.Set_FtPrec(k_PropVar_TimePrec_100ns);
}
@@ -842,7 +843,7 @@ public:
int dotPos = name.ReverseFind_Dot();
if (dotPos < 0)
dotPos = name.Len();
- _before = name.Left(dotPos);
+ _before.SetFrom(name.Ptr(), dotPos);
_after = name.Ptr(dotPos);
}
diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h
index 3ba88d2b..3ba88d2b 100644..100755
--- a/CPP/7zip/Archive/Wim/WimHandler.h
+++ b/CPP/7zip/Archive/Wim/WimHandler.h
diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
index 6b4497fe..5e8365a4 100644..100755
--- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
+++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
@@ -32,8 +32,8 @@ static int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const By
unsigned left = 0, right = sorted.Size();
while (left != right)
{
- unsigned mid = (left + right) / 2;
- unsigned index = sorted[mid];
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned index = sorted[mid];
const Byte *hash2 = streams[index].Hash;
unsigned i;
@@ -124,9 +124,9 @@ static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned
unsigned left = 0, right = indexes.Size();
while (left != right)
{
- unsigned mid = (left + right) / 2;
- unsigned index = indexes[mid];
- int comp = Compare_HardLink_MetaItems(mi, metaItems[index]);
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned index = indexes[mid];
+ const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]);
if (comp == 0)
return index;
if (comp < 0)
@@ -203,8 +203,8 @@ bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, u
unsigned left = 0, right = Dirs.Size();
while (left != right)
{
- unsigned mid = (left + right) / 2;
- int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
if (comp == 0)
{
index = mid;
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
index fef6b34f..f805521a 100644..100755
--- a/CPP/7zip/Archive/Wim/WimIn.cpp
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -567,9 +567,12 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
for (unsigned i = 0; i < len; i++)
{
wchar_t c = Get16(meta + i * 2);
- // 18.06
- if (c == CHAR_PATH_SEPARATOR || c == '/')
- c = '_';
+ if (c == L'/')
+ c = L'_';
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ else if (c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme
+ #endif
dest[i] = c;
}
}
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h
index 9e835b01..9e835b01 100644..100755
--- a/CPP/7zip/Archive/Wim/WimIn.h
+++ b/CPP/7zip/Archive/Wim/WimIn.h
diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp
index ecebe8d9..e143f91c 100644..100755
--- a/CPP/7zip/Archive/Wim/WimRegister.cpp
+++ b/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -10,13 +10,20 @@ namespace NArchive {
namespace NWim {
REGISTER_ARC_IO(
- "wim", "wim swm esd ppkg", 0, 0xE6,
- kSignature,
- 0,
- NArcInfoFlags::kAltStreams |
- NArcInfoFlags::kNtSecure |
- NArcInfoFlags::kSymLinks |
- NArcInfoFlags::kHardLinks
+ "wim", "wim swm esd ppkg", NULL, 0xE6
+ , kSignature, 0
+ , NArcInfoFlags::kAltStreams
+ | NArcInfoFlags::kNtSecure
+ | NArcInfoFlags::kSymLinks
+ | NArcInfoFlags::kHardLinks
+ | NArcInfoFlags::kCTime
+ // | NArcInfoFlags::kCTime_Default
+ | NArcInfoFlags::kATime
+ // | NArcInfoFlags::kATime_Default
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
, NULL)
}}
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
index b5a1972d..b5a1972d 100644..100755
--- a/CPP/7zip/Archive/XarHandler.cpp
+++ b/CPP/7zip/Archive/XarHandler.cpp
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp
index f1afab66..d358ca56 100644..100755
--- a/CPP/7zip/Archive/XzHandler.cpp
+++ b/CPP/7zip/Archive/XzHandler.cpp
@@ -1089,7 +1089,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{
- *timeType = NFileTimeType::kUnix;
+ *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
+ // *timeType = NFileTimeType::kUnix;
return S_OK;
}
@@ -1136,7 +1137,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (prop.vt != VT_UI8)
return E_INVALIDARG;
dataSize = prop.uhVal.QuadPart;
- RINOK(updateCallback->SetTotal(dataSize));
}
NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
@@ -1266,15 +1266,28 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
}
- CMyComPtr<ISequentialInStream> fileInStream;
- RINOK(updateCallback->GetStream(0, &fileInStream));
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(updateCallback, true);
-
- RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress));
-
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+ if (!fileInStream)
+ return S_FALSE;
+ {
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ UInt64 size;
+ if (streamGetSize->GetSize(&size) == S_OK)
+ dataSize = size;
+ }
+ }
+ RINOK(updateCallback->SetTotal(dataSize));
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+ RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress));
+ }
+
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
@@ -1415,9 +1428,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
REGISTER_ARC_IO(
"xz", "xz txz", "* .tar", 0xC,
- XZ_SIG,
- 0,
- NArcInfoFlags::kKeepName,
- NULL)
+ XZ_SIG, 0
+ , NArcInfoFlags::kKeepName
+ , 0
+ , NULL)
}}
diff --git a/CPP/7zip/Archive/XzHandler.h b/CPP/7zip/Archive/XzHandler.h
index 24e8eeb4..24e8eeb4 100644..100755
--- a/CPP/7zip/Archive/XzHandler.h
+++ b/CPP/7zip/Archive/XzHandler.h
diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp
index 29934367..29934367 100644..100755
--- a/CPP/7zip/Archive/ZHandler.cpp
+++ b/CPP/7zip/Archive/ZHandler.cpp
diff --git a/CPP/7zip/Archive/Zip/StdAfx.h b/CPP/7zip/Archive/Zip/StdAfx.h
index 2854ff3e..2854ff3e 100644..100755
--- a/CPP/7zip/Archive/Zip/StdAfx.h
+++ b/CPP/7zip/Archive/Zip/StdAfx.h
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
index 2bb57d5c..2bb57d5c 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h
index 0aa44adf..0aa44adf 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipAddCommon.h
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h
diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
index 842991c4..842991c4 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h
+++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp
index d8168bbe..1b3985fd 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipHandler.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -190,6 +190,8 @@ static const Byte kProps[] =
kpidVolumeIndex,
kpidOffset
// kpidIsAltStream
+ // , kpidChangeTime // for debug
+ // , 255 // for debug
};
static const Byte kArcProps[] =
@@ -347,6 +349,34 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
+
+static bool NtfsUnixTimeToProp(bool fromCentral,
+ const CExtraBlock &extra,
+ unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop)
+{
+ {
+ FILETIME ft;
+ if (extra.GetNtfsTime(ntfsIndex, ft))
+ {
+ PropVariant_SetFrom_NtfsTime(prop, ft);
+ return true;
+ }
+ }
+ {
+ UInt32 unixTime = 0;
+ if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime))
+ return false;
+ /*
+ // we allow unixTime == 0
+ if (unixTime == 0)
+ return false;
+ */
+ PropVariant_SetFrom_UnixTime(prop, unixTime);
+ return true;
+ }
+}
+
+
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
@@ -392,6 +422,30 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPackSize: prop = item.PackSize; break;
+ case kpidCTime:
+ NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kCTime,
+ NFileHeader::NUnixTime::kCTime, prop);
+ break;
+
+ case kpidATime:
+ NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kATime,
+ NFileHeader::NUnixTime::kATime, prop);
+ break;
+
+ case kpidMTime:
+ {
+ if (!NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kMTime,
+ NFileHeader::NUnixTime::kMTime, prop))
+ {
+ if (item.Time != 0)
+ PropVariant_SetFrom_DosTime(prop, item.Time);
+ }
+ break;
+ }
+
case kpidTimeType:
{
FILETIME ft;
@@ -399,7 +453,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
UInt32 type;
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
type = NFileTimeType::kWindows;
- else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime))
+ else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime))
type = NFileTimeType::kUnix;
else
type = NFileTimeType::kDOS;
@@ -407,64 +461,28 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
break;
}
- case kpidCTime:
- {
- FILETIME utc;
- bool defined = true;
- if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc))
- {
- UInt32 unixTime = 0;
- if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime))
- NTime::UnixTimeToFileTime(unixTime, utc);
- else
- defined = false;
- }
- if (defined)
- prop = utc;
- break;
- }
-
- case kpidATime:
- {
- FILETIME utc;
- bool defined = true;
- if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc))
- {
- UInt32 unixTime = 0;
- if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime))
- NTime::UnixTimeToFileTime(unixTime, utc);
- else
- defined = false;
- }
- if (defined)
- prop = utc;
-
- break;
- }
-
- case kpidMTime:
+ /*
+ // for debug to get Dos time values:
+ case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break;
+ // for debug
+ // time difference (dos - utc)
+ case 255:
{
- FILETIME utc;
- bool defined = true;
- if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
+ if (NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kMTime,
+ NFileHeader::NUnixTime::kMTime, prop))
{
- UInt32 unixTime = 0;
- if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime))
- NTime::UnixTimeToFileTime(unixTime, utc);
- else
+ FILETIME localFileTime;
+ if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime))
{
- FILETIME localFileTime;
- if (item.Time == 0)
- defined = false;
- else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
- !LocalFileTimeToFileTime(&localFileTime, &utc))
- utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ UInt64 t1 = FILETIME_To_UInt64(prop.filetime);
+ UInt64 t2 = FILETIME_To_UInt64(localFileTime);
+ prop.Set_Int64(t2 - t1);
}
}
- if (defined)
- prop = utc;
break;
}
+ */
case kpidAttrib: prop = item.GetWinAttrib(); break;
@@ -1122,7 +1140,18 @@ HRESULT CZipDecoder::Decode(
AString_Wipe charPassword;
if (password)
{
- UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
+ /*
+ // 22.00: do we need UTF-8 passwords here ?
+ if (item.IsUtf8()) // 22.00
+ {
+ // throw 1;
+ ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword);
+ }
+ else
+ */
+ {
+ UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
+ }
/*
if (wzAesMode || pkAesMode)
{
@@ -1341,6 +1370,8 @@ HRESULT CZipDecoder::Decode(
if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted())
{
+ // for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter
+ // here we use filter without CopyCoder
readFromFilter = false;
COutStreamWithPadPKCS7 *padStreamSpec = NULL;
@@ -1425,33 +1456,44 @@ HRESULT CZipDecoder::Decode(
const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
if (processed + padSize > coderPackSize)
truncatedError = true;
+ else if (processed + padSize < coderPackSize)
+ dataAfterEnd = true;
else
{
- if (processed + padSize < coderPackSize)
- dataAfterEnd = true;
- else
{
- // here we can PKCS7 padding data from reminder (it can be inside stream buffer in coder).
+ // here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder).
CMyComPtr<ICompressReadUnusedFromInBuf> readInStream;
coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream);
- if (readInStream)
+ // CCopyCoder() for kStore doesn't read data outside of (item.Size)
+ if (readInStream || id == NFileHeader::NCompressionMethod::kStore)
{
- // change pad size, it we support another block size in ZipStron
- // here we request more to detect error with data after end.
+ // change pad size, if we support another block size in ZipStrong.
+ // here we request more data to detect error with data after end.
const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16;
Byte buf[kBufSize];
- UInt32 processedSize;
- RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
+ UInt32 processedSize = 0;
+ if (readInStream)
+ {
+ RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
+ }
if (processedSize > padSize)
dataAfterEnd = true;
else
{
- if (ReadStream_FALSE(filterStream, buf + processedSize, padSize - processedSize) != S_OK)
- padError = true;
- else
- for (unsigned i = 0; i < padSize; i++)
- if (buf[i] != padSize)
- padError = true;
+ size_t processedSize2 = kBufSize - processedSize;
+ result = ReadStream(filterStream, buf + processedSize, &processedSize2);
+ if (result == S_OK)
+ {
+ processedSize2 += processedSize;
+ if (processedSize2 > padSize)
+ dataAfterEnd = true;
+ else if (processedSize2 < padSize)
+ truncatedError = true;
+ else
+ for (unsigned i = 0; i < padSize; i++)
+ if (buf[i] != padSize)
+ padError = true;
+ }
}
}
}
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h
index 3043e41c..a70a1a76 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipHandler.h
+++ b/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -57,7 +57,9 @@ private:
int m_MainMethod;
bool m_ForceAesMode;
- bool m_WriteNtfsTimeExtra;
+
+ CHandlerTimeOptions TimeOptions;
+
bool _removeSfxBlock;
bool m_ForceLocal;
bool m_ForceUtf8;
@@ -71,7 +73,8 @@ private:
_props.Init();
m_MainMethod = -1;
m_ForceAesMode = false;
- m_WriteNtfsTimeExtra = true;
+ TimeOptions.Init();
+ TimeOptions.Prec = k_PropVar_TimePrec_0;
_removeSfxBlock = false;
m_ForceLocal = false;
m_ForceUtf8 = false;
diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
index a9b3eae5..77a71df2 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -30,7 +30,7 @@ namespace NZip {
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{
- *timeType = NFileTimeType::kDOS;
+ *timeType = TimeOptions.Prec;
return S_OK;
}
@@ -207,27 +207,58 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
*/
+ // 22.00 : kpidTimeType is useless here : the code was disabled
+ /*
{
CPropVariant prop;
RINOK(callback->GetProperty(i, kpidTimeType, &prop));
if (prop.vt == VT_UI4)
- ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows);
+ ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows);
else
- ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra;
+ ui.NtfsTime_IsDefined = _Write_NtfsTime;
}
- RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime));
- RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime));
- RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime));
+ */
+
+ if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime));
+ if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime));
+ if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime));
+ if (TimeOptions.Prec != k_PropVar_TimePrec_DOS)
{
- FILETIME localFileTime = { 0, 0 };
- if (ui.Ntfs_MTime.dwHighDateTime != 0 ||
- ui.Ntfs_MTime.dwLowDateTime != 0)
- if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime))
- return E_INVALIDARG;
- FileTimeToDosTime(localFileTime, ui.Time);
+ if (TimeOptions.Prec == k_PropVar_TimePrec_Unix ||
+ TimeOptions.Prec == k_PropVar_TimePrec_Base)
+ ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime);
+ else
+ {
+ /*
+ // if we want to store zero timestamps as zero timestamp, use the following:
+ ui.Write_NtfsTime =
+ _Write_MTime ||
+ _Write_ATime ||
+ _Write_CTime;
+ */
+
+ // We treat zero timestamp as no timestamp
+ ui.Write_NtfsTime =
+ ! FILETIME_IsZero (ui.Ntfs_MTime) ||
+ ! FILETIME_IsZero (ui.Ntfs_ATime) ||
+ ! FILETIME_IsZero (ui.Ntfs_CTime);
+ }
}
+ /*
+ how 0 in dos time works:
+ win10 explorer extract : some random date 1601-04-25.
+ winrar 6.10 : write time.
+ 7zip : MTime of archive is used
+ how 0 in tar works:
+ winrar 6.10 : 1970
+ 0 in dos field can show that there is no timestamp.
+ we write correct 1970-01-01 in dos field, to support correct extraction in Win10.
+ */
+
+ UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time);
+
NItemName::ReplaceSlashes_OsToUnix(name);
bool needSlash = ui.IsDir;
@@ -441,11 +472,21 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (mainMethod != NFileHeader::NCompressionMethod::kStore)
options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore);
+ CUpdateOptions uo;
+ uo.Write_MTime = TimeOptions.Write_MTime.Val;
+ uo.Write_ATime = TimeOptions.Write_ATime.Val;
+ uo.Write_CTime = TimeOptions.Write_CTime.Val;
+ /*
+ uo.Write_NtfsTime = _Write_NtfsTime &&
+ (_Write_MTime || _Write_ATime || _Write_CTime);
+ uo.Write_UnixTime = _Write_UnixTime;
+ */
+
return Update(
EXTERNAL_CODECS_VARS
m_Items, updateItems, outStream,
m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
- options, callback);
+ uo, options, callback);
COM_TRY_END2
}
@@ -494,10 +535,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
return E_INVALIDARG;
}
}
- else if (name.IsEqualTo("tc"))
- {
- RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra));
- }
+
+
+
else if (name.IsEqualTo("cl"))
{
RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal));
@@ -532,7 +572,12 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
}
else
{
- RINOK(_props.SetProperty(name, prop));
+ bool processed = false;
+ RINOK(TimeOptions.Parse(name, prop, processed));
+ if (!processed)
+ {
+ RINOK(_props.SetProperty(name, prop));
+ }
}
// RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
}
diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h
index c47659ac..34fa359b 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipHeader.h
+++ b/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -88,14 +88,15 @@ namespace NFileHeader
{
kZip64 = 0x01,
kNTFS = 0x0A,
+ kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK
kStrongEncrypt = 0x17,
kIzNtSecurityDescriptor = 0x4453,
- kUnixTime = 0x5455,
- kUnixExtra = 0x5855,
+ kUnixTime = 0x5455, // "UT" (time) Info-ZIP
+ kUnix1 = 0x5855, // Info-ZIP
kIzUnicodeComment = 0x6375,
kIzUnicodeName = 0x7075,
- kUnix2Extra = 0x7855,
- kUnix3Extra = 0x7875,
+ kUnix2 = 0x7855, // Info-ZIP
+ kUnixN = 0x7875, // Info-ZIP
kWzAES = 0x9901,
kApkAlign = 0xD935
};
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
index 076d6bb5..f2b69a9c 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipIn.cpp
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -1045,9 +1045,24 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo
if (cdItem)
{
- if (isOK && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
- { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
-
+ if (isOK)
+ {
+ if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
+ { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
+ /*
+ else if (size == 8)
+ {
+ size -= 8;
+ const UInt64 v = ReadUInt64();
+ // soong_zip, an AOSP tool (written in the Go) writes incorrect value.
+ // we can ignore that minor error here
+ if (v != cdItem->LocalHeaderPos)
+ isOK = false; // ignore error
+ // isOK = false; // force error
+ }
+ */
+ }
+
if (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
{ if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }}
}
@@ -1926,7 +1941,7 @@ static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
{
if (left >= right)
return -1;
- const unsigned index = (left + right) / 2;
+ const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2);
const CItemEx &item2 = items[index];
if (item.Disk < item2.Disk)
right = index;
diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h
index 1498afed..1498afed 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipIn.h
+++ b/CPP/7zip/Archive/Zip/ZipIn.h
diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp
index be336485..cffbb78a 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipItem.cpp
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -30,11 +30,12 @@ static const CUInt32PCharPair g_ExtraTypes[] =
{
{ NExtraID::kZip64, "Zip64" },
{ NExtraID::kNTFS, "NTFS" },
+ { NExtraID::kUnix0, "UNIX" },
{ NExtraID::kStrongEncrypt, "StrongCrypto" },
{ NExtraID::kUnixTime, "UT" },
- { NExtraID::kUnixExtra, "UX" },
- { NExtraID::kUnix2Extra, "Ux" },
- { NExtraID::kUnix3Extra, "ux" },
+ { NExtraID::kUnix1, "UX" },
+ { NExtraID::kUnix2, "Ux" },
+ { NExtraID::kUnixN, "ux" },
{ NExtraID::kIzUnicodeComment, "uc" },
{ NExtraID::kIzUnicodeName, "up" },
{ NExtraID::kIzNtSecurityDescriptor, "SD" },
@@ -50,6 +51,23 @@ void CExtraSubBlock::PrintInfo(AString &s) const
if (pair.Value == ID)
{
s += pair.Name;
+ if (ID == NExtraID::kUnixTime)
+ {
+ if (Data.Size() >= 1)
+ {
+ s += ':';
+ const Byte flags = Data[0];
+ if (flags & 1) s += 'M';
+ if (flags & 2) s += 'A';
+ if (flags & 4) s += 'C';
+ const UInt32 size = (UInt32)(Data.Size()) - 1;
+ if (size % 4 == 0)
+ {
+ s += ':';
+ s.Add_UInt32(size / 4);
+ }
+ }
+ }
/*
if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
{
@@ -133,14 +151,22 @@ bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
return false;
}
-bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const
+bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const
{
+ /* Info-Zip :
+ The central-header extra field contains the modification
+ time only, or no timestamp at all.
+ Size of Data is used to flag its presence or absence
+ If "Flags" indicates that Modtime is present in the local header
+ field, it MUST be present in the central header field, too
+ */
+
res = 0;
UInt32 size = (UInt32)Data.Size();
if (ID != NExtraID::kUnixTime || size < 5)
return false;
const Byte *p = (const Byte *)Data;
- Byte flags = *p++;
+ const Byte flags = *p++;
size--;
if (isCentral)
{
@@ -168,18 +194,35 @@ bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res
}
-bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const
+// Info-ZIP's abandoned "Unix1 timestamps & owner ID info"
+
+bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const
{
res = 0;
- const size_t size = Data.Size();
- unsigned offset = index * 4;
- if (ID != NExtraID::kUnixExtra || size < offset + 4)
+ const unsigned offset = index * 4;
+ if (Data.Size() < offset + 4)
+ return false;
+ if (ID != NExtraID::kUnix0 &&
+ ID != NExtraID::kUnix1)
return false;
const Byte *p = (const Byte *)Data + offset;
res = GetUi32(p);
return true;
}
+/*
+// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps"
+bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const
+{
+ res = 0;
+ const unsigned offset = index * 4;
+ if (ID != NExtraID::kUnix0 || Data.Size() < offset)
+ return false;
+ const Byte *p = (const Byte *)Data + offset;
+ res = GetUi32(p);
+ return true;
+}
+*/
bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
{
@@ -199,7 +242,7 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
{
const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kUnixTime)
- return sb.ExtractUnixTime(isCentral, index, res);
+ return sb.Extract_UnixTime(isCentral, index, res);
}
}
@@ -214,8 +257,9 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
FOR_VECTOR (i, SubBlocks)
{
const CExtraSubBlock &sb = SubBlocks[i];
- if (sb.ID == NFileHeader::NExtraID::kUnixExtra)
- return sb.ExtractUnixExtraTime(index, res);
+ if (sb.ID == NFileHeader::NExtraID::kUnix0 ||
+ sb.ID == NFileHeader::NExtraID::kUnix1)
+ return sb.Extract_Unix01_Time(index, res);
}
}
return false;
diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h
index 6ee87658..934d7ecf 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipItem.h
+++ b/CPP/7zip/Archive/Zip/ZipItem.h
@@ -31,8 +31,9 @@ struct CExtraSubBlock
CByteBuffer Data;
bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
- bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
- bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const;
+ bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
+ bool Extract_Unix01_Time(unsigned index, UInt32 &res) const;
+ // bool Extract_Unix_Time(unsigned index, UInt32 &res) const;
bool CheckIzUnicode(const AString &s) const;
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp
index efed0a41..8f3f43bf 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -4,6 +4,7 @@
#include "../../../../C/7zCrc.h"
+#include "../../../Windows/TimeUtils.h"
#include "../../Common/OffsetStream.h"
#include "ZipOut.h"
@@ -110,6 +111,40 @@ void COutArchive::WriteUtfName(const CItemOut &item)
WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
}
+
+static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8);
+static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4);
+
+void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
+{
+ if (writeNtfs)
+ {
+ // windows explorer ignores that extra
+ Write16(NFileHeader::NExtraID::kNTFS);
+ Write16(k_Ntfs_ExtraSize);
+ Write32(0); // reserved
+ Write16(NFileHeader::NNtfsExtra::kTagTime);
+ Write16(8 * 3);
+ WriteNtfsTime(item.Ntfs_MTime);
+ WriteNtfsTime(item.Ntfs_ATime);
+ WriteNtfsTime(item.Ntfs_CTime);
+ }
+
+ if (item.Write_UnixTime)
+ {
+ // windows explorer ignores that extra
+ // by specification : should we write to local header also?
+ Write16(NFileHeader::NExtraID::kUnixTime);
+ Write16(k_UnixTime_ExtraSize);
+ const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
+ Write8(flags);
+ UInt32 unixTime;
+ NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime);
+ Write32(unixTime);
+ }
+}
+
+
void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
{
m_LocalHeaderPos = m_CurPos;
@@ -122,8 +157,14 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
if (needCheck && m_IsZip64)
isZip64 = true;
+ // Why don't we write NTFS timestamps to local header?
+ // Probably we want to reduce size of archive?
+ const bool writeNtfs = false; // do not write NTFS timestamp to local header
+ // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header
const UInt32 localExtraSize = (UInt32)(
(isZip64 ? (4 + 8 + 8): 0)
+ + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ item.Get_UtfName_ExtraSize()
+ item.LocalExtra.GetSize());
if ((UInt16)localExtraSize != localExtraSize)
@@ -168,13 +209,12 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
Write64(packSize);
}
+ WriteTimeExtra(item, writeNtfs);
+
WriteUtfName(item);
WriteExtra(item.LocalExtra);
- // Why don't we write NTFS timestamps to local header?
- // Probably we want to reduce size of archive?
-
const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
throw CSystemException(E_FAIL);
@@ -231,10 +271,10 @@ void COutArchive::WriteDescriptor(const CItemOut &item)
void COutArchive::WriteCentralHeader(const CItemOut &item)
{
- bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
- bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
- bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
- bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+ const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
+ const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
+ const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
+ const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
Write32(NSignature::kCentralFileHeader);
Write8(item.MadeByVersion.Version);
@@ -249,10 +289,11 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write16((UInt16)item.Name.Len());
const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
- const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
+ const bool writeNtfs = item.Write_NtfsTime;
const size_t centralExtraSize =
(isZip64 ? 4 + zip64ExtraSize : 0)
- + (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0)
+ + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ item.Get_UtfName_ExtraSize()
+ item.CentralExtra.GetSize();
@@ -283,18 +324,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write64(item.LocalHeaderPos);
}
- if (item.NtfsTimeIsDefined)
- {
- Write16(NFileHeader::NExtraID::kNTFS);
- Write16(kNtfsExtraSize);
- Write32(0); // reserved
- Write16(NFileHeader::NNtfsExtra::kTagTime);
- Write16(8 * 3);
- WriteNtfsTime(item.Ntfs_MTime);
- WriteNtfsTime(item.Ntfs_ATime);
- WriteNtfsTime(item.Ntfs_CTime);
- }
-
+ WriteTimeExtra(item, writeNtfs);
WriteUtfName(item);
WriteExtra(item.CentralExtra);
@@ -304,15 +334,15 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
{
- UInt64 cdOffset = GetCurPos();
+ const UInt64 cdOffset = GetCurPos();
FOR_VECTOR (i, items)
WriteCentralHeader(items[i]);
- UInt64 cd64EndOffset = GetCurPos();
- UInt64 cdSize = cd64EndOffset - cdOffset;
- bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
- bool cdSize64 = DOES_NEED_ZIP64(cdSize);
- bool items64 = items.Size() >= 0xFFFF;
- bool isZip64 = (cdOffset64 || cdSize64 || items64);
+ const UInt64 cd64EndOffset = GetCurPos();
+ const UInt64 cdSize = cd64EndOffset - cdOffset;
+ const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
+ const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
+ const bool items64 = items.Size() >= 0xFFFF;
+ const bool isZip64 = (cdOffset64 || cdSize64 || items64);
// isZip64 = true; // to test Zip64
diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h
index 3546411c..a645d67f 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipOut.h
+++ b/CPP/7zip/Archive/Zip/ZipOut.h
@@ -18,7 +18,8 @@ public:
FILETIME Ntfs_MTime;
FILETIME Ntfs_ATime;
FILETIME Ntfs_CTime;
- bool NtfsTimeIsDefined;
+ bool Write_NtfsTime;
+ bool Write_UnixTime;
// It's possible that NtfsTime is not defined, but there is NtfsTime in Extra.
@@ -32,7 +33,10 @@ public:
return 4 + 5 + size;
}
- CItemOut(): NtfsTimeIsDefined(false) {}
+ CItemOut():
+ Write_NtfsTime(false),
+ Write_UnixTime(false)
+ {}
};
@@ -62,6 +66,7 @@ class COutArchive
Write32(ft.dwHighDateTime);
}
+ void WriteTimeExtra(const CItemOut &item, bool writeNtfs);
void WriteUtfName(const CItemOut &item);
void WriteExtra(const CExtraBlock &extra);
void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp
index e6929f1b..3ad47153 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipRegister.cpp
+++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -20,9 +20,19 @@ REGISTER_ARC_IO(
"zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1,
k_Signature,
0,
- NArcInfoFlags::kFindSignature |
- NArcInfoFlags::kMultiSignature |
- NArcInfoFlags::kUseGlobalOffset,
- IsArc_Zip)
+ NArcInfoFlags::kFindSignature
+ | NArcInfoFlags::kMultiSignature
+ | NArcInfoFlags::kUseGlobalOffset
+ | NArcInfoFlags::kCTime
+ // | NArcInfoFlags::kCTime_Default
+ | NArcInfoFlags::kATime
+ // | NArcInfoFlags::kATime_Default
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
+ , IsArc_Zip)
}}
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
index 26636c78..7f13071a 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -74,7 +74,9 @@ static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &ite
item.Ntfs_MTime = ui.Ntfs_MTime;
item.Ntfs_ATime = ui.Ntfs_ATime;
item.Ntfs_CTime = ui.Ntfs_CTime;
- item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+
+ item.Write_UnixTime = ui.Write_UnixTime;
+ item.Write_NtfsTime = ui.Write_NtfsTime;
}
static void SetFileHeader(
@@ -476,12 +478,9 @@ static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *o
}
-static inline bool IsZero_FILETIME(const FILETIME &ft)
-{
- return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0);
-}
-
-static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream,
+static void UpdatePropsFromStream(
+ const CUpdateOptions &options,
+ CUpdateItem &item, ISequentialInStream *fileInStream,
IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
{
CMyComPtr<IStreamGetProps> getProps;
@@ -505,36 +504,100 @@ static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileIn
}
item.Size = size;
}
-
- if (!IsZero_FILETIME(mTime))
- {
- item.Ntfs_MTime = mTime;
- FILETIME loc = { 0, 0 };
- if (FileTimeToLocalFileTime(&mTime, &loc))
+
+ if (options.Write_MTime)
+ if (!FILETIME_IsZero(mTime))
{
- item.Time = 0;
- NTime::FileTimeToDosTime(loc, item.Time);
+ item.Ntfs_MTime = mTime;
+ NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time);
}
- }
- if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime;
- if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime;
+ if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime;
+ if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime;
item.Attrib = attrib;
}
+/*
+static HRESULT ReportProps(
+ IArchiveUpdateCallbackArcProp *reportArcProp,
+ UInt32 index,
+ const CItemOut &item,
+ bool isAesMode)
+{
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+
+ NCOM::PropVarEm_Set_UInt64(&prop, item.Size);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
+
+ NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop));
+
+ if (!isAesMode)
+ {
+ NCOM::PropVarEm_Set_UInt32(&prop, item.Crc);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
+ }
+
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK));
+
+ // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished))
+
+ return S_OK;
+}
+*/
+
+/*
+struct CTotalStats
+{
+ UInt64 Size;
+ UInt64 PackSize;
+
+ void UpdateWithItem(const CItemOut &item)
+ {
+ Size += item.Size;
+ PackSize += item.PackSize;
+ }
+};
+
+static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ CTotalStats &st)
+{
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kArcProp, 0, kpidSize, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kArcProp, 0, kpidPackSize, &prop));
+ }
+ return S_OK;
+}
+*/
+
+
static HRESULT Update2St(
DECL_EXTERNAL_CODECS_LOC_VARS
COutArchive &archive,
CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems,
+ const CUpdateOptions &updateOptions,
const CCompressionMethodMode *options, bool outSeqMode,
const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback,
UInt64 &totalComplexity,
- IArchiveUpdateCallbackFile *opCallback)
+ IArchiveUpdateCallbackFile *opCallback
+ // , IArchiveUpdateCallbackArcProp *reportArcProp
+ )
{
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
@@ -575,7 +638,8 @@ static HRESULT Update2St(
}
else
{
- CMyComPtr<ISequentialInStream> fileInStream;
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
if (res == S_FALSE)
{
@@ -596,7 +660,7 @@ static HRESULT Update2St(
}
// seqMode = true; // to test seqMode
- UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
+ UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
CCompressingResult compressingResult;
@@ -629,10 +693,11 @@ static HRESULT Update2St(
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
archive.WriteLocalHeader_Replace(item);
-
- RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
- unpackSizeTotal += item.Size;
- packSizeTotal += item.PackSize;
+ }
+ // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode()))
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ unpackSizeTotal += item.Size;
+ packSizeTotal += item.PackSize;
}
}
else
@@ -656,6 +721,14 @@ static HRESULT Update2St(
archive.WriteCentralDir(items, comment);
+ /*
+ CTotalStats stat;
+ stat.Size = unpackSizeTotal;
+ stat.PackSize = packSizeTotal;
+ if (reportArcProp)
+ RINOK(ReportArcProps(reportArcProp, stat))
+ */
+
lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1;
return lps->SetCur();
}
@@ -667,6 +740,7 @@ static HRESULT Update2(
CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems,
+ const CUpdateOptions &updateOptions,
const CCompressionMethodMode &options, bool outSeqMode,
const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback)
@@ -674,6 +748,11 @@ static HRESULT Update2(
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
+ /*
+ CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
+ updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
+ */
+
bool unknownComplexity = false;
UInt64 complexity = 0;
UInt64 numFilesToCompress = 0;
@@ -901,11 +980,23 @@ static HRESULT Update2(
return Update2St(
EXTERNAL_CODECS_LOC_VARS
archive, inArchive,
- inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback);
+ inputItems, updateItems,
+ updateOptions,
+ &options2, outSeqMode,
+ comment, updateCallback, totalComplexity,
+ opCallback
+ // , reportArcProp
+ );
#ifndef _7ZIP_ST
+ /*
+ CTotalStats stat;
+ stat.Size = 0;
+ stat.PackSize = 0;
+ */
+
CObjectVector<CItemOut> items;
CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
@@ -1021,7 +1112,7 @@ static HRESULT Update2(
RINOK(res);
if (!fileInStream)
return E_INVALIDARG;
- UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
+ UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
@@ -1122,6 +1213,13 @@ static HRESULT Update2(
memRef.WriteToStream(memManager.GetBlockSize(), outStream);
archive.MoveCurPos(item.PackSize);
memRef.FreeOpt(&memManager);
+ /*
+ if (reportArcProp)
+ {
+ stat.UpdateWithItem(item);
+ RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
+ }
+ */
}
else
{
@@ -1202,6 +1300,14 @@ static HRESULT Update2(
options.IsRealAesMode(), options.AesKeyMode, item);
archive.WriteLocalHeader_Replace(item);
+
+ /*
+ if (reportArcProp)
+ {
+ stat.UpdateWithItem(item);
+ RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
+ }
+ */
}
else
{
@@ -1230,7 +1336,14 @@ static HRESULT Update2(
RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL));
archive.WriteCentralDir(items, comment);
-
+
+ /*
+ if (reportArcProp)
+ {
+ RINOK(ReportArcProps(reportArcProp, stat));
+ }
+ */
+
complexity += kCentralHeaderSize * updateItems.Size() + 1;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
@@ -1472,6 +1585,7 @@ HRESULT Update(
CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
CInArchive *inArchive, bool removeSfx,
+ const CUpdateOptions &updateOptions,
const CCompressionMethodMode &compressionMethodMode,
IArchiveUpdateCallback *updateCallback)
{
@@ -1529,6 +1643,7 @@ HRESULT Update(
EXTERNAL_CODECS_LOC_VARS
outArchive, inArchive,
inputItems, updateItems,
+ updateOptions,
compressionMethodMode, outSeqMode,
inArchive ? &inArchive->ArcInfo.Comment : NULL,
updateCallback);
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h
index 95e72a47..d1e35347 100644..100755
--- a/CPP/7zip/Archive/Zip/ZipUpdate.h
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -30,7 +30,9 @@ struct CUpdateItem
bool NewData;
bool NewProps;
bool IsDir;
- bool NtfsTimeIsDefined;
+ bool Write_NtfsTime;
+ bool Write_UnixTime;
+ // bool Write_UnixTime_ATime;
bool IsUtf8;
// bool IsAltStream;
int IndexInArc;
@@ -50,30 +52,50 @@ struct CUpdateItem
void Clear()
{
IsDir = false;
- NtfsTimeIsDefined = false;
+
+ Write_NtfsTime = false;
+ Write_UnixTime = false;
+
IsUtf8 = false;
// IsAltStream = false;
+ Time = 0;
Size = 0;
Name.Empty();
Name_Utf.Free();
Comment.Free();
+
+ FILETIME_Clear(Ntfs_MTime);
+ FILETIME_Clear(Ntfs_ATime);
+ FILETIME_Clear(Ntfs_CTime);
}
CUpdateItem():
IsDir(false),
- NtfsTimeIsDefined(false),
+ Write_NtfsTime(false),
+ Write_UnixTime(false),
IsUtf8(false),
// IsAltStream(false),
+ Time(0),
Size(0)
{}
};
+
+struct CUpdateOptions
+{
+ bool Write_MTime;
+ bool Write_ATime;
+ bool Write_CTime;
+};
+
+
HRESULT Update(
DECL_EXTERNAL_CODECS_LOC_VARS
const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream,
CInArchive *inArchive, bool removeSfx,
+ const CUpdateOptions &updateOptions,
const CCompressionMethodMode &compressionMethodMode,
IArchiveUpdateCallback *updateCallback);
diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile
index 7512ad56..7512ad56 100644..100755
--- a/CPP/7zip/Archive/makefile
+++ b/CPP/7zip/Archive/makefile