aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2022-06-20 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2023-12-17 13:35:20 +0500
commita3e1d227377188734b82f023f96f8e25dc40f3e6 (patch)
tree23cad8d47eb23d26ea727b4f7f4a65124f724065
parentf19f813537c7aea1c20749c914e756b54a9c3cf5 (diff)
download7zip-a3e1d227377188734b82f023f96f8e25dc40f3e6.tar.gz
7zip-a3e1d227377188734b82f023f96f8e25dc40f3e6.tar.bz2
7zip-a3e1d227377188734b82f023f96f8e25dc40f3e6.zip
22.0022.00
-rw-r--r--Asm/x86/7zAsm.asm7
-rw-r--r--Asm/x86/Sha256Opt.asm32
-rw-r--r--C/7zTypes.h14
-rw-r--r--C/7zVersion.h10
-rw-r--r--CPP/7zip/7zip_gcc.mak8
-rw-r--r--CPP/7zip/Archive/7z/7zFolderInStream.cpp123
-rw-r--r--CPP/7zip/Archive/7z/7zFolderInStream.h31
-rw-r--r--CPP/7zip/Archive/7z/7zHandler.cpp2
-rw-r--r--CPP/7zip/Archive/7z/7zHandler.h5
-rw-r--r--CPP/7zip/Archive/7z/7zHandlerOut.cpp39
-rw-r--r--CPP/7zip/Archive/7z/7zRegister.cpp10
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.cpp141
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.h14
-rw-r--r--CPP/7zip/Archive/ApfsHandler.cpp3546
-rw-r--r--CPP/7zip/Archive/ArHandler.cpp14
-rw-r--r--CPP/7zip/Archive/ArchiveExports.cpp1
-rw-r--r--CPP/7zip/Archive/ArjHandler.cpp10
-rw-r--r--CPP/7zip/Archive/Bz2Handler.cpp100
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.cpp10
-rw-r--r--CPP/7zip/Archive/Chm/ChmIn.h11
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.cpp77
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.h26
-rw-r--r--CPP/7zip/Archive/Common/ItemNameUtils.cpp23
-rw-r--r--CPP/7zip/Archive/Common/ItemNameUtils.h2
-rw-r--r--CPP/7zip/Archive/CpioHandler.cpp6
-rw-r--r--CPP/7zip/Archive/DllExports2.cpp18
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp51
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp15
-rw-r--r--CPP/7zip/Archive/GptHandler.cpp75
-rw-r--r--CPP/7zip/Archive/GzHandler.cpp217
-rw-r--r--CPP/7zip/Archive/HandlerCont.cpp55
-rw-r--r--CPP/7zip/Archive/HandlerCont.h12
-rw-r--r--CPP/7zip/Archive/HfsHandler.cpp21
-rw-r--r--CPP/7zip/Archive/IArchive.h89
-rw-r--r--CPP/7zip/Archive/Icons/apfs.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Iso/IsoHandler.cpp24
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.cpp2
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.h15
-rw-r--r--CPP/7zip/Archive/Iso/IsoItem.h13
-rw-r--r--CPP/7zip/Archive/LpHandler.cpp1173
-rw-r--r--CPP/7zip/Archive/LzhHandler.cpp15
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp7
-rw-r--r--CPP/7zip/Archive/PeHandler.cpp6
-rw-r--r--CPP/7zip/Archive/PpmdHandler.cpp2
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp44
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp41
-rw-r--r--CPP/7zip/Archive/Rar/RarVol.h17
-rw-r--r--CPP/7zip/Archive/RpmHandler.cpp6
-rw-r--r--CPP/7zip/Archive/SparseHandler.cpp548
-rw-r--r--CPP/7zip/Archive/SplitHandler.cpp7
-rw-r--r--CPP/7zip/Archive/SquashfsHandler.cpp155
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.cpp445
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.h27
-rw-r--r--CPP/7zip/Archive/Tar/TarHandlerOut.cpp209
-rw-r--r--CPP/7zip/Archive/Tar/TarHeader.cpp77
-rw-r--r--CPP/7zip/Archive/Tar/TarHeader.h8
-rw-r--r--CPP/7zip/Archive/Tar/TarIn.cpp945
-rw-r--r--CPP/7zip/Archive/Tar/TarIn.h130
-rw-r--r--CPP/7zip/Archive/Tar/TarItem.h246
-rw-r--r--CPP/7zip/Archive/Tar/TarOut.cpp561
-rw-r--r--CPP/7zip/Archive/Tar/TarOut.h31
-rw-r--r--CPP/7zip/Archive/Tar/TarRegister.cpp16
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.cpp406
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.h39
-rw-r--r--CPP/7zip/Archive/Udf/UdfHandler.cpp20
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.cpp2
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.h2
-rw-r--r--CPP/7zip/Archive/VhdHandler.cpp3
-rw-r--r--CPP/7zip/Archive/VhdxHandler.cpp28
-rw-r--r--CPP/7zip/Archive/VmdkHandler.cpp2
-rw-r--r--CPP/7zip/Archive/Wim/WimHandler.cpp3
-rw-r--r--CPP/7zip/Archive/Wim/WimHandlerOut.cpp14
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.cpp9
-rw-r--r--CPP/7zip/Archive/Wim/WimRegister.cpp21
-rw-r--r--CPP/7zip/Archive/XzHandler.cpp43
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.cpp178
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.h7
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandlerOut.cpp81
-rw-r--r--CPP/7zip/Archive/Zip/ZipHeader.h9
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp23
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.cpp68
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.h5
-rw-r--r--CPP/7zip/Archive/Zip/ZipOut.cpp86
-rw-r--r--CPP/7zip/Archive/Zip/ZipOut.h9
-rw-r--r--CPP/7zip/Archive/Zip/ZipRegister.cpp18
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp171
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.h28
-rw-r--r--CPP/7zip/Bundles/Alone2/makefile1
-rw-r--r--CPP/7zip/Bundles/Alone2/makefile.gcc1
-rw-r--r--CPP/7zip/Bundles/Fm/makefile1
-rw-r--r--CPP/7zip/Bundles/Fm/resource.rc2
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc.mak4
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc_gcc.mak4
-rw-r--r--CPP/7zip/Bundles/Format7zF/Format7z.dsp20
-rw-r--r--CPP/7zip/Bundles/Format7zF/resource.rc3
-rw-r--r--CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp2
-rw-r--r--CPP/7zip/Common/FileStreams.cpp292
-rw-r--r--CPP/7zip/Common/FileStreams.h42
-rw-r--r--CPP/7zip/Common/InBuffer.cpp3
-rw-r--r--CPP/7zip/Common/LimitedStreams.cpp68
-rw-r--r--CPP/7zip/Common/LimitedStreams.h21
-rw-r--r--CPP/7zip/Common/PropId.cpp9
-rw-r--r--CPP/7zip/Common/RegisterArc.h24
-rw-r--r--CPP/7zip/Common/UniqBlocks.cpp8
-rw-r--r--CPP/7zip/Common/UniqBlocks.h19
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.cpp23
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.h6
-rw-r--r--CPP/7zip/Compress/BitlDecoder.h4
-rw-r--r--CPP/7zip/Compress/DeflateDecoder.cpp1
-rw-r--r--CPP/7zip/Compress/LzmaEncoder.cpp7
-rw-r--r--CPP/7zip/Guid.txt8
-rw-r--r--CPP/7zip/IStream.h7
-rw-r--r--CPP/7zip/PropID.h48
-rw-r--r--CPP/7zip/UI/Agent/Agent.cpp65
-rw-r--r--CPP/7zip/UI/Agent/Agent.h8
-rw-r--r--CPP/7zip/UI/Agent/AgentOut.cpp53
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.cpp101
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.h6
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolder.cpp6
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolderOut.cpp8
-rw-r--r--CPP/7zip/UI/Agent/IFolderArchive.h9
-rw-r--r--CPP/7zip/UI/Client7z/Client7z.cpp198
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp36
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.h7
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp315
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.h97
-rw-r--r--CPP/7zip/UI/Common/ArchiveOpenCallback.cpp12
-rw-r--r--CPP/7zip/UI/Common/CompressCall.cpp7
-rw-r--r--CPP/7zip/UI/Common/CompressCall.h2
-rw-r--r--CPP/7zip/UI/Common/CompressCall2.cpp28
-rw-r--r--CPP/7zip/UI/Common/DirItem.h249
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp242
-rw-r--r--CPP/7zip/UI/Common/Extract.cpp55
-rw-r--r--CPP/7zip/UI/Common/Extract.h4
-rw-r--r--CPP/7zip/UI/Common/ExtractMode.h10
-rw-r--r--CPP/7zip/UI/Common/ExtractingFilePath.cpp11
-rw-r--r--CPP/7zip/UI/Common/HashCalc.cpp85
-rw-r--r--CPP/7zip/UI/Common/HashCalc.h6
-rw-r--r--CPP/7zip/UI/Common/LoadCodecs.cpp48
-rw-r--r--CPP/7zip/UI/Common/LoadCodecs.h40
-rw-r--r--CPP/7zip/UI/Common/OpenArchive.cpp166
-rw-r--r--CPP/7zip/UI/Common/OpenArchive.h42
-rw-r--r--CPP/7zip/UI/Common/PropIDUtils.cpp51
-rw-r--r--CPP/7zip/UI/Common/Update.cpp205
-rw-r--r--CPP/7zip/UI/Common/Update.h3
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp205
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.h27
-rw-r--r--CPP/7zip/UI/Common/UpdatePair.cpp125
-rw-r--r--CPP/7zip/UI/Common/UpdateProduce.cpp2
-rw-r--r--CPP/7zip/UI/Common/UpdateProduce.h4
-rw-r--r--CPP/7zip/UI/Common/ZipRegistry.cpp105
-rw-r--r--CPP/7zip/UI/Common/ZipRegistry.h47
-rw-r--r--CPP/7zip/UI/Console/ExtractCallbackConsole.cpp7
-rw-r--r--CPP/7zip/UI/Console/ExtractCallbackConsole.h21
-rw-r--r--CPP/7zip/UI/Console/List.cpp72
-rw-r--r--CPP/7zip/UI/Console/Main.cpp32
-rw-r--r--CPP/7zip/UI/Console/PercentPrinter.cpp3
-rw-r--r--CPP/7zip/UI/Console/UpdateCallbackConsole.cpp169
-rw-r--r--CPP/7zip/UI/Console/UpdateCallbackConsole.h5
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.cpp5
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.h1
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.cpp105
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.h5
-rw-r--r--CPP/7zip/UI/FileManager/HelpUtils.cpp42
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage.cpp76
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage.h5
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage2.rc15
-rw-r--r--CPP/7zip/UI/FileManager/MenuPageRes.h4
-rw-r--r--CPP/7zip/UI/FileManager/MyLoadMenu.cpp3
-rw-r--r--CPP/7zip/UI/FileManager/Panel.cpp5
-rw-r--r--CPP/7zip/UI/FileManager/Panel.h5
-rw-r--r--CPP/7zip/UI/FileManager/PanelCopy.cpp21
-rw-r--r--CPP/7zip/UI/FileManager/PanelCrc.cpp1
-rw-r--r--CPP/7zip/UI/FileManager/PanelItemOpen.cpp19
-rw-r--r--CPP/7zip/UI/FileManager/PanelItems.cpp6
-rw-r--r--CPP/7zip/UI/FileManager/PanelMenu.cpp2
-rw-r--r--CPP/7zip/UI/FileManager/PropertyName.rc7
-rw-r--r--CPP/7zip/UI/FileManager/PropertyNameRes.h7
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp724
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.h168
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.rc27
-rw-r--r--CPP/7zip/UI/GUI/CompressDialogRes.h33
-rw-r--r--CPP/7zip/UI/GUI/CompressOptionsDialog.rc76
-rw-r--r--CPP/7zip/UI/GUI/GUI.cpp4
-rw-r--r--CPP/7zip/UI/GUI/GUI.dsp16
-rw-r--r--CPP/7zip/UI/GUI/UpdateGUI.cpp182
-rw-r--r--CPP/Common/Common.h2
-rw-r--r--CPP/Common/MyCom.h1
-rw-r--r--CPP/Common/MyLinux.h33
-rw-r--r--CPP/Common/MyString.cpp187
-rw-r--r--CPP/Common/MyString.h3
-rw-r--r--CPP/Common/MyVector.h215
-rw-r--r--CPP/Common/MyWindows.h2
-rw-r--r--CPP/Common/NewHandler.cpp19
-rw-r--r--CPP/Common/StringToInt.cpp27
-rw-r--r--CPP/Common/StringToInt.h1
-rw-r--r--CPP/Windows/FileDir.cpp73
-rw-r--r--CPP/Windows/FileDir.h10
-rw-r--r--CPP/Windows/FileFind.cpp133
-rw-r--r--CPP/Windows/FileFind.h95
-rw-r--r--CPP/Windows/FileIO.cpp88
-rw-r--r--CPP/Windows/FileIO.h44
-rw-r--r--CPP/Windows/PropVariant.cpp132
-rw-r--r--CPP/Windows/PropVariant.h52
-rw-r--r--CPP/Windows/PropVariantConv.cpp58
-rw-r--r--CPP/Windows/PropVariantConv.h5
-rw-r--r--CPP/Windows/SecurityUtils.cpp2
-rw-r--r--CPP/Windows/TimeUtils.cpp220
-rw-r--r--CPP/Windows/TimeUtils.h130
-rw-r--r--DOC/7zip.wxs4
-rw-r--r--DOC/src-history.txt6
211 files changed, 15196 insertions, 2397 deletions
diff --git a/Asm/x86/7zAsm.asm b/Asm/x86/7zAsm.asm
index 6275bb7..19c40da 100644
--- a/Asm/x86/7zAsm.asm
+++ b/Asm/x86/7zAsm.asm
@@ -1,7 +1,12 @@
1; 7zAsm.asm -- ASM macros 1; 7zAsm.asm -- ASM macros
2; 2021-12-25 : Igor Pavlov : Public domain 2; 2022-05-16 : Igor Pavlov : Public domain
3 3
4 4
5; UASM can require these changes
6; OPTION FRAMEPRESERVEFLAGS:ON
7; OPTION PROLOGUE:NONE
8; OPTION EPILOGUE:NONE
9
5ifdef @wordsize 10ifdef @wordsize
6; @wordsize is defined only in JWASM and ASMC and is not defined in MASM 11; @wordsize is defined only in JWASM and ASMC and is not defined in MASM
7; @wordsize eq 8 for 64-bit x64 12; @wordsize eq 8 for 64-bit x64
diff --git a/Asm/x86/Sha256Opt.asm b/Asm/x86/Sha256Opt.asm
index 5d02c90..3e9f6ed 100644
--- a/Asm/x86/Sha256Opt.asm
+++ b/Asm/x86/Sha256Opt.asm
@@ -1,5 +1,5 @@
1; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions 1; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions
2; 2021-03-10 : Igor Pavlov : Public domain 2; 2022-04-17 : Igor Pavlov : Public domain
3 3
4include 7zAsm.asm 4include 7zAsm.asm
5 5
@@ -54,14 +54,20 @@ ifndef x64
54 .686 54 .686
55 .xmm 55 .xmm
56endif 56endif
57 57
58; jwasm-based assemblers for linux and linker from new versions of binutils
59; can generate incorrect code for load [ARRAY + offset] instructions.
60; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem
61 rTable equ r0
62 ; rTable equ K_CONST
63
58ifdef x64 64ifdef x64
59 rNum equ REG_ABI_PARAM_2 65 rNum equ REG_ABI_PARAM_2
60 if (IS_LINUX eq 0) 66 if (IS_LINUX eq 0)
61 LOCAL_SIZE equ (16 * 2) 67 LOCAL_SIZE equ (16 * 2)
62 endif 68 endif
63else 69else
64 rNum equ r0 70 rNum equ r3
65 LOCAL_SIZE equ (16 * 1) 71 LOCAL_SIZE equ (16 * 1)
66endif 72endif
67 73
@@ -103,15 +109,18 @@ MY_PROLOG macro
103 movdqa [r4 + 16], xmm9 109 movdqa [r4 + 16], xmm9
104 endif 110 endif
105 else ; x86 111 else ; x86
112 push r3
113 push r5
114 mov r5, r4
115 NUM_PUSH_REGS equ 2
116 PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS))
106 if (IS_CDECL gt 0) 117 if (IS_CDECL gt 0)
107 mov rState, [r4 + REG_SIZE * 1] 118 mov rState, [r4 + PARAM_OFFSET]
108 mov rData, [r4 + REG_SIZE * 2] 119 mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1]
109 mov rNum, [r4 + REG_SIZE * 3] 120 mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2]
110 else ; fastcall 121 else ; fastcall
111 mov rNum, [r4 + REG_SIZE * 1] 122 mov rNum, [r4 + PARAM_OFFSET]
112 endif 123 endif
113 push r5
114 mov r5, r4
115 and r4, -16 124 and r4, -16
116 sub r4, LOCAL_SIZE 125 sub r4, LOCAL_SIZE
117 endif 126 endif
@@ -129,6 +138,7 @@ MY_EPILOG macro
129 else ; x86 138 else ; x86
130 mov r4, r5 139 mov r4, r5
131 pop r5 140 pop r5
141 pop r3
132 endif 142 endif
133 MY_ENDP 143 MY_ENDP
134endm 144endm
@@ -171,7 +181,7 @@ pre2 equ 2
171 181
172 182
173RND4 macro k 183RND4 macro k
174 movdqa msg, xmmword ptr [K_CONST + (k) * 16] 184 movdqa msg, xmmword ptr [rTable + (k) * 16]
175 paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4))) 185 paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4)))
176 MY_sha256rnds2 state0_N, state1_N 186 MY_sha256rnds2 state0_N, state1_N
177 pshufd msg, msg, 0eH 187 pshufd msg, msg, 0eH
@@ -210,6 +220,8 @@ endm
210MY_PROC Sha256_UpdateBlocks_HW, 3 220MY_PROC Sha256_UpdateBlocks_HW, 3
211 MY_PROLOG 221 MY_PROLOG
212 222
223 lea rTable, [K_CONST]
224
213 cmp rNum, 0 225 cmp rNum, 0
214 je end_c 226 je end_c
215 227
diff --git a/C/7zTypes.h b/C/7zTypes.h
index fe4fde3..f7d7071 100644
--- a/C/7zTypes.h
+++ b/C/7zTypes.h
@@ -1,5 +1,5 @@
1/* 7zTypes.h -- Basic types 1/* 7zTypes.h -- Basic types
22021-12-25 : Igor Pavlov : Public domain */ 22022-04-01 : Igor Pavlov : Public domain */
3 3
4#ifndef __7Z_TYPES_H 4#ifndef __7Z_TYPES_H
5#define __7Z_TYPES_H 5#define __7Z_TYPES_H
@@ -133,10 +133,6 @@ typedef int WRes;
133#define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) 133#define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
134*/ 134*/
135 135
136// gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits
137typedef long INT_PTR;
138typedef unsigned long UINT_PTR;
139
140#define TEXT(quote) quote 136#define TEXT(quote) quote
141 137
142#define FILE_ATTRIBUTE_READONLY 0x0001 138#define FILE_ATTRIBUTE_READONLY 0x0001
@@ -520,6 +516,14 @@ struct ISzAlloc
520 516
521#endif 517#endif
522 518
519#define k_PropVar_TimePrec_0 0
520#define k_PropVar_TimePrec_Unix 1
521#define k_PropVar_TimePrec_DOS 2
522#define k_PropVar_TimePrec_HighPrec 3
523#define k_PropVar_TimePrec_Base 16
524#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7)
525#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9)
526
523EXTERN_C_END 527EXTERN_C_END
524 528
525#endif 529#endif
diff --git a/C/7zVersion.h b/C/7zVersion.h
index e9363d3..89fffd9 100644
--- a/C/7zVersion.h
+++ b/C/7zVersion.h
@@ -1,7 +1,7 @@
1#define MY_VER_MAJOR 21 1#define MY_VER_MAJOR 22
2#define MY_VER_MINOR 07 2#define MY_VER_MINOR 00
3#define MY_VER_BUILD 0 3#define MY_VER_BUILD 0
4#define MY_VERSION_NUMBERS "21.07" 4#define MY_VERSION_NUMBERS "22.00"
5#define MY_VERSION MY_VERSION_NUMBERS 5#define MY_VERSION MY_VERSION_NUMBERS
6 6
7#ifdef MY_CPU_NAME 7#ifdef MY_CPU_NAME
@@ -10,12 +10,12 @@
10 #define MY_VERSION_CPU MY_VERSION 10 #define MY_VERSION_CPU MY_VERSION
11#endif 11#endif
12 12
13#define MY_DATE "2021-12-26" 13#define MY_DATE "2022-06-15"
14#undef MY_COPYRIGHT 14#undef MY_COPYRIGHT
15#undef MY_VERSION_COPYRIGHT_DATE 15#undef MY_VERSION_COPYRIGHT_DATE
16#define MY_AUTHOR_NAME "Igor Pavlov" 16#define MY_AUTHOR_NAME "Igor Pavlov"
17#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" 17#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
18#define MY_COPYRIGHT_CR "Copyright (c) 1999-2021 Igor Pavlov" 18#define MY_COPYRIGHT_CR "Copyright (c) 1999-2022 Igor Pavlov"
19 19
20#ifdef USE_COPYRIGHT_CR 20#ifdef USE_COPYRIGHT_CR
21 #define MY_COPYRIGHT MY_COPYRIGHT_CR 21 #define MY_COPYRIGHT MY_COPYRIGHT_CR
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
index e2698a6..b242459 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -382,6 +382,8 @@ $O/VirtThread.o: ../../Common/VirtThread.cpp
382 $(CXX) $(CXXFLAGS) $< 382 $(CXX) $(CXXFLAGS) $<
383 383
384 384
385$O/ApfsHandler.o: ../../Archive/ApfsHandler.cpp
386 $(CXX) $(CXXFLAGS) $<
385$O/ApmHandler.o: ../../Archive/ApmHandler.cpp 387$O/ApmHandler.o: ../../Archive/ApmHandler.cpp
386 $(CXX) $(CXXFLAGS) $< 388 $(CXX) $(CXXFLAGS) $<
387$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp 389$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp
@@ -390,6 +392,8 @@ $O/ArHandler.o: ../../Archive/ArHandler.cpp
390 $(CXX) $(CXXFLAGS) $< 392 $(CXX) $(CXXFLAGS) $<
391$O/ArjHandler.o: ../../Archive/ArjHandler.cpp 393$O/ArjHandler.o: ../../Archive/ArjHandler.cpp
392 $(CXX) $(CXXFLAGS) $< 394 $(CXX) $(CXXFLAGS) $<
395$O/AvbHandler.o: ../../Archive/AvbHandler.cpp
396 $(CXX) $(CXXFLAGS) $<
393$O/Base64Handler.o: ../../Archive/Base64Handler.cpp 397$O/Base64Handler.o: ../../Archive/Base64Handler.cpp
394 $(CXX) $(CXXFLAGS) $< 398 $(CXX) $(CXXFLAGS) $<
395$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp 399$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp
@@ -426,6 +430,8 @@ $O/HfsHandler.o: ../../Archive/HfsHandler.cpp
426 $(CXX) $(CXXFLAGS) $< 430 $(CXX) $(CXXFLAGS) $<
427$O/IhexHandler.o: ../../Archive/IhexHandler.cpp 431$O/IhexHandler.o: ../../Archive/IhexHandler.cpp
428 $(CXX) $(CXXFLAGS) $< 432 $(CXX) $(CXXFLAGS) $<
433$O/LpHandler.o: ../../Archive/LpHandler.cpp
434 $(CXX) $(CXXFLAGS) $<
429$O/LzhHandler.o: ../../Archive/LzhHandler.cpp 435$O/LzhHandler.o: ../../Archive/LzhHandler.cpp
430 $(CXX) $(CXXFLAGS) $< 436 $(CXX) $(CXXFLAGS) $<
431$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp 437$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp
@@ -448,6 +454,8 @@ $O/QcowHandler.o: ../../Archive/QcowHandler.cpp
448 $(CXX) $(CXXFLAGS) $< 454 $(CXX) $(CXXFLAGS) $<
449$O/RpmHandler.o: ../../Archive/RpmHandler.cpp 455$O/RpmHandler.o: ../../Archive/RpmHandler.cpp
450 $(CXX) $(CXXFLAGS) $< 456 $(CXX) $(CXXFLAGS) $<
457$O/SparseHandler.o: ../../Archive/SparseHandler.cpp
458 $(CXX) $(CXXFLAGS) $<
451$O/SplitHandler.o: ../../Archive/SplitHandler.cpp 459$O/SplitHandler.o: ../../Archive/SplitHandler.cpp
452 $(CXX) $(CXXFLAGS) $< 460 $(CXX) $(CXXFLAGS) $<
453$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp 461$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
index a68edf4..cf50e69 100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -2,6 +2,8 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#include "../../../Windows/TimeUtils.h"
6
5#include "7zFolderInStream.h" 7#include "7zFolderInStream.h"
6 8
7namespace NArchive { 9namespace NArchive {
@@ -13,17 +15,17 @@ void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
13 _updateCallback = updateCallback; 15 _updateCallback = updateCallback;
14 _indexes = indexes; 16 _indexes = indexes;
15 _numFiles = numFiles; 17 _numFiles = numFiles;
16 _index = 0;
17 18
18 Processed.ClearAndReserve(numFiles); 19 Processed.ClearAndReserve(numFiles);
19 CRCs.ClearAndReserve(numFiles); 20 CRCs.ClearAndReserve(numFiles);
20 Sizes.ClearAndReserve(numFiles); 21 Sizes.ClearAndReserve(numFiles);
21
22 _pos = 0;
23 _crc = CRC_INIT_VAL;
24 _size_Defined = false;
25 _size = 0;
26 22
23 if (Need_CTime) CTimes.ClearAndReserve(numFiles);
24 if (Need_ATime) ATimes.ClearAndReserve(numFiles);
25 if (Need_MTime) MTimes.ClearAndReserve(numFiles);
26 if (Need_Attrib) Attribs.ClearAndReserve(numFiles);
27 TimesDefined.ClearAndReserve(numFiles);
28
27 _stream.Release(); 29 _stream.Release();
28} 30}
29 31
@@ -32,44 +34,101 @@ HRESULT CFolderInStream::OpenStream()
32 _pos = 0; 34 _pos = 0;
33 _crc = CRC_INIT_VAL; 35 _crc = CRC_INIT_VAL;
34 _size_Defined = false; 36 _size_Defined = false;
37 _times_Defined = false;
35 _size = 0; 38 _size = 0;
39 FILETIME_Clear(_cTime);
40 FILETIME_Clear(_aTime);
41 FILETIME_Clear(_mTime);
42 _attrib = 0;
36 43
37 while (_index < _numFiles) 44 while (Processed.Size() < _numFiles)
38 { 45 {
39 CMyComPtr<ISequentialInStream> stream; 46 CMyComPtr<ISequentialInStream> stream;
40 HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream); 47 const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream);
41 if (result != S_OK) 48 if (result != S_OK && result != S_FALSE)
42 { 49 return result;
43 if (result != S_FALSE)
44 return result;
45 }
46 50
47 _stream = stream; 51 _stream = stream;
48 52
49 if (stream) 53 if (stream)
50 { 54 {
51 CMyComPtr<IStreamGetSize> streamGetSize;
52 stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
53 if (streamGetSize)
54 { 55 {
55 if (streamGetSize->GetSize(&_size) == S_OK) 56 CMyComPtr<IStreamGetProps> getProps;
56 _size_Defined = true; 57 stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
58 if (getProps)
59 {
60 // access could be changed in first myx pass
61 if (getProps->GetProps(&_size,
62 Need_CTime ? &_cTime : NULL,
63 Need_ATime ? &_aTime : NULL,
64 Need_MTime ? &_mTime : NULL,
65 Need_Attrib ? &_attrib : NULL)
66 == S_OK)
67 {
68 _size_Defined = true;
69 _times_Defined = true;
70 }
71 return S_OK;
72 }
73 }
74 {
75 CMyComPtr<IStreamGetSize> streamGetSize;
76 stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
77 if (streamGetSize)
78 {
79 if (streamGetSize->GetSize(&_size) == S_OK)
80 _size_Defined = true;
81 }
82 return S_OK;
57 } 83 }
58 return S_OK;
59 } 84 }
60 85
61 _index++; 86 RINOK(AddFileInfo(result == S_OK));
62 RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
63 AddFileInfo(result == S_OK);
64 } 87 }
65 return S_OK; 88 return S_OK;
66} 89}
67 90
68void CFolderInStream::AddFileInfo(bool isProcessed) 91static void AddFt(CRecordVector<UInt64> &vec, const FILETIME &ft)
69{ 92{
70 Processed.Add(isProcessed); 93 vec.AddInReserved(FILETIME_To_UInt64(ft));
71 Sizes.Add(_pos); 94}
72 CRCs.Add(CRC_GET_DIGEST(_crc)); 95
96/*
97HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp,
98 UInt32 index, UInt64 size, const UInt32 *crc)
99{
100 PROPVARIANT prop;
101 prop.vt = VT_EMPTY;
102 prop.wReserved1 = 0;
103
104 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size);
105 RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
106 if (crc)
107 {
108 NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc);
109 RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
110 }
111 return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK);
112}
113*/
114
115HRESULT CFolderInStream::AddFileInfo(bool isProcessed)
116{
117 // const UInt32 index = _indexes[Processed.Size()];
118 Processed.AddInReserved(isProcessed);
119 Sizes.AddInReserved(_pos);
120 const UInt32 crc = CRC_GET_DIGEST(_crc);
121 CRCs.AddInReserved(crc);
122 TimesDefined.AddInReserved(_times_Defined);
123 if (Need_CTime) AddFt(CTimes, _cTime);
124 if (Need_ATime) AddFt(ATimes, _aTime);
125 if (Need_MTime) AddFt(MTimes, _mTime);
126 if (Need_Attrib) Attribs.AddInReserved(_attrib);
127 /*
128 if (isProcessed && _reportArcProp)
129 RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc))
130 */
131 return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
73} 132}
74 133
75STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 134STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
@@ -95,18 +154,10 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
95 } 154 }
96 155
97 _stream.Release(); 156 _stream.Release();
98 _index++; 157 RINOK(AddFileInfo(true));
99 AddFileInfo(true);
100
101 _pos = 0;
102 _crc = CRC_INIT_VAL;
103 _size_Defined = false;
104 _size = 0;
105
106 RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
107 } 158 }
108 159
109 if (_index >= _numFiles) 160 if (Processed.Size() >= _numFiles)
110 break; 161 break;
111 RINOK(OpenStream()); 162 RINOK(OpenStream());
112 } 163 }
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h
index 805db54..f054e68 100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.h
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -23,21 +23,37 @@ class CFolderInStream:
23 UInt64 _pos; 23 UInt64 _pos;
24 UInt32 _crc; 24 UInt32 _crc;
25 bool _size_Defined; 25 bool _size_Defined;
26 bool _times_Defined;
26 UInt64 _size; 27 UInt64 _size;
28 FILETIME _cTime;
29 FILETIME _aTime;
30 FILETIME _mTime;
31 UInt32 _attrib;
27 32
28 const UInt32 *_indexes;
29 unsigned _numFiles; 33 unsigned _numFiles;
30 unsigned _index; 34 const UInt32 *_indexes;
31 35
32 CMyComPtr<IArchiveUpdateCallback> _updateCallback; 36 CMyComPtr<IArchiveUpdateCallback> _updateCallback;
33 37
34 HRESULT OpenStream(); 38 HRESULT OpenStream();
35 void AddFileInfo(bool isProcessed); 39 HRESULT AddFileInfo(bool isProcessed);
36 40
37public: 41public:
38 CRecordVector<bool> Processed; 42 CRecordVector<bool> Processed;
39 CRecordVector<UInt32> CRCs; 43 CRecordVector<UInt32> CRCs;
40 CRecordVector<UInt64> Sizes; 44 CRecordVector<UInt64> Sizes;
45 CRecordVector<UInt64> CTimes;
46 CRecordVector<UInt64> ATimes;
47 CRecordVector<UInt64> MTimes;
48 CRecordVector<UInt32> Attribs;
49 CRecordVector<bool> TimesDefined;
50
51 bool Need_CTime;
52 bool Need_ATime;
53 bool Need_MTime;
54 bool Need_Attrib;
55
56 // CMyComPtr<IArchiveUpdateCallbackArcProp> _reportArcProp;
41 57
42 MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize) 58 MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
43 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); 59 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
@@ -45,7 +61,7 @@ public:
45 61
46 void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles); 62 void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);
47 63
48 bool WasFinished() const { return _index == _numFiles; } 64 bool WasFinished() const { return Processed.Size() == _numFiles; }
49 65
50 UInt64 GetFullSize() const 66 UInt64 GetFullSize() const
51 { 67 {
@@ -54,6 +70,13 @@ public:
54 size += Sizes[i]; 70 size += Sizes[i];
55 return size; 71 return size;
56 } 72 }
73
74 CFolderInStream():
75 Need_CTime(false),
76 Need_ATime(false),
77 Need_MTime(false),
78 Need_Attrib(false)
79 {}
57}; 80};
58 81
59}} 82}}
diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp
index 9e344c3..ca22f88 100644
--- 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
278{ 278{
279 UInt64 value; 279 UInt64 value;
280 if (v.GetItem(index, value)) 280 if (v.GetItem(index, value))
281 PropVarEm_Set_FileTime64(prop, value); 281 PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns);
282} 282}
283 283
284bool CHandler::IsFolderEncrypted(CNum folderIndex) const 284bool CHandler::IsFolderEncrypted(CNum folderIndex) const
diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h
index cbc2d02..08bd654 100644
--- a/CPP/7zip/Archive/7z/7zHandler.h
+++ b/CPP/7zip/Archive/7z/7zHandler.h
@@ -49,9 +49,8 @@ public:
49 bool _encryptHeaders; 49 bool _encryptHeaders;
50 // bool _useParents; 9.26 50 // bool _useParents; 9.26
51 51
52 CBoolPair Write_CTime; 52 CHandlerTimeOptions TimeOptions;
53 CBoolPair Write_ATime; 53
54 CBoolPair Write_MTime;
55 CBoolPair Write_Attrib; 54 CBoolPair Write_Attrib;
56 55
57 bool _useMultiThreadMixer; 56 bool _useMultiThreadMixer;
diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
index 8f875ce..bf4e7a6 100644
--- 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
384 384
385 CObjectVector<CUpdateItem> updateItems; 385 CObjectVector<CUpdateItem> updateItems;
386 386
387 bool need_CTime = (Write_CTime.Def && Write_CTime.Val); 387 bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
388 bool need_ATime = (Write_ATime.Def && Write_ATime.Val); 388 bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
389 bool need_MTime = (Write_MTime.Def ? Write_MTime.Val : true); 389 bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
390 bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true); 390 bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
391 391
392 if (db && !db->Files.IsEmpty()) 392 if (db && !db->Files.IsEmpty())
393 { 393 {
394 if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); 394 if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
395 if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); 395 if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
396 if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); 396 if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
397 if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty(); 397 if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
398 } 398 }
399 399
@@ -719,6 +719,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
719 int level = GetLevel(); 719 int level = GetLevel();
720 720
721 CUpdateOptions options; 721 CUpdateOptions options;
722 options.Need_CTime = need_CTime;
723 options.Need_ATime = need_ATime;
724 options.Need_MTime = need_MTime;
725 options.Need_Attrib = need_Attrib;
726
722 options.Method = &methodMode; 727 options.Method = &methodMode;
723 options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; 728 options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
724 options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); 729 options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
@@ -817,9 +822,7 @@ void COutHandler::InitProps7z()
817 _encryptHeaders = false; 822 _encryptHeaders = false;
818 // _useParents = false; 823 // _useParents = false;
819 824
820 Write_CTime.Init(); 825 TimeOptions.Init();
821 Write_ATime.Init();
822 Write_MTime.Init();
823 Write_Attrib.Init(); 826 Write_Attrib.Init();
824 827
825 _useMultiThreadMixer = true; 828 _useMultiThreadMixer = true;
@@ -954,10 +957,20 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
954 return S_OK; 957 return S_OK;
955 } 958 }
956 959
957 if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); 960 {
958 if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); 961 bool processed;
959 if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); 962 RINOK(TimeOptions.Parse(name, value, processed));
960 963 if (processed)
964 {
965 if ( TimeOptions.Prec != (UInt32)(Int32)-1
966 && TimeOptions.Prec != k_PropVar_TimePrec_0
967 && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
968 && TimeOptions.Prec != k_PropVar_TimePrec_100ns)
969 return E_INVALIDARG;
970 return S_OK;
971 }
972 }
973
961 if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); 974 if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
962 975
963 if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); 976 if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp
index 389b540..eac8b4f 100644
--- a/CPP/7zip/Archive/7z/7zRegister.cpp
+++ b/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -15,7 +15,13 @@ REGISTER_ARC_IO_DECREMENT_SIG(
15 "7z", "7z", NULL, 7, 15 "7z", "7z", NULL, 7,
16 k_Signature_Dec, 16 k_Signature_Dec,
17 0, 17 0,
18 NArcInfoFlags::kFindSignature, 18 NArcInfoFlags::kFindSignature
19 NULL); 19 | NArcInfoFlags::kCTime
20 | NArcInfoFlags::kATime
21 | NArcInfoFlags::kMTime
22 | NArcInfoFlags::kMTime_Default
23 , TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows)
24 | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows)
25 , NULL);
20 26
21}} 27}}
diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp
index b641d93..b6fd192 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.cpp
+++ b/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -804,10 +804,20 @@ struct CAnalysis
804 bool ParseExe; 804 bool ParseExe;
805 bool ParseAll; 805 bool ParseAll;
806 806
807 /*
808 bool Need_ATime;
809 bool ATime_Defined;
810 FILETIME ATime;
811 */
812
807 CAnalysis(): 813 CAnalysis():
808 ParseWav(true), 814 ParseWav(true),
809 ParseExe(false), 815 ParseExe(false),
810 ParseAll(false) 816 ParseAll(false)
817 /*
818 , Need_ATime(false)
819 , ATime_Defined(false)
820 */
811 {} 821 {}
812 822
813 HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); 823 HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode);
@@ -887,6 +897,18 @@ HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMo
887 HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze); 897 HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);
888 if (result == S_OK && stream) 898 if (result == S_OK && stream)
889 { 899 {
900 /*
901 if (Need_ATime)
902 {
903 // access time could be changed in analysis pass
904 CMyComPtr<IStreamGetProps> getProps;
905 stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
906 if (getProps)
907 if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK)
908 ATime_Defined = true;
909 }
910 */
911
890 size_t size = kAnalysisBufSize; 912 size_t size = kAnalysisBufSize;
891 result = ReadStream(stream, Buffer, &size); 913 result = ReadStream(stream, Buffer, &size);
892 stream.Release(); 914 stream.Release();
@@ -1586,6 +1608,11 @@ HRESULT Update(
1586 CMyComPtr<IArchiveExtractCallbackMessage> extractCallback; 1608 CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;
1587 updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback); 1609 updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);
1588 1610
1611 /*
1612 CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
1613 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
1614 */
1615
1589 // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); 1616 // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
1590 1617
1591 /* 1618 /*
@@ -1756,6 +1783,7 @@ HRESULT Update(
1756 1783
1757 { 1784 {
1758 CAnalysis analysis; 1785 CAnalysis analysis;
1786 // analysis.Need_ATime = options.Need_ATime;
1759 if (options.AnalysisLevel == 0) 1787 if (options.AnalysisLevel == 0)
1760 { 1788 {
1761 analysis.ParseWav = false; 1789 analysis.ParseWav = false;
@@ -1790,7 +1818,15 @@ HRESULT Update(
1790 CFilterMode2 fm; 1818 CFilterMode2 fm;
1791 if (useFilters) 1819 if (useFilters)
1792 { 1820 {
1821 // analysis.ATime_Defined = false;
1793 RINOK(analysis.GetFilterGroup(i, ui, fm)); 1822 RINOK(analysis.GetFilterGroup(i, ui, fm));
1823 /*
1824 if (analysis.ATime_Defined)
1825 {
1826 ui.ATime = FILETIME_To_UInt64(analysis.ATime);
1827 ui.ATime_WasReadByAnalysis = true;
1828 }
1829 */
1794 } 1830 }
1795 fm.Encrypted = method.PasswordIsDefined; 1831 fm.Encrypted = method.PasswordIsDefined;
1796 1832
@@ -2374,13 +2410,33 @@ HRESULT Update(
2374 2410
2375 RINOK(lps->SetCur()); 2411 RINOK(lps->SetCur());
2376 2412
2413 /*
2414 const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size();
2415
2416 if (opCallback)
2417 {
2418 RINOK(opCallback->ReportOperation(
2419 NEventIndexType::kBlockIndex, (UInt32)folderIndex,
2420 NUpdateNotifyOp::kAdd));
2421 }
2422 */
2423
2424
2377 CFolderInStream *inStreamSpec = new CFolderInStream; 2425 CFolderInStream *inStreamSpec = new CFolderInStream;
2378 CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); 2426 CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
2427
2428 // inStreamSpec->_reportArcProp = reportArcProp;
2429
2430 inStreamSpec->Need_CTime = options.Need_CTime;
2431 inStreamSpec->Need_ATime = options.Need_ATime;
2432 inStreamSpec->Need_MTime = options.Need_MTime;
2433 inStreamSpec->Need_Attrib = options.Need_Attrib;
2434
2379 inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); 2435 inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
2380 2436
2381 unsigned startPackIndex = newDatabase.PackSizes.Size(); 2437 unsigned startPackIndex = newDatabase.PackSizes.Size();
2382 UInt64 curFolderUnpackSize = totalSize; 2438 UInt64 curFolderUnpackSize = totalSize;
2383 // curFolderUnpackSize = (UInt64)(Int64)-1; 2439 // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug
2384 2440
2385 RINOK(encoder.Encode( 2441 RINOK(encoder.Encode(
2386 EXTERNAL_CODECS_LOC_VARS 2442 EXTERNAL_CODECS_LOC_VARS
@@ -2393,8 +2449,11 @@ HRESULT Update(
2393 if (!inStreamSpec->WasFinished()) 2449 if (!inStreamSpec->WasFinished())
2394 return E_FAIL; 2450 return E_FAIL;
2395 2451
2452 UInt64 packSize = 0;
2453 // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex;
2396 for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) 2454 for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
2397 lps->OutSize += newDatabase.PackSizes[startPackIndex]; 2455 packSize += newDatabase.PackSizes[startPackIndex];
2456 lps->OutSize += packSize;
2398 2457
2399 lps->InSize += curFolderUnpackSize; 2458 lps->InSize += curFolderUnpackSize;
2400 // for () 2459 // for ()
@@ -2403,7 +2462,9 @@ HRESULT Update(
2403 2462
2404 CNum numUnpackStreams = 0; 2463 CNum numUnpackStreams = 0;
2405 UInt64 skippedSize = 0; 2464 UInt64 skippedSize = 0;
2406 2465 UInt64 procSize = 0;
2466 // unsigned numProcessedFiles = 0;
2467
2407 for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) 2468 for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
2408 { 2469 {
2409 const CUpdateItem &ui = updateItems[indices[i + subIndex]]; 2470 const CUpdateItem &ui = updateItems[indices[i + subIndex]];
@@ -2429,14 +2490,16 @@ HRESULT Update(
2429 */ 2490 */
2430 if (!inStreamSpec->Processed[subIndex]) 2491 if (!inStreamSpec->Processed[subIndex])
2431 { 2492 {
2493 // we don't add file here
2432 skippedSize += ui.Size; 2494 skippedSize += ui.Size;
2433 continue; 2495 continue; // comment it for debug
2434 // file.Name += ".locked"; 2496 // name += ".locked"; // for debug
2435 } 2497 }
2436 2498
2437 file.Crc = inStreamSpec->CRCs[subIndex]; 2499 file.Crc = inStreamSpec->CRCs[subIndex];
2438 file.Size = inStreamSpec->Sizes[subIndex]; 2500 file.Size = inStreamSpec->Sizes[subIndex];
2439 2501
2502 procSize += file.Size;
2440 // if (file.Size >= 0) // test purposes 2503 // if (file.Size >= 0) // test purposes
2441 if (file.Size != 0) 2504 if (file.Size != 0)
2442 { 2505 {
@@ -2450,6 +2513,23 @@ HRESULT Update(
2450 file.HasStream = false; 2513 file.HasStream = false;
2451 } 2514 }
2452 2515
2516 if (inStreamSpec->TimesDefined[subIndex])
2517 {
2518 if (inStreamSpec->Need_CTime)
2519 { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; }
2520 if (inStreamSpec->Need_ATime
2521 // && !ui.ATime_WasReadByAnalysis
2522 )
2523 { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; }
2524 if (inStreamSpec->Need_MTime)
2525 { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; }
2526 if (inStreamSpec->Need_Attrib)
2527 {
2528 file2.AttribDefined = true;
2529 file2.Attrib = inStreamSpec->Attribs[subIndex];
2530 }
2531 }
2532
2453 /* 2533 /*
2454 file.Parent = ui.ParentFolderIndex; 2534 file.Parent = ui.ParentFolderIndex;
2455 if (ui.TreeFolderIndex >= 0) 2535 if (ui.TreeFolderIndex >= 0)
@@ -2457,9 +2537,22 @@ HRESULT Update(
2457 if (totalSecureDataSize != 0) 2537 if (totalSecureDataSize != 0)
2458 newDatabase.SecureIDs.Add(ui.SecureIndex); 2538 newDatabase.SecureIDs.Add(ui.SecureIndex);
2459 */ 2539 */
2540 /*
2541 if (reportArcProp)
2542 {
2543 RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size,
2544 file.CrcDefined ? &file.Crc : NULL))
2545 }
2546 */
2547
2548 // numProcessedFiles++;
2460 newDatabase.AddFile(file, file2, name); 2549 newDatabase.AddFile(file, file2, name);
2461 } 2550 }
2462 2551
2552 // it's optional check to ensure that sizes are correct
2553 if (procSize != curFolderUnpackSize)
2554 return E_FAIL;
2555
2463 // numUnpackStreams = 0 is very bad case for locked files 2556 // numUnpackStreams = 0 is very bad case for locked files
2464 // v3.13 doesn't understand it. 2557 // v3.13 doesn't understand it.
2465 newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); 2558 newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
@@ -2470,6 +2563,44 @@ HRESULT Update(
2470 complexity -= skippedSize; 2563 complexity -= skippedSize;
2471 RINOK(updateCallback->SetTotal(complexity)); 2564 RINOK(updateCallback->SetTotal(complexity));
2472 } 2565 }
2566
2567 /*
2568 if (reportArcProp)
2569 {
2570 PROPVARIANT prop;
2571 prop.vt = VT_EMPTY;
2572 prop.wReserved1 = 0;
2573 {
2574 NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles);
2575 RINOK(reportArcProp->ReportProp(
2576 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop));
2577 }
2578 {
2579 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize);
2580 RINOK(reportArcProp->ReportProp(
2581 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop));
2582 }
2583 {
2584 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize);
2585 RINOK(reportArcProp->ReportProp(
2586 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop));
2587 }
2588 {
2589 NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams);
2590 RINOK(reportArcProp->ReportProp(
2591 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop));
2592 }
2593 RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK));
2594 }
2595 */
2596 /*
2597 if (opCallback)
2598 {
2599 RINOK(opCallback->ReportOperation(
2600 NEventIndexType::kBlockIndex, (UInt32)folderIndex,
2601 NUpdateNotifyOp::kOpFinished));
2602 }
2603 */
2473 } 2604 }
2474 } 2605 }
2475 2606
diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h
index 7c0f78a..e6c48ca 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.h
+++ b/CPP/7zip/Archive/7z/7zUpdate.h
@@ -62,6 +62,8 @@ struct CUpdateItem
62 bool ATimeDefined; 62 bool ATimeDefined;
63 bool MTimeDefined; 63 bool MTimeDefined;
64 64
65 // bool ATime_WasReadByAnalysis;
66
65 // int SecureIndex; // 0 means (no_security) 67 // int SecureIndex; // 0 means (no_security)
66 68
67 bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } 69 bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
@@ -76,6 +78,7 @@ struct CUpdateItem
76 CTimeDefined(false), 78 CTimeDefined(false),
77 ATimeDefined(false), 79 ATimeDefined(false),
78 MTimeDefined(false) 80 MTimeDefined(false)
81 // , ATime_WasReadByAnalysis(false)
79 // SecureIndex(0) 82 // SecureIndex(0)
80 {} 83 {}
81 void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } 84 void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
@@ -103,6 +106,11 @@ struct CUpdateOptions
103 bool RemoveSfxBlock; 106 bool RemoveSfxBlock;
104 bool MultiThreadMixer; 107 bool MultiThreadMixer;
105 108
109 bool Need_CTime;
110 bool Need_ATime;
111 bool Need_MTime;
112 bool Need_Attrib;
113
106 CUpdateOptions(): 114 CUpdateOptions():
107 Method(NULL), 115 Method(NULL),
108 HeaderMethod(NULL), 116 HeaderMethod(NULL),
@@ -114,7 +122,11 @@ struct CUpdateOptions
114 SolidExtension(false), 122 SolidExtension(false),
115 UseTypeSorting(true), 123 UseTypeSorting(true),
116 RemoveSfxBlock(false), 124 RemoveSfxBlock(false),
117 MultiThreadMixer(true) 125 MultiThreadMixer(true),
126 Need_CTime(false),
127 Need_ATime(false),
128 Need_MTime(false),
129 Need_Attrib(false)
118 {} 130 {}
119}; 131};
120 132
diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp
new file mode 100644
index 0000000..8312456
--- /dev/null
+++ b/CPP/7zip/Archive/ApfsHandler.cpp
@@ -0,0 +1,3546 @@
1// ApfsHandler.cpp
2
3#include "StdAfx.h"
4
5// #define SHOW_DEBUG_INFO
6
7#ifdef SHOW_DEBUG_INFO
8#include <stdio.h>
9#define PRF(x) x
10#else
11#define PRF(x)
12#endif
13
14#include "../../../C/CpuArch.h"
15
16#include "../../Common/ComTry.h"
17#include "../../Common/IntToString.h"
18#include "../../Common/MyLinux.h"
19#include "../../Common/UTFConvert.h"
20
21#include "../../Windows/PropVariantConv.h"
22#include "../../Windows/PropVariantUtils.h"
23#include "../../Windows/TimeUtils.h"
24
25#include "../Common/LimitedStreams.h"
26#include "../Common/ProgressUtils.h"
27#include "../Common/RegisterArc.h"
28#include "../Common/StreamObjects.h"
29#include "../Common/StreamUtils.h"
30
31#include "../Compress/CopyCoder.h"
32
33#include "Common/ItemNameUtils.h"
34
35// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files.
36#define APFS_SHOW_ALT_STREAMS
37
38#define VI_MINUS1 ((unsigned)(int)-1)
39#define IsViDef(x) ((int)(x) != -1)
40#define IsViNotDef(x) ((int)(x) == -1)
41
42#define Get16(p) GetUi16(p)
43#define Get32(p) GetUi32(p)
44#define Get64(p) GetUi64(p)
45
46#define G16(_offs_, dest) dest = Get16(p + (_offs_));
47#define G32(_offs_, dest) dest = Get32(p + (_offs_));
48#define G64(_offs_, dest) dest = Get64(p + (_offs_));
49
50namespace NArchive {
51namespace NApfs {
52
53#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
54
55static void ConvertByteToHex(unsigned val, char *s)
56{
57 unsigned t;
58 t = val >> 4;
59 s[0] = ValToHex(t);
60 t = val & 0xF;
61 s[1] = ValToHex(t);
62}
63
64struct CUuid
65{
66 Byte Data[16];
67
68 void SetHex_To_str(char *s) const
69 {
70 for (unsigned i = 0; i < 16; i++)
71 ConvertByteToHex(Data[i], s + i * 2);
72 s[32] = 0;
73 }
74
75 void AddHexToString(UString &dest) const
76 {
77 char temp[32 + 4];
78 SetHex_To_str(temp);
79 dest += temp;
80 }
81
82 void SetFrom(const Byte *p) { memcpy(Data, p, 16); }
83};
84
85
86typedef UInt64 oid_t;
87typedef UInt64 xid_t;
88typedef Int64 paddr_t;
89
90#define G64o G64
91#define G64x G64
92// #define G64a G64
93
94/*
95struct prange_t
96{
97 paddr_t start_paddr;
98 UInt64 block_count;
99
100 void Parse(const Byte *p)
101 {
102 G64a (0, start_paddr);
103 G64 (8, block_count);
104 }
105};
106*/
107
108#define OBJECT_TYPE_NX_SUPERBLOCK 0x1
109#define OBJECT_TYPE_BTREE 0x2
110#define OBJECT_TYPE_BTREE_NODE 0x3
111/*
112#define OBJECT_TYPE_SPACEMAN 0x5
113#define OBJECT_TYPE_SPACEMAN_CAB 0x6
114#define OBJECT_TYPE_SPACEMAN_CIB 0x7
115#define OBJECT_TYPE_SPACEMAN_BITMAP 0x8
116#define OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x9
117#define OBJECT_TYPE_EXTENT_LIST_TREE 0xa
118*/
119#define OBJECT_TYPE_OMAP 0xb
120/*
121#define OBJECT_TYPE_CHECKPOINT_MAP 0xc
122*/
123#define OBJECT_TYPE_FS 0xd
124#define OBJECT_TYPE_FSTREE 0xe
125/*
126#define OBJECT_TYPE_BLOCKREFTREE 0xf
127#define OBJECT_TYPE_SNAPMETATREE 0x10
128#define OBJECT_TYPE_NX_REAPER 0x11
129#define OBJECT_TYPE_NX_REAP_LIST 0x12
130#define OBJECT_TYPE_OMAP_SNAPSHOT 0x13
131#define OBJECT_TYPE_EFI_JUMPSTART 0x14
132#define OBJECT_TYPE_FUSION_MIDDLE_TREE 0x15
133#define OBJECT_TYPE_NX_FUSION_WBC 0x16
134#define OBJECT_TYPE_NX_FUSION_WBC_LIST 0x17
135#define OBJECT_TYPE_ER_STATE 0x18
136#define OBJECT_TYPE_GBITMAP 0x19
137#define OBJECT_TYPE_GBITMAP_TREE 0x1a
138#define OBJECT_TYPE_GBITMAP_BLOCK 0x1b
139#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x1c
140#define OBJECT_TYPE_SNAP_META_EXT 0x1d
141#define OBJECT_TYPE_INTEGRITY_META 0x1e
142#define OBJECT_TYPE_FEXT_TREE 0x1f
143#define OBJECT_TYPE_RESERVED_20 0x20
144
145#define OBJECT_TYPE_INVALID 0x0
146#define OBJECT_TYPE_TEST 0xff
147#define OBJECT_TYPE_CONTAINER_KEYBAG 'keys'
148#define OBJECT_TYPE_VOLUME_KEYBAG 'recs'
149#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey'
150
151#define OBJ_VIRTUAL 0x0
152#define OBJ_EPHEMERAL 0x80000000
153#define OBJ_PHYSICAL 0x40000000
154
155#define OBJ_NOHEADER 0x20000000
156#define OBJ_ENCRYPTED 0x10000000
157#define OBJ_NONPERSISTENT 0x08000000
158*/
159#define OBJECT_TYPE_MASK 0x0000ffff
160/*
161#define OBJECT_TYPE_FLAGS_MASK 0xffff0000
162#define OBJ_STORAGETYPE_MASK 0xc0000000
163#define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000
164*/
165
166// #define MAX_CKSUM_SIZE 8
167
168// obj_phys_t
169struct CPhys
170{
171 // Byte cksum[MAX_CKSUM_SIZE];
172 oid_t oid;
173 xid_t xid;
174 UInt32 type;
175 UInt32 subtype;
176
177 UInt32 GetType() const { return type & OBJECT_TYPE_MASK; }
178 void Parse(const Byte *p);
179};
180
181void CPhys::Parse(const Byte *p)
182{
183 // memcpy(cksum, p, MAX_CKSUM_SIZE);
184 G64o (8, oid);
185 G64x (0x10, xid);
186 G32 (0x18, type);
187 G32 (0x1C, subtype);
188}
189
190#define NX_MAX_FILE_SYSTEMS 100
191/*
192#define NX_EPH_INFO_COUNT 4
193#define NX_EPH_MIN_BLOCK_COUNT 8
194#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4
195#define NX_TX_MIN_CHECKPOINT_COUNT 4
196#define NX_EPH_INFO_VERSION_1 1
197*/
198
199/*
200typedef enum
201{
202 NX_CNTR_OBJ_CKSUM_SET = 0,
203 NX_CNTR_OBJ_CKSUM_FAIL = 1,
204 NX_NUM_COUNTERS = 32
205} counter_id_t;
206*/
207
208/* Incompatible volume feature flags */
209#define APFS_INCOMPAT_CASE_INSENSITIVE (1 << 0)
210/*
211#define APFS_INCOMPAT_DATALESS_SNAPS (1 << 1)
212#define APFS_INCOMPAT_ENC_ROLLED (1 << 2)
213*/
214#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE (1 << 3)
215/*
216#define APFS_INCOMPAT_INCOMPLETE_RESTORE (1 << 4)
217#define APFS_INCOMPAT_SEALED_VOLUME (1 << 5)
218#define APFS_INCOMPAT_RESERVED_40 (1 << 6)
219*/
220
221static const char * const g_APFS_INCOMPAT_Flags[] =
222{
223 "CASE_INSENSITIVE"
224 , "DATALESS_SNAPS"
225 , "ENC_ROLLED"
226 , "NORMALIZATION_INSENSITIVE"
227 , "INCOMPLETE_RESTORE"
228 , "SEALED_VOLUME"
229};
230
231/*
232#define APFS_SUPPORTED_INCOMPAT_MASK \
233 ( APFS_INCOMPAT_CASE_INSENSITIVE \
234 | APFS_INCOMPAT_DATALESS_SNAPS \
235 | APFS_INCOMPAT_ENC_ROLLED \
236 | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \
237 | APFS_INCOMPAT_INCOMPLETE_RESTORE \
238 | APFS_INCOMPAT_SEALED_VOLUME \
239 | APFS_INCOMPAT_RESERVED_40 \
240)
241*/
242
243// superblock_t
244struct CSuperBlock
245{
246 // CPhys o;
247 // UInt32 magic;
248 UInt32 block_size;
249 unsigned block_size_Log;
250 UInt64 block_count;
251 // UInt64 features;
252 // UInt64 readonly_compatible_features;
253 // UInt64 incompatible_features;
254 CUuid uuid;
255 /*
256 oid_t next_oid;
257 xid_t next_xid;
258 UInt32 xp_desc_blocks;
259 UInt32 xp_data_blocks;
260 paddr_t xp_desc_base;
261 paddr_t xp_data_base;
262 UInt32 xp_desc_next;
263 UInt32 xp_data_next;
264 UInt32 xp_desc_index;
265 UInt32 xp_desc_len;
266 UInt32 xp_data_index;
267 UInt32 xp_data_len;
268 oid_t spaceman_oid;
269 */
270 oid_t omap_oid;
271 // oid_t reaper_oid;
272 // UInt32 test_type;
273 UInt32 max_file_systems;
274 // oid_t fs_oid[NX_MAX_FILE_SYSTEMS];
275 /*
276 UInt64 counters[NX_NUM_COUNTERS]; // counter_id_t
277 prange_t blocked_out_prange;
278 oid_t evict_mapping_tree_oid;
279 UInt64 flags;
280 paddr_t efi_jumpstart;
281 CUuid fusion_uuid;
282 prange_t keylocker;
283 UInt64 ephemeral_info[NX_EPH_INFO_COUNT];
284 oid_t test_oid;
285 oid_t fusion_mt_oid;
286 oid_t fusion_wbc_oid;
287 prange_t fusion_wbc;
288 UInt64 newest_mounted_version;
289 prange_t mkb_locker;
290 */
291
292 bool Parse(const Byte *p);
293};
294
295struct CSuperBlock2
296{
297 oid_t fs_oid[NX_MAX_FILE_SYSTEMS];
298 void Parse(const Byte *p)
299 {
300 for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++)
301 {
302 G64o (0xb8 + i * 8, fs_oid[i]);
303 }
304 }
305};
306
307
308// we include one additional byte of next field (block_size)
309static const unsigned k_SignatureOffset = 32;
310static const Byte k_Signature[] = { 'N', 'X', 'S', 'B', 0 };
311
312// size must be 4 bytes aligned
313static UInt64 Fletcher64(const Byte *data, size_t size)
314{
315 const UInt32 kMax32 = 0xffffffff;
316 const UInt64 val = 0; // startVal
317 UInt64 a = val & kMax32;
318 UInt64 b = (val >> 32) & kMax32;
319 for (size_t i = 0; i < size; i += 4)
320 {
321 a += GetUi32(data + i);
322 b += a;
323 }
324 a %= kMax32;
325 b %= kMax32;
326 b = (UInt32)(kMax32 - ((a + b) % kMax32));
327 a = (UInt32)(kMax32 - ((a + b) % kMax32));
328 return (a << 32) | b;
329}
330
331static bool CheckFletcher64(const Byte *p, size_t size)
332{
333 const UInt64 calculated_checksum = Fletcher64(p + 8, size - 8);
334 const UInt64 stored_checksum = Get64(p);
335 return (stored_checksum == calculated_checksum);
336}
337
338
339static unsigned GetLogSize(UInt32 size)
340{
341 unsigned k;
342 for (k = 0; k < 32; k++)
343 if (((UInt32)1 << k) == size)
344 return k;
345 return k;
346}
347
348static const unsigned kApfsHeaderSize = 1 << 12;
349
350// #define OID_INVALID 0
351#define OID_NX_SUPERBLOCK 1
352// #define OID_RESERVED_COUNT 1024
353// This range of identifiers is reserved for physical, virtual, and ephemeral objects
354
355bool CSuperBlock::Parse(const Byte *p)
356{
357 CPhys o;
358 o.Parse(p);
359 if (o.oid != OID_NX_SUPERBLOCK)
360 return false;
361 if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK)
362 return false;
363 if (o.subtype != 0)
364 return false;
365 if (memcmp(p + k_SignatureOffset, k_Signature, 4) != 0)
366 return false;
367 if (!CheckFletcher64(p, kApfsHeaderSize))
368 return false;
369
370 G32 (0x24, block_size);
371 {
372 unsigned logSize = GetLogSize(block_size);
373 if (logSize < 12 || logSize > 16)
374 return false;
375 block_size_Log = logSize;
376 }
377
378 G64 (0x28, block_count);
379
380 static const UInt64 kArcSize_MAX = (UInt64)1 << 62;
381 if (block_count > (kArcSize_MAX >> block_size_Log))
382 return false;
383
384 // G64 (0x30, features);
385 // G64 (0x38, readonly_compatible_features);
386 // G64 (0x40, incompatible_features);
387 uuid.SetFrom(p + 0x48);
388 /*
389 G64o (0x58, next_oid);
390 G64x (0x60, next_xid);
391 G32 (0x68, xp_desc_blocks);
392 G32 (0x6c, xp_data_blocks);
393 G64a (0x70, xp_desc_base);
394 G64a (0x78, xp_data_base);
395 G32 (0x80, xp_desc_next);
396 G32 (0x84, xp_data_next);
397 G32 (0x88, xp_desc_index);
398 G32 (0x8c, xp_desc_len);
399 G32 (0x90, xp_data_index);
400 G32 (0x94, xp_data_len);
401 G64o (0x98, spaceman_oid);
402 */
403 G64o (0xa0, omap_oid);
404 // G64o (0xa8, reaper_oid);
405 // G32 (0xb0, test_type);
406 G32 (0xb4, max_file_systems);
407 if (max_file_systems > NX_MAX_FILE_SYSTEMS)
408 return false;
409 /*
410 {
411 for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++)
412 {
413 G64o (0xb8 + i * 8, fs_oid[i]);
414 }
415 }
416 */
417 /*
418 {
419 for (unsigned i = 0; i < NX_NUM_COUNTERS; i++)
420 {
421 G64 (0x3d8 + i * 8, counters[i]);
422 }
423 }
424 blocked_out_prange.Parse(p + 0x4d8);
425 G64o (0x4e8, evict_mapping_tree_oid);
426 #define NX_CRYPTO_SW 0x00000004LL
427 G64 (0x4f0, flags);
428 G64a (0x4f8, efi_jumpstart);
429 fusion_uuid.SetFrom(p + 0x500);
430 keylocker.Parse(p + 0x510);
431 {
432 for (unsigned i = 0; i < NX_EPH_INFO_COUNT; i++)
433 {
434 G64 (0x520 + i * 8, ephemeral_info[i]);
435 }
436 }
437 G64o (0x540, test_oid);
438 G64o (0x548, fusion_mt_oid);
439 G64o (0x550, fusion_wbc_oid);
440 fusion_wbc.Parse(p + 0x558);
441 G64 (0x568, newest_mounted_version); // decimal 1412141 001 000 000
442 mkb_locker.Parse(p + 0x570);
443 */
444
445 return true;
446}
447
448
449
450struct C_omap_phys
451{
452 // om_ prefix
453 // CPhys o;
454 /*
455 UInt32 flags;
456 UInt32 snap_count;
457 UInt32 tree_type;
458 UInt32 snapshot_tree_type;
459 */
460 oid_t tree_oid;
461 /*
462 oid_t snapshot_tree_oid;
463 xid_t most_recent_snap;
464 xid_t pending_revert_min;
465 xid_t pending_revert_max;
466 */
467 bool Parse(const Byte *p, size_t size, oid_t oid);
468};
469
470bool C_omap_phys::Parse(const Byte *p, size_t size, oid_t oid)
471{
472 CPhys o;
473 if (!CheckFletcher64(p, size))
474 return false;
475 o.Parse(p);
476 if (o.GetType() != OBJECT_TYPE_OMAP)
477 return false;
478 if (o.oid != oid)
479 return false;
480 /*
481 G32 (0x20, flags);
482 G32 (0x24, snap_count);
483 G32 (0x28, tree_type);
484 G32 (0x2C, snapshot_tree_type);
485 */
486 G64o (0x30, tree_oid);
487 /*
488 G64o (0x38, snapshot_tree_oid);
489 G64x (0x40, most_recent_snap);
490 G64x (0x48, pending_revert_min);
491 G64x (0x50, pending_revert_max);
492 */
493 return true;
494}
495
496
497// #define BTOFF_INVALID 0xffff
498/* This value is stored in the off field of nloc_t to indicate that
499there's no offset. For example, the last entry in a free
500list has no entry after it, so it uses this value for its off field. */
501
502// A location within a B-tree node
503struct nloc
504{
505 UInt16 off;
506 UInt16 len;
507
508 void Parse(const Byte *p)
509 {
510 G16 (0, off);
511 G16 (2, len);
512 }
513 UInt32 GetEnd() const { return (UInt32)off + len; }
514 bool CheckOverLimit(UInt32 limit)
515 {
516 return off < limit && len <= limit - off;
517 }
518};
519
520
521// The location, within a B-tree node, of a key and value
522struct kvloc
523{
524 nloc k;
525 nloc v;
526
527 void Parse(const Byte *p)
528 {
529 k.Parse(p);
530 v.Parse(p + 4);
531 }
532};
533
534
535// The location, within a B-tree node, of a fixed-size key and value
536struct kvoff
537{
538 UInt16 k;
539 UInt16 v;
540
541 void Parse(const Byte *p)
542 {
543 G16 (0, k);
544 G16 (2, v);
545 }
546};
547
548
549#define BTNODE_ROOT (1 << 0)
550#define BTNODE_LEAF (1 << 1)
551#define BTNODE_FIXED_KV_SIZE (1 << 2)
552/*
553#define BTNODE_HASHED (1 << 3)
554#define BTNODE_NOHEADER (1 << 4)
555#define BTNODE_CHECK_KOFF_INVAL (1 << 15)
556*/
557
558static const unsigned k_Toc_offset = 0x38;
559
560// btree_node_phys
561struct CBTreeNodePhys
562{
563 // btn_ prefix
564 CPhys o;
565 UInt16 flags;
566 UInt16 level; // the number of child levels below this node. 0 - for a leaf node, 1 for the immediate parent of a leaf node
567 UInt32 nkeys; // The number of keys stored in this node.
568 nloc table_space;
569 /*
570 nloc free_space;
571 nloc key_free_list;
572 nloc val_free_list;
573 */
574
575 bool Is_FIXED_KV_SIZE() const { return (flags & BTNODE_FIXED_KV_SIZE) != 0; }
576
577 bool Parse(const Byte *p, size_t size)
578 {
579 if (!CheckFletcher64(p, size))
580 return false;
581 o.Parse(p);
582 G16 (0x20, flags);
583 G16 (0x22, level);
584 G32 (0x24, nkeys);
585 table_space.Parse(p + 0x28);
586 /*
587 free_space.Parse(p + 0x2C);
588 key_free_list.Parse(p + 0x30);
589 val_free_list.Parse(p + 0x34);
590 */
591 return true;
592 }
593};
594
595/*
596#define BTREE_UINT64_KEYS (1 << 0)
597#define BTREE_SEQUENTIAL_INSERT (1 << 1)
598#define BTREE_ALLOW_GHOSTS (1 << 2)
599*/
600#define BTREE_EPHEMERAL (1 << 3)
601#define BTREE_PHYSICAL (1 << 4)
602/*
603#define BTREE_NONPERSISTENT (1 << 5)
604#define BTREE_KV_NONALIGNED (1 << 6)
605#define BTREE_HASHED (1 << 7)
606*/
607
608/*
609 BTREE_EPHEMERAL: The nodes in the B-tree use ephemeral object identifiers to link to child nodes
610 BTREE_PHYSICAL : The nodes in the B-tree use physical object identifiers to link to child nodes.
611 If neither flag is set, nodes in the B-tree use virtual object
612 identifiers to link to their child nodes.
613*/
614
615// Static information about a B-tree.
616struct btree_info_fixed
617{
618 UInt32 flags;
619 UInt32 node_size;
620 UInt32 key_size;
621 UInt32 val_size;
622
623 void Parse(const Byte *p)
624 {
625 G32 (0, flags);
626 G32 (4, node_size);
627 G32 (8, key_size);
628 G32 (12, val_size);
629 }
630};
631
632static const unsigned k_btree_info_Size = 0x28;
633
634struct btree_info
635{
636 btree_info_fixed fixed;
637 UInt32 longest_key;
638 UInt32 longest_val;
639 UInt64 key_count;
640 UInt64 node_count;
641
642 bool Is_EPHEMERAL() const { return (fixed.flags & BTREE_EPHEMERAL) != 0; }
643 bool Is_PHYSICAL() const { return (fixed.flags & BTREE_PHYSICAL) != 0; }
644
645 void Parse(const Byte *p)
646 {
647 fixed.Parse(p);
648 G32 (0x10, longest_key);
649 G32 (0x14, longest_val);
650 G64 (0x18, key_count);
651 G64 (0x20, node_count);
652 }
653};
654
655
656/*
657typedef UInt32 cp_key_class_t;
658typedef UInt32 cp_key_os_version_t;
659typedef UInt16 cp_key_revision_t;
660typedef UInt32 crypto_flags_t;
661
662struct wrapped_meta_crypto_state
663{
664 UInt16 major_version;
665 UInt16 minor_version;
666 crypto_flags_t cpflags;
667 cp_key_class_t persistent_class;
668 cp_key_os_version_t key_os_version;
669 cp_key_revision_t key_revision;
670 // UInt16 unused;
671
672 void Parse(const Byte *p)
673 {
674 G16 (0, major_version);
675 G16 (2, minor_version);
676 G32 (4, cpflags);
677 G32 (8, persistent_class);
678 G32 (12, key_os_version);
679 G16 (16, key_revision);
680 }
681};
682*/
683
684
685#define APFS_MODIFIED_NAMELEN 32
686#define sizeof__apfs_modified_by_t (APFS_MODIFIED_NAMELEN + 16);
687
688struct apfs_modified_by_t
689{
690 Byte id[APFS_MODIFIED_NAMELEN];
691 UInt64 timestamp;
692 xid_t last_xid;
693
694 void Parse(const Byte *p)
695 {
696 memcpy(id, p, APFS_MODIFIED_NAMELEN);
697 p += APFS_MODIFIED_NAMELEN;
698 G64 (0, timestamp);
699 G64x (8, last_xid);
700 }
701};
702
703
704#define APFS_MAX_HIST 8
705#define APFS_VOLNAME_LEN 256
706
707struct CApfs
708{
709 // apfs_
710 CPhys o;
711 // UInt32 magic;
712 UInt32 fs_index; // e index of the object identifier for this volume's file system in the container's array of file systems.
713 // UInt64 features;
714 // UInt64 readonly_compatible_features;
715 UInt64 incompatible_features;
716 UInt64 unmount_time;
717 // UInt64 fs_reserve_block_count;
718 // UInt64 fs_quota_block_count;
719 UInt64 fs_alloc_count;
720 // wrapped_meta_crypto_state meta_crypto;
721 // UInt32 root_tree_type;
722 /* The type of the root file-system tree.
723 The value is typically OBJ_VIRTUAL | OBJECT_TYPE_BTREE,
724 with a subtype of OBJECT_TYPE_FSTREE */
725
726 // UInt32 extentref_tree_type;
727 // UInt32 snap_meta_tree_type;
728 oid_t omap_oid;
729 oid_t root_tree_oid;
730 /*
731 oid_t extentref_tree_oid;
732 oid_t snap_meta_tree_oid;
733 xid_t revert_to_xid;
734 oid_t revert_to_sblock_oid;
735 UInt64 next_obj_id;
736 */
737 UInt64 num_files;
738 UInt64 num_directories;
739 UInt64 num_symlinks;
740 UInt64 num_other_fsobjects;
741 UInt64 num_snapshots;
742 UInt64 total_blocks_alloced;
743 UInt64 total_blocks_freed;
744 CUuid vol_uuid;
745 UInt64 last_mod_time;
746 UInt64 fs_flags;
747 apfs_modified_by_t formatted_by;
748 apfs_modified_by_t modified_by[APFS_MAX_HIST];
749 Byte volname[APFS_VOLNAME_LEN];
750 /*
751 UInt32 next_doc_id;
752 UInt16 role; // APFS_VOL_ROLE_NONE APFS_VOL_ROLE_SYSTEM ....
753 UInt16 reserved;
754 xid_t root_to_xid;
755 oid_t er_state_oid;
756 UInt64 cloneinfo_id_epoch;
757 UInt64 cloneinfo_xid;
758 oid_t snap_meta_ext_oid;
759 CUuid volume_group_id;
760 oid_t integrity_meta_oid;
761 oid_t fext_tree_oid;
762 UInt32 fext_tree_type;
763 UInt32 reserved_type;
764 oid_t reserved_oid;
765 */
766
767 UInt64 GetTotalItems() const
768 {
769 return num_files + num_directories + num_symlinks + num_other_fsobjects;
770 }
771
772 bool IsHashedName() const
773 {
774 return
775 (incompatible_features & APFS_INCOMPAT_CASE_INSENSITIVE) != 0 ||
776 (incompatible_features & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) != 0;
777 }
778
779 bool Parse(const Byte *p, size_t size);
780};
781
782
783bool CApfs::Parse(const Byte *p, size_t size)
784{
785 o.Parse(p);
786 if (Get32(p + 32) != 0x42535041) // { 'A', 'P', 'S', 'B' };
787 return false;
788 if (o.GetType() != OBJECT_TYPE_FS)
789 return false;
790 if (!CheckFletcher64(p, size))
791 return false;
792 // if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) return false;
793
794 G32 (0x24, fs_index);
795 // G64 (0x28, features);
796 // G64 (0x30, readonly_compatible_features);
797 G64 (0x38, incompatible_features);
798 G64 (0x40, unmount_time);
799 // G64 (0x48, fs_reserve_block_count);
800 // G64 (0x50, fs_quota_block_count);
801 G64 (0x58, fs_alloc_count);
802 // meta_crypto.Parse(p + 0x60);
803 // G32 (0x74, root_tree_type);
804 // G32 (0x78, extentref_tree_type);
805 // G32 (0x7C, snap_meta_tree_type);
806
807 G64o (0x80, omap_oid);
808 G64o (0x88, root_tree_oid);
809 /*
810 G64o (0x90, extentref_tree_oid);
811 G64o (0x98, snap_meta_tree_oid);
812 G64x (0xa0, revert_to_xid);
813 G64o (0xa8, revert_to_sblock_oid);
814 G64 (0xb0, next_obj_id);
815 */
816 G64 (0xb8, num_files);
817 G64 (0xc0, num_directories);
818 G64 (0xc8, num_symlinks);
819 G64 (0xd0, num_other_fsobjects);
820 G64 (0xd8, num_snapshots);
821 G64 (0xe0, total_blocks_alloced);
822 G64 (0xe8, total_blocks_freed);
823 vol_uuid.SetFrom(p + 0xf0);
824 G64 (0x100, last_mod_time);
825 G64 (0x108, fs_flags);
826 p += 0x110;
827 formatted_by.Parse(p);
828 p += sizeof__apfs_modified_by_t;
829 for (unsigned i = 0; i < APFS_MAX_HIST; i++)
830 {
831 modified_by[i].Parse(p);
832 p += sizeof__apfs_modified_by_t;
833 }
834 memcpy(volname, p, APFS_VOLNAME_LEN);
835 p += APFS_VOLNAME_LEN;
836 /*
837 G32 (0, next_doc_id);
838 G16 (4, role);
839 G16 (6, reserved);
840 G64x (8, root_to_xid);
841 G64o (0x10, er_state_oid);
842 G64 (0x18, cloneinfo_id_epoch);
843 G64 (0x20, cloneinfo_xid);
844 G64o (0x28, snap_meta_ext_oid);
845 volume_group_id.SetFrom(p + 0x30);
846 G64o (0x40, integrity_meta_oid);
847 G64o (0x48, fext_tree_oid);
848 G32 (0x50, fext_tree_type);
849 G32 (0x54, reserved_type);
850 G64o (0x58, reserved_oid);
851 */
852 return true;
853}
854
855
856#define OBJ_ID_MASK 0x0fffffffffffffff
857/*
858#define OBJ_TYPE_MASK 0xf000000000000000
859#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000
860*/
861#define OBJ_TYPE_SHIFT 60
862
863typedef enum
864{
865 APFS_TYPE_ANY = 0,
866 APFS_TYPE_SNAP_METADATA = 1,
867 APFS_TYPE_EXTENT = 2,
868 APFS_TYPE_INODE = 3,
869 APFS_TYPE_XATTR = 4,
870 APFS_TYPE_SIBLING_LINK = 5,
871 APFS_TYPE_DSTREAM_ID = 6,
872 APFS_TYPE_CRYPTO_STATE = 7,
873 APFS_TYPE_FILE_EXTENT = 8,
874 APFS_TYPE_DIR_REC = 9,
875 APFS_TYPE_DIR_STATS = 10,
876 APFS_TYPE_SNAP_NAME = 11,
877 APFS_TYPE_SIBLING_MAP = 12,
878 APFS_TYPE_FILE_INFO = 13,
879 APFS_TYPE_MAX_VALID = 13,
880 APFS_TYPE_MAX = 15,
881 APFS_TYPE_INVALID = 15
882} j_obj_types;
883
884
885struct j_key_t
886{
887 UInt64 obj_id_and_type;
888
889 void Parse(const Byte *p) { G64(0, obj_id_and_type); }
890 unsigned GetType() const { return (unsigned)(obj_id_and_type >> OBJ_TYPE_SHIFT); }
891 UInt64 GetID() const { return obj_id_and_type & OBJ_ID_MASK; }
892};
893
894
895
896#define J_DREC_LEN_MASK 0x000003ff
897/*
898#define J_DREC_HASH_MASK 0xfffff400
899#define J_DREC_HASH_SHIFT 10
900*/
901
902static const unsigned k_SizeOf_j_drec_val = 0x12;
903
904struct j_drec_val
905{
906 UInt64 file_id;
907 UInt64 date_added; /* The time that this directory entry was added to the directory.
908 It's not updated when modifying the directory entry for example,
909 by renaming a file without moving it to a different directory. */
910 UInt16 flags;
911
912 // bool IsFlags_File() const { return flags == MY_LIN_DT_REG; }
913 bool IsFlags_Unknown() const { return flags == MY_LIN_DT_UNKNOWN; }
914 bool IsFlags_Dir() const { return flags == MY_LIN_DT_DIR; }
915
916 // uint8_t xfields[];
917 void Parse(const Byte *p)
918 {
919 G64 (0, file_id);
920 G64 (8, date_added);
921 G16 (0x10, flags);
922 }
923};
924
925
926struct CItem
927{
928 // j_key_t hdr;
929 UInt64 ParentId;
930 AString Name;
931 j_drec_val Val;
932
933 unsigned ParentItemIndex;
934 unsigned RefIndex;
935 // unsigned iNode_Index;
936
937 CItem():
938 ParentItemIndex(VI_MINUS1),
939 RefIndex(VI_MINUS1)
940 // iNode_Index(VI_MINUS1)
941 {}
942};
943
944
945/*
946#define INVALID_INO_NUM 0
947#define ROOT_DIR_PARENT 1 // parent for "root" and "private-dir", there's no inode on disk with this inode number.
948*/
949#define ROOT_DIR_INO_NUM 2 // "root" - parent for all main files
950#define PRIV_DIR_INO_NUM 3 // "private-dir"
951/*
952#define SNAP_DIR_INO_NUM 6 // the directory where snapshot metadata is stored. Snapshot inodes are stored in the snapshot metedata tree.
953#define PURGEABLE_DIR_INO_NUM 7
954#define MIN_USER_INO_NUM 16
955
956#define UNIFIED_ID_SPACE_MARK 0x0800000000000000
957*/
958
959/*
960typedef enum
961{
962INODE_IS_APFS_PRIVATE = 0x00000001,
963INODE_MAINTAIN_DIR_STATS = 0x00000002,
964INODE_DIR_STATS_ORIGIN = 0x00000004,
965INODE_PROT_CLASS_EXPLICIT = 0x00000008,
966INODE_WAS_CLONED = 0x00000010,
967INODE_FLAG_UNUSED = 0x00000020,
968INODE_HAS_SECURITY_EA = 0x00000040,
969INODE_BEING_TRUNCATED = 0x00000080,
970INODE_HAS_FINDER_INFO = 0x00000100,
971INODE_IS_SPARSE = 0x00000200,
972INODE_WAS_EVER_CLONED = 0x00000400,
973INODE_ACTIVE_FILE_TRIMMED = 0x00000800,
974INODE_PINNED_TO_MAIN = 0x00001000,
975INODE_PINNED_TO_TIER2 = 0x00002000,
976INODE_HAS_RSRC_FORK = 0x00004000,
977INODE_NO_RSRC_FORK = 0x00008000,
978INODE_ALLOCATION_SPILLEDOVER = 0x00010000,
979INODE_FAST_PROMOTE = 0x00020000,
980INODE_HAS_UNCOMPRESSED_SIZE = 0x00040000,
981INODE_IS_PURGEABLE = 0x00080000,
982INODE_WANTS_TO_BE_PURGEABLE = 0x00100000,
983INODE_IS_SYNC_ROOT = 0x00200000,
984INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000,
985
986
987INODE_INHERITED_INTERNAL_FLAGS = \
988 ( INODE_MAINTAIN_DIR_STATS \
989 | INODE_SNAPSHOT_COW_EXEMPTION),
990
991INODE_CLONED_INTERNAL_FLAGS = \
992 ( INODE_HAS_RSRC_FORK \
993 | INODE_NO_RSRC_FORK \
994 | INODE_HAS_FINDER_INFO \
995 | INODE_SNAPSHOT_COW_EXEMPTION),
996}
997j_inode_flags;
998
999
1000#define APFS_VALID_INTERNAL_INODE_FLAGS \
1001( INODE_IS_APFS_PRIVATE \
1002| INODE_MAINTAIN_DIR_STATS \
1003| INODE_DIR_STATS_ORIGIN \
1004| INODE_PROT_CLASS_EXPLICIT \
1005| INODE_WAS_CLONED \
1006| INODE_HAS_SECURITY_EA \
1007| INODE_BEING_TRUNCATED \
1008| INODE_HAS_FINDER_INFO \
1009| INODE_IS_SPARSE \
1010| INODE_WAS_EVER_CLONED \
1011| INODE_ACTIVE_FILE_TRIMMED \
1012| INODE_PINNED_TO_MAIN \
1013| INODE_PINNED_TO_TIER2 \
1014| INODE_HAS_RSRC_FORK \
1015| INODE_NO_RSRC_FORK \
1016| INODE_ALLOCATION_SPILLEDOVER \
1017| INODE_FAST_PROMOTE \
1018| INODE_HAS_UNCOMPRESSED_SIZE \
1019| INODE_IS_PURGEABLE \
1020| INODE_WANTS_TO_BE_PURGEABLE \
1021| INODE_IS_SYNC_ROOT \
1022| INODE_SNAPSHOT_COW_EXEMPTION)
1023
1024#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2)
1025*/
1026
1027static const char * const g_INODE_Flags[] =
1028{
1029 "IS_APFS_PRIVATE"
1030 , "MAINTAIN_DIR_STATS"
1031 , "DIR_STATS_ORIGIN"
1032 , "PROT_CLASS_EXPLICIT"
1033 , "WAS_CLONED"
1034 , "FLAG_UNUSED"
1035 , "HAS_SECURITY_EA"
1036 , "BEING_TRUNCATED"
1037 , "HAS_FINDER_INFO"
1038 , "IS_SPARSE"
1039 , "WAS_EVER_CLONED"
1040 , "ACTIVE_FILE_TRIMMED"
1041 , "PINNED_TO_MAIN"
1042 , "PINNED_TO_TIER2"
1043 , "HAS_RSRC_FORK"
1044 , "NO_RSRC_FORK"
1045 , "ALLOCATION_SPILLEDOVER"
1046 , "FAST_PROMOTE"
1047 , "HAS_UNCOMPRESSED_SIZE"
1048 , "IS_PURGEABLE"
1049 , "WANTS_TO_BE_PURGEABLE"
1050 , "IS_SYNC_ROOT"
1051 , "SNAPSHOT_COW_EXEMPTION"
1052};
1053
1054
1055// bsd stat.h
1056/*
1057#define MY__UF_SETTABLE 0x0000ffff // mask of owner changeable flags
1058#define MY__UF_NODUMP 0x00000001 // do not dump file
1059#define MY__UF_IMMUTABLE 0x00000002 // file may not be changed
1060#define MY__UF_APPEND 0x00000004 // writes to file may only append
1061#define MY__UF_OPAQUE 0x00000008 // directory is opaque wrt. union
1062#define MY__UF_NOUNLINK 0x00000010 // file entry may not be removed or renamed Not implement in MacOS
1063#define MY__UF_COMPRESSED 0x00000020 // file entry is compressed
1064#define MY__UF_TRACKED 0x00000040 // notify about file entry changes
1065#define MY__UF_DATAVAULT 0x00000080 // entitlement required for reading and writing
1066#define MY__UF_HIDDEN 0x00008000 // file entry is hidden
1067
1068#define MY__SF_SETTABLE 0xffff0000 // mask of superuser changeable flags
1069#define MY__SF_ARCHIVED 0x00010000 // file is archived
1070#define MY__SF_IMMUTABLE 0x00020000 // file may not be changed
1071#define MY__SF_APPEND 0x00040000 // writes to file may only append
1072#define MY__SF_RESTRICTED 0x00080000 // entitlement required for writing
1073#define MY__SF_NOUNLINK 0x00100000 // file entry may not be removed, renamed or used as mount point
1074#define MY__SF_SNAPSHOT 0x00200000 // snapshot inode
1075Not implement in MacOS
1076*/
1077
1078static const char * const g_INODE_BSD_Flags[] =
1079{
1080 "UF_NODUMP"
1081 , "UF_IMMUTABLE"
1082 , "UF_APPEND"
1083 , "UF_OPAQUE"
1084 , "UF_NOUNLINK"
1085 , "UF_COMPRESSED"
1086 , "UF_TRACKED"
1087 , "UF_DATAVAULT"
1088 , NULL, NULL, NULL, NULL
1089 , NULL, NULL, NULL
1090 , "UF_HIDDEN"
1091
1092 , "SF_ARCHIVE"
1093 , "SF_IMMUTABLE"
1094 , "SF_APPEND"
1095 , "SF_RESTRICTED"
1096 , "SF_NOUNLINK"
1097 , "SF_SNAPSHOT"
1098};
1099
1100/*
1101#define INO_EXT_TYPE_SNAP_XID 1
1102#define INO_EXT_TYPE_DELTA_TREE_OID 2
1103#define INO_EXT_TYPE_DOCUMENT_ID 3
1104*/
1105#define INO_EXT_TYPE_NAME 4
1106/*
1107#define INO_EXT_TYPE_PREV_FSIZE 5
1108#define INO_EXT_TYPE_RESERVED_6 6
1109#define INO_EXT_TYPE_FINDER_INFO 7
1110*/
1111#define INO_EXT_TYPE_DSTREAM 8
1112/*
1113#define INO_EXT_TYPE_RESERVED_9 9
1114#define INO_EXT_TYPE_DIR_STATS_KEY 10
1115#define INO_EXT_TYPE_FS_UUID 11
1116#define INO_EXT_TYPE_RESERVED_12 12
1117#define INO_EXT_TYPE_SPARSE_BYTES 13
1118#define INO_EXT_TYPE_RDEV 14
1119#define INO_EXT_TYPE_PURGEABLE_FLAGS 15
1120#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16
1121*/
1122
1123
1124static const unsigned k_SizeOf_j_dstream = 8 * 5;
1125
1126struct j_dstream
1127{
1128 UInt64 size;
1129 UInt64 alloced_size;
1130 UInt64 default_crypto_id;
1131 UInt64 total_bytes_written;
1132 UInt64 total_bytes_read;
1133
1134 void Parse(const Byte *p)
1135 {
1136 G64 (0, size);
1137 G64 (0x8, alloced_size);
1138 G64 (0x10, default_crypto_id);
1139 G64 (0x18, total_bytes_written);
1140 G64 (0x20, total_bytes_read);
1141 }
1142};
1143
1144static const unsigned k_SizeOf_j_file_extent_val = 8 * 3;
1145
1146#define J_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffU
1147// #define J_FILE_EXTENT_FLAG_MASK 0xff00000000000000U
1148// #define J_FILE_EXTENT_FLAG_SHIFT 56
1149
1150#define EXTENT_GET_LEN(x) ((x) & J_FILE_EXTENT_LEN_MASK)
1151
1152struct j_file_extent_val
1153{
1154 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.
1155 // There are currently no flags defined
1156 UInt64 phys_block_num; // The physical block address that the extent starts at
1157 // UInt64 crypto_id; // The encryption key or the encryption tweak used in this extent.
1158
1159 void Parse(const Byte *p)
1160 {
1161 G64 (0, len_and_flags);
1162 G64 (0x8, phys_block_num);
1163 // G64 (0x10, crypto_id);
1164 }
1165};
1166
1167
1168struct CExtent
1169{
1170 UInt64 logical_offset;
1171 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.
1172 // There are currently no flags defined
1173 UInt64 phys_block_num; // The physical block address that the extent starts at
1174};
1175
1176
1177typedef UInt32 MY__uid_t;
1178typedef UInt32 MY__gid_t;
1179typedef UInt16 MY__mode_t;
1180
1181
1182typedef enum
1183{
1184 XATTR_DATA_STREAM = 1 << 0,
1185 XATTR_DATA_EMBEDDED = 1 << 1,
1186 XATTR_FILE_SYSTEM_OWNED = 1 << 2,
1187 XATTR_RESERVED_8 = 1 << 3
1188} j_xattr_flags;
1189
1190
1191struct CAttr
1192{
1193 AString Name;
1194 UInt32 flags;
1195 CByteBuffer Data;
1196
1197 j_dstream dstream;
1198 bool dstream_defined;
1199 UInt64 Id;
1200
1201 bool Is_dstream_OK_for_SymLink() const
1202 {
1203 return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0;
1204 }
1205
1206 CAttr():
1207 dstream_defined(false)
1208 {}
1209
1210 bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; }
1211 bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; }
1212};
1213
1214
1215// j_inode_val_t
1216struct CNode
1217{
1218 unsigned ItemIndex; // index to CItem. We set it only if Node is directory.
1219 unsigned NumCalcedLinks; // Num links to that node
1220 // unsigned NumItems; // Num Items in that node
1221
1222 UInt64 parent_id; // The identifier of the file system record for the parent directory.
1223 UInt64 private_id;
1224 UInt64 create_time;
1225 UInt64 mod_time;
1226 UInt64 change_time;
1227 UInt64 access_time;
1228 UInt64 internal_flags;
1229 union
1230 {
1231 UInt32 nchildren; /* The number of directory entries.
1232 is valid only if the inode is a directory */
1233 UInt32 nlink; /* The number of hard links whose target is this inode.
1234 is valid only if the inode isn't a directory.
1235 Inodes with multiple hard links (nlink > 1)
1236 - The parent_id field refers to the parent directory of the primary link.
1237 - The name field contains the name of the primary link.
1238 - The INO_EXT_TYPE_NAME extended field contains the name of this link.
1239 */
1240 };
1241 // cp_key_class_t default_protection_class;
1242 UInt32 write_generation_counter;
1243 UInt32 bsd_flags;
1244 MY__uid_t owner;
1245 MY__gid_t group;
1246 MY__mode_t mode;
1247 UInt16 pad1;
1248 // UInt64 uncompressed_size;
1249
1250 j_dstream dstream;
1251 AString PrimaryName;
1252 bool dstream_defined;
1253 bool refcnt_defined;
1254 UInt32 refcnt; // j_dstream_id_val_t
1255 CRecordVector<CExtent> Extents;
1256 CObjectVector<CAttr> Attrs;
1257 unsigned SymLinkIndex; // index in Attrs
1258
1259 CNode():
1260 ItemIndex(VI_MINUS1),
1261 NumCalcedLinks(0),
1262 // NumItems(0),
1263 dstream_defined(false),
1264 refcnt_defined(false),
1265 SymLinkIndex(VI_MINUS1)
1266 {}
1267
1268 bool IsDir() const { return MY_LIN_S_ISDIR(mode); }
1269 bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); }
1270 unsigned Get_Type_From_mode() const { return mode >> 12; }
1271
1272 bool GetSize(unsigned attrIndex, UInt64 &size) const
1273 {
1274 if (IsViNotDef(attrIndex))
1275 {
1276 if (dstream_defined)
1277 {
1278 size = dstream.size;
1279 return true;
1280 }
1281 if (!IsSymLink())
1282 return false;
1283 attrIndex = SymLinkIndex;
1284 if (IsViNotDef(attrIndex))
1285 return false;
1286 }
1287 const CAttr &attr = Attrs[(unsigned)attrIndex];
1288 if (attr.dstream_defined)
1289 size = attr.dstream.size;
1290 else
1291 size = attr.Data.Size();
1292 return true;
1293 }
1294
1295 bool GetPackSize(unsigned attrIndex, UInt64 &size) const
1296 {
1297 if (IsViNotDef(attrIndex))
1298 {
1299 if (dstream_defined)
1300 {
1301 size = dstream.alloced_size;
1302 return true;
1303 }
1304 if (!IsSymLink())
1305 return false;
1306 attrIndex = SymLinkIndex;
1307 if (IsViNotDef(attrIndex))
1308 return false;
1309 }
1310 const CAttr &attr = Attrs[(unsigned)attrIndex];
1311 if (attr.dstream_defined)
1312 size = attr.dstream.alloced_size;
1313 else
1314 size = attr.Data.Size();
1315 return true;
1316 }
1317
1318 void Parse(const Byte *p);
1319};
1320
1321
1322// it's used for Attr streams
1323struct CSmallNode
1324{
1325 CRecordVector<CExtent> Extents;
1326 // UInt32 NumLinks;
1327 // CSmallNode(): NumLinks(0) {};
1328};
1329
1330static const unsigned k_SizeOf_j_inode_val = 0x5c;
1331
1332void CNode::Parse(const Byte *p)
1333{
1334 G64 (0, parent_id);
1335 G64 (0x8, private_id);
1336 G64 (0x10, create_time);
1337 G64 (0x18, mod_time);
1338 G64 (0x20, change_time);
1339 G64 (0x28, access_time);
1340 G64 (0x30, internal_flags);
1341 {
1342 G32(0x38, nchildren);
1343 // G32(0x38, nlink);
1344 }
1345 // G32(0x3c, default_protection_class);
1346 G32(0x40, write_generation_counter);
1347 G32(0x44, bsd_flags);
1348 G32(0x48, owner);
1349 G32(0x4c, group);
1350 G16(0x50, mode);
1351 // G16(0x52, pad1);
1352 // G64 (0x54, uncompressed_size);
1353}
1354
1355
1356struct CRef
1357{
1358 unsigned ItemIndex;
1359 unsigned NodeIndex;
1360 unsigned ParentRefIndex;
1361
1362 #ifdef APFS_SHOW_ALT_STREAMS
1363 unsigned AttrIndex;
1364 bool IsAltStream() const { return IsViDef(AttrIndex); }
1365 unsigned GetAttrIndex() const { return AttrIndex; };
1366 #else
1367 unsigned GetAttrIndex() const { return VI_MINUS1; };
1368 #endif
1369};
1370
1371
1372struct CRef2
1373{
1374 unsigned VolIndex;
1375 unsigned RefIndex;
1376};
1377
1378
1379struct CVol
1380{
1381 CObjectVector<CNode> Nodes;
1382 CRecordVector<UInt64> NodeIDs;
1383 CObjectVector<CItem> Items;
1384 CRecordVector<CRef> Refs;
1385
1386 CObjectVector<CSmallNode> SmallNodes;
1387 CRecordVector<UInt64> SmallNodeIDs;
1388
1389 unsigned StartRef2Index; // ref2_Index for Refs[0] item
1390 unsigned RootRef2Index; // ref2_Index of virtual root folder (Volume1)
1391 CApfs apfs;
1392 bool NodeNotFound;
1393 bool ThereAreUnlinkedNodes;
1394 bool WrongInodeLink;
1395 bool UnsupportedFeature;
1396
1397 unsigned NumItems_In_PrivateDir;
1398 unsigned NumAltStreams;
1399
1400 UString RootName;
1401
1402 bool ThereAreErrors() const
1403 {
1404 return NodeNotFound || ThereAreUnlinkedNodes || WrongInodeLink;
1405 }
1406
1407 void AddComment(UString &s) const;
1408
1409 HRESULT FillRefs();
1410
1411 CVol():
1412 StartRef2Index(0),
1413 RootRef2Index(VI_MINUS1),
1414 NodeNotFound(false),
1415 ThereAreUnlinkedNodes(false),
1416 WrongInodeLink(false),
1417 UnsupportedFeature(false),
1418 NumItems_In_PrivateDir(0),
1419 NumAltStreams(0)
1420 {}
1421};
1422
1423
1424static void ApfsTimeToFileTime(UInt64 apfsTime, FILETIME &ft, UInt32 &ns100)
1425{
1426 const UInt64 s = apfsTime / 1000000000;
1427 const UInt32 ns = (UInt32)(apfsTime % 1000000000);
1428 ns100 = (ns % 100);
1429 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(s) + ns / 100;
1430 ft.dwLowDateTime = (DWORD)v;
1431 ft.dwHighDateTime = (DWORD)(v >> 32);
1432}
1433
1434static void AddComment_Name(UString &s, const char *name)
1435{
1436 s += name;
1437 s += ": ";
1438}
1439
1440/*
1441static void AddComment_Bool(UString &s, const char *name, bool val)
1442{
1443 AddComment_Name(s, name);
1444 s += val ? "+" : "-";
1445 s.Add_LF();
1446}
1447*/
1448
1449static void AddComment_UInt64(UString &s, const char *name, UInt64 v)
1450{
1451 AddComment_Name(s, name);
1452 s.Add_UInt64(v);
1453 s.Add_LF();
1454}
1455
1456
1457static void AddComment_Time(UString &s, const char *name, UInt64 v)
1458{
1459 AddComment_Name(s, name);
1460
1461 FILETIME ft;
1462 UInt32 ns100;
1463 ApfsTimeToFileTime(v, ft, ns100);
1464 char temp[64];
1465 ConvertUtcFileTimeToString2(ft, ns100, temp
1466 // , kTimestampPrintLevel_SEC);
1467 , kTimestampPrintLevel_NS);
1468 s += temp;
1469 s.Add_LF();
1470}
1471
1472
1473static void AddComment_modified_by_t(UString &s, const char *name, const apfs_modified_by_t &v)
1474{
1475 AddComment_Name(s, name);
1476 AString s2;
1477 s2.SetFrom_CalcLen((const char *)v.id, sizeof(v.id));
1478 s += s2;
1479 s.Add_LF();
1480 s += " ";
1481 AddComment_Time(s, "timestamp", v.timestamp);
1482 s += " ";
1483 AddComment_UInt64(s, "last_xid", v.last_xid);
1484}
1485
1486
1487static void AddVolInternalName_toString(UString &s, const CApfs &apfs)
1488{
1489 AString temp;
1490 temp.SetFrom_CalcLen((const char *)apfs.volname, sizeof(apfs.volname));
1491 UString unicode;
1492 ConvertUTF8ToUnicode(temp, unicode);
1493 s += unicode;
1494}
1495
1496
1497void CVol::AddComment(UString &s) const
1498{
1499 AddComment_UInt64(s, "fs_index", apfs.fs_index);
1500 {
1501 AddComment_Name(s, "volume_name");
1502 AddVolInternalName_toString(s, apfs);
1503 s.Add_LF();
1504 }
1505 AddComment_Name(s, "vol_uuid");
1506 apfs.vol_uuid.AddHexToString(s);
1507 s.Add_LF();
1508
1509 AddComment_Name(s, "incompatible_features");
1510 s += FlagsToString(g_APFS_INCOMPAT_Flags,
1511 ARRAY_SIZE(g_APFS_INCOMPAT_Flags),
1512 (UInt32)apfs.incompatible_features);
1513 s.Add_LF();
1514
1515 // AddComment_UInt64(s, "reserve_block_count", apfs.fs_reserve_block_count, false);
1516 // AddComment_UInt64(s, "quota_block_count", apfs.fs_quota_block_count);
1517 AddComment_UInt64(s, "fs_alloc_count", apfs.fs_alloc_count);
1518
1519 AddComment_UInt64(s, "num_files", apfs.num_files);
1520 AddComment_UInt64(s, "num_directories", apfs.num_directories);
1521 AddComment_UInt64(s, "num_symlinks", apfs.num_symlinks);
1522 AddComment_UInt64(s, "num_other_fsobjects", apfs.num_other_fsobjects);
1523
1524 AddComment_UInt64(s, "Num_Attr_Streams", NumAltStreams);
1525
1526 AddComment_UInt64(s, "num_snapshots", apfs.num_snapshots);
1527 AddComment_UInt64(s, "total_blocks_alloced", apfs.total_blocks_alloced);
1528 AddComment_UInt64(s, "total_blocks_freed", apfs.total_blocks_freed);
1529
1530 AddComment_Time(s, "unmounted", apfs.unmount_time);
1531 AddComment_Time(s, "last_modified", apfs.last_mod_time);
1532 AddComment_modified_by_t(s, "formatted_by", apfs.formatted_by);
1533 for (unsigned i = 0; i < ARRAY_SIZE(apfs.modified_by); i++)
1534 {
1535 const apfs_modified_by_t &v = apfs.modified_by[i];
1536 if (v.last_xid == 0 && v.timestamp == 0 && v.id[0] == 0)
1537 continue;
1538 AString name ("modified_by[");
1539 name.Add_UInt32(i);
1540 name += ']';
1541 AddComment_modified_by_t(s, name.Ptr(), v);
1542 }
1543}
1544
1545
1546
1547struct CKeyValPair
1548{
1549 CByteBuffer Key;
1550 CByteBuffer Val;
1551 // unsigned ValPos; // for alognment
1552};
1553
1554
1555struct omap_key
1556{
1557 oid_t oid; // The object identifier
1558 xid_t xid; // The transaction identifier
1559 void Parse(const Byte *p)
1560 {
1561 G64o (0, oid);
1562 G64x (8, xid);
1563 }
1564};
1565
1566/*
1567#define OMAP_VAL_DELETED (1 << 0)
1568#define OMAP_VAL_SAVED (1 << 1)
1569#define OMAP_VAL_ENCRYPTED (1 << 2)
1570#define OMAP_VAL_NOHEADER (1 << 3)
1571#define OMAP_VAL_CRYPTO_GENERATION (1 << 4)
1572*/
1573
1574struct omap_val
1575{
1576 UInt32 flags;
1577 UInt32 size;
1578 paddr_t paddr;
1579
1580 void Parse(const Byte *p)
1581 {
1582 G32 (0, flags);
1583 G32 (4, size);
1584 G64 (8, paddr);
1585 }
1586};
1587
1588
1589struct CObjectMap
1590{
1591 CRecordVector<UInt64> Keys;
1592 CRecordVector<omap_val> Vals;
1593
1594 bool Parse(const CObjectVector<CKeyValPair> &pairs);
1595 int FindKey(UInt64 id) const { return Keys.FindInSorted(id); }
1596};
1597
1598bool CObjectMap::Parse(const CObjectVector<CKeyValPair> &pairs)
1599{
1600 omap_key prev;
1601 prev.oid = 0;
1602 prev.xid = 0;
1603 FOR_VECTOR (i, pairs)
1604 {
1605 const CKeyValPair &pair = pairs[i];
1606 if (pair.Key.Size() != 16 || pair.Val.Size() != 16)
1607 return false;
1608 omap_key key;
1609 key.Parse(pair.Key);
1610 omap_val val;
1611 val.Parse(pair.Val);
1612 /* Object map B-trees are sorted by object identifier and then by transaction identifier
1613 but it's possible to have identical Ids in map ?
1614 do we need to look transaction id ?
1615 and search key with largest transaction id? */
1616 if (key.oid <= prev.oid)
1617 return false;
1618 prev = key;
1619 Keys.Add(key.oid);
1620 Vals.Add(val);
1621 }
1622 return true;
1623}
1624
1625
1626struct CMap
1627{
1628 CObjectVector<CKeyValPair> Pairs;
1629
1630 CObjectMap Omap;
1631 btree_info bti;
1632 UInt64 NumNodes;
1633
1634 // we use thnese options to check:
1635 UInt32 Subtype;
1636 bool IsPhysical;
1637
1638 bool CheckAtFinish() const
1639 {
1640 return NumNodes == bti.node_count && Pairs.Size() == bti.key_count;
1641 }
1642
1643 CMap():
1644 NumNodes(0),
1645 Subtype(0),
1646 IsPhysical(true)
1647 {}
1648};
1649
1650
1651
1652struct CDatabase
1653{
1654 CRecordVector<CRef2> Refs2;
1655 CObjectVector<CVol> Vols;
1656
1657 bool HeadersError;
1658 bool ThereAreAltStreams;
1659 bool UnsupportedFeature;
1660
1661 CSuperBlock sb;
1662
1663 IInStream *OpenInStream;
1664 IArchiveOpenCallback *OpenCallback;
1665 UInt64 ProgressVal_Cur;
1666 UInt64 ProgressVal_Prev;
1667 UInt64 ProgressVal_NumFilesTotal;
1668 CObjectVector<CByteBuffer> Buffers;
1669
1670 UInt64 GetSize(const UInt32 index) const;
1671
1672 void Clear()
1673 {
1674 HeadersError = false;
1675 UnsupportedFeature = false;
1676 ThereAreAltStreams = false;
1677
1678 ProgressVal_Cur = 0;
1679 ProgressVal_Prev = 0;
1680 ProgressVal_NumFilesTotal = 0;
1681
1682 Vols.Clear();
1683 Refs2.Clear();
1684 Buffers.Clear();
1685 }
1686
1687 HRESULT SeekReadBlock_FALSE(UInt64 oid, void *data);
1688 void GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const;
1689 HRESULT ReadMap(UInt64 oid, CMap &map, unsigned recurseLevel);
1690 HRESULT ReadObjectMap(UInt64 oid, CObjectMap &map);
1691 HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid);
1692 HRESULT Open2();
1693
1694 HRESULT GetStream2(
1695 IInStream *apfsInStream,
1696 const CRecordVector<CExtent> *extents, UInt64 rem,
1697 ISequentialInStream **stream);
1698};
1699
1700
1701HRESULT CDatabase::SeekReadBlock_FALSE(UInt64 oid, void *data)
1702{
1703 if (OpenCallback)
1704 {
1705 if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22))
1706 {
1707 RINOK(OpenCallback->SetCompleted(NULL, &ProgressVal_Cur));
1708 ProgressVal_Prev = ProgressVal_Cur;
1709 }
1710 ProgressVal_Cur += sb.block_size;
1711 }
1712 if (oid == 0 || oid >= sb.block_count)
1713 return S_FALSE;
1714 RINOK(OpenInStream->Seek(oid << sb.block_size_Log, STREAM_SEEK_SET, NULL));
1715 return ReadStream_FALSE(OpenInStream, data, sb.block_size);
1716}
1717
1718
1719
1720API_FUNC_static_IsArc IsArc_APFS(const Byte *p, size_t size)
1721{
1722 if (size < kApfsHeaderSize)
1723 return k_IsArc_Res_NEED_MORE;
1724 CSuperBlock sb;
1725 if (!sb.Parse(p))
1726 return k_IsArc_Res_NO;
1727 return k_IsArc_Res_YES;
1728}
1729}
1730
1731
1732
1733HRESULT CDatabase::ReadMap(UInt64 oid, CMap &map, unsigned recurseLevel)
1734{
1735 // is it allowed to use big number of levels ?
1736 if (recurseLevel > (1 << 10))
1737 return S_FALSE;
1738
1739 const UInt32 blockSize = sb.block_size;
1740 if (Buffers.Size() <= recurseLevel)
1741 {
1742 Buffers.AddNew();
1743 if (Buffers.Size() <= recurseLevel)
1744 throw 123;
1745 Buffers.Back().Alloc(blockSize);
1746 }
1747 const Byte *buf;
1748 {
1749 CByteBuffer &buf2 = Buffers[recurseLevel];
1750 RINOK(SeekReadBlock_FALSE(oid, buf2));
1751 buf = buf2;
1752 }
1753
1754 CBTreeNodePhys bt;
1755 if (!bt.Parse(buf, blockSize))
1756 return S_FALSE;
1757
1758 map.NumNodes++;
1759
1760 /* Specification: All values are stored in leaf nodes, which
1761 makes these B+ trees, and the values in nonleaf nodes are object
1762 identifiers of child nodes.
1763
1764 The entries in the table of contents are sorted by key. The comparison function used for sorting depends on the keys type
1765 - Object map B-trees are sorted by object identifier and then by transaction identifier.
1766 - Free queue B-trees are sorted by transaction identifier and then by physical address.
1767 - File-system records are sorted according to the rules listed in File-System Objects.
1768 */
1769
1770 if (bt.o.subtype != map.Subtype)
1771 return S_FALSE;
1772
1773 unsigned endLimit = blockSize;
1774
1775 if (recurseLevel == 0)
1776 {
1777 if (bt.o.GetType() != OBJECT_TYPE_BTREE)
1778 return S_FALSE;
1779 if ((bt.flags & BTNODE_ROOT) == 0)
1780 return S_FALSE;
1781 endLimit -= k_btree_info_Size;
1782 map.bti.Parse(buf + endLimit);
1783 btree_info &bti = map.bti;
1784 if (bti.fixed.key_size >= blockSize)
1785 return S_FALSE;
1786 if (bti.Is_EPHEMERAL() &&
1787 bti.Is_PHYSICAL())
1788 return S_FALSE;
1789 if (bti.Is_PHYSICAL() != map.IsPhysical)
1790 return S_FALSE;
1791 // we don't allow volumes with big number of Keys
1792 const UInt32 kNumItemsMax = k_VectorSizeMax;
1793 if (map.bti.node_count > kNumItemsMax)
1794 return S_FALSE;
1795 if (map.bti.key_count > kNumItemsMax)
1796 return S_FALSE;
1797 }
1798 else
1799 {
1800 if (bt.o.GetType() != OBJECT_TYPE_BTREE_NODE)
1801 return S_FALSE;
1802 if ((bt.flags & BTNODE_ROOT) != 0)
1803 return S_FALSE;
1804 if (map.NumNodes > map.bti.node_count
1805 || map.Pairs.Size() > map.bti.key_count)
1806 return S_FALSE;
1807 }
1808
1809 const bool isLeaf = (bt.flags & BTNODE_LEAF) != 0;
1810
1811 if (isLeaf)
1812 {
1813 if (bt.level != 0)
1814 return S_FALSE;
1815 }
1816 else
1817 {
1818 if (bt.level == 0)
1819 return S_FALSE;
1820 }
1821
1822 if (!bt.table_space.CheckOverLimit(endLimit - k_Toc_offset))
1823 return S_FALSE;
1824
1825 const unsigned tableEnd = k_Toc_offset + bt.table_space.GetEnd();
1826 const unsigned keyValRange = endLimit - tableEnd;
1827 const unsigned tocEntrySize = bt.Is_FIXED_KV_SIZE() ? 4 : 8;
1828 if (bt.table_space.len / tocEntrySize < bt.nkeys)
1829 return S_FALSE;
1830
1831 for (unsigned i = 0; i < bt.nkeys; i++)
1832 {
1833 const Byte *p = buf + k_Toc_offset + bt.table_space.off + i * tocEntrySize;
1834 if (bt.Is_FIXED_KV_SIZE())
1835 {
1836 kvoff a;
1837 a.Parse(p);
1838 if (a.k + map.bti.fixed.key_size > keyValRange
1839 || a.v > keyValRange)
1840 return S_FALSE;
1841 {
1842 CKeyValPair pair;
1843
1844 const Byte *p2 = buf + k_Toc_offset + bt.table_space.len;
1845 p2 += a.k;
1846 pair.Key.CopyFrom(p2, map.bti.fixed.key_size);
1847
1848 p2 = buf + endLimit;
1849 p2 -= a.v;
1850 if (isLeaf)
1851 {
1852 if (a.v < map.bti.fixed.val_size)
1853 return S_FALSE;
1854 pair.Val.CopyFrom(p2, map.bti.fixed.val_size);
1855 // pair.ValPos = endLimit - a.v;
1856 map.Pairs.Add(pair);
1857 continue;
1858 }
1859 {
1860 if (a.v < 8)
1861 return S_FALSE;
1862 // value is only 64-bit for non leaf.
1863 const oid_t oidNext = Get64(p2);
1864 if (map.bti.Is_PHYSICAL())
1865 {
1866 RINOK(ReadMap(oidNext, map, recurseLevel + 1));
1867 continue;
1868 }
1869 else
1870 {
1871 // fixme
1872 return S_FALSE;
1873 }
1874 }
1875 }
1876 }
1877 else
1878 {
1879 kvloc a;
1880 a.Parse(p);
1881 if (!a.k.CheckOverLimit(keyValRange)
1882 || a.v.off > keyValRange
1883 || a.v.len > a.v.off)
1884 return S_FALSE;
1885 {
1886 CKeyValPair pair;
1887 const Byte *p2 = buf + k_Toc_offset + bt.table_space.len;
1888 p2 += a.k.off;
1889 pair.Key.CopyFrom(p2, a.k.len);
1890
1891 p2 = buf + endLimit;
1892 p2 -= a.v.off;
1893 if (isLeaf)
1894 {
1895 pair.Val.CopyFrom(p2, a.v.len);
1896 // pair.ValPos = endLimit - a.v.off;
1897 map.Pairs.Add(pair);
1898 continue;
1899 }
1900 {
1901 if (a.v.off < 8 || a.v.len != 8)
1902 return S_FALSE;
1903 // value is only 64-bit for non leaf.
1904 const oid_t oidNext = Get64(p2);
1905
1906 if (map.bti.Is_PHYSICAL())
1907 {
1908 return S_FALSE;
1909 // the code was not tested:
1910 // RINOK(ReadMap(oidNext, map, recurseLevel + 1));
1911 // continue;
1912 }
1913 else
1914 {
1915 const int index = map.Omap.FindKey(oidNext);
1916 if (index == -1)
1917 return S_FALSE;
1918 const omap_val &ov = map.Omap.Vals[(unsigned)index];
1919 if (ov.size != blockSize) // change it : it must be multiple of
1920 return S_FALSE;
1921 RINOK(ReadMap(ov.paddr, map, recurseLevel + 1));
1922 continue;
1923 }
1924 }
1925 }
1926 }
1927 }
1928
1929 if (recurseLevel == 0)
1930 if (!map.CheckAtFinish())
1931 return S_FALSE;
1932 return S_OK;
1933}
1934
1935
1936
1937HRESULT CDatabase::ReadObjectMap(UInt64 oid, CObjectMap &omap)
1938{
1939 CByteBuffer buf;
1940 const size_t blockSize = sb.block_size;
1941 buf.Alloc(blockSize);
1942 RINOK(SeekReadBlock_FALSE(oid, buf));
1943 C_omap_phys op;
1944 if (!op.Parse(buf, blockSize, oid))
1945 return S_FALSE;
1946 CMap map;
1947 map.Subtype = OBJECT_TYPE_OMAP;
1948 map.IsPhysical = true;
1949 RINOK(ReadMap(op.tree_oid, map, 0));
1950 if (!omap.Parse(map.Pairs))
1951 return S_FALSE;
1952 return S_OK;
1953}
1954
1955
1956
1957HRESULT CDatabase::Open2()
1958{
1959 Clear();
1960 CSuperBlock2 sb2;
1961 {
1962 Byte buf[kApfsHeaderSize];
1963 RINOK(ReadStream_FALSE(OpenInStream, buf, kApfsHeaderSize));
1964 if (!sb.Parse(buf))
1965 return S_FALSE;
1966 sb2.Parse(buf);
1967 }
1968
1969 {
1970 CObjectMap omap;
1971 RINOK(ReadObjectMap(sb.omap_oid, omap));
1972 unsigned numRefs = 0;
1973 for (unsigned i = 0; i < sb.max_file_systems; i++)
1974 {
1975 const oid_t oid = sb2.fs_oid[i];
1976 if (oid == 0)
1977 continue;
1978 // for (unsigned k = 0; k < 1; k++) // for debug
1979 RINOK(OpenVolume(omap, oid));
1980 const unsigned a = Vols.Back().Refs.Size();
1981 numRefs += a;
1982 if (numRefs < a)
1983 return S_FALSE; // overflow
1984 }
1985 }
1986
1987 const bool needVolumePrefix = (Vols.Size() > 1);
1988 // const bool needVolumePrefix = true; // for debug
1989 {
1990 unsigned numRefs = 0;
1991 FOR_VECTOR (i, Vols)
1992 {
1993 const unsigned a = Vols[i].Refs.Size();
1994 numRefs += a;
1995 if (numRefs < a)
1996 return S_FALSE; // overflow
1997 }
1998 numRefs += Vols.Size();
1999 if (numRefs < Vols.Size())
2000 return S_FALSE; // overflow
2001 Refs2.Reserve(numRefs);
2002 }
2003 {
2004 FOR_VECTOR (i, Vols)
2005 {
2006 CVol &vol = Vols[i];
2007
2008 CRef2 ref2;
2009 ref2.VolIndex = i;
2010
2011 if (needVolumePrefix)
2012 {
2013 vol.RootName = "Volume";
2014 vol.RootName.Add_UInt32(1 + (UInt32)i);
2015 vol.RootRef2Index = Refs2.Size();
2016 ref2.RefIndex = VI_MINUS1;
2017 Refs2.Add(ref2);
2018 }
2019
2020 vol.StartRef2Index = Refs2.Size();
2021 const unsigned numItems = vol.Refs.Size();
2022 for (unsigned k = 0; k < numItems; k++)
2023 {
2024 ref2.RefIndex = k;
2025 Refs2.Add(ref2);
2026 }
2027 }
2028 }
2029 return S_OK;
2030}
2031
2032
2033HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
2034{
2035 const size_t blockSize = sb.block_size;
2036 CByteBuffer buf;
2037 {
2038 const int index = omap.FindKey(fs_oid);
2039 if (index == -1)
2040 return S_FALSE;
2041 const omap_val &ov = omap.Vals[(unsigned)index];
2042 if (ov.size != blockSize) // change it : it must be multiple of
2043 return S_FALSE;
2044 buf.Alloc(blockSize);
2045 RINOK(SeekReadBlock_FALSE(ov.paddr, buf));
2046 }
2047
2048 CVol &vol = Vols.AddNew();
2049 CApfs &apfs = vol.apfs;
2050
2051 if (!apfs.Parse(buf, blockSize))
2052 return S_FALSE;
2053
2054 /* For each volume, read the root file system tree's virtual object
2055 identifier from the apfs_root_tree_oid field,
2056 and then look it up in the volume object map indicated
2057 by the omap_oid field. */
2058
2059 CMap map;
2060 {
2061 ReadObjectMap(apfs.omap_oid, map.Omap);
2062 const int index = map.Omap.FindKey(apfs.root_tree_oid);
2063 if (index == -1)
2064 return S_FALSE;
2065 const omap_val &ov = map.Omap.Vals[(unsigned)index];
2066 if (ov.size != blockSize) // change it : it must be multiple of
2067 return S_FALSE;
2068 map.Subtype = OBJECT_TYPE_FSTREE;
2069 map.IsPhysical = false;
2070 RINOK(ReadMap(ov.paddr, map, 0));
2071 }
2072
2073 bool NeedReadSymLink = false;
2074
2075 {
2076 const bool isHashed = apfs.IsHashedName();
2077 UInt64 prevId = 1;
2078
2079 {
2080 const UInt64 numApfsItems = vol.apfs.GetTotalItems()
2081 + 2; // we will have 2 additional hidden directories: root and private-dir
2082 const UInt64 numApfsItems_Reserve = numApfsItems
2083 + 16; // we reserve 16 for some possible unexpected items
2084 if (numApfsItems_Reserve < map.Pairs.Size())
2085 {
2086 vol.Items.ClearAndReserve((unsigned)numApfsItems_Reserve);
2087 vol.Nodes.ClearAndReserve((unsigned)numApfsItems_Reserve);
2088 vol.NodeIDs.ClearAndReserve((unsigned)numApfsItems_Reserve);
2089 }
2090 if (OpenCallback)
2091 {
2092 const UInt64 numFiles = ProgressVal_NumFilesTotal + numApfsItems;
2093 RINOK(OpenCallback->SetTotal(&numFiles, NULL));
2094 }
2095 }
2096
2097 FOR_VECTOR (i, map.Pairs)
2098 {
2099 if (OpenCallback && (i & 0xffff) == 1)
2100 {
2101 const UInt64 numFiles = ProgressVal_NumFilesTotal +
2102 (vol.Items.Size() + vol.Nodes.Size()) / 2;
2103 RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur));
2104 }
2105
2106 const CKeyValPair &pair = map.Pairs[i];
2107 j_key_t jkey;
2108 if (pair.Key.Size() < 8)
2109 return S_FALSE;
2110 const Byte *p = pair.Key;
2111 jkey.Parse(p);
2112 const unsigned type = jkey.GetType();
2113 const UInt64 id = jkey.GetID();
2114 if (id < prevId)
2115 return S_FALSE; // IDs must be sorted
2116 prevId = id;
2117
2118 PRF(printf("\n%6d: id=%6d type = %2d", i, (unsigned)id, type));
2119
2120 if (type == APFS_TYPE_INODE)
2121 {
2122 PRF(printf (" INODE"));
2123 if (pair.Key.Size() != 8 ||
2124 pair.Val.Size() < k_SizeOf_j_inode_val)
2125 return S_FALSE;
2126
2127 CNode inode;
2128 inode.Parse(pair.Val);
2129
2130 if (inode.private_id != id)
2131 {
2132 /* private_id : The unique identifier used by this file's data stream.
2133 This identifier appears in the owning_obj_id field of j_phys_ext_val_t
2134 records that describe the extents where the data is stored.
2135 For an inode that doesn't have data, the value of this
2136 field is the file-system object's identifier.
2137 */
2138 // APFS_TYPE_EXTENT allow to link physical address extents.
2139 // we don't support case (private_id != id)
2140 UnsupportedFeature = true;
2141 // return S_FALSE;
2142 }
2143 const UInt32 extraSize = (UInt32)pair.Val.Size() - k_SizeOf_j_inode_val;
2144 if (extraSize != 0)
2145 {
2146 if (extraSize < 4)
2147 return S_FALSE;
2148 /*
2149 struct xf_blob
2150 {
2151 uint16_t xf_num_exts;
2152 uint16_t xf_used_data;
2153 uint8_t xf_data[];
2154 };
2155 */
2156 const Byte *p2 = pair.Val + k_SizeOf_j_inode_val;
2157 const UInt32 xf_num_exts = Get16(p2);
2158 const UInt32 xf_used_data = Get16(p2 + 2);
2159 UInt32 offset = 4 + (UInt32)xf_num_exts * 4;
2160 if (offset + xf_used_data != extraSize)
2161 return S_FALSE;
2162 for (unsigned k = 0; k < xf_num_exts; k++)
2163 {
2164 // struct x_field
2165 const Byte *p3 = p2 + 4 + k * 4;
2166 const Byte x_type = p3[0];
2167 // const Byte x_flags = p3[1];
2168 const UInt32 x_size = Get16(p3 + 2);
2169 const UInt32 x_size_ceil = (x_size + 7) & ~(UInt32)7;
2170 if (offset + x_size_ceil > extraSize)
2171 return S_FALSE;
2172 const Byte *p4 = p2 + offset;
2173 if (x_type == INO_EXT_TYPE_NAME)
2174 {
2175 if (x_size < 2)
2176 return S_FALSE;
2177 inode.PrimaryName.SetFrom_CalcLen((const char *)p4, x_size);
2178 PRF(printf(" PrimaryName = %s", inode.PrimaryName.Ptr()));
2179 if (inode.PrimaryName.Len() != x_size - 1)
2180 HeadersError = true;
2181 // return S_FALSE;
2182 }
2183 else if (x_type == INO_EXT_TYPE_DSTREAM)
2184 {
2185 if (x_size != k_SizeOf_j_dstream)
2186 return S_FALSE;
2187 if (inode.dstream_defined)
2188 return S_FALSE;
2189 inode.dstream.Parse(p4);
2190 inode.dstream_defined = true;
2191 }
2192 else
2193 {
2194 // UnsupportedFeature = true;
2195 // return S_FALSE;
2196 }
2197 offset += x_size_ceil;
2198 }
2199 if (offset != extraSize)
2200 return S_FALSE;
2201 }
2202
2203 if (!vol.NodeIDs.IsEmpty())
2204 if (id <= vol.NodeIDs.Back())
2205 return S_FALSE;
2206 vol.Nodes.Add(inode);
2207 vol.NodeIDs.Add(id);
2208 continue;
2209 }
2210
2211 if (type == APFS_TYPE_XATTR)
2212 {
2213 PRF(printf(" XATTR"));
2214
2215 /*
2216 struct j_xattr_key
2217 {
2218 j_key_t hdr;
2219 uint16_t name_len;
2220 uint8_t name[0];
2221 }
2222 */
2223
2224 UInt32 len;
2225 unsigned nameOffset;
2226 {
2227 nameOffset = 8 + 2;
2228 if (pair.Key.Size() < nameOffset + 1)
2229 return S_FALSE;
2230 len = Get16(p + 8);
2231 }
2232 if (nameOffset + len != pair.Key.Size())
2233 return S_FALSE;
2234
2235 CAttr attr;
2236 attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
2237 if (attr.Name.Len() != len - 1)
2238 return S_FALSE;
2239
2240 PRF(printf(" name=%s", attr.Name.Ptr()));
2241
2242 const unsigned k_SizeOf_j_xattr_val = 4;
2243 if (pair.Val.Size() < k_SizeOf_j_xattr_val)
2244 return S_FALSE;
2245 /*
2246 struct j_xattr_val
2247 {
2248 uint16_t flags;
2249 uint16_t xdata_len;
2250 uint8_t xdata[0];
2251 }
2252 */
2253 attr.flags = Get16(pair.Val);
2254 const UInt32 xdata_len = Get16(pair.Val + 2);
2255
2256 PRF(printf(" flags=%x xdata_len = %d",
2257 (unsigned)attr.flags,
2258 (unsigned)xdata_len));
2259
2260 const Byte *p4 = pair.Val + 4;
2261
2262 if (k_SizeOf_j_xattr_val + xdata_len != pair.Val.Size())
2263 return S_FALSE;
2264 if (attr.Is_EMBEDDED())
2265 attr.Data.CopyFrom(p4, xdata_len);
2266 else if (attr.Is_STREAM())
2267 {
2268 // why (attr.flags == 0x11) here? (0x11 is undocummented flag)
2269 if (k_SizeOf_j_xattr_val + 8 + k_SizeOf_j_dstream != pair.Val.Size())
2270 return S_FALSE;
2271 attr.Id = Get64(p4);
2272 attr.dstream.Parse(p4 + 8);
2273 attr.dstream_defined = true;
2274 PRF(printf(" streamID=%d", (unsigned)attr.Id));
2275 }
2276 else
2277 {
2278 // unknown attribute
2279 // UnsupportedFeature = true;
2280 // return S_FALSE;
2281 }
2282
2283 if (vol.NodeIDs.IsEmpty() ||
2284 vol.NodeIDs.Back() != id)
2285 {
2286 return S_FALSE;
2287 // UnsupportedFeature = true;
2288 // continue;
2289 }
2290 CNode &inode = vol.Nodes.Back();
2291 if (attr.Name.IsEqualTo("com.apple.fs.symlink"))
2292 {
2293 inode.SymLinkIndex = inode.Attrs.Size();
2294 if (attr.Is_dstream_OK_for_SymLink())
2295 NeedReadSymLink = true;
2296 }
2297 else
2298 vol.NumAltStreams++;
2299 inode.Attrs.Add(attr);
2300 continue;
2301 }
2302
2303 if (type == APFS_TYPE_DSTREAM_ID)
2304 {
2305 PRF(printf(" DSTREAM_ID"));
2306 if (pair.Key.Size() != 8)
2307 return S_FALSE;
2308 // j_dstream_id_val_t
2309 if (pair.Val.Size() != 4)
2310 return S_FALSE;
2311 const UInt32 refcnt = Get32(pair.Val);
2312
2313 // The data stream record can be deleted when its reference count reaches zero.
2314 PRF(printf(" refcnt = %8d", (unsigned)refcnt));
2315
2316 if (vol.NodeIDs.IsEmpty())
2317 return S_FALSE;
2318
2319 if (vol.NodeIDs.Back() != id)
2320 {
2321 // is it possible ?
2322 // continue;
2323 return S_FALSE;
2324 }
2325
2326 CNode &inode = vol.Nodes.Back();
2327
2328 if (inode.refcnt_defined)
2329 return S_FALSE;
2330
2331 inode.refcnt = refcnt;
2332 inode.refcnt_defined = true;
2333 if (inode.refcnt != (UInt32)inode.nlink)
2334 {
2335 // is it possible ?
2336 // return S_FALSE;
2337 }
2338 continue;
2339 }
2340
2341 if (type == APFS_TYPE_FILE_EXTENT)
2342 {
2343 PRF(printf(" FILE_EXTENT"));
2344 /*
2345 struct j_file_extent_key
2346 {
2347 j_key_t hdr;
2348 uint64_t logical_addr;
2349 }
2350 */
2351 if (pair.Key.Size() != 16)
2352 return S_FALSE;
2353 // The offset within the file's data, in bytes, for the data stored in this extent
2354 const UInt64 logical_addr = Get64(p + 8);
2355
2356 j_file_extent_val eval;
2357 if (pair.Val.Size() != k_SizeOf_j_file_extent_val)
2358 return S_FALSE;
2359 eval.Parse(pair.Val);
2360
2361 if (logical_addr != 0)
2362 {
2363 PRF(printf(" logical_addr = %d", (unsigned)logical_addr));
2364 }
2365 PRF(printf(" len = %8d pos = %8d",
2366 (unsigned)eval.len_and_flags,
2367 (unsigned)eval.phys_block_num
2368 ));
2369
2370 CExtent ext;
2371 ext.logical_offset = logical_addr;
2372 ext.len_and_flags = eval.len_and_flags;
2373 ext.phys_block_num = eval.phys_block_num;
2374
2375 if (vol.NodeIDs.IsEmpty())
2376 return S_FALSE;
2377 if (vol.NodeIDs.Back() != id)
2378 {
2379 // extents for Attributs;
2380 if (vol.SmallNodeIDs.IsEmpty() ||
2381 vol.SmallNodeIDs.Back() != id)
2382 {
2383 vol.SmallNodeIDs.Add(id);
2384 vol.SmallNodes.AddNew();
2385 }
2386 vol.SmallNodes.Back().Extents.Add(ext);
2387 continue;
2388 // return S_FALSE;
2389 }
2390
2391 CNode &inode = vol.Nodes.Back();
2392 inode.Extents.Add(ext);
2393 continue;
2394 }
2395
2396 if (type == APFS_TYPE_DIR_REC)
2397 {
2398 UInt32 len;
2399 unsigned nameOffset;
2400
2401 if (isHashed)
2402 {
2403 /*
2404 struct j_drec_hashed_key
2405 {
2406 j_key_t hdr;
2407 UInt32 name_len_and_hash;
2408 uint8_t name[0];
2409 }
2410 */
2411 nameOffset = 8 + 4;
2412 if (pair.Key.Size() < nameOffset + 1)
2413 return S_FALSE;
2414 const UInt32 name_len_and_hash = Get32(p + 8);
2415 len = name_len_and_hash & J_DREC_LEN_MASK;
2416 }
2417 else
2418 {
2419 /*
2420 struct j_drec_key
2421 {
2422 j_key_t hdr;
2423 UInt16 name_len; // The length of the name, including the final null character
2424 uint8_t name[0]; // The name, represented as a null-terminated UTF-8 string
2425 }
2426 */
2427 nameOffset = 8 + 2;
2428 if (pair.Key.Size() < nameOffset + 1)
2429 return S_FALSE;
2430 len = Get16(p + 8);
2431 }
2432 if (nameOffset + len != pair.Key.Size())
2433 return S_FALSE;
2434 CItem item;
2435 item.ParentId = id;
2436 item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
2437 if (item.Name.Len() != len - 1)
2438 return S_FALSE;
2439
2440 if (pair.Val.Size() < k_SizeOf_j_drec_val)
2441 return S_FALSE;
2442
2443 item.Val.Parse(pair.Val);
2444
2445 if (pair.Val.Size() > k_SizeOf_j_drec_val)
2446 {
2447 // fixme: parse extra fields;
2448 // UnsupportedFeature = true;
2449 // return S_FALSE;
2450 }
2451
2452 vol.Items.Add(item);
2453
2454 /*
2455 if (!vol.NodeIDs.IsEmpty() && vol.NodeIDs.Back() == id)
2456 vol.Nodes.Back().NumItems++;
2457 */
2458 if (id == PRIV_DIR_INO_NUM)
2459 vol.NumItems_In_PrivateDir++;
2460
2461 PRF(printf(" next=%6d flags=%2x %s",
2462 (unsigned)item.Val.file_id,
2463 (unsigned)item.Val.flags,
2464 item.Name.Ptr()));
2465 continue;
2466 }
2467
2468 UnsupportedFeature = true;
2469 // return S_FALSE;
2470 }
2471 ProgressVal_NumFilesTotal += vol.Items.Size();
2472 }
2473
2474 if (NeedReadSymLink)
2475 {
2476 /* we read external streams for SymLinks to CAttr.Data
2477 So we can get SymLink for GetProperty(kpidSymLink) later */
2478 FOR_VECTOR (i, vol.Nodes)
2479 {
2480 CNode &node = vol.Nodes[i];
2481 if (IsViNotDef(node.SymLinkIndex))
2482 continue;
2483 CAttr &attr = node.Attrs[(unsigned)node.SymLinkIndex];
2484 // FOR_VECTOR (k, node.Attrs) { CAttr &attr = node.Attrs[(unsigned)k]; // for debug
2485 if (attr.Data.Size() != 0
2486 || !attr.Is_dstream_OK_for_SymLink())
2487 continue;
2488 const UInt32 size = (UInt32)attr.dstream.size;
2489 const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
2490 if (idIndex == -1)
2491 continue;
2492 CMyComPtr<ISequentialInStream> inStream;
2493 const HRESULT res = GetStream2(
2494 OpenInStream,
2495 &vol.SmallNodes[(unsigned)idIndex].Extents,
2496 size, &inStream);
2497 if (res == S_OK && inStream)
2498 {
2499 CByteBuffer buf2;
2500 buf2.Alloc(size);
2501 if (ReadStream_FAIL(inStream, buf2, size) == S_OK)
2502 attr.Data = buf2;
2503 }
2504 }
2505 }
2506
2507 const HRESULT res = vol.FillRefs();
2508
2509 if (vol.ThereAreErrors())
2510 HeadersError = true;
2511 if (vol.UnsupportedFeature)
2512 UnsupportedFeature = true;
2513 if (vol.NumAltStreams != 0)
2514 ThereAreAltStreams = true;
2515
2516 return res;
2517}
2518
2519
2520
2521HRESULT CVol::FillRefs()
2522{
2523 {
2524 // we fill Refs[*]
2525 // we
2526 // and set Nodes[*].ItemIndex for Nodes that are dictories;
2527 FOR_VECTOR (i, Items)
2528 {
2529 CItem &item = Items[i];
2530 const UInt64 id = item.Val.file_id;
2531 // if (item.Id == ROOT_DIR_PARENT) continue;
2532 /* for two root folders items
2533 we don't set Node.ItemIndex; */
2534 // so nodes
2535 if (id == ROOT_DIR_INO_NUM)
2536 continue;
2537 if (id == PRIV_DIR_INO_NUM)
2538 if (NumItems_In_PrivateDir == 0) // if (inode.NumItems == 0)
2539 continue;
2540
2541 CRef ref;
2542 ref.ItemIndex = i;
2543 // ref.NodeIndex = VI_MINUS1;
2544 ref.ParentRefIndex = VI_MINUS1;
2545 #ifdef APFS_SHOW_ALT_STREAMS
2546 ref.AttrIndex = VI_MINUS1;
2547 #endif
2548 const int index = NodeIDs.FindInSorted(id);
2549 // const int index = -1; // for debug
2550 ref.NodeIndex = (unsigned)index;
2551 item.RefIndex = Refs.Size();
2552 Refs.Add(ref);
2553
2554 if (index == -1)
2555 {
2556 NodeNotFound = true;
2557 continue;
2558 // return S_FALSE;
2559 }
2560
2561 // item.iNode_Index = index;
2562 CNode &inode = Nodes[(unsigned)index];
2563 if (!item.Val.IsFlags_Unknown()
2564 && inode.Get_Type_From_mode() != item.Val.flags)
2565 {
2566 Refs.Back().NodeIndex = VI_MINUS1;
2567 WrongInodeLink = true;
2568 continue;
2569 // return S_FALSE;
2570 }
2571
2572 const bool isDir = inode.IsDir();
2573 if (isDir)
2574 {
2575 if (IsViDef(inode.ItemIndex))
2576 {
2577 // hard links to dirs are not supported
2578 Refs.Back().NodeIndex = VI_MINUS1;
2579 WrongInodeLink = true;
2580 continue;
2581 }
2582 inode.ItemIndex = i;
2583 }
2584 inode.NumCalcedLinks++;
2585
2586 #ifdef APFS_SHOW_ALT_STREAMS
2587 if (!isDir)
2588 {
2589 // we use alt streams only for files
2590 const unsigned numAttrs = inode.Attrs.Size();
2591 if (numAttrs != 0)
2592 {
2593 ref.ParentRefIndex = item.RefIndex;
2594 for (unsigned k = 0; k < numAttrs; k++)
2595 {
2596 if (k == inode.SymLinkIndex)
2597 continue;
2598 ref.AttrIndex = k;
2599 Refs.Add(ref);
2600 /*
2601 const CAttr &attr = inode.Attrs[k];
2602 if (attr.dstream_defined)
2603 {
2604 const int idIndex = SmallNodeIDs.FindInSorted(attr.Id);
2605 if (idIndex != -1)
2606 SmallNodes[(unsigned)idIndex].NumLinks++; // for debug
2607 }
2608 */
2609 }
2610 }
2611 }
2612 #endif
2613 }
2614 }
2615
2616
2617 {
2618 // fill ghost nodes
2619 CRef ref;
2620 ref.ItemIndex = VI_MINUS1;
2621 ref.ParentRefIndex = VI_MINUS1;
2622 #ifdef APFS_SHOW_ALT_STREAMS
2623 ref.AttrIndex = VI_MINUS1;
2624 #endif
2625 FOR_VECTOR (i, Nodes)
2626 {
2627 if (Nodes[i].NumCalcedLinks != 0)
2628 continue;
2629 const UInt64 id = NodeIDs[i];
2630 if (id == ROOT_DIR_INO_NUM ||
2631 id == PRIV_DIR_INO_NUM)
2632 continue;
2633 ThereAreUnlinkedNodes = true;
2634 ref.NodeIndex = i;
2635 Refs.Add(ref);
2636 }
2637 }
2638
2639 /* if want to create Refs for ghost data streams,
2640 we need additional CRef::SmallNodeIndex field */
2641
2642 {
2643 /* all Nodes[*].ItemIndex were already filled for directory Nodes,
2644 except of "root" and "private-dir" Nodes. */
2645
2646 // now we fill Items[*].ParentItemIndex and Refs[*].ParentRefIndex
2647
2648 UInt64 prev_ID = (UInt64)(Int64)-1;
2649 unsigned prev_ParentItemIndex = VI_MINUS1;
2650
2651 FOR_VECTOR (i, Items)
2652 {
2653 CItem &item = Items[i];
2654 const UInt64 id = item.ParentId; // it's id of parent NODE
2655 if (id != prev_ID)
2656 {
2657 prev_ID = id;
2658 prev_ParentItemIndex = VI_MINUS1;
2659 const int index = NodeIDs.FindInSorted(id);
2660 if (index == -1)
2661 continue;
2662 prev_ParentItemIndex = Nodes[(unsigned)index].ItemIndex;
2663 }
2664
2665 if (IsViNotDef(prev_ParentItemIndex))
2666 continue;
2667 item.ParentItemIndex = prev_ParentItemIndex;
2668 if (IsViNotDef(item.RefIndex))
2669 {
2670 // RefIndex is not set for 2 Items (root folders)
2671 // but there is no node for them usually
2672 continue;
2673 }
2674 CRef &ref = Refs[item.RefIndex];
2675
2676 /*
2677 // it's optional check that parent_id is set correclty
2678 if (IsViDef(ref.NodeIndex))
2679 {
2680 const CNode &node = Nodes[ref.NodeIndex];
2681 if (node.IsDir() && node.parent_id != id)
2682 return S_FALSE;
2683 }
2684 */
2685
2686 /*
2687 if (id == ROOT_DIR_INO_NUM)
2688 {
2689 // ItemIndex in Node for ROOT_DIR_INO_NUM was not set bofere
2690 // probably unused now.
2691 ref.ParentRefIndex = VI_MINUS1;
2692 }
2693 else
2694 */
2695 ref.ParentRefIndex = Items[prev_ParentItemIndex].RefIndex;
2696 }
2697 }
2698
2699 {
2700 // check for loops
2701 const unsigned numItems = Items.Size();
2702 if (numItems + 1 == 0)
2703 return S_FALSE;
2704 CUIntArr arr;
2705 arr.Alloc(numItems);
2706 {
2707 for (unsigned i = 0; i < numItems; i++)
2708 arr[i] = 0;
2709 }
2710 for (unsigned i = 0; i < numItems;)
2711 {
2712 unsigned k = i++;
2713 for (;;)
2714 {
2715 const unsigned a = arr[k];
2716 if (a != 0)
2717 {
2718 if (a == i)
2719 return S_FALSE;
2720 break;
2721 }
2722 arr[k] = i;
2723 k = Items[k].ParentItemIndex;
2724 if (IsViNotDef(k))
2725 break;
2726 }
2727 }
2728 }
2729
2730 return S_OK;
2731}
2732
2733
2734
2735class CHandler:
2736 public IInArchive,
2737 public IArchiveGetRawProps,
2738 public IInArchiveGetStream,
2739 public CMyUnknownImp,
2740 public CDatabase
2741{
2742 CMyComPtr<IInStream> _stream;
2743public:
2744 MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream)
2745 INTERFACE_IInArchive(;)
2746 INTERFACE_IArchiveGetRawProps(;)
2747 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
2748};
2749
2750
2751STDMETHODIMP CHandler::Open(IInStream *inStream,
2752 const UInt64 * /* maxCheckStartPosition */,
2753 IArchiveOpenCallback *callback)
2754{
2755 COM_TRY_BEGIN
2756 Close();
2757 OpenInStream = inStream;
2758 OpenCallback = callback;
2759 RINOK(Open2());
2760 _stream = inStream;
2761 return S_OK;
2762 COM_TRY_END
2763}
2764
2765
2766STDMETHODIMP CHandler::Close()
2767{
2768 _stream.Release();
2769 Clear();
2770 return S_OK;
2771}
2772
2773
2774enum
2775{
2776 kpidBytesWritten = kpidUserDefined,
2777 kpidBytesRead,
2778 kpidPrimeName,
2779 kpidParentINode,
2780 kpidAddTime,
2781 kpidGeneration,
2782 kpidBsdFlags
2783};
2784
2785static const CStatProp kProps[] =
2786{
2787 { NULL, kpidPath, VT_BSTR },
2788 { NULL, kpidSize, VT_UI8 },
2789 { NULL, kpidPackSize, VT_UI8 },
2790 { NULL, kpidPosixAttrib, VT_UI4 },
2791 { NULL, kpidMTime, VT_FILETIME },
2792 { NULL, kpidCTime, VT_FILETIME },
2793 { NULL, kpidATime, VT_FILETIME },
2794 { NULL, kpidChangeTime, VT_FILETIME },
2795 { "Added Time", kpidAddTime, VT_FILETIME },
2796 { NULL, kpidINode, VT_UI8 },
2797 { NULL, kpidLinks, VT_UI4 },
2798 { NULL, kpidSymLink, VT_BSTR },
2799 { NULL, kpidUserId, VT_UI4 },
2800 { NULL, kpidGroupId, VT_UI4 },
2801 #ifdef APFS_SHOW_ALT_STREAMS
2802 { NULL, kpidIsAltStream, VT_BOOL },
2803 #endif
2804 { "Parent iNode", kpidParentINode, VT_UI8 },
2805 { "Primary Name", kpidPrimeName, VT_BSTR },
2806 { "Generation", kpidGeneration, VT_UI4 },
2807 { "Written Size", kpidBytesWritten, VT_UI8 },
2808 { "Read Size", kpidBytesRead, VT_UI8 },
2809 { "BSD Flags", kpidBsdFlags, VT_UI4 }
2810};
2811
2812
2813static const Byte kArcProps[] =
2814{
2815 kpidName,
2816 kpidId,
2817 kpidClusterSize,
2818 kpidCTime,
2819 kpidMTime,
2820 kpidComment
2821};
2822
2823IMP_IInArchive_Props_WITH_NAME
2824IMP_IInArchive_ArcProps
2825
2826
2827static void ApfsTimeToProp(UInt64 hfsTime, NWindows::NCOM::CPropVariant &prop)
2828{
2829 if (hfsTime == 0)
2830 return;
2831 FILETIME ft;
2832 UInt32 ns100;
2833 ApfsTimeToFileTime(hfsTime, ft, ns100);
2834 prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
2835}
2836
2837
2838STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
2839{
2840 COM_TRY_BEGIN
2841 NWindows::NCOM::CPropVariant prop;
2842 const CApfs *apfs = NULL;
2843 if (Vols.Size() == 1)
2844 apfs = &Vols[0].apfs;
2845 switch (propID)
2846 {
2847 case kpidPhySize:
2848 prop = (UInt64)sb.block_count << sb.block_size_Log;
2849 break;
2850 case kpidClusterSize: prop = (UInt32)(sb.block_size); break;
2851 case kpidMTime:
2852 if (apfs)
2853 ApfsTimeToProp(apfs->modified_by[0].timestamp, prop);
2854 break;
2855 case kpidCTime:
2856 if (apfs)
2857 ApfsTimeToProp(apfs->formatted_by.timestamp, prop);
2858 break;
2859 case kpidIsTree: prop = true; break;
2860 case kpidErrorFlags:
2861 {
2862 UInt32 flags = 0;
2863 if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
2864 if (flags != 0)
2865 prop = flags;
2866 break;
2867 }
2868 case kpidWarningFlags:
2869 {
2870 UInt32 flags = 0;
2871 if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature;
2872 if (flags != 0)
2873 prop = flags;
2874 break;
2875 }
2876
2877 case kpidName:
2878 {
2879 if (apfs)
2880 {
2881 UString s;
2882 AddVolInternalName_toString(s, *apfs);
2883 s += ".apfs";
2884 prop = s;
2885 }
2886 break;
2887 }
2888
2889 case kpidId:
2890 {
2891 char s[32 + 4];
2892 sb.uuid.SetHex_To_str(s);
2893 prop = s;
2894 break;
2895 }
2896
2897 case kpidComment:
2898 {
2899 UString s;
2900 {
2901 AddComment_UInt64(s, "block_size", sb.block_size);
2902
2903 FOR_VECTOR (i, Vols)
2904 {
2905 if (Vols.Size() > 1)
2906 {
2907 if (i != 0)
2908 {
2909 s += "----";
2910 s.Add_LF();
2911 }
2912 AddComment_UInt64(s, "Volume", i + 1);
2913 }
2914 Vols[i].AddComment(s);
2915 }
2916 }
2917 prop = s;
2918 break;
2919 }
2920
2921 #ifdef APFS_SHOW_ALT_STREAMS
2922 case kpidIsAltStream:
2923 prop = ThereAreAltStreams;
2924 // prop = false; // for debug
2925 break;
2926 #endif
2927 }
2928 prop.Detach(value);
2929 return S_OK;
2930 COM_TRY_END
2931}
2932
2933
2934STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
2935{
2936 *numProps = 0;
2937 return S_OK;
2938}
2939
2940
2941STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
2942{
2943 *name = NULL;
2944 *propID = 0;
2945 return S_OK;
2946}
2947
2948
2949STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)
2950{
2951 *parentType = NParentType::kDir;
2952
2953 const CRef2 &ref2 = Refs2[index];
2954 const CVol &vol = Vols[ref2.VolIndex];
2955 UInt32 parentIndex = (UInt32)(Int32)-1;
2956 *parentType = NParentType::kDir;
2957
2958 if (IsViDef(ref2.RefIndex))
2959 {
2960 const CRef &ref = vol.Refs[ref2.RefIndex];
2961 #ifdef APFS_SHOW_ALT_STREAMS
2962 if (ref.IsAltStream())
2963 *parentType = NParentType::kAltStream;
2964 #endif
2965 if (IsViDef(ref.ParentRefIndex))
2966 parentIndex = (UInt32)(ref.ParentRefIndex + vol.StartRef2Index);
2967 else if (index != vol.RootRef2Index && IsViDef(vol.RootRef2Index))
2968 parentIndex = (UInt32)vol.RootRef2Index;
2969 }
2970
2971 *parent = parentIndex;
2972 return S_OK;
2973}
2974
2975
2976STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
2977{
2978 *data = NULL;
2979 *dataSize = 0;
2980 *propType = 0;
2981 UNUSED_VAR(index);
2982 UNUSED_VAR(propID);
2983 return S_OK;
2984}
2985
2986
2987static void Utf8Name_to_InterName(const AString &src, UString &dest)
2988{
2989 ConvertUTF8ToUnicode(src, dest);
2990 NItemName::NormalizeSlashes_in_FileName_for_OsPath(dest);
2991}
2992
2993
2994static void AddNodeName(UString &s, const CNode &inode, UInt64 id)
2995{
2996 s += "node";
2997 s.Add_UInt64(id);
2998 if (!inode.PrimaryName.IsEmpty())
2999 {
3000 s += '.';
3001 UString s2;
3002 Utf8Name_to_InterName(inode.PrimaryName, s2);
3003 s += s2;
3004 }
3005}
3006
3007
3008void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const
3009{
3010 const unsigned kNumLevelsMax = (1 << 10);
3011 const unsigned kLenMax = (1 << 12);
3012 UString s;
3013 const CRef2 &ref2 = Refs2[index];
3014 const CVol &vol = Vols[ref2.VolIndex];
3015
3016 if (IsViDef(ref2.RefIndex))
3017 {
3018 const CRef &ref = vol.Refs[ref2.RefIndex];
3019 unsigned cur = ref.ItemIndex;
3020 if (IsViNotDef(cur))
3021 {
3022 if (inode)
3023 AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]);
3024 }
3025 else
3026 {
3027 for (unsigned i = 0;; i++)
3028 {
3029 if (i >= kNumLevelsMax || s.Len() > kLenMax)
3030 {
3031 s.Insert(0, UString("[LONG_PATH]"));
3032 break;
3033 }
3034 const CItem &item = vol.Items[(unsigned)cur];
3035 UString s2;
3036 Utf8Name_to_InterName(item.Name, s2);
3037 // s2 += "a\\b"; // for debug
3038 s.Insert(0, s2);
3039 cur = item.ParentItemIndex;
3040 if (IsViNotDef(cur))
3041 break;
3042 // ParentItemIndex was not set for sch items
3043 // if (item.ParentId == ROOT_DIR_INO_NUM) break;
3044 s.InsertAtFront(WCHAR_PATH_SEPARATOR);
3045 }
3046 }
3047
3048 #ifdef APFS_SHOW_ALT_STREAMS
3049 if (IsViDef(ref.AttrIndex) && inode)
3050 {
3051 s += ':';
3052 UString s2;
3053 Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2);
3054 // s2 += "a\\b"; // for debug
3055 s += s2;
3056 }
3057 #endif
3058 }
3059
3060 if (!vol.RootName.IsEmpty())
3061 {
3062 if (IsViDef(ref2.RefIndex))
3063 s.InsertAtFront(WCHAR_PATH_SEPARATOR);
3064 s.Insert(0, vol.RootName);
3065 }
3066
3067 path = s;
3068}
3069
3070
3071
3072STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
3073{
3074 COM_TRY_BEGIN
3075 NWindows::NCOM::CPropVariant prop;
3076
3077 const CRef2 &ref2 = Refs2[index];
3078 const CVol &vol = Vols[ref2.VolIndex];
3079
3080 if (IsViNotDef(ref2.RefIndex))
3081 {
3082 switch (propID)
3083 {
3084 case kpidName:
3085 case kpidPath:
3086 GetItemPath(index, NULL, prop);
3087 break;
3088 case kpidIsDir:
3089 prop = true;
3090 break;
3091 }
3092 prop.Detach(value);
3093 return S_OK;
3094 }
3095
3096 const CRef &ref = vol.Refs[ref2.RefIndex];
3097
3098 const CItem *item = NULL;
3099 if (IsViDef(ref.ItemIndex))
3100 item = &vol.Items[ref.ItemIndex];
3101
3102 const CNode *inode = NULL;
3103 if (IsViDef(ref.NodeIndex))
3104 inode = &vol.Nodes[ref.NodeIndex];
3105
3106 switch (propID)
3107 {
3108 case kpidPath:
3109 GetItemPath(index, inode, prop);
3110 break;
3111 case kpidPrimeName:
3112 {
3113 if (inode
3114 #ifdef APFS_SHOW_ALT_STREAMS
3115 && !ref.IsAltStream()
3116 #endif
3117 && !inode->PrimaryName.IsEmpty())
3118 {
3119 UString s;
3120 ConvertUTF8ToUnicode(inode->PrimaryName, s);
3121 /*
3122 // for debug:
3123 if (inode.PrimaryName != item.Name) throw 123456;
3124 */
3125 prop = s;
3126 }
3127 break;
3128 }
3129
3130 case kpidName:
3131 {
3132 UString s;
3133 #ifdef APFS_SHOW_ALT_STREAMS
3134 if (ref.IsAltStream())
3135 {
3136 // if (inode)
3137 {
3138 const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex];
3139 ConvertUTF8ToUnicode(attr.Name, s);
3140 }
3141 }
3142 else
3143 #endif
3144 {
3145 if (item)
3146 ConvertUTF8ToUnicode(item->Name, s);
3147 else if (inode)
3148 AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]);
3149 else
3150 break;
3151 }
3152 // s += "s/1bs\\2"; // for debug:
3153 prop = s;
3154 break;
3155 }
3156
3157 case kpidSymLink:
3158 if (inode)
3159 {
3160 if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex))
3161 {
3162 const CByteBuffer &buf = inode->Attrs[(unsigned)inode->SymLinkIndex].Data;
3163 if (buf.Size() != 0)
3164 {
3165 AString s;
3166 s.SetFrom_CalcLen((const char *)(const Byte *)buf, (unsigned)buf.Size());
3167 if (s.Len() == buf.Size() - 1)
3168 {
3169 UString u;
3170 ConvertUTF8ToUnicode(s, u);
3171 prop = u;
3172 }
3173 }
3174 }
3175 }
3176 break;
3177
3178 case kpidSize:
3179 if (inode)
3180 {
3181 UInt64 size;
3182 if (inode->GetSize(ref.GetAttrIndex(), size))
3183 prop = size;
3184 }
3185 break;
3186
3187 case kpidPackSize:
3188 if (inode)
3189 {
3190 UInt64 size;
3191 if (inode->GetPackSize(ref.GetAttrIndex(), size))
3192 prop = size;
3193 }
3194 break;
3195
3196 case kpidIsDir:
3197 {
3198 bool isDir = false;
3199 if (inode)
3200 isDir = inode->IsDir();
3201 else if (item)
3202 isDir = item->Val.IsFlags_Dir();
3203 prop = isDir;
3204 break;
3205 }
3206
3207 case kpidPosixAttrib:
3208 {
3209 if (inode)
3210 {
3211 UInt32 mode = inode->mode;
3212 #ifdef APFS_SHOW_ALT_STREAMS
3213 if (ref.IsAltStream())
3214 {
3215 mode &= 0666; // we disable execution
3216 mode |= MY_LIN_S_IFREG;
3217 }
3218 #endif
3219 prop = (UInt32)mode;
3220 }
3221 else if (item && !item->Val.IsFlags_Unknown())
3222 prop = (UInt32)(item->Val.flags << 12);
3223 break;
3224 }
3225
3226 case kpidCTime: if (inode) ApfsTimeToProp(inode->create_time, prop); break;
3227 case kpidMTime: if (inode) ApfsTimeToProp(inode->mod_time, prop); break;
3228 case kpidATime: if (inode) ApfsTimeToProp(inode->access_time, prop); break;
3229 case kpidChangeTime: if (inode) ApfsTimeToProp(inode->change_time, prop); break;
3230 case kpidAddTime: if (item) ApfsTimeToProp(item->Val.date_added, prop); break;
3231
3232 case kpidBytesWritten:
3233 #ifdef APFS_SHOW_ALT_STREAMS
3234 if (!ref.IsAltStream())
3235 #endif
3236 if (inode && inode->dstream_defined)
3237 prop = inode->dstream.total_bytes_written;
3238 break;
3239 case kpidBytesRead:
3240 #ifdef APFS_SHOW_ALT_STREAMS
3241 if (!ref.IsAltStream())
3242 #endif
3243 if (inode && inode->dstream_defined)
3244 prop = inode->dstream.total_bytes_read;
3245 break;
3246
3247 #ifdef APFS_SHOW_ALT_STREAMS
3248 case kpidIsAltStream:
3249 prop = ref.IsAltStream();
3250 break;
3251 #endif
3252
3253 case kpidCharacts:
3254 if (inode)
3255 {
3256 FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop);
3257 }
3258 break;
3259
3260 case kpidBsdFlags:
3261 if (inode)
3262 {
3263 FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop);
3264 }
3265 break;
3266
3267 case kpidGeneration:
3268 if (inode)
3269 prop = inode->write_generation_counter;
3270 break;
3271
3272 case kpidUserId:
3273 if (inode)
3274 prop = (UInt32)inode->owner;
3275 break;
3276
3277 case kpidGroupId:
3278 if (inode)
3279 prop = (UInt32)inode->group;
3280 break;
3281
3282 case kpidLinks:
3283 if (inode && !inode->IsDir())
3284 prop = (UInt32)inode->nlink;
3285 break;
3286
3287 case kpidINode:
3288 #ifdef APFS_SHOW_ALT_STREAMS
3289 // here we can disable iNode for alt stream.
3290 // if (!ref.IsAltStream())
3291 #endif
3292 if (IsViDef(ref.NodeIndex))
3293 prop = (UInt32)vol.NodeIDs[ref.NodeIndex];
3294 break;
3295
3296 case kpidParentINode:
3297 if (inode)
3298 prop = (UInt32)inode->parent_id;
3299 break;
3300 }
3301 prop.Detach(value);
3302 return S_OK;
3303 COM_TRY_END
3304}
3305
3306
3307UInt64 CDatabase::GetSize(const UInt32 index) const
3308{
3309 const CRef2 &ref2 = Refs2[index];
3310 const CVol &vol = Vols[ref2.VolIndex];
3311 if (IsViNotDef(ref2.RefIndex))
3312 return 0;
3313 const CRef &ref = vol.Refs[ref2.RefIndex];
3314 if (IsViNotDef(ref.NodeIndex))
3315 return 0;
3316 const CNode &inode = vol.Nodes[ref.NodeIndex];
3317 UInt64 size;
3318 if (inode.GetSize(ref.GetAttrIndex(), size))
3319 return size;
3320 return 0;
3321}
3322
3323
3324STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
3325 Int32 testMode, IArchiveExtractCallback *extractCallback)
3326{
3327 COM_TRY_BEGIN
3328 const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
3329 if (allFilesMode)
3330 numItems = Refs2.Size();
3331 if (numItems == 0)
3332 return S_OK;
3333 UInt32 i;
3334
3335 {
3336 UInt64 totalSize = 0;
3337 for (i = 0; i < numItems; i++)
3338 {
3339 const UInt32 index = allFilesMode ? i : indices[i];
3340 totalSize += GetSize(index);
3341 }
3342 RINOK(extractCallback->SetTotal(totalSize));
3343 }
3344
3345 UInt64 currentTotalSize = 0, currentItemSize = 0;
3346
3347 CLocalProgress *lps = new CLocalProgress;
3348 CMyComPtr<ICompressProgressInfo> progress = lps;
3349 lps->Init(extractCallback, false);
3350
3351 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
3352 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
3353
3354 for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
3355 {
3356 lps->InSize = currentTotalSize;
3357 lps->OutSize = currentTotalSize;
3358 RINOK(lps->SetCur());
3359
3360 const UInt32 index = allFilesMode ? i : indices[i];
3361 const CRef2 &ref2 = Refs2[index];
3362 const CVol &vol = Vols[ref2.VolIndex];
3363
3364 currentItemSize = GetSize(index);
3365
3366 CMyComPtr<ISequentialOutStream> realOutStream;
3367
3368 const Int32 askMode = testMode ?
3369 NExtract::NAskMode::kTest :
3370 NExtract::NAskMode::kExtract;
3371 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
3372
3373 if (IsViNotDef(ref2.RefIndex))
3374 {
3375 RINOK(extractCallback->PrepareOperation(askMode));
3376 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
3377 continue;
3378 }
3379
3380 const CRef &ref = vol.Refs[ref2.RefIndex];
3381 bool isDir = false;
3382 if (IsViDef(ref.NodeIndex))
3383 isDir = vol.Nodes[ref.NodeIndex].IsDir();
3384 else if (IsViDef(ref.ItemIndex))
3385 isDir =
3386 #ifdef APFS_SHOW_ALT_STREAMS
3387 !ref.IsAltStream() &&
3388 #endif
3389 vol.Items[ref.ItemIndex].Val.IsFlags_Dir();
3390
3391 if (isDir)
3392 {
3393 RINOK(extractCallback->PrepareOperation(askMode));
3394 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
3395 continue;
3396 }
3397 if (!testMode && !realOutStream)
3398 continue;
3399 RINOK(extractCallback->PrepareOperation(askMode));
3400 int opRes = NExtract::NOperationResult::kDataError;
3401
3402 CMyComPtr<ISequentialInStream> inStream;
3403 if (GetStream(index, &inStream) == S_OK && inStream)
3404 {
3405 RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
3406 opRes = NExtract::NOperationResult::kDataError;
3407 if (copyCoderSpec->TotalSize == currentItemSize)
3408 opRes = NExtract::NOperationResult::kOK;
3409 else if (copyCoderSpec->TotalSize < currentItemSize)
3410 opRes = NExtract::NOperationResult::kUnexpectedEnd;
3411 }
3412
3413 realOutStream.Release();
3414 RINOK(extractCallback->SetOperationResult(opRes));
3415 }
3416 return S_OK;
3417 COM_TRY_END
3418}
3419
3420
3421STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
3422{
3423 *numItems = Refs2.Size();
3424 return S_OK;
3425}
3426
3427
3428STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
3429{
3430 *stream = NULL;
3431
3432 const CRef2 &ref2 = Refs2[index];
3433 const CVol &vol = Vols[ref2.VolIndex];
3434 if (IsViNotDef(ref2.RefIndex))
3435 return S_FALSE;
3436
3437 const CRef &ref = vol.Refs[ref2.RefIndex];
3438 if (IsViNotDef(ref.NodeIndex))
3439 return S_FALSE;
3440 const CNode &inode = vol.Nodes[ref.NodeIndex];
3441
3442 const CRecordVector<CExtent> *extents;
3443 UInt64 rem = 0;
3444
3445 unsigned attrIndex = ref.GetAttrIndex();
3446
3447 if (IsViNotDef(attrIndex)
3448 && !inode.dstream_defined
3449 && inode.IsSymLink())
3450 {
3451 attrIndex = inode.SymLinkIndex;
3452 if (IsViNotDef(attrIndex))
3453 return S_FALSE;
3454 }
3455
3456 if (IsViDef(attrIndex))
3457 {
3458 const CAttr &attr = inode.Attrs[(unsigned)attrIndex];
3459 if (!attr.dstream_defined)
3460 {
3461 CBufInStream *streamSpec = new CBufInStream;
3462 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
3463 streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this);
3464 *stream = streamTemp.Detach();
3465 return S_OK;
3466 }
3467 const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
3468 if (idIndex == -1)
3469 return S_FALSE;
3470 extents = &vol.SmallNodes[(unsigned)idIndex].Extents;
3471 rem = attr.dstream.size;
3472 }
3473 else
3474 {
3475 if (IsViDef(ref.ItemIndex))
3476 if (vol.Items[ref.ItemIndex].Val.IsFlags_Dir())
3477 return S_FALSE;
3478 if (inode.IsDir())
3479 return S_FALSE;
3480 if (inode.dstream_defined)
3481 rem = inode.dstream.size;
3482 extents = &inode.Extents;
3483 }
3484 return GetStream2(_stream, extents, rem, stream);
3485}
3486
3487
3488
3489HRESULT CDatabase::GetStream2(
3490 IInStream *apfsInStream,
3491 const CRecordVector<CExtent> *extents, UInt64 rem,
3492 ISequentialInStream **stream)
3493{
3494 CExtentsStream *extentStreamSpec = new CExtentsStream();
3495 CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
3496
3497 UInt64 virt = 0;
3498 FOR_VECTOR (i, *extents)
3499 {
3500 const CExtent &e = (*extents)[i];
3501 if (virt != e.logical_offset)
3502 return S_FALSE;
3503 const UInt64 len = EXTENT_GET_LEN(e.len_and_flags);
3504 if (len == 0)
3505 {
3506 return S_FALSE;
3507 // continue;
3508 }
3509 if (rem == 0)
3510 return S_FALSE;
3511 UInt64 cur = len;
3512 if (cur > rem)
3513 cur = rem;
3514 CSeekExtent se;
3515 se.Phy = (UInt64)e.phys_block_num << sb.block_size_Log;
3516 se.Virt = virt;
3517 virt += cur;
3518 rem -= cur;
3519 extentStreamSpec->Extents.Add(se);
3520 if (rem == 0)
3521 if (i != extents->Size() - 1)
3522 return S_FALSE;
3523 }
3524
3525 if (rem != 0)
3526 return S_FALSE;
3527
3528 CSeekExtent se;
3529 se.Phy = 0;
3530 se.Virt = virt;
3531 extentStreamSpec->Extents.Add(se);
3532 extentStreamSpec->Stream = apfsInStream;
3533 extentStreamSpec->Init();
3534 *stream = extentStream.Detach();
3535 return S_OK;
3536}
3537
3538
3539REGISTER_ARC_I(
3540 "APFS", "apfs img", NULL, 0xc3,
3541 k_Signature,
3542 k_SignatureOffset,
3543 0,
3544 IsArc_APFS)
3545
3546}}
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp
index 0bea8b4..6cd72bb 100644
--- a/CPP/7zip/Archive/ArHandler.cpp
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -322,8 +322,8 @@ static const Byte kProps[] =
322 kpidSize, 322 kpidSize,
323 kpidMTime, 323 kpidMTime,
324 kpidPosixAttrib, 324 kpidPosixAttrib,
325 kpidUser, 325 kpidUserId,
326 kpidGroup 326 kpidGroupId
327}; 327};
328 328
329IMP_IInArchive_Props 329IMP_IInArchive_Props
@@ -734,15 +734,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
734 case kpidMTime: 734 case kpidMTime:
735 { 735 {
736 if (item.MTime != 0) 736 if (item.MTime != 0)
737 { 737 PropVariant_SetFrom_UnixTime(prop, item.MTime);
738 FILETIME fileTime;
739 NTime::UnixTimeToFileTime(item.MTime, fileTime);
740 prop = fileTime;
741 }
742 break; 738 break;
743 } 739 }
744 case kpidUser: if (item.User != 0) prop = item.User; break; 740 case kpidUserId: if (item.User != 0) prop = item.User; break;
745 case kpidGroup: if (item.Group != 0) prop = item.Group; break; 741 case kpidGroupId: if (item.Group != 0) prop = item.Group; break;
746 case kpidPosixAttrib: 742 case kpidPosixAttrib:
747 if (item.TextFileIndex < 0) 743 if (item.TextFileIndex < 0)
748 prop = item.Mode; 744 prop = item.Mode;
diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp
index 6549b3d..8a441bc 100644
--- a/CPP/7zip/Archive/ArchiveExports.cpp
+++ b/CPP/7zip/Archive/ArchiveExports.cpp
@@ -115,6 +115,7 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value
115 case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break; 115 case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break;
116 case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break; 116 case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break;
117 case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break; 117 case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break;
118 case NArchive::NHandlerPropID::kTimeFlags: prop = (UInt32)arc.TimeFlags; break;
118 case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break; 119 case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break;
119 // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break; 120 // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break;
120 121
diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp
index 0e353dc..125b9c2 100644
--- a/CPP/7zip/Archive/ArjHandler.cpp
+++ b/CPP/7zip/Archive/ArjHandler.cpp
@@ -682,15 +682,7 @@ static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
682{ 682{
683 if (dosTime == 0) 683 if (dosTime == 0)
684 return; 684 return;
685 FILETIME localFileTime, utc; 685 PropVariant_SetFrom_DosTime(prop, dosTime);
686 if (NTime::DosTimeToFileTime(dosTime, localFileTime))
687 {
688 if (!LocalFileTimeToFileTime(&localFileTime, &utc))
689 utc.dwHighDateTime = utc.dwLowDateTime = 0;
690 }
691 else
692 utc.dwHighDateTime = utc.dwLowDateTime = 0;
693 prop = utc;
694} 686}
695 687
696static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) 688static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)
diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp
index b0c2f75..c89a53c 100644
--- a/CPP/7zip/Archive/Bz2Handler.cpp
+++ b/CPP/7zip/Archive/Bz2Handler.cpp
@@ -305,29 +305,91 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
305} 305}
306 306
307 307
308/*
309static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
310{
311 return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
312}
313
314static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
315{
316 return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
317}
318
319static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
320 const UInt64 *unpackSize,
321 const UInt64 *numBlocks)
322{
323 NCOM::CPropVariant sizeProp;
324 if (unpackSize)
325 {
326 sizeProp = *unpackSize;
327 RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
328 RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
329 }
330
331 if (unpackSize)
332 {
333 RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
334 }
335 if (numBlocks)
336 {
337 NCOM::CPropVariant prop;
338 prop = *numBlocks;
339 RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop));
340 }
341 return S_OK;
342}
343*/
308 344
309static HRESULT UpdateArchive( 345static HRESULT UpdateArchive(
310 UInt64 unpackSize, 346 UInt64 unpackSize,
311 ISequentialOutStream *outStream, 347 ISequentialOutStream *outStream,
312 const CProps &props, 348 const CProps &props,
313 IArchiveUpdateCallback *updateCallback) 349 IArchiveUpdateCallback *updateCallback
350 // , ArchiveUpdateCallbackArcProp *reportArcProp
351 )
314{ 352{
315 RINOK(updateCallback->SetTotal(unpackSize)); 353 {
316 CMyComPtr<ISequentialInStream> fileInStream; 354 CMyComPtr<ISequentialInStream> fileInStream;
317 RINOK(updateCallback->GetStream(0, &fileInStream)); 355 RINOK(updateCallback->GetStream(0, &fileInStream));
318 CLocalProgress *localProgressSpec = new CLocalProgress; 356 if (!fileInStream)
319 CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec; 357 return S_FALSE;
320 localProgressSpec->Init(updateCallback, true); 358 {
321 NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; 359 CMyComPtr<IStreamGetSize> streamGetSize;
322 CMyComPtr<ICompressCoder> encoder = encoderSpec; 360 fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
323 RINOK(props.SetCoderProps(encoderSpec, NULL)); 361 if (streamGetSize)
324 RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); 362 {
363 UInt64 size;
364 if (streamGetSize->GetSize(&size) == S_OK)
365 unpackSize = size;
366 }
367 }
368 RINOK(updateCallback->SetTotal(unpackSize));
369 CLocalProgress *localProgressSpec = new CLocalProgress;
370 CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
371 localProgressSpec->Init(updateCallback, true);
372 {
373 NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
374 CMyComPtr<ICompressCoder> encoder = encoderSpec;
375 RINOK(props.SetCoderProps(encoderSpec, NULL));
376 RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
377 /*
378 if (reportArcProp)
379 {
380 unpackSize = encoderSpec->GetInProcessedSize();
381 RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks));
382 }
383 */
384 }
385 }
325 return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); 386 return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
326} 387}
327 388
328STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) 389STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
329{ 390{
330 *type = NFileTimeType::kUnix; 391 *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
392 // *timeType = NFileTimeType::kUnix;
331 return S_OK; 393 return S_OK;
332} 394}
333 395
@@ -345,6 +407,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
345 return E_FAIL; 407 return E_FAIL;
346 RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); 408 RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
347 409
410 /*
411 CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
412 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
413 */
414
348 if (IntToBool(newProps)) 415 if (IntToBool(newProps))
349 { 416 {
350 { 417 {
@@ -396,6 +463,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
396 463
397 return NCompress::CopyStream(_stream, outStream, progress); 464 return NCompress::CopyStream(_stream, outStream, progress);
398 465
466 // return ReportArcProps(reportArcProp, NULL, NULL);
467
399 COM_TRY_END 468 COM_TRY_END
400} 469}
401 470
@@ -410,7 +479,8 @@ REGISTER_ARC_IO(
410 "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, 479 "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
411 k_Signature, 480 k_Signature,
412 0, 481 0,
413 NArcInfoFlags::kKeepName, 482 NArcInfoFlags::kKeepName
414 IsArc_BZip2) 483 , 0
484 , IsArc_BZip2)
415 485
416}} 486}}
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
index fafd7aa..804c921 100644
--- 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
295 295
296 case kpidMTime: 296 case kpidMTime:
297 { 297 {
298 FILETIME localFileTime, utcFileTime; 298 PropVariant_SetFrom_DosTime(prop, item.Time);
299 if (NTime::DosTimeToFileTime(item.Time, localFileTime))
300 {
301 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
302 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
303 }
304 else
305 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
306 prop = utcFileTime;
307 break; 299 break;
308 } 300 }
309 301
diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h
index f7b75d8..7cba0c7 100644
--- a/CPP/7zip/Archive/Chm/ChmIn.h
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -84,6 +84,11 @@ struct CResetTable
84 // unsigned BlockSizeBits; 84 // unsigned BlockSizeBits;
85 CRecordVector<UInt64> ResetOffsets; 85 CRecordVector<UInt64> ResetOffsets;
86 86
87 CResetTable():
88 UncompressedSize(0),
89 CompressedSize(0)
90 {}
91
87 bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const 92 bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
88 { 93 {
89 if (blockIndex >= ResetOffsets.Size()) 94 if (blockIndex >= ResetOffsets.Size())
@@ -118,6 +123,12 @@ struct CLzxInfo
118 123
119 CResetTable ResetTable; 124 CResetTable ResetTable;
120 125
126 CLzxInfo():
127 Version(0),
128 ResetIntervalBits(0),
129 CacheSize(0)
130 {}
131
121 unsigned GetNumDictBits() const 132 unsigned GetNumDictBits() const
122 { 133 {
123 if (Version == 2 || Version == 3) 134 if (Version == 2 || Version == 3)
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 8901220..1b9a93e 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -240,34 +240,42 @@ void CSingleMethodProps::Init()
240} 240}
241 241
242 242
243HRESULT CSingleMethodProps::SetProperty(const wchar_t *name2, const PROPVARIANT &value)
244{
245 // processed = false;
246 UString name = name2;
247 name.MakeLower_Ascii();
248 if (name.IsEmpty())
249 return E_INVALIDARG;
250 if (name.IsPrefixedBy_Ascii_NoCase("x"))
251 {
252 UInt32 a = 9;
253 RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
254 _level = a;
255 AddProp_Level(a);
256 // processed = true;
257 return S_OK;
258 }
259 {
260 HRESULT hres;
261 if (SetCommonProperty(name, value, hres))
262 {
263 // processed = true;
264 return S_OK;
265 }
266 }
267 RINOK(ParseMethodFromPROPVARIANT(name, value));
268 return S_OK;
269}
270
271
243HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) 272HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
244{ 273{
245 Init(); 274 Init();
246 275
247 for (UInt32 i = 0; i < numProps; i++) 276 for (UInt32 i = 0; i < numProps; i++)
248 { 277 {
249 UString name = names[i]; 278 RINOK(SetProperty(names[i], values[i]));
250 name.MakeLower_Ascii();
251 if (name.IsEmpty())
252 return E_INVALIDARG;
253 const PROPVARIANT &value = values[i];
254 if (name[0] == L'x')
255 {
256 UInt32 a = 9;
257 RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
258 _level = a;
259 AddProp_Level(a);
260 continue;
261 }
262 {
263 HRESULT hres;
264 if (SetCommonProperty(name, value, hres))
265 {
266 RINOK(hres)
267 continue;
268 }
269 }
270 RINOK(ParseMethodFromPROPVARIANT(names[i], value));
271 } 279 }
272 280
273 return S_OK; 281 return S_OK;
@@ -275,4 +283,29 @@ HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PR
275 283
276#endif 284#endif
277 285
286
287static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
288{
289 RINOK(PROPVARIANT_to_bool(prop, dest.Val));
290 dest.Def = true;
291 return S_OK;
292}
293
294HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed)
295{
296 processed = true;
297 if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); }
298 if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); }
299 if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); }
300 if (name.IsPrefixedBy_Ascii_NoCase("tp"))
301 {
302 UInt32 v = 0;
303 RINOK(ParsePropToUInt32(name.Ptr(2), prop, v));
304 Prec = v;
305 return S_OK;
306 }
307 processed = false;
308 return S_OK;
309}
310
278} 311}
diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h
index b3d07e9..41ee189 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -16,6 +16,7 @@ class CCommonMethodProps
16protected: 16protected:
17 void InitCommon() 17 void InitCommon()
18 { 18 {
19 // _Write_MTime = true;
19 #ifndef _7ZIP_ST 20 #ifndef _7ZIP_ST
20 _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); 21 _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
21 _numThreads_WasForced = false; 22 _numThreads_WasForced = false;
@@ -118,11 +119,36 @@ public:
118 CSingleMethodProps() { InitSingle(); } 119 CSingleMethodProps() { InitSingle(); }
119 120
120 int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } 121 int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
122 HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values);
121 HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); 123 HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
122}; 124};
123 125
124#endif 126#endif
125 127
128struct CHandlerTimeOptions
129{
130 CBoolPair Write_MTime;
131 CBoolPair Write_ATime;
132 CBoolPair Write_CTime;
133 UInt32 Prec;
134
135 void Init()
136 {
137 Write_MTime.Init();
138 Write_MTime.Val = true;
139 Write_ATime.Init();
140 Write_CTime.Init();
141 Prec = (UInt32)(Int32)-1;
142 }
143
144 CHandlerTimeOptions()
145 {
146 Init();
147 }
148
149 HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed);
150};
151
126} 152}
127 153
128#endif 154#endif
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
index 905a863..8caf1d1 100644
--- 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
79} 79}
80 80
81 81
82void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *name, unsigned len)
83{
84 for (unsigned i = 0; i < len; i++)
85 {
86 wchar_t c = name[i];
87 if (c == L'/')
88 c = L'_';
89 #if WCHAR_PATH_SEPARATOR != L'/'
90 else if (c == L'\\')
91 c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
92 #endif
93 else
94 continue;
95 name[i] = c;
96 }
97}
98
99void NormalizeSlashes_in_FileName_for_OsPath(UString &name)
100{
101 NormalizeSlashes_in_FileName_for_OsPath(name.GetBuf(), name.Len());
102}
103
104
82bool HasTailSlash(const AString &name, UINT 105bool HasTailSlash(const AString &name, UINT
83 #if defined(_WIN32) && !defined(UNDER_CE) 106 #if defined(_WIN32) && !defined(UNDER_CE)
84 codePage 107 codePage
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h
index 6a4d6c7..3f5f4e8 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.h
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -14,6 +14,8 @@ UString GetOsPath(const UString &name);
14UString GetOsPath_Remove_TailSlash(const UString &name); 14UString GetOsPath_Remove_TailSlash(const UString &name);
15 15
16void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); 16void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false);
17void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len);
18void NormalizeSlashes_in_FileName_for_OsPath(UString &name);
17 19
18bool HasTailSlash(const AString &name, UINT codePage); 20bool HasTailSlash(const AString &name, UINT codePage);
19 21
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
index ffdab16..b7e7564 100644
--- 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
652 case kpidMTime: 652 case kpidMTime:
653 { 653 {
654 if (item.MTime != 0) 654 if (item.MTime != 0)
655 { 655 PropVariant_SetFrom_UnixTime(prop, item.MTime);
656 FILETIME utc;
657 NTime::UnixTimeToFileTime(item.MTime, utc);
658 prop = utc;
659 }
660 break; 656 break;
661 } 657 }
662 case kpidPosixAttrib: prop = item.Mode; break; 658 case kpidPosixAttrib: prop = item.Mode; break;
diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp
index 967a7cb..1f71486 100644
--- a/CPP/7zip/Archive/DllExports2.cpp
+++ b/CPP/7zip/Archive/DllExports2.cpp
@@ -125,6 +125,24 @@ STDAPI SetCaseSensitive(Int32 caseSensitive)
125 return S_OK; 125 return S_OK;
126} 126}
127 127
128/*
129UInt32 g_ClientVersion;
130STDAPI SetClientVersion(UInt32 version);
131STDAPI SetClientVersion(UInt32 version)
132{
133 g_ClientVersion = version;
134 return S_OK;
135}
136*/
137
138/*
139STDAPI SetProperty(Int32 id, const PROPVARIANT *value);
140STDAPI SetProperty(Int32 id, const PROPVARIANT *value)
141{
142 return S_OK;
143}
144*/
145
128#ifdef EXTERNAL_CODECS 146#ifdef EXTERNAL_CODECS
129 147
130CExternalCodecs g_ExternalCodecs; 148CExternalCodecs g_ExternalCodecs;
diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp
index 6c095d9..01e12ed 100644
--- a/CPP/7zip/Archive/ExtHandler.cpp
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -343,6 +343,8 @@ struct CHeader
343 bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; } 343 bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; }
344 bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; } 344 bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; }
345 345
346 UInt64 GetPhySize() const { return NumBlocks << BlockBits; }
347
346 bool Parse(const Byte *p); 348 bool Parse(const Byte *p);
347}; 349};
348 350
@@ -638,7 +640,7 @@ struct CNode
638 CExtTime MTime; 640 CExtTime MTime;
639 CExtTime ATime; 641 CExtTime ATime;
640 CExtTime CTime; 642 CExtTime CTime;
641 // CExtTime InodeChangeTime; 643 CExtTime ChangeTime;
642 // CExtTime DTime; 644 // CExtTime DTime;
643 645
644 UInt64 NumBlocks; 646 UInt64 NumBlocks;
@@ -674,14 +676,14 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
674 ATime.Extra = 0; 676 ATime.Extra = 0;
675 CTime.Extra = 0; 677 CTime.Extra = 0;
676 CTime.Val = 0; 678 CTime.Val = 0;
677 // InodeChangeTime.Extra = 0; 679 ChangeTime.Extra = 0;
678 // DTime.Extra = 0; 680 // DTime.Extra = 0;
679 681
680 LE_16 (0x00, Mode); 682 LE_16 (0x00, Mode);
681 LE_16 (0x02, Uid); 683 LE_16 (0x02, Uid);
682 LE_32 (0x04, FileSize); 684 LE_32 (0x04, FileSize);
683 LE_32 (0x08, ATime.Val); 685 LE_32 (0x08, ATime.Val);
684 // LE_32 (0x0C, InodeChangeTime.Val); 686 LE_32 (0x0C, ChangeTime.Val);
685 LE_32 (0x10, MTime.Val); 687 LE_32 (0x10, MTime.Val);
686 // LE_32 (0x14, DTime.Val); 688 // LE_32 (0x14, DTime.Val);
687 LE_16 (0x18, Gid); 689 LE_16 (0x18, Gid);
@@ -742,7 +744,7 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
742 { 744 {
743 // UInt16 checksumUpper; 745 // UInt16 checksumUpper;
744 // LE_16 (0x82, checksumUpper); 746 // LE_16 (0x82, checksumUpper);
745 // LE_32 (0x84, InodeChangeTime.Extra); 747 LE_32 (0x84, ChangeTime.Extra);
746 LE_32 (0x88, MTime.Extra); 748 LE_32 (0x88, MTime.Extra);
747 LE_32 (0x8C, ATime.Extra); 749 LE_32 (0x8C, ATime.Extra);
748 LE_32 (0x90, CTime.Val); 750 LE_32 (0x90, CTime.Val);
@@ -1148,7 +1150,7 @@ HRESULT CHandler::Open2(IInStream *inStream)
1148 } 1150 }
1149 1151
1150 _isArc = true; 1152 _isArc = true;
1151 _phySize = _h.NumBlocks << _h.BlockBits; 1153 _phySize = _h.GetPhySize();
1152 1154
1153 if (_openCallback) 1155 if (_openCallback)
1154 { 1156 {
@@ -1744,8 +1746,8 @@ static const UInt32 kProps[] =
1744 kpidLinks, 1746 kpidLinks,
1745 kpidSymLink, 1747 kpidSymLink,
1746 kpidCharacts, 1748 kpidCharacts,
1747 kpidUser, 1749 kpidUserId,
1748 kpidGroup 1750 kpidGroupId
1749}; 1751};
1750 1752
1751 1753
@@ -1792,11 +1794,7 @@ static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVa
1792static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop) 1794static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop)
1793{ 1795{
1794 if (val != 0) 1796 if (val != 0)
1795 { 1797 PropVariant_SetFrom_UnixTime(prop, val);
1796 FILETIME ft;
1797 NTime::UnixTimeToFileTime(val, ft);
1798 prop = ft;
1799 }
1800} 1798}
1801 1799
1802STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 1800STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
@@ -1988,15 +1986,19 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
1988 return; 1986 return;
1989 1987
1990 FILETIME ft; 1988 FILETIME ft;
1989 unsigned low100ns = 0;
1991 // if (t.Extra != 0) 1990 // if (t.Extra != 0)
1992 { 1991 {
1993 // 1901-2446 : 1992 // 1901-2446 :
1994 Int64 v = (Int64)(Int32)t.Val; 1993 Int64 v = (Int64)(Int32)t.Val;
1995 v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp 1994 v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp
1996 UInt64 ft64 = NTime::UnixTime64ToFileTime64(v); 1995 UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v);
1997 const UInt32 ns = (t.Extra >> 2); 1996 const UInt32 ns = (t.Extra >> 2);
1998 if (ns < 1000000000) 1997 if (ns < 1000000000)
1998 {
1999 ft64 += ns / 100; 1999 ft64 += ns / 100;
2000 low100ns = (unsigned)(ns % 100);
2001 }
2000 ft.dwLowDateTime = (DWORD)ft64; 2002 ft.dwLowDateTime = (DWORD)ft64;
2001 ft.dwHighDateTime = (DWORD)(ft64 >> 32); 2003 ft.dwHighDateTime = (DWORD)(ft64 >> 32);
2002 } 2004 }
@@ -2011,7 +2013,7 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
2011 // NTime::UnixTimeToFileTime(t.Val, ft); // for 2013 // NTime::UnixTimeToFileTime(t.Val, ft); // for
2012 } 2014 }
2013 */ 2015 */
2014 prop = ft; 2016 prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns);
2015} 2017}
2016 2018
2017 2019
@@ -2103,10 +2105,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
2103 case kpidCTime: ExtTimeToProp(node.CTime, prop); break; 2105 case kpidCTime: ExtTimeToProp(node.CTime, prop); break;
2104 case kpidATime: ExtTimeToProp(node.ATime, prop); break; 2106 case kpidATime: ExtTimeToProp(node.ATime, prop); break;
2105 // case kpidDTime: ExtTimeToProp(node.DTime, prop); break; 2107 // case kpidDTime: ExtTimeToProp(node.DTime, prop); break;
2106 // case kpidChangeTime: ExtTimeToProp(node.InodeChangeTime, prop); break; 2108 case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break;
2107 2109 case kpidUserId: prop = (UInt32)node.Uid; break;
2108 case kpidUser: prop = (UInt32)node.Uid; break; 2110 case kpidGroupId: prop = (UInt32)node.Gid; break;
2109 case kpidGroup: prop = (UInt32)node.Gid; break;
2110 case kpidLinks: prop = node.NumLinks; break; 2111 case kpidLinks: prop = node.NumLinks; break;
2111 case kpidINode: prop = (UInt32)item.Node; break; 2112 case kpidINode: prop = (UInt32)item.Node; break;
2112 case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break; 2113 case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break;
@@ -2827,17 +2828,29 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
2827} 2828}
2828 2829
2829 2830
2830API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size) 2831API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
2832API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize)
2831{ 2833{
2834 if (phySize)
2835 *phySize = 0;
2832 if (size < kHeaderSize) 2836 if (size < kHeaderSize)
2833 return k_IsArc_Res_NEED_MORE; 2837 return k_IsArc_Res_NEED_MORE;
2834 CHeader h; 2838 CHeader h;
2835 if (!h.Parse(p + kHeaderDataOffset)) 2839 if (!h.Parse(p + kHeaderDataOffset))
2836 return k_IsArc_Res_NO; 2840 return k_IsArc_Res_NO;
2841 if (phySize)
2842 *phySize = h.GetPhySize();
2837 return k_IsArc_Res_YES; 2843 return k_IsArc_Res_YES;
2838} 2844}
2845
2846
2847API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
2848API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size)
2849{
2850 return IsArc_Ext_PhySize(p, size, NULL);
2839} 2851}
2840 2852
2853
2841static const Byte k_Signature[] = { 0x53, 0xEF }; 2854static const Byte k_Signature[] = { 0x53, 0xEF };
2842 2855
2843REGISTER_ARC_I( 2856REGISTER_ARC_I(
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index 1cbc850..826b4fd 100644
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -111,14 +111,14 @@ static int GetLog(UInt32 num)
111 111
112static const UInt32 kHeaderSize = 512; 112static const UInt32 kHeaderSize = 512;
113 113
114API_FUNC_static_IsArc IsArc_Fat(const Byte *p, size_t size) 114API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
115API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
115{ 116{
116 if (size < kHeaderSize) 117 if (size < kHeaderSize)
117 return k_IsArc_Res_NEED_MORE; 118 return k_IsArc_Res_NEED_MORE;
118 CHeader h; 119 CHeader h;
119 return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO; 120 return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO;
120} 121}
121}
122 122
123bool CHeader::Parse(const Byte *p) 123bool CHeader::Parse(const Byte *p)
124{ 124{
@@ -846,17 +846,18 @@ static const CStatProp kArcProps[] =
846IMP_IInArchive_Props 846IMP_IInArchive_Props
847IMP_IInArchive_ArcProps_WITH_NAME 847IMP_IInArchive_ArcProps_WITH_NAME
848 848
849
849static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop) 850static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
850{ 851{
851 FILETIME localFileTime, utc; 852 FILETIME localFileTime, utc;
852 if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime)) 853 if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
853 if (LocalFileTimeToFileTime(&localFileTime, &utc)) 854 if (LocalFileTimeToFileTime(&localFileTime, &utc))
854 { 855 {
855 UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; 856 UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
856 t64 += ms10 * 100000; 857 t64 += ms10 * 100000;
857 utc.dwLowDateTime = (DWORD)t64; 858 utc.dwLowDateTime = (DWORD)t64;
858 utc.dwHighDateTime = (DWORD)(t64 >> 32); 859 utc.dwHighDateTime = (DWORD)(t64 >> 32);
859 prop = utc; 860 prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2);
860 } 861 }
861} 862}
862 863
@@ -892,7 +893,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
892 case kpidPhySize: prop = PhySize; break; 893 case kpidPhySize: prop = PhySize; break;
893 case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; 894 case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
894 case kpidHeadersSize: prop = GetHeadersSize(); break; 895 case kpidHeadersSize: prop = GetHeadersSize(); break;
895 case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break; 896 case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break;
896 case kpidShortComment: 897 case kpidShortComment:
897 case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; 898 case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
898 case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; 899 case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
@@ -920,9 +921,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
920 case kpidPath: prop = GetItemPath(index); break; 921 case kpidPath: prop = GetItemPath(index); break;
921 case kpidShortName: prop = item.GetShortName(); break; 922 case kpidShortName: prop = item.GetShortName(); break;
922 case kpidIsDir: prop = item.IsDir(); break; 923 case kpidIsDir: prop = item.IsDir(); break;
923 case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break; 924 case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
924 case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; 925 case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
925 case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break; 926 case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break;
926 case kpidAttrib: prop = (UInt32)item.Attrib; break; 927 case kpidAttrib: prop = (UInt32)item.Attrib; break;
927 case kpidSize: if (!item.IsDir()) prop = item.Size; break; 928 case kpidSize: if (!item.IsDir()) prop = item.Size; break;
928 case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; 929 case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp
index 2b3a673..0d2caa3 100644
--- a/CPP/7zip/Archive/GptHandler.cpp
+++ b/CPP/7zip/Archive/GptHandler.cpp
@@ -23,6 +23,11 @@
23using namespace NWindows; 23using namespace NWindows;
24 24
25namespace NArchive { 25namespace NArchive {
26
27namespace NFat {
28API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
29}
30
26namespace NGpt { 31namespace NGpt {
27 32
28#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 } 33#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }
@@ -51,6 +56,7 @@ struct CPartition
51 UInt64 FirstLba; 56 UInt64 FirstLba;
52 UInt64 LastLba; 57 UInt64 LastLba;
53 UInt64 Flags; 58 UInt64 Flags;
59 const char *Ext; // detected later
54 Byte Name[kNameLen * 2]; 60 Byte Name[kNameLen * 2];
55 61
56 bool IsUnused() const 62 bool IsUnused() const
@@ -73,6 +79,7 @@ struct CPartition
73 LastLba = Get64(p + 40); 79 LastLba = Get64(p + 40);
74 Flags = Get64(p + 48); 80 Flags = Get64(p + 48);
75 memcpy(Name, p + 56, kNameLen * 2); 81 memcpy(Name, p + 56, kNameLen * 2);
82 Ext = NULL;
76 } 83 }
77}; 84};
78 85
@@ -252,6 +259,28 @@ HRESULT CHandler::Open2(IInStream *stream)
252 return S_OK; 259 return S_OK;
253} 260}
254 261
262
263
264static const unsigned k_Ntfs_Fat_HeaderSize = 512;
265
266static const Byte k_NtfsSignature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
267
268static bool IsNtfs(const Byte *p)
269{
270 if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
271 return false;
272 if (memcmp(p + 3, k_NtfsSignature, ARRAY_SIZE(k_NtfsSignature)) != 0)
273 return false;
274 switch (p[0])
275 {
276 case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
277 case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
278 default: return false;
279 }
280 return true;
281}
282
283
255STDMETHODIMP CHandler::Open(IInStream *stream, 284STDMETHODIMP CHandler::Open(IInStream *stream,
256 const UInt64 * /* maxCheckStartPosition */, 285 const UInt64 * /* maxCheckStartPosition */,
257 IArchiveOpenCallback * /* openArchiveCallback */) 286 IArchiveOpenCallback * /* openArchiveCallback */)
@@ -260,6 +289,42 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
260 Close(); 289 Close();
261 RINOK(Open2(stream)); 290 RINOK(Open2(stream));
262 _stream = stream; 291 _stream = stream;
292
293 FOR_VECTOR (fileIndex, _items)
294 {
295 CPartition &item = _items[fileIndex];
296 const int typeIndex = FindPartType(item.Type);
297 if (typeIndex < 0)
298 continue;
299 const CPartType &t = kPartTypes[(unsigned)typeIndex];
300 if (t.Ext)
301 {
302 item.Ext = t.Ext;
303 continue;
304 }
305 if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows"))
306 {
307 CMyComPtr<ISequentialInStream> inStream;
308 if (GetStream(fileIndex, &inStream) == S_OK && inStream)
309 {
310 Byte temp[k_Ntfs_Fat_HeaderSize];
311 if (ReadStream_FAIL(inStream, temp, k_Ntfs_Fat_HeaderSize) == S_OK)
312 {
313 if (IsNtfs(temp))
314 {
315 item.Ext = "ntfs";
316 continue;
317 }
318 if (NFat::IsArc_Fat(temp, k_Ntfs_Fat_HeaderSize) == k_IsArc_Res_YES)
319 {
320 item.Ext = "fat";
321 continue;
322 }
323 }
324 }
325 }
326 }
327
263 return S_OK; 328 return S_OK;
264 COM_TRY_END 329 COM_TRY_END
265} 330}
@@ -355,13 +420,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
355 } 420 }
356 { 421 {
357 s += '.'; 422 s += '.';
358 const char *ext = NULL; 423 s += (item.Ext ? item.Ext : "img");
359 int typeIndex = FindPartType(item.Type);
360 if (typeIndex >= 0)
361 ext = kPartTypes[(unsigned)typeIndex].Ext;
362 if (!ext)
363 ext = "img";
364 s += ext;
365 } 424 }
366 prop = s; 425 prop = s;
367 break; 426 break;
@@ -375,7 +434,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
375 { 434 {
376 char s[48]; 435 char s[48];
377 const char *res; 436 const char *res;
378 int typeIndex = FindPartType(item.Type); 437 const int typeIndex = FindPartType(item.Type);
379 if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type) 438 if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
380 res = kPartTypes[(unsigned)typeIndex].Type; 439 res = kPartTypes[(unsigned)typeIndex].Type;
381 else 440 else
diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp
index 0054840..35e642e 100644
--- a/CPP/7zip/Archive/GzHandler.cpp
+++ b/CPP/7zip/Archive/GzHandler.cpp
@@ -475,6 +475,7 @@ class CHandler:
475 NDecoder::CCOMCoder *_decoderSpec; 475 NDecoder::CCOMCoder *_decoderSpec;
476 476
477 CSingleMethodProps _props; 477 CSingleMethodProps _props;
478 CHandlerTimeOptions _timeOptions;
478 479
479public: 480public:
480 MY_UNKNOWN_IMP4( 481 MY_UNKNOWN_IMP4(
@@ -487,8 +488,15 @@ public:
487 STDMETHOD(OpenSeq)(ISequentialInStream *stream); 488 STDMETHOD(OpenSeq)(ISequentialInStream *stream);
488 STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); 489 STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
489 490
490 CHandler() 491 CHandler():
492 _isArc(false),
493 _decoderSpec(NULL)
494 {}
495
496 void CreateDecoder()
491 { 497 {
498 if (_decoder)
499 return;
492 _decoderSpec = new NDecoder::CCOMCoder; 500 _decoderSpec = new NDecoder::CCOMCoder;
493 _decoder = _decoderSpec; 501 _decoder = _decoderSpec;
494 } 502 }
@@ -528,7 +536,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
528 case kpidErrorFlags: 536 case kpidErrorFlags:
529 { 537 {
530 UInt32 v = 0; 538 UInt32 v = 0;
531 if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; 539 if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
532 if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; 540 if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
533 if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; 541 if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
534 prop = v; 542 prop = v;
@@ -567,12 +575,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
567 break; 575 break;
568 // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break; 576 // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
569 case kpidMTime: 577 case kpidMTime:
578 // gzip specification: MTIME = 0 means no time stamp is available.
570 if (_item.Time != 0) 579 if (_item.Time != 0)
571 { 580 PropVariant_SetFrom_UnixTime(prop, _item.Time);
572 FILETIME utc; 581 break;
573 NTime::UnixTimeToFileTime(_item.Time, utc); 582 case kpidTimeType:
574 prop = utc; 583 if (_item.Time != 0)
575 } 584 prop = (UInt32)NFileTimeType::kUnix;
576 break; 585 break;
577 case kpidSize: 586 case kpidSize:
578 { 587 {
@@ -644,6 +653,7 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
644 try 653 try
645 { 654 {
646 Close(); 655 Close();
656 CreateDecoder();
647 _decoderSpec->SetInStream(stream); 657 _decoderSpec->SetInStream(stream);
648 _decoderSpec->InitInStream(true); 658 _decoderSpec->InitInStream(true);
649 RINOK(_item.ReadHeader(_decoderSpec)); 659 RINOK(_item.ReadHeader(_decoderSpec));
@@ -672,7 +682,8 @@ STDMETHODIMP CHandler::Close()
672 _headerSize = 0; 682 _headerSize = 0;
673 683
674 _stream.Release(); 684 _stream.Release();
675 _decoderSpec->ReleaseInStream(); 685 if (_decoder)
686 _decoderSpec->ReleaseInStream();
676 return S_OK; 687 return S_OK;
677} 688}
678 689
@@ -699,6 +710,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
699 710
700 extractCallback->PrepareOperation(askMode); 711 extractCallback->PrepareOperation(askMode);
701 712
713 CreateDecoder();
714
702 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; 715 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
703 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); 716 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
704 outStreamSpec->SetStream(realOutStream); 717 outStreamSpec->SetStream(realOutStream);
@@ -873,21 +886,99 @@ static const Byte kHostOS =
873 NHostOS::kUnix; 886 NHostOS::kUnix;
874 #endif 887 #endif
875 888
889
890/*
891static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
892{
893 return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
894}
895
896static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
897{
898 return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
899}
900
901static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
902 const CItem &item,
903 bool needTime,
904 bool needCrc,
905 const UInt64 *unpackSize)
906{
907 NCOM::CPropVariant timeProp;
908 NCOM::CPropVariant sizeProp;
909 if (needTime)
910 {
911 FILETIME ft;
912 NTime::UnixTimeToFileTime(item.Time, ft);
913 timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
914 }
915 if (unpackSize)
916 {
917 sizeProp = *unpackSize;
918 RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
919 }
920 if (needCrc)
921 {
922 NCOM::CPropVariant prop;
923 prop = item.Crc;
924 RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop));
925 }
926 {
927 RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp));
928 }
929
930 RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
931
932 if (unpackSize)
933 {
934 RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
935 }
936 {
937 RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp));
938 }
939 return S_OK;
940}
941*/
942
876static HRESULT UpdateArchive( 943static HRESULT UpdateArchive(
877 ISequentialOutStream *outStream, 944 ISequentialOutStream *outStream,
878 UInt64 unpackSize, 945 UInt64 unpackSize,
879 CItem &item, 946 CItem &item,
880 const CSingleMethodProps &props, 947 const CSingleMethodProps &props,
881 IArchiveUpdateCallback *updateCallback) 948 const CHandlerTimeOptions &timeOptions,
949 IArchiveUpdateCallback *updateCallback
950 // , IArchiveUpdateCallbackArcProp *reportArcProp
951 )
882{ 952{
883 UInt64 complexity = 0; 953 UInt64 unpackSizeReal;
884 RINOK(updateCallback->SetTotal(unpackSize)); 954 {
885 RINOK(updateCallback->SetCompleted(&complexity));
886
887 CMyComPtr<ISequentialInStream> fileInStream; 955 CMyComPtr<ISequentialInStream> fileInStream;
888 956
889 RINOK(updateCallback->GetStream(0, &fileInStream)); 957 RINOK(updateCallback->GetStream(0, &fileInStream));
890 958
959 if (!fileInStream)
960 return S_FALSE;
961
962 {
963 CMyComPtr<IStreamGetProps> getProps;
964 fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
965 if (getProps)
966 {
967 FILETIME mTime;
968 UInt64 size;
969 if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK)
970 {
971 unpackSize = size;
972 if (timeOptions.Write_MTime.Val)
973 NTime::FileTime_To_UnixTime(mTime, item.Time);
974 }
975 }
976 }
977
978 UInt64 complexity = 0;
979 RINOK(updateCallback->SetTotal(unpackSize));
980 RINOK(updateCallback->SetCompleted(&complexity));
981
891 CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC; 982 CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
892 CMyComPtr<ISequentialInStream> crcStream(inStreamSpec); 983 CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
893 inStreamSpec->SetStream(fileInStream); 984 inStreamSpec->SetStream(fileInStream);
@@ -911,14 +1002,50 @@ static HRESULT UpdateArchive(
911 RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); 1002 RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
912 1003
913 item.Crc = inStreamSpec->GetCRC(); 1004 item.Crc = inStreamSpec->GetCRC();
914 item.Size32 = (UInt32)inStreamSpec->GetSize(); 1005 unpackSizeReal = inStreamSpec->GetSize();
1006 item.Size32 = (UInt32)unpackSizeReal;
915 RINOK(item.WriteFooter(outStream)); 1007 RINOK(item.WriteFooter(outStream));
1008 }
1009 /*
1010 if (reportArcProp)
1011 {
1012 RINOK(ReportArcProps(reportArcProp,
1013 item,
1014 props._Write_MTime, // item.Time != 0,
1015 true, // writeCrc
1016 &unpackSizeReal));
1017 }
1018 */
916 return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); 1019 return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
917} 1020}
918 1021
1022
919STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) 1023STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
920{ 1024{
921 *timeType = NFileTimeType::kUnix; 1025 /*
1026 if (_item.Time != 0)
1027 {
1028 we set NFileTimeType::kUnix in precision,
1029 and we return NFileTimeType::kUnix in kpidTimeType
1030 so GetFileTimeType() value is not used in any version of 7-zip.
1031 }
1032 else // (_item.Time == 0)
1033 {
1034 kpidMTime and kpidTimeType are not defined
1035 before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList();
1036 22.00 : GetFileTimeType() value is not used
1037 }
1038 */
1039
1040 UInt32 t;
1041 t = NFileTimeType::kUnix;
1042 if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val)
1043 {
1044 t = GET_FileTimeType_NotDefined_for_GetFileTimeType;
1045 // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21
1046 // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21
1047 }
1048 *timeType = t;
922 return S_OK; 1049 return S_OK;
923} 1050}
924 1051
@@ -936,6 +1063,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
936 return E_FAIL; 1063 return E_FAIL;
937 RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); 1064 RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
938 1065
1066 /*
1067 CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
1068 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
1069 */
1070
939 CItem newItem; 1071 CItem newItem;
940 1072
941 if (!IntToBool(newProps)) 1073 if (!IntToBool(newProps))
@@ -945,11 +1077,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
945 else 1077 else
946 { 1078 {
947 newItem.HostOS = kHostOS; 1079 newItem.HostOS = kHostOS;
1080 if (_timeOptions.Write_MTime.Val)
948 { 1081 {
949 NCOM::CPropVariant prop; 1082 NCOM::CPropVariant prop;
950 RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); 1083 RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
951 if (prop.vt == VT_FILETIME) 1084 if (prop.vt == VT_FILETIME)
952 NTime::FileTimeToUnixTime(prop.filetime, newItem.Time); 1085 NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time);
953 else if (prop.vt == VT_EMPTY) 1086 else if (prop.vt == VT_EMPTY)
954 newItem.Time = 0; 1087 newItem.Time = 0;
955 else 1088 else
@@ -990,7 +1123,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
990 return E_INVALIDARG; 1123 return E_INVALIDARG;
991 size = prop.uhVal.QuadPart; 1124 size = prop.uhVal.QuadPart;
992 } 1125 }
993 return UpdateArchive(outStream, size, newItem, _props, updateCallback); 1126 return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback);
994 } 1127 }
995 1128
996 if (indexInArchive != 0) 1129 if (indexInArchive != 0)
@@ -1022,6 +1155,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1022 } 1155 }
1023 RINOK(_stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL)); 1156 RINOK(_stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL));
1024 1157
1158 /*
1159 if (reportArcProp)
1160 ReportArcProps(reportArcProp, newItem,
1161 _props._Write_MTime,
1162 false, // writeCrc
1163 NULL); // unpacksize
1164 */
1165
1025 return NCompress::CopyStream(_stream, outStream, progress); 1166 return NCompress::CopyStream(_stream, outStream, progress);
1026 1167
1027 COM_TRY_END 1168 COM_TRY_END
@@ -1029,16 +1170,48 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1029 1170
1030STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) 1171STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
1031{ 1172{
1032 return _props.SetProperties(names, values, numProps); 1173 _timeOptions.Init();
1174 _props.Init();
1175
1176 for (UInt32 i = 0; i < numProps; i++)
1177 {
1178 UString name = names[i];
1179 name.MakeLower_Ascii();
1180 if (name.IsEmpty())
1181 return E_INVALIDARG;
1182 const PROPVARIANT &value = values[i];
1183 {
1184 bool processed = false;
1185 RINOK(_timeOptions.Parse(name, value, processed));
1186 if (processed)
1187 {
1188 if (_timeOptions.Write_CTime.Val ||
1189 _timeOptions.Write_ATime.Val)
1190 return E_INVALIDARG;
1191 if ( _timeOptions.Prec != (UInt32)(Int32)-1
1192 && _timeOptions.Prec != k_PropVar_TimePrec_0
1193 && _timeOptions.Prec != k_PropVar_TimePrec_Unix
1194 && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec
1195 && _timeOptions.Prec != k_PropVar_TimePrec_Base)
1196 return E_INVALIDARG;
1197 continue;
1198 }
1199 }
1200 RINOK(_props.SetProperty(name, value));
1201 }
1202 return S_OK;
1033} 1203}
1034 1204
1035static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 }; 1205static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 };
1036 1206
1037REGISTER_ARC_IO( 1207REGISTER_ARC_IO(
1038 "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF, 1208 "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF,
1039 k_Signature, 1209 k_Signature, 0,
1040 0, 1210 NArcInfoFlags::kKeepName
1041 NArcInfoFlags::kKeepName, 1211 | NArcInfoFlags::kMTime
1042 IsArc_Gz) 1212 | NArcInfoFlags::kMTime_Default
1213 , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
1214 | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
1215 , IsArc_Gz)
1043 1216
1044}} 1217}}
diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp
index 6f196de..3cbfdac 100644
--- a/CPP/7zip/Archive/HandlerCont.cpp
+++ b/CPP/7zip/Archive/HandlerCont.cpp
@@ -14,6 +14,10 @@
14 14
15namespace NArchive { 15namespace NArchive {
16 16
17namespace NExt {
18API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
19}
20
17STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, 21STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
18 Int32 testMode, IArchiveExtractCallback *extractCallback) 22 Int32 testMode, IArchiveExtractCallback *extractCallback)
19{ 23{
@@ -132,11 +136,12 @@ STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosit
132} 136}
133 137
134static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }; 138static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
135 139// static const Byte k_Ext_Signature[] = { 0x53, 0xEF };
140// static const unsigned k_Ext_Signature_offset = 0x438;
136 141
137static const char *GetImgExt(ISequentialInStream *stream) 142static const char *GetImgExt(ISequentialInStream *stream)
138{ 143{
139 const size_t kHeaderSize = 1 << 10; 144 const size_t kHeaderSize = 1 << 11;
140 Byte buf[kHeaderSize]; 145 Byte buf[kHeaderSize];
141 if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK) 146 if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
142 { 147 {
@@ -146,6 +151,8 @@ static const char *GetImgExt(ISequentialInStream *stream)
146 return "gpt"; 151 return "gpt";
147 return "mbr"; 152 return "mbr";
148 } 153 }
154 if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES)
155 return "ext";
149 } 156 }
150 return NULL; 157 return NULL;
151} 158}
@@ -208,6 +215,33 @@ STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
208 return S_OK; 215 return S_OK;
209} 216}
210 217
218
219class CHandlerImgProgress:
220 public ICompressProgressInfo,
221 public CMyUnknownImp
222{
223public:
224 CHandlerImg &Handler;
225 CMyComPtr<ICompressProgressInfo> _ratioProgress;
226
227 CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {}
228
229 // MY_UNKNOWN_IMP1(ICompressProgressInfo)
230 MY_UNKNOWN_IMP
231
232 STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
233};
234
235
236STDMETHODIMP CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
237{
238 UInt64 inSize2;
239 if (Handler.Get_PackSizeProcessed(inSize2))
240 inSize = &inSize2;
241 return _ratioProgress->SetRatioInfo(inSize, outSize);
242}
243
244
211STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems, 245STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
212 Int32 testMode, IArchiveExtractCallback *extractCallback) 246 Int32 testMode, IArchiveExtractCallback *extractCallback)
213{ 247{
@@ -227,10 +261,6 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
227 return S_OK; 261 return S_OK;
228 RINOK(extractCallback->PrepareOperation(askMode)); 262 RINOK(extractCallback->PrepareOperation(askMode));
229 263
230 CLocalProgress *lps = new CLocalProgress;
231 CMyComPtr<ICompressProgressInfo> progress = lps;
232 lps->Init(extractCallback, false);
233
234 int opRes = NExtract::NOperationResult::kDataError; 264 int opRes = NExtract::NOperationResult::kDataError;
235 265
236 ClearStreamVars(); 266 ClearStreamVars();
@@ -242,6 +272,19 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
242 272
243 if (hres == S_OK && inStream) 273 if (hres == S_OK && inStream)
244 { 274 {
275 CLocalProgress *lps = new CLocalProgress;
276 CMyComPtr<ICompressProgressInfo> progress = lps;
277 lps->Init(extractCallback, false);
278
279 if (Init_PackSizeProcessed())
280 {
281 CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
282 CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
283 imgProgressSpec->_ratioProgress = progress;
284 progress.Release();
285 progress = imgProgress;
286 }
287
245 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); 288 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
246 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; 289 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
247 290
diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h
index 0b92d19..3c64592 100644
--- a/CPP/7zip/Archive/HandlerCont.h
+++ b/CPP/7zip/Archive/HandlerCont.h
@@ -94,7 +94,19 @@ protected:
94 94
95 virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; 95 virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
96 virtual void CloseAtError(); 96 virtual void CloseAtError();
97
98 // returns (true), if Get_PackSizeProcessed() is required in Extract()
99 virtual bool Init_PackSizeProcessed()
100 {
101 return false;
102 }
97public: 103public:
104 virtual bool Get_PackSizeProcessed(UInt64 &size)
105 {
106 size = 0;
107 return false;
108 }
109
98 MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) 110 MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
99 INTERFACE_IInArchive_Img(PURE) 111 INTERFACE_IInArchive_Img(PURE)
100 112
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
index b70a291..f0a85f1 100644
--- a/CPP/7zip/Archive/HfsHandler.cpp
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -240,7 +240,7 @@ struct CItem
240 UInt32 ID; 240 UInt32 ID;
241 UInt32 CTime; 241 UInt32 CTime;
242 UInt32 MTime; 242 UInt32 MTime;
243 // UInt32 AttrMTime; 243 UInt32 AttrMTime;
244 UInt32 ATime; 244 UInt32 ATime;
245 // UInt32 BackupDate; 245 // UInt32 BackupDate;
246 246
@@ -1000,7 +1000,7 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
1000 1000
1001 item.CTime = Get32(r + 0xC); 1001 item.CTime = Get32(r + 0xC);
1002 item.MTime = Get32(r + 0x10); 1002 item.MTime = Get32(r + 0x10);
1003 // item.AttrMTime = Get32(r + 0x14); 1003 item.AttrMTime = Get32(r + 0x14);
1004 item.ATime = Get32(r + 0x18); 1004 item.ATime = Get32(r + 0x18);
1005 // item.BackupDate = Get32(r + 0x1C); 1005 // item.BackupDate = Get32(r + 0x1C);
1006 1006
@@ -1404,6 +1404,7 @@ static const Byte kProps[] =
1404 kpidCTime, 1404 kpidCTime,
1405 kpidMTime, 1405 kpidMTime,
1406 kpidATime, 1406 kpidATime,
1407 kpidChangeTime,
1407 kpidPosixAttrib 1408 kpidPosixAttrib
1408}; 1409};
1409 1410
@@ -1421,9 +1422,11 @@ IMP_IInArchive_ArcProps
1421 1422
1422static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) 1423static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
1423{ 1424{
1425 if (hfsTime == 0)
1426 return;
1424 FILETIME ft; 1427 FILETIME ft;
1425 HfsTimeToFileTime(hfsTime, ft); 1428 HfsTimeToFileTime(hfsTime, ft);
1426 prop = ft; 1429 prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
1427} 1430}
1428 1431
1429STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 1432STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
@@ -1447,10 +1450,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
1447 case kpidMTime: HfsTimeToProp(Header.MTime, prop); break; 1450 case kpidMTime: HfsTimeToProp(Header.MTime, prop); break;
1448 case kpidCTime: 1451 case kpidCTime:
1449 { 1452 {
1450 FILETIME localFt, ft; 1453 if (Header.CTime != 0)
1451 HfsTimeToFileTime(Header.CTime, localFt); 1454 {
1452 if (LocalFileTimeToFileTime(&localFt, &ft)) 1455 FILETIME localFt, ft;
1453 prop = ft; 1456 HfsTimeToFileTime(Header.CTime, localFt);
1457 if (LocalFileTimeToFileTime(&localFt, &ft))
1458 prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
1459 }
1454 break; 1460 break;
1455 } 1461 }
1456 case kpidIsTree: prop = true; break; 1462 case kpidIsTree: prop = true; break;
@@ -1578,6 +1584,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1578 case kpidCTime: HfsTimeToProp(item.CTime, prop); break; 1584 case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
1579 case kpidMTime: HfsTimeToProp(item.MTime, prop); break; 1585 case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
1580 case kpidATime: HfsTimeToProp(item.ATime, prop); break; 1586 case kpidATime: HfsTimeToProp(item.ATime, prop); break;
1587 case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break;
1581 1588
1582 case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; 1589 case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break;
1583 } 1590 }
diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h
index 6df76d2..9551dfa 100644
--- a/CPP/7zip/Archive/IArchive.h
+++ b/CPP/7zip/Archive/IArchive.h
@@ -38,9 +38,11 @@ namespace NFileTimeType
38{ 38{
39 enum EEnum 39 enum EEnum
40 { 40 {
41 kWindows, 41 kNotDefined = -1,
42 kWindows = 0,
42 kUnix, 43 kUnix,
43 kDOS 44 kDOS,
45 k1ns
44 }; 46 };
45} 47}
46 48
@@ -60,8 +62,31 @@ namespace NArcInfoFlags
60 const UInt32 kHardLinks = 1 << 11; // the handler supports hard links 62 const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
61 const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches 63 const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches
62 const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums) 64 const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums)
65 const UInt32 kCTime = 1 << 14;
66 const UInt32 kCTime_Default = 1 << 15;
67 const UInt32 kATime = 1 << 16;
68 const UInt32 kATime_Default = 1 << 17;
69 const UInt32 kMTime = 1 << 18;
70 const UInt32 kMTime_Default = 1 << 19;
71 // const UInt32 kTTime_Reserved = 1 << 20;
72 // const UInt32 kTTime_Reserved_Default = 1 << 21;
63} 73}
64 74
75namespace NArcInfoTimeFlags
76{
77 const unsigned kTime_Prec_Mask_bit_index = 0;
78 const unsigned kTime_Prec_Mask_num_bits = 26;
79
80 const unsigned kTime_Prec_Default_bit_index = 27;
81 const unsigned kTime_Prec_Default_num_bits = 5;
82}
83
84#define TIME_PREC_TO_ARC_FLAGS_MASK(x) \
85 ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (x)))
86
87#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(x) \
88 ((UInt32)(x) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index)
89
65namespace NArchive 90namespace NArchive
66{ 91{
67 namespace NHandlerPropID 92 namespace NHandlerPropID
@@ -79,8 +104,8 @@ namespace NArchive
79 kSignatureOffset, // VT_UI4 104 kSignatureOffset, // VT_UI4
80 kAltStreams, // VT_BOOL 105 kAltStreams, // VT_BOOL
81 kNtSecure, // VT_BOOL 106 kNtSecure, // VT_BOOL
82 kFlags // VT_UI4 107 kFlags, // VT_UI4
83 // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR) 108 kTimeFlags // VT_UI4
84 }; 109 };
85 } 110 }
86 111
@@ -123,6 +148,7 @@ namespace NArchive
123 kInArcIndex, 148 kInArcIndex,
124 kBlockIndex, 149 kBlockIndex,
125 kOutArcIndex 150 kOutArcIndex
151 // kArcProp
126 }; 152 };
127 } 153 }
128 154
@@ -133,7 +159,8 @@ namespace NArchive
133 enum 159 enum
134 { 160 {
135 kOK = 0 161 kOK = 0
136 // , kError 162 // kError = 1,
163 // kError_FileChanged
137 }; 164 };
138 } 165 }
139 } 166 }
@@ -461,9 +488,10 @@ namespace NUpdateNotifyOp
461 kSkip, 488 kSkip,
462 kDelete, 489 kDelete,
463 kHeader, 490 kHeader,
464 kHashRead 491 kHashRead,
465 492 kInFileChanged
466 // kNumDefined 493 // , kOpFinished
494 // , kNumDefined
467 }; 495 };
468}; 496};
469 497
@@ -493,6 +521,20 @@ ARCHIVE_INTERFACE(IArchiveGetDiskProperty, 0x84)
493}; 521};
494 522
495/* 523/*
524#define INTERFACE_IArchiveUpdateCallbackArcProp(x) \
525 STDMETHOD(ReportProp)(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x; \
526 STDMETHOD(ReportRawProp)(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x; \
527 STDMETHOD(ReportFinished)(UInt32 indexType, UInt32 index, Int32 opRes) x; \
528 STDMETHOD(DoNeedArcProp)(PROPID propID, Int32 *answer) x; \
529
530
531ARCHIVE_INTERFACE(IArchiveUpdateCallbackArcProp, 0x85)
532{
533 INTERFACE_IArchiveUpdateCallbackArcProp(PURE);
534};
535*/
536
537/*
496UpdateItems() 538UpdateItems()
497------------- 539-------------
498 540
@@ -636,9 +678,40 @@ extern "C"
636 678
637 typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); 679 typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
638 typedef HRESULT (WINAPI *Func_SetLargePageMode)(); 680 typedef HRESULT (WINAPI *Func_SetLargePageMode)();
681 // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version);
639 682
640 typedef IOutArchive * (*Func_CreateOutArchive)(); 683 typedef IOutArchive * (*Func_CreateOutArchive)();
641 typedef IInArchive * (*Func_CreateInArchive)(); 684 typedef IInArchive * (*Func_CreateInArchive)();
642} 685}
643 686
687
688/*
689 if there is no time in archive, external MTime of archive
690 will be used instead of _item.Time from archive.
691 For 7-zip before 22.00 we need to return some supported value.
692 But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00.
693 So we return highest precision value supported by old 7-Zip.
694 new 7-Zip 22.00 doesn't use that value in usual cases.
695*/
696
697
698#define DECLARE_AND_SET_CLIENT_VERSION_VAR
699#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
700 NFileTimeType::kWindows
701
702/*
703extern UInt32 g_ClientVersion;
704
705#define GET_CLIENT_VERSION(major, minor) \
706 ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor)))
707
708#define DECLARE_AND_SET_CLIENT_VERSION_VAR \
709 UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR);
710
711#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
712 ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \
713 (UInt32)(Int32)NFileTimeType::kNotDefined : \
714 NFileTimeType::kWindows))
715*/
716
644#endif 717#endif
diff --git a/CPP/7zip/Archive/Icons/apfs.ico b/CPP/7zip/Archive/Icons/apfs.ico
new file mode 100644
index 0000000..124eb76
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/apfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp
index 87f4aa3..8588a7c 100644
--- a/CPP/7zip/Archive/Iso/IsoHandler.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -6,9 +6,6 @@
6#include "../../../Common/MyLinux.h" 6#include "../../../Common/MyLinux.h"
7#include "../../../Common/StringConvert.h" 7#include "../../../Common/StringConvert.h"
8 8
9#include "../../../Windows/PropVariant.h"
10#include "../../../Windows/TimeUtils.h"
11
12#include "../../Common/LimitedStreams.h" 9#include "../../Common/LimitedStreams.h"
13#include "../../Common/ProgressUtils.h" 10#include "../../Common/ProgressUtils.h"
14 11
@@ -34,8 +31,8 @@ static const Byte kProps[] =
34 // kpidCTime, 31 // kpidCTime,
35 // kpidATime, 32 // kpidATime,
36 kpidPosixAttrib, 33 kpidPosixAttrib,
37 // kpidUser, 34 // kpidUserId,
38 // kpidGroup, 35 // kpidGroupId,
39 // kpidLinks, 36 // kpidLinks,
40 kpidSymLink 37 kpidSymLink
41}; 38};
@@ -127,8 +124,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
127 prop = s; 124 prop = s;
128 break; 125 break;
129 } 126 }
130 case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } 127 case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
131 case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; } 128 case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
132 } 129 }
133 } 130 }
134 131
@@ -242,8 +239,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
242 case kpidPosixAttrib: 239 case kpidPosixAttrib:
243 /* 240 /*
244 case kpidLinks: 241 case kpidLinks:
245 case kpidUser: 242 case kpidUserId:
246 case kpidGroup: 243 case kpidGroupId:
247 */ 244 */
248 { 245 {
249 if (_archive.IsSusp) 246 if (_archive.IsSusp)
@@ -254,8 +251,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
254 case kpidPosixAttrib: t = k_Px_Mode; break; 251 case kpidPosixAttrib: t = k_Px_Mode; break;
255 /* 252 /*
256 case kpidLinks: t = k_Px_Links; break; 253 case kpidLinks: t = k_Px_Links; break;
257 case kpidUser: t = k_Px_User; break; 254 case kpidUserId: t = k_Px_User; break;
258 case kpidGroup: t = k_Px_Group; break; 255 case kpidGroupId: t = k_Px_Group; break;
259 */ 256 */
260 } 257 }
261 UInt32 v; 258 UInt32 v;
@@ -276,9 +273,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
276 // case kpidCTime: 273 // case kpidCTime:
277 // case kpidATime: 274 // case kpidATime:
278 { 275 {
279 FILETIME utc; 276 // if
280 if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc)) 277 item.DateTime.GetFileTime(prop);
281 prop = utc;
282 /* 278 /*
283 else 279 else
284 { 280 {
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
index 211b3ee..6780235 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.cpp
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -587,6 +587,8 @@ HRESULT CInArchive::Open2()
587 for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) 587 for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
588 if (VolDescs[MainVolDescIndex].IsJoliet()) 588 if (VolDescs[MainVolDescIndex].IsJoliet())
589 break; 589 break;
590 /* FIXME: some volume can contain Rock Ridge, that is better than
591 Joliet volume. So we need some way to detect such case */
590 // MainVolDescIndex = 0; // to read primary volume 592 // MainVolDescIndex = 0; // to read primary volume
591 const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; 593 const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
592 if (vd.LogicalBlockSize != kBlockSize) 594 if (vd.LogicalBlockSize != kBlockSize)
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
index 347f9e9..a705b06 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.h
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -127,17 +127,18 @@ struct CDateTime
127 bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && 127 bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
128 Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } 128 Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
129 129
130 bool GetFileTime(FILETIME &ft) const 130 bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
131 { 131 {
132 UInt64 value; 132 UInt64 v;
133 bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); 133 const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v);
134 if (res) 134 if (res)
135 { 135 {
136 value -= (Int64)((Int32)GmtOffset * 15 * 60); 136 v -= (Int64)((Int32)GmtOffset * 15 * 60);
137 value *= 10000000; 137 v *= 10000000;
138 if (Hundredths < 100)
139 v += (UInt32)Hundredths * 100000;
140 prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2);
138 } 141 }
139 ft.dwLowDateTime = (DWORD)value;
140 ft.dwHighDateTime = (DWORD)(value >> 32);
141 return res; 142 return res;
142 } 143 }
143}; 144};
diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h
index a42ae03..8c2a725 100644
--- a/CPP/7zip/Archive/Iso/IsoItem.h
+++ b/CPP/7zip/Archive/Iso/IsoItem.h
@@ -25,17 +25,16 @@ struct CRecordingDateTime
25 Byte Second; 25 Byte Second;
26 signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. 26 signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
27 27
28 bool GetFileTime(FILETIME &ft) const 28 bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
29 { 29 {
30 UInt64 value; 30 UInt64 v;
31 bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value); 31 const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v);
32 if (res) 32 if (res)
33 { 33 {
34 value -= (Int64)((Int32)GmtOffset * 15 * 60); 34 v -= (Int64)((Int32)GmtOffset * 15 * 60);
35 value *= 10000000; 35 v *= 10000000;
36 prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base);
36 } 37 }
37 ft.dwLowDateTime = (DWORD)value;
38 ft.dwHighDateTime = (DWORD)(value >> 32);
39 return res; 38 return res;
40 } 39 }
41}; 40};
diff --git a/CPP/7zip/Archive/LpHandler.cpp b/CPP/7zip/Archive/LpHandler.cpp
new file mode 100644
index 0000000..b2720f4
--- /dev/null
+++ b/CPP/7zip/Archive/LpHandler.cpp
@@ -0,0 +1,1173 @@
1// LpHandler.cpp
2
3#include "StdAfx.h"
4
5#include "../../../C/CpuArch.h"
6#include "../../../C/Sha256.h"
7
8#include "../../Common/ComTry.h"
9#include "../../Common/IntToString.h"
10#include "../../Common/MyBuffer.h"
11
12#include "../../Windows/PropVariantUtils.h"
13
14#include "../Common/LimitedStreams.h"
15#include "../Common/ProgressUtils.h"
16#include "../Common/RegisterArc.h"
17#include "../Common/StreamUtils.h"
18
19#include "../Compress/CopyCoder.h"
20
21#define Get16(p) GetUi16(p)
22#define Get32(p) GetUi32(p)
23#define Get64(p) GetUi64(p)
24
25#define G16(_offs_, dest) dest = Get16(p + (_offs_));
26#define G32(_offs_, dest) dest = Get32(p + (_offs_));
27#define G64(_offs_, dest) dest = Get64(p + (_offs_));
28
29using namespace NWindows;
30
31namespace NArchive {
32
33namespace NExt {
34API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
35}
36
37namespace NLp {
38
39/*
40Android 10+ use Android's Dynamic Partitions to allow the
41different read-only system partitions (e.g. system, vendor, product)
42to share the same pool of storage space (as LVM in Linux).
43Name for partition: "super" (for GPT) or "super.img" (for file).
44Dynamic Partition Tools: lpmake
45All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.):
46boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
47*/
48
49#define LP_METADATA_MAJOR_VERSION 10
50// #define LP_METADATA_MINOR_VERSION_MIN 0
51// #define LP_METADATA_MINOR_VERSION_MAX 2
52
53// #define LP_SECTOR_SIZE 512
54static const unsigned kSectorSizeLog = 9;
55
56/* Amount of space reserved at the start of every super partition to avoid
57 * creating an accidental boot sector. */
58#define LP_PARTITION_RESERVED_BYTES 4096
59#define LP_METADATA_GEOMETRY_SIZE 4096
60#define LP_METADATA_HEADER_MAGIC 0x414C5030
61
62#define SIGNATURE { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 }
63static const unsigned k_SignatureSize = 8;
64static const Byte k_Signature[k_SignatureSize] = SIGNATURE;
65
66// The length (36) is the same as the maximum length of a GPT partition name.
67static const unsigned kNameLen = 36;
68
69static void AddName36ToString(AString &s, const char *name, bool strictConvert)
70{
71 for (unsigned i = 0; i < kNameLen; i++)
72 {
73 char c = name[i];
74 if (c == 0)
75 return;
76 if (strictConvert && c < 32)
77 c = '_';
78 s += c;
79 }
80}
81
82
83static const unsigned k_Geometry_Size = 0x34;
84
85// LpMetadataGeometry
86struct CGeometry
87{
88 // UInt32 magic;
89 // UInt32 struct_size;
90 // Byte checksum[32]; /* SHA256 checksum of this struct, with this field set to 0. */
91
92 /* Maximum amount of space a single copy of the metadata can use,
93 a multiple of LP_SECTOR_SIZE. */
94 UInt32 metadata_max_size;
95
96 /* Number of copies of the metadata to keep.
97 For Non-A/B: 1, For A/B: 2, for A/B/C: 3.
98 A backup copy of each slot is kept */
99 UInt32 metadata_slot_count;
100
101 /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */
102 UInt32 logical_block_size;
103
104 bool Parse(const Byte *p)
105 {
106 G32 (40, metadata_max_size);
107 G32 (44, metadata_slot_count);
108 G32 (48, logical_block_size);
109 if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20))
110 return false;
111 if (metadata_max_size == 0)
112 return false;
113 if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0)
114 return false;
115 return true;
116 }
117
118 UInt64 GetTotalMetadataSize() const
119 {
120 // there are 2 copies of GEOMETRY and METADATA slots
121 return LP_PARTITION_RESERVED_BYTES +
122 LP_METADATA_GEOMETRY_SIZE * 2 +
123 ((UInt64)metadata_max_size * metadata_slot_count) * 2;
124 }
125};
126
127
128
129// LpMetadataTableDescriptor
130struct CDescriptor
131{
132 UInt32 offset; /* Location of the table, relative to end of the metadata header. */
133 UInt32 num_entries; /* Number of entries in the table. */
134 UInt32 entry_size; /* Size of each entry in the table, in bytes. */
135
136 void Parse(const Byte *p)
137 {
138 G32 (0, offset);
139 G32 (4, num_entries);
140 G32 (8, entry_size);
141 }
142
143 bool CheckLimits(UInt32 limit) const
144 {
145 if (entry_size == 0)
146 return false;
147 const UInt32 size = num_entries * entry_size;
148 if (size / entry_size != num_entries)
149 return false;
150 if (offset > limit || limit - offset < size)
151 return false;
152 return true;
153 }
154};
155
156
157// #define LP_PARTITION_ATTR_NONE 0x0
158// #define LP_PARTITION_ATTR_READONLY (1 << 0)
159
160/* This flag is only intended to be used with super_empty.img and super.img on
161 * retrofit devices. On these devices there are A and B super partitions, and
162 * we don't know ahead of time which slot the image will be applied to.
163 *
164 * If set, the partition name needs a slot suffix applied. The slot suffix is
165 * determined by the metadata slot number (0 = _a, 1 = _b).
166 */
167// #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
168
169/* This flag is applied automatically when using MetadataBuilder::NewForUpdate.
170 * It signals that the partition was created (or modified) for a snapshot-based
171 * update. If this flag is not present, the partition was likely flashed via
172 * fastboot.
173 */
174// #define LP_PARTITION_ATTR_UPDATED (1 << 2)
175
176/* This flag marks a partition as disabled. It should not be used or mapped. */
177// #define LP_PARTITION_ATTR_DISABLED (1 << 3)
178
179static const char * const g_PartitionAttr[] =
180{
181 "READONLY"
182 , "SLOT_SUFFIXED"
183 , "UPDATED"
184 , "DISABLED"
185};
186
187static unsigned const k_MetaPartition_Size = 52;
188
189// LpMetadataPartition
190struct CPartition
191{
192 /* ASCII characters: alphanumeric or _. at least one ASCII character,
193 (name) must be unique across all partition names. */
194 char name[kNameLen];
195
196 UInt32 attributes; /* (LP_PARTITION_ATTR_*). */
197
198 /* Index of the first extent owned by this partition. The extent will
199 * start at logical sector 0. Gaps between extents are not allowed. */
200 UInt32 first_extent_index;
201
202 /* Number of extents in the partition. Every partition must have at least one extent. */
203 UInt32 num_extents;
204
205 /* Group this partition belongs to. */
206 UInt32 group_index;
207
208 void Parse(const Byte *p)
209 {
210 memcpy(name, p, kNameLen);
211 G32 (36, attributes);
212 G32 (40, first_extent_index);
213 G32 (44, num_extents);
214 G32 (48, group_index);
215 }
216
217 // calced properties:
218 UInt32 MethodsMask;
219 UInt64 NumSectors;
220 UInt64 NumSectors_Pack;
221 const char *Ext;
222
223 UInt64 GetSize() const { return NumSectors << kSectorSizeLog; }
224 UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; }
225
226 CPartition():
227 MethodsMask(0),
228 NumSectors(0),
229 NumSectors_Pack(0),
230 Ext(NULL)
231 {}
232};
233
234
235
236
237#define LP_TARGET_TYPE_LINEAR 0
238/* This extent is a dm-zero target. The index is ignored and must be 0. */
239#define LP_TARGET_TYPE_ZERO 1
240
241static const char * const g_Methods[] =
242{
243 "RAW" // "LINEAR"
244 , "ZERO"
245};
246
247static unsigned const k_MetaExtent_Size = 24;
248
249// LpMetadataExtent
250struct CExtent
251{
252 UInt64 num_sectors; /* Length in 512-byte sectors. */
253 UInt32 target_type; /* Target type for device-mapper (LP_TARGET_TYPE_*). */
254
255 /* for LINEAR: The sector on the physical partition that this extent maps onto.
256 for ZERO: must be 0. */
257 UInt64 target_data;
258
259 /* for LINEAR: index into the block devices table.
260 for ZERO: must be 0. */
261 UInt32 target_source;
262
263 bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; }
264
265 void Parse(const Byte *p)
266 {
267 G64 (0, num_sectors);
268 G32 (8, target_type);
269 G64 (12, target_data);
270 G32 (20, target_source);
271 }
272};
273
274
275/* This flag is only intended to be used with super_empty.img and super.img on
276 * retrofit devices. If set, the group needs a slot suffix to be interpreted
277 * correctly. The suffix is automatically applied by ReadMetadata().
278 */
279// #define LP_GROUP_SLOT_SUFFIXED (1 << 0)
280static unsigned const k_Group_Size = 48;
281
282// LpMetadataPartitionGroup
283struct CGroup
284{
285 char name[kNameLen];
286 UInt32 flags; /* (LP_GROUP_*). */
287 UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */
288
289 void Parse(const Byte *p)
290 {
291 memcpy(name, p, kNameLen);
292 G32 (36, flags);
293 G64 (40, maximum_size);
294 }
295};
296
297
298
299
300/* This flag is only intended to be used with super_empty.img and super.img on
301 * retrofit devices. On these devices there are A and B super partitions, and
302 * we don't know ahead of time which slot the image will be applied to.
303 *
304 * If set, the block device needs a slot suffix applied before being used with
305 * IPartitionOpener. The slot suffix is determined by the metadata slot number
306 * (0 = _a, 1 = _b).
307 */
308// #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
309
310static unsigned const k_Device_Size = 64;
311
312/* This struct defines an entry in the block_devices table. There must be at
313 * least one device, and the first device must represent the partition holding
314 * the super metadata.
315 */
316// LpMetadataBlockDevice
317struct CDevice
318{
319 /* 0: First usable sector for allocating logical partitions. this will be
320 * the first sector after the initial geometry blocks, followed by the
321 * space consumed by metadata_max_size*metadata_slot_count*2.
322 */
323 UInt64 first_logical_sector;
324
325 /* 8: Alignment for defining partitions or partition extents. For example,
326 * an alignment of 1MiB will require that all partitions have a size evenly
327 * divisible by 1MiB, and that the smallest unit the partition can grow by
328 * is 1MiB.
329 *
330 * Alignment is normally determined at runtime when growing or adding
331 * partitions. If for some reason the alignment cannot be determined, then
332 * this predefined alignment in the geometry is used instead. By default
333 * it is set to 1MiB.
334 */
335 UInt32 alignment;
336
337 /* 12: Alignment offset for "stacked" devices. For example, if the "super"
338 * partition itself is not aligned within the parent block device's
339 * partition table, then we adjust for this in deciding where to place
340 * |first_logical_sector|.
341 *
342 * Similar to |alignment|, this will be derived from the operating system.
343 * If it cannot be determined, it is assumed to be 0.
344 */
345 UInt32 alignment_offset;
346
347 /* 16: Block device size, as specified when the metadata was created. This
348 * can be used to verify the geometry against a target device.
349 */
350 UInt64 size;
351
352 /* 24: Partition name in the GPT*/
353 char partition_name[kNameLen];
354
355 /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
356 UInt32 flags;
357
358 void Parse(const Byte *p)
359 {
360 memcpy(partition_name, p + 24, kNameLen);
361 G64 (0, first_logical_sector);
362 G32 (8, alignment);
363 G32 (12, alignment_offset);
364 G64 (16, size);
365 G32 (60, flags);
366 }
367};
368
369
370/* This device uses Virtual A/B. Note that on retrofit devices, the expanded
371 * header may not be present.
372 */
373// #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1
374
375static const char * const g_Header_Flags[] =
376{
377 "VIRTUAL_AB"
378};
379
380
381static const unsigned k_LpMetadataHeader10_size = 128;
382static const unsigned k_LpMetadataHeader12_size = 256;
383
384struct LpMetadataHeader
385{
386 /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */
387 UInt32 magic;
388
389 /* 4: Version number required to read this metadata. If the version is not
390 * equal to the library version, the metadata should be considered
391 * incompatible.
392 */
393 UInt16 major_version;
394
395 /* 6: Minor version. A library supporting newer features should be able to
396 * read metadata with an older minor version. However, an older library
397 * should not support reading metadata if its minor version is higher.
398 */
399 UInt16 minor_version;
400
401 /* 8: The size of this header struct. */
402 UInt32 header_size;
403
404 /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as
405 * if this field were set to 0.
406 */
407 // Byte header_checksum[32];
408
409 /* 44: The total size of all tables. This size is contiguous; tables may not
410 * have gaps in between, and they immediately follow the header.
411 */
412 UInt32 tables_size;
413
414 /* 48: SHA256 checksum of all table contents. */
415 Byte tables_checksum[32];
416
417 /* 80: Partition table descriptor. */
418 CDescriptor partitions;
419 /* 92: Extent table descriptor. */
420 CDescriptor extents;
421 /* 104: Updateable group descriptor. */
422 CDescriptor groups;
423 /* 116: Block device table. */
424 CDescriptor block_devices;
425
426 /* Everything past here is header version 1.2+, and is only included if
427 * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
428 * zero these additional fields.
429 */
430
431 /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are
432 * independent of the version number and intended to be informational only.
433 * New flags can be added without bumping the version.
434 */
435 // UInt32 flags;
436
437 /* 132: Reserved (zero), pad to 256 bytes. */
438 // Byte reserved[124];
439
440 void Parse128(const Byte *p)
441 {
442 G32 (0, magic);
443 G16 (4, major_version);
444 G16 (6, minor_version);
445 G32 (8, header_size)
446 // Byte header_checksum[32];
447 G32 (44, tables_size)
448 memcpy (tables_checksum, p + 48, 32);
449 partitions.Parse(p + 80);
450 extents.Parse(p + 92);
451 groups.Parse(p + 104);
452 block_devices.Parse(p + 116);
453 /* Everything past here is header version 1.2+, and is only included if
454 * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
455 * zero these additional fields.
456 */
457 }
458};
459
460
461static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum)
462{
463 CSha256 sha;
464 Sha256_Init(&sha);
465 Sha256_Update(&sha, data, size);
466 Byte calced[32];
467 Sha256_Final(&sha, calced);
468 return memcmp(checksum, calced, 32) == 0;
469}
470
471static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset)
472{
473 Byte checksum[32];
474 Byte *shaData = &data[hashOffset];
475 memcpy(checksum, shaData, 32);
476 memset(shaData, 0, 32);
477 return CheckSha256(data, size, checksum);
478}
479
480
481
482class CHandler:
483 public IInArchive,
484 public IInArchiveGetStream,
485 public CMyUnknownImp
486{
487 CRecordVector<CPartition> _items;
488 CRecordVector<CExtent> Extents;
489
490 CMyComPtr<IInStream> _stream;
491 UInt64 _totalSize;
492 // UInt64 _usedSize;
493 // UInt64 _headersSize;
494
495 CGeometry geom;
496 UInt16 Major_version;
497 UInt16 Minor_version;
498 UInt32 Flags;
499
500 Int32 _mainFileIndex;
501 UInt32 MethodsMask;
502 bool _headerWarning;
503 AString GroupsString;
504 AString DevicesString;
505 AString DeviceArcName;
506
507 HRESULT Open2(IInStream *stream);
508
509public:
510 MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
511 INTERFACE_IInArchive(;)
512 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
513};
514
515
516static void AddComment_UInt64(AString &s, const char *name, UInt64 val)
517{
518 s.Add_Space();
519 s += name;
520 s += '=';
521 s.Add_UInt64(val);
522}
523
524
525static bool IsBufZero(const Byte *data, size_t size)
526{
527 for (size_t i = 0; i < size; i += 4)
528 if (*(const UInt32 *)(const void *)(data + i) != 0)
529 return false;
530 return true;
531}
532
533
534HRESULT CHandler::Open2(IInStream *stream)
535{
536 RINOK(stream->Seek(LP_PARTITION_RESERVED_BYTES, STREAM_SEEK_SET, NULL));
537 {
538 Byte buf[k_Geometry_Size];
539 RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size));
540 if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
541 return S_FALSE;
542 if (!geom.Parse(buf))
543 return S_FALSE;
544 if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8))
545 return S_FALSE;
546 }
547
548 CByteBuffer buffer;
549 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
550 buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2);
551 {
552 // buffer.Size() >= LP_PARTITION_RESERVED_BYTES
553 RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES));
554 if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES))
555 {
556 _headerWarning = true;
557 // return S_FALSE;
558 }
559 }
560
561 RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2));
562 // we check that 2 copies of GEOMETRY are identical:
563 if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0
564 || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size))
565 {
566 _headerWarning = true;
567 // return S_FALSE;
568 }
569
570 RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size));
571 LpMetadataHeader header;
572 header.Parse128(buffer);
573 if (header.magic != LP_METADATA_HEADER_MAGIC ||
574 header.major_version != LP_METADATA_MAJOR_VERSION ||
575 header.header_size < k_LpMetadataHeader10_size)
576 return S_FALSE;
577 Flags = 0;
578 if (header.header_size > k_LpMetadataHeader10_size)
579 {
580 if (header.header_size != k_LpMetadataHeader12_size)
581 return S_FALSE;
582 RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size,
583 header.header_size - k_LpMetadataHeader10_size));
584 Flags = Get32(buffer + k_LpMetadataHeader10_size);
585 }
586 Major_version = header.major_version;
587 Minor_version = header.minor_version;
588
589 if (!CheckSha256_csOffset(buffer, header.header_size, 12))
590 return S_FALSE;
591
592 if (geom.metadata_max_size < header.tables_size ||
593 geom.metadata_max_size - header.tables_size < header.header_size)
594 return S_FALSE;
595
596 buffer.AllocAtLeast(header.tables_size);
597 RINOK(ReadStream_FALSE(stream, buffer, header.tables_size));
598
599 const UInt64 totalMetaSize = geom.GetTotalMetadataSize();
600 // _headersSize = _totalSize;
601 _totalSize = totalMetaSize;
602
603 if (!CheckSha256(buffer, header.tables_size, header.tables_checksum))
604 return S_FALSE;
605
606 {
607 const CDescriptor &d = header.partitions;
608 if (!d.CheckLimits(header.tables_size))
609 return S_FALSE;
610 if (d.entry_size != k_MetaPartition_Size)
611 return S_FALSE;
612 for (UInt32 i = 0; i < d.num_entries; i++)
613 {
614 CPartition part;
615 part.Parse(buffer + d.offset + i * d.entry_size);
616 const UInt32 extLimit = part.first_extent_index + part.num_extents;
617 if (extLimit < part.first_extent_index ||
618 extLimit > header.extents.num_entries ||
619 part.group_index >= header.groups.num_entries)
620 return S_FALSE;
621 _items.Add(part);
622 }
623 }
624 {
625 const CDescriptor &d = header.extents;
626 if (!d.CheckLimits(header.tables_size))
627 return S_FALSE;
628 if (d.entry_size != k_MetaExtent_Size)
629 return S_FALSE;
630 for (UInt32 i = 0; i < d.num_entries; i++)
631 {
632 CExtent e;
633 e.Parse(buffer + d.offset + i * d.entry_size);
634 // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE;
635 if (e.IsRAW())
636 {
637 if (e.target_source >= header.block_devices.num_entries)
638 return S_FALSE;
639 const UInt64 endSector = e.target_data + e.num_sectors;
640 const UInt64 endOffset = endSector << kSectorSizeLog;
641 if (_totalSize < endOffset)
642 _totalSize = endOffset;
643 }
644 MethodsMask |= (UInt32)1 << e.target_type;
645 Extents.Add(e);
646 }
647 }
648
649 // _usedSize = _totalSize;
650 {
651 const CDescriptor &d = header.groups;
652 if (!d.CheckLimits(header.tables_size))
653 return S_FALSE;
654 if (d.entry_size != k_Group_Size)
655 return S_FALSE;
656 AString s;
657 for (UInt32 i = 0; i < d.num_entries; i++)
658 {
659 CGroup g;
660 g.Parse(buffer + d.offset + i * d.entry_size);
661 if (_totalSize < g.maximum_size)
662 _totalSize = g.maximum_size;
663 s += " ";
664 AddName36ToString(s, g.name, true);
665 AddComment_UInt64(s, "maximum_size", g.maximum_size);
666 AddComment_UInt64(s, "flags", g.flags);
667 s.Add_LF();
668 }
669 GroupsString = s;
670 }
671
672 {
673 const CDescriptor &d = header.block_devices;
674 if (!d.CheckLimits(header.tables_size))
675 return S_FALSE;
676 if (d.entry_size != k_Device_Size)
677 return S_FALSE;
678 AString s;
679 // CRecordVector<CDevice> devices;
680 for (UInt32 i = 0; i < d.num_entries; i++)
681 {
682 CDevice v;
683 v.Parse(buffer + d.offset + i * d.entry_size);
684 // if (i == 0)
685 {
686 // it's super_device is first device;
687 if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog))
688 return S_FALSE;
689 }
690 if (_totalSize < v.size)
691 _totalSize = v.size;
692 s += " ";
693 if (i == 0)
694 AddName36ToString(DeviceArcName, v.partition_name, true);
695 // devices.Add(v);
696 AddName36ToString(s, v.partition_name, true);
697 AddComment_UInt64(s, "size", v.size);
698 AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector);
699 AddComment_UInt64(s, "alignment", v.alignment);
700 AddComment_UInt64(s, "alignment_offset", v.alignment_offset);
701 AddComment_UInt64(s, "flags", v.flags);
702 s.Add_LF();
703 }
704 DevicesString = s;
705 }
706
707 {
708 FOR_VECTOR (i, _items)
709 {
710 CPartition &part = _items[i];
711 if (part.first_extent_index > Extents.Size() ||
712 part.num_extents > Extents.Size() - part.first_extent_index)
713 return S_FALSE;
714
715 UInt64 numSectors = 0;
716 UInt64 numSectors_Pack = 0;
717 UInt32 methods = 0;
718 for (UInt32 k = 0; k < part.num_extents; k++)
719 {
720 const CExtent &e = Extents[part.first_extent_index + k];
721 numSectors += e.num_sectors;
722 if (e.IsRAW())
723 numSectors_Pack += e.num_sectors;
724 methods |= (UInt32)1 << e.target_type;
725 }
726 part.NumSectors = numSectors;
727 part.NumSectors_Pack = numSectors_Pack;
728 part.MethodsMask = methods;
729 }
730 }
731
732 return S_OK;
733}
734
735
736STDMETHODIMP CHandler::Open(IInStream *stream,
737 const UInt64 * /* maxCheckStartPosition */,
738 IArchiveOpenCallback * /* openArchiveCallback */)
739{
740 COM_TRY_BEGIN
741 Close();
742 RINOK(Open2(stream));
743 _stream = stream;
744
745 int mainFileIndex = -1;
746 unsigned numNonEmptyParts = 0;
747
748 FOR_VECTOR (fileIndex, _items)
749 {
750 CPartition &item = _items[fileIndex];
751 if (item.NumSectors != 0)
752 {
753 mainFileIndex = fileIndex;
754 numNonEmptyParts++;
755 CMyComPtr<ISequentialInStream> parseStream;
756 if (GetStream(fileIndex, &parseStream) == S_OK && parseStream)
757 {
758 const size_t kParseSize = 1 << 11;
759 Byte buf[kParseSize];
760 if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK)
761 {
762 UInt64 extSize;
763 if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES)
764 if (extSize == item.GetSize())
765 item.Ext = "ext";
766 }
767 }
768 }
769 }
770 if (numNonEmptyParts == 1)
771 _mainFileIndex = mainFileIndex;
772
773 return S_OK;
774 COM_TRY_END
775}
776
777
778STDMETHODIMP CHandler::Close()
779{
780 _totalSize = 0;
781 // _usedSize = 0;
782 // _headersSize = 0;
783 _items.Clear();
784 Extents.Clear();
785 _stream.Release();
786 _mainFileIndex = -1;
787 _headerWarning = false;
788 MethodsMask = 0;
789 GroupsString.Empty();
790 DevicesString.Empty();
791 DeviceArcName.Empty();
792 return S_OK;
793}
794
795
796static const Byte kProps[] =
797{
798 kpidPath,
799 kpidSize,
800 kpidPackSize,
801 kpidCharacts,
802 kpidMethod,
803 kpidNumBlocks,
804 kpidOffset
805};
806
807static const Byte kArcProps[] =
808{
809 kpidUnpackVer,
810 kpidMethod,
811 kpidClusterSize,
812 // kpidHeadersSize,
813 // kpidFreeSpace,
814 kpidName,
815 kpidComment
816};
817
818IMP_IInArchive_Props
819IMP_IInArchive_ArcProps
820
821STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
822{
823 COM_TRY_BEGIN
824 NCOM::CPropVariant prop;
825 switch (propID)
826 {
827 case kpidMainSubfile:
828 {
829 if (_mainFileIndex >= 0)
830 prop = (UInt32)_mainFileIndex;
831 break;
832 }
833 case kpidPhySize: prop = _totalSize; break;
834
835 // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break;
836 // case kpidHeadersSize: prop = _headersSize; break;
837
838 case kpidMethod:
839 {
840 const UInt32 m = MethodsMask;
841 if (m != 0)
842 {
843 FLAGS_TO_PROP(g_Methods, m, prop);
844 }
845 break;
846 }
847
848 case kpidUnpackVer:
849 {
850 AString s;
851 s.Add_UInt32(Major_version);
852 s += '.';
853 s.Add_UInt32(Minor_version);
854 prop = s;
855 break;
856 }
857
858 case kpidClusterSize:
859 prop = geom.logical_block_size;
860 break;
861
862 case kpidComment:
863 {
864 AString s;
865
866 s += "metadata_slot_count: ";
867 s.Add_UInt32(geom.metadata_slot_count);
868 s.Add_LF();
869
870 s += "metadata_max_size: ";
871 s.Add_UInt32(geom.metadata_max_size);
872 s.Add_LF();
873
874 if (Flags != 0)
875 {
876 s += "flags: ";
877 s += FlagsToString(g_Header_Flags, ARRAY_SIZE(g_Header_Flags), Flags);
878 s.Add_LF();
879 }
880
881 if (!GroupsString.IsEmpty())
882 {
883 s += "Groups:";
884 s.Add_LF();
885 s += GroupsString;
886 }
887
888 if (!DevicesString.IsEmpty())
889 {
890 s += "BlockDevices:";
891 s.Add_LF();
892 s += DevicesString;
893 }
894
895 if (!s.IsEmpty())
896 prop = s;
897 break;
898 }
899
900 case kpidName:
901 if (!DeviceArcName.IsEmpty())
902 prop = DeviceArcName + ".lpimg";
903 break;
904
905 case kpidWarningFlags:
906 if (_headerWarning)
907 {
908 UInt32 v = kpv_ErrorFlags_HeadersError;
909 prop = v;
910 }
911 break;
912 }
913 prop.Detach(value);
914 return S_OK;
915 COM_TRY_END
916}
917
918
919STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
920{
921 *numItems = _items.Size();
922 return S_OK;
923}
924
925
926STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
927{
928 COM_TRY_BEGIN
929 NCOM::CPropVariant prop;
930
931 const CPartition &item = _items[index];
932
933 switch (propID)
934 {
935 case kpidPath:
936 {
937 AString s;
938 AddName36ToString(s, item.name, false);
939 if (s.IsEmpty())
940 s.Add_UInt32(index);
941 if (item.num_extents != 0)
942 {
943 s += '.';
944 s += (item.Ext ? item.Ext : "img");
945 }
946 prop = s;
947 break;
948 }
949
950 case kpidSize: prop = item.GetSize(); break;
951 case kpidPackSize: prop = item.GetPackSize(); break;
952 case kpidNumBlocks: prop = item.num_extents; break;
953 case kpidMethod:
954 {
955 const UInt32 m = item.MethodsMask;
956 if (m != 0)
957 {
958 FLAGS_TO_PROP(g_Methods, m, prop);
959 }
960 break;
961 }
962 case kpidOffset:
963 if (item.num_extents != 0)
964 if (item.first_extent_index < Extents.Size())
965 prop = Extents[item.first_extent_index].target_data << kSectorSizeLog;
966 break;
967
968 case kpidCharacts:
969 {
970 AString s;
971 s += "group:";
972 s.Add_UInt32(item.group_index);
973 s.Add_Space();
974 s += FlagsToString(g_PartitionAttr, ARRAY_SIZE(g_PartitionAttr), item.attributes);
975 prop = s;
976 break;
977 }
978 }
979
980 prop.Detach(value);
981 return S_OK;
982 COM_TRY_END
983}
984
985
986
987STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
988{
989 COM_TRY_BEGIN
990 *stream = NULL;
991
992 const CPartition &item = _items[index];
993
994 if (item.first_extent_index > Extents.Size()
995 || item.num_extents > Extents.Size() - item.first_extent_index)
996 return S_FALSE;
997
998 if (item.num_extents == 0)
999 return CreateLimitedInStream(_stream, 0, 0, stream);
1000
1001 if (item.num_extents == 1)
1002 {
1003 const CExtent &e = Extents[item.first_extent_index];
1004 if (e.IsRAW())
1005 {
1006 const UInt64 pos = e.target_data << kSectorSizeLog;
1007 if ((pos >> kSectorSizeLog) != e.target_data)
1008 return S_FALSE;
1009 const UInt64 size = item.GetSize();
1010 if (pos + size < pos)
1011 return S_FALSE;
1012 return CreateLimitedInStream(_stream, pos, size, stream);
1013 }
1014 }
1015
1016 CExtentsStream *extentStreamSpec = new CExtentsStream();
1017 CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
1018
1019 // const unsigned kNumDebugExtents = 10;
1020 extentStreamSpec->Extents.Reserve(item.num_extents + 1
1021 // + kNumDebugExtents
1022 );
1023
1024 UInt64 virt = 0;
1025 for (UInt32 k = 0; k < item.num_extents; k++)
1026 {
1027 const CExtent &e = Extents[item.first_extent_index + k];
1028
1029 CSeekExtent se;
1030 {
1031 const UInt64 numSectors = e.num_sectors;
1032 if (numSectors == 0)
1033 {
1034 continue;
1035 // return S_FALSE;
1036 }
1037 const UInt64 numBytes = numSectors << kSectorSizeLog;
1038 if ((numBytes >> kSectorSizeLog) != numSectors)
1039 return S_FALSE;
1040 if (numBytes >= ((UInt64)1 << 63) - virt)
1041 return S_FALSE;
1042
1043 se.Virt = virt;
1044 virt += numBytes;
1045 }
1046
1047 const UInt64 phySector = e.target_data;
1048 if (e.target_type == LP_TARGET_TYPE_ZERO)
1049 {
1050 if (phySector != 0)
1051 return S_FALSE;
1052 se.SetAs_ZeroFill();
1053 }
1054 else if (e.target_type == LP_TARGET_TYPE_LINEAR)
1055 {
1056 se.Phy = phySector << kSectorSizeLog;
1057 if ((se.Phy >> kSectorSizeLog) != phySector)
1058 return S_FALSE;
1059 if (se.Phy >= ((UInt64)1 << 63))
1060 return S_FALSE;
1061 }
1062 else
1063 return S_FALSE;
1064
1065 extentStreamSpec->Extents.AddInReserved(se);
1066
1067 /*
1068 {
1069 // for debug
1070 const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents;
1071 for (unsigned i = 0; i < kNumDebugExtents; i++)
1072 {
1073 se.Phy += kAdd;
1074 // se.Phy += (UInt64)1 << 63; // for debug
1075 // se.Phy += 1; // for debug
1076 se.Virt += kAdd;
1077 extentStreamSpec->Extents.AddInReserved(se);
1078 }
1079 }
1080 */
1081 }
1082
1083 CSeekExtent se;
1084 se.Phy = 0;
1085 se.Virt = virt;
1086 extentStreamSpec->Extents.Add(se);
1087 extentStreamSpec->Stream = _stream;
1088 extentStreamSpec->Init();
1089 *stream = extentStream.Detach();
1090
1091 return S_OK;
1092 COM_TRY_END
1093}
1094
1095
1096STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1097 Int32 testMode, IArchiveExtractCallback *extractCallback)
1098{
1099 COM_TRY_BEGIN
1100 const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1101 if (allFilesMode)
1102 numItems = _items.Size();
1103 if (numItems == 0)
1104 return S_OK;
1105 UInt64 totalSize = 0;
1106 UInt32 i;
1107 for (i = 0; i < numItems; i++)
1108 {
1109 const UInt32 index = allFilesMode ? i : indices[i];
1110 totalSize += _items[index].GetSize();
1111 }
1112 extractCallback->SetTotal(totalSize);
1113
1114 totalSize = 0;
1115
1116 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
1117 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
1118
1119 CLocalProgress *lps = new CLocalProgress;
1120 CMyComPtr<ICompressProgressInfo> progress = lps;
1121 lps->Init(extractCallback, false);
1122
1123 for (i = 0; i < numItems; i++)
1124 {
1125 lps->InSize = totalSize;
1126 lps->OutSize = totalSize;
1127 RINOK(lps->SetCur());
1128 CMyComPtr<ISequentialOutStream> outStream;
1129 const Int32 askMode = testMode ?
1130 NExtract::NAskMode::kTest :
1131 NExtract::NAskMode::kExtract;
1132 const UInt32 index = allFilesMode ? i : indices[i];
1133
1134 RINOK(extractCallback->GetStream(index, &outStream, askMode));
1135
1136 const UInt64 size = _items[index].GetSize();
1137 totalSize += size;
1138 if (!testMode && !outStream)
1139 continue;
1140
1141 RINOK(extractCallback->PrepareOperation(askMode));
1142
1143 CMyComPtr<ISequentialInStream> inStream;
1144 const HRESULT hres = GetStream(index, &inStream);
1145 int opRes = NExtract::NOperationResult::kUnsupportedMethod;
1146 if (hres != S_FALSE)
1147 {
1148 if (hres != S_OK)
1149 return hres;
1150 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
1151 opRes = NExtract::NOperationResult::kDataError;
1152 if (copyCoderSpec->TotalSize == size)
1153 opRes = NExtract::NOperationResult::kOK;
1154 else if (copyCoderSpec->TotalSize < size)
1155 opRes = NExtract::NOperationResult::kUnexpectedEnd;
1156 }
1157 outStream.Release();
1158 RINOK(extractCallback->SetOperationResult(opRes));
1159 }
1160
1161 return S_OK;
1162 COM_TRY_END
1163}
1164
1165
1166REGISTER_ARC_I(
1167 "LP", "lpimg img", NULL, 0xc1,
1168 k_Signature,
1169 LP_PARTITION_RESERVED_BYTES,
1170 0,
1171 NULL)
1172
1173}}
diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp
index e1984d2..6711da6 100644
--- 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
487 case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break; 487 case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break;
488 case kpidMTime: 488 case kpidMTime:
489 { 489 {
490 FILETIME utc;
491 UInt32 unixTime; 490 UInt32 unixTime;
492 if (item.GetUnixTime(unixTime)) 491 if (item.GetUnixTime(unixTime))
493 NTime::UnixTimeToFileTime(unixTime, utc); 492 PropVariant_SetFrom_UnixTime(prop, unixTime);
494 else 493 else
495 { 494 PropVariant_SetFrom_DosTime(prop, item.ModifiedTime);
496 FILETIME localFileTime;
497 if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
498 {
499 if (!LocalFileTimeToFileTime(&localFileTime, &utc))
500 utc.dwHighDateTime = utc.dwLowDateTime = 0;
501 }
502 else
503 utc.dwHighDateTime = utc.dwLowDateTime = 0;
504 }
505 prop = utc;
506 break; 495 break;
507 } 496 }
508 // case kpidAttrib: prop = (UInt32)item.Attributes; break; 497 // case kpidAttrib: prop = (UInt32)item.Attributes; break;
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index daa01fe..7d0c6f7 100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -278,7 +278,7 @@ struct CSiAttr
278{ 278{
279 UInt64 CTime; 279 UInt64 CTime;
280 UInt64 MTime; 280 UInt64 MTime;
281 // UInt64 ThisRecMTime; 281 UInt64 ThisRecMTime;
282 UInt64 ATime; 282 UInt64 ATime;
283 UInt32 Attrib; 283 UInt32 Attrib;
284 284
@@ -300,7 +300,7 @@ bool CSiAttr::Parse(const Byte *p, unsigned size)
300 return false; 300 return false;
301 G64(p + 0x00, CTime); 301 G64(p + 0x00, CTime);
302 G64(p + 0x08, MTime); 302 G64(p + 0x08, MTime);
303 // G64(p + 0x10, ThisRecMTime); 303 G64(p + 0x10, ThisRecMTime);
304 G64(p + 0x18, ATime); 304 G64(p + 0x18, ATime);
305 G32(p + 0x20, Attrib); 305 G32(p + 0x20, Attrib);
306 SecurityId = 0; 306 SecurityId = 0;
@@ -2301,6 +2301,7 @@ static const Byte kProps[] =
2301 kpidMTime, 2301 kpidMTime,
2302 kpidCTime, 2302 kpidCTime,
2303 kpidATime, 2303 kpidATime,
2304 kpidChangeTime,
2304 kpidAttrib, 2305 kpidAttrib,
2305 kpidLinks, 2306 kpidLinks,
2306 kpidINode, 2307 kpidINode,
@@ -2577,7 +2578,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
2577 case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; 2578 case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
2578 case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; 2579 case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
2579 case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break; 2580 case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break;
2580 // case kpidRecMTime: if (fn) NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break; 2581 case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break;
2581 2582
2582 /* 2583 /*
2583 case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break; 2584 case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break;
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
index ee26557..34a38ac 100644
--- a/CPP/7zip/Archive/PeHandler.cpp
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -885,11 +885,7 @@ IMP_IInArchive_ArcProps_WITH_NAME
885static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) 885static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
886{ 886{
887 if (unixTime != 0) 887 if (unixTime != 0)
888 { 888 PropVariant_SetFrom_UnixTime(prop, unixTime);
889 FILETIME ft;
890 NTime::UnixTimeToFileTime(unixTime, ft);
891 prop = ft;
892 }
893} 889}
894 890
895STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 891STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp
index 05a07e5..101bfd9 100644
--- a/CPP/7zip/Archive/PpmdHandler.cpp
+++ b/CPP/7zip/Archive/PpmdHandler.cpp
@@ -174,7 +174,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
174 { 174 {
175 // time can be in Unix format ??? 175 // time can be in Unix format ???
176 FILETIME utc; 176 FILETIME utc;
177 if (NTime::DosTimeToFileTime(_item.Time, utc)) 177 if (NTime::DosTime_To_FileTime(_item.Time, utc))
178 prop = utc; 178 prop = utc;
179 break; 179 break;
180 } 180 }
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
index bb8a2ed..563695f 100644
--- 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
1591static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop) 1591static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop)
1592{ 1592{
1593 unsigned size; 1593 unsigned size;
1594 int offset = item.FindExtra(NExtraID::kTime, size); 1594 const int offset = item.FindExtra(NExtraID::kTime, size);
1595 if (offset < 0) 1595 if (offset < 0)
1596 return; 1596 return;
1597 1597
1598 const Byte *p = item.Extra + (unsigned)offset; 1598 const Byte *p = item.Extra + (unsigned)offset;
1599 UInt64 flags; 1599 UInt64 flags;
1600 { 1600 {
1601 unsigned num = ReadVarInt(p, size, &flags); 1601 const unsigned num = ReadVarInt(p, size, &flags);
1602 if (num == 0) 1602 if (num == 0)
1603 return; 1603 return;
1604 p += num; 1604 p += num;
@@ -1610,8 +1610,8 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
1610 1610
1611 unsigned numStamps = 0; 1611 unsigned numStamps = 0;
1612 unsigned curStamp = 0; 1612 unsigned curStamp = 0;
1613 unsigned i; 1613
1614 for (i = 0; i < 3; i++) 1614 for (unsigned i = 0; i < 3; i++)
1615 if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) 1615 if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0)
1616 { 1616 {
1617 if (i == stampIndex) 1617 if (i == stampIndex)
@@ -1620,20 +1620,28 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
1620 } 1620 }
1621 1621
1622 FILETIME ft; 1622 FILETIME ft;
1623 1623
1624 unsigned timePrec = 0;
1625 unsigned ns100 = 0;
1626
1624 if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) 1627 if ((flags & NTimeRecord::NFlags::kUnixTime) != 0)
1625 { 1628 {
1626 curStamp *= 4; 1629 curStamp *= 4;
1627 if (curStamp + 4 > size) 1630 if (curStamp + 4 > size)
1628 return; 1631 return;
1629 const Byte *p2 = p + curStamp; 1632 p += curStamp;
1630 UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2)); 1633 UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p));
1631 numStamps *= 4; 1634 numStamps *= 4;
1635 timePrec = k_PropVar_TimePrec_Unix;
1632 if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) 1636 if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size)
1633 { 1637 {
1634 const UInt32 ns = Get32(p2 + numStamps) & 0x3FFFFFFF; 1638 const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF;
1635 if (ns < 1000000000) 1639 if (ns < 1000000000)
1640 {
1636 val += ns / 100; 1641 val += ns / 100;
1642 ns100 = (unsigned)(ns % 100);
1643 timePrec = k_PropVar_TimePrec_1ns;
1644 }
1637 } 1645 }
1638 ft.dwLowDateTime = (DWORD)val; 1646 ft.dwLowDateTime = (DWORD)val;
1639 ft.dwHighDateTime = (DWORD)(val >> 32); 1647 ft.dwHighDateTime = (DWORD)(val >> 32);
@@ -1643,12 +1651,12 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
1643 curStamp *= 8; 1651 curStamp *= 8;
1644 if (curStamp + 8 > size) 1652 if (curStamp + 8 > size)
1645 return; 1653 return;
1646 const Byte *p2 = p + curStamp; 1654 p += curStamp;
1647 ft.dwLowDateTime = Get32(p2); 1655 ft.dwLowDateTime = Get32(p);
1648 ft.dwHighDateTime = Get32(p2 + 4); 1656 ft.dwHighDateTime = Get32(p + 4);
1649 } 1657 }
1650 1658
1651 prop = ft; 1659 prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100);
1652} 1660}
1653 1661
1654 1662
@@ -1715,21 +1723,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1715 { 1723 {
1716 TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop); 1724 TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop);
1717 if (prop.vt == VT_EMPTY && item.Has_UnixMTime()) 1725 if (prop.vt == VT_EMPTY && item.Has_UnixMTime())
1718 { 1726 PropVariant_SetFrom_UnixTime(prop, item.UnixMTime);
1719 FILETIME ft;
1720 NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft);
1721 prop = ft;
1722 }
1723 if (prop.vt == VT_EMPTY && ref.Parent >= 0) 1727 if (prop.vt == VT_EMPTY && ref.Parent >= 0)
1724 { 1728 {
1725 const CItem &baseItem = _items[_refs[ref.Parent].Item]; 1729 const CItem &baseItem = _items[_refs[ref.Parent].Item];
1726 TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop); 1730 TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop);
1727 if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime()) 1731 if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime())
1728 { 1732 PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime);
1729 FILETIME ft;
1730 NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft);
1731 prop = ft;
1732 }
1733 } 1733 }
1734 break; 1734 break;
1735 } 1735 }
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
index 7491c50..ecadf85 100644
--- 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)
360static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) 360static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
361{ 361{
362 rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); 362 rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
363 unsigned numDigits = (mask & 3); 363 const unsigned numDigits = (mask & 3);
364 rarTime.SubTime[0] = 364 rarTime.SubTime[0] =
365 rarTime.SubTime[1] = 365 rarTime.SubTime[1] =
366 rarTime.SubTime[2] = 0; 366 rarTime.SubTime[2] = 0;
@@ -405,8 +405,8 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
405 405
406 item.MTime.LowSecond = 0; 406 item.MTime.LowSecond = 0;
407 item.MTime.SubTime[0] = 407 item.MTime.SubTime[0] =
408 item.MTime.SubTime[1] = 408 item.MTime.SubTime[1] =
409 item.MTime.SubTime[2] = 0; 409 item.MTime.SubTime[2] = 0;
410 410
411 p += kFileHeaderSize; 411 p += kFileHeaderSize;
412 size -= kFileHeaderSize; 412 size -= kFileHeaderSize;
@@ -941,31 +941,32 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
941 return S_OK; 941 return S_OK;
942} 942}
943 943
944static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) 944static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &ft)
945{ 945{
946 if (!NTime::DosTimeToFileTime(rarTime.DosTime, result)) 946 if (!NTime::DosTime_To_FileTime(rarTime.DosTime, ft))
947 return false; 947 return false;
948 UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; 948 UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
949 value += (UInt64)rarTime.LowSecond * 10000000; 949 v += (UInt32)rarTime.LowSecond * 10000000;
950 value += ((UInt64)rarTime.SubTime[2] << 16) + 950 v +=
951 ((UInt64)rarTime.SubTime[1] << 8) + 951 ((UInt32)rarTime.SubTime[2] << 16) +
952 ((UInt64)rarTime.SubTime[0]); 952 ((UInt32)rarTime.SubTime[1] << 8) +
953 result.dwLowDateTime = (DWORD)value; 953 ((UInt32)rarTime.SubTime[0]);
954 result.dwHighDateTime = DWORD(value >> 32); 954 ft.dwLowDateTime = (DWORD)v;
955 ft.dwHighDateTime = (DWORD)(v >> 32);
955 return true; 956 return true;
956} 957}
957 958
958static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) 959static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop)
959{ 960{
960 FILETIME localFileTime, utcFileTime; 961 FILETIME localFileTime, utc;
961 if (RarTimeToFileTime(rarTime, localFileTime)) 962 if (RarTimeToFileTime(rarTime, localFileTime)
962 { 963 && LocalFileTimeToFileTime(&localFileTime, &utc))
963 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) 964 prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
964 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; 965 /*
965 }
966 else 966 else
967 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; 967 utc.dwHighDateTime = utc.dwLowDateTime = 0;
968 prop = utcFileTime; 968 // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
969 */
969} 970}
970 971
971STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 972STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h
index 9626433..2f5bbd3 100644
--- a/CPP/7zip/Archive/Rar/RarVol.h
+++ b/CPP/7zip/Archive/Rar/RarVol.h
@@ -52,7 +52,7 @@ public:
52 ext.IsEqualTo_Ascii_NoCase("r01")) 52 ext.IsEqualTo_Ascii_NoCase("r01"))
53 { 53 {
54 _changed = ext; 54 _changed = ext;
55 _before = name.Left(dotPos + 1); 55 _before.SetFrom(name.Ptr(), dotPos + 1);
56 return true; 56 return true;
57 } 57 }
58 } 58 }
@@ -60,16 +60,23 @@ public:
60 60
61 if (newStyle) 61 if (newStyle)
62 { 62 {
63 unsigned i = base.Len(); 63 unsigned k = base.Len();
64
65 for (; k != 0; k--)
66 if (IsDigit(base[k - 1]))
67 break;
68
69 unsigned i = k;
64 70
65 for (; i != 0; i--) 71 for (; i != 0; i--)
66 if (!IsDigit(base[i - 1])) 72 if (!IsDigit(base[i - 1]))
67 break; 73 break;
68 74
69 if (i != base.Len()) 75 if (i != k)
70 { 76 {
71 _before = base.Left(i); 77 _before.SetFrom(base.Ptr(), i);
72 _changed = base.Ptr(i); 78 _changed.SetFrom(base.Ptr(i), k - i);
79 _after.Insert(0, base.Ptr(k));
73 return true; 80 return true;
74 } 81 }
75 } 82 }
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
index e0ec28c..366f8ef 100644
--- a/CPP/7zip/Archive/RpmHandler.cpp
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -215,11 +215,7 @@ class CHandler: public CHandlerCont
215 void SetTime(NCOM::CPropVariant &prop) const 215 void SetTime(NCOM::CPropVariant &prop) const
216 { 216 {
217 if (_time_Defined && _buildTime != 0) 217 if (_time_Defined && _buildTime != 0)
218 { 218 PropVariant_SetFrom_UnixTime(prop, _buildTime);
219 FILETIME ft;
220 NTime::UnixTimeToFileTime(_buildTime, ft);
221 prop = ft;
222 }
223 } 219 }
224 220
225 void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const 221 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 100644
index 0000000..47e3ed8
--- /dev/null
+++ b/CPP/7zip/Archive/SparseHandler.cpp
@@ -0,0 +1,548 @@
1// SparseHandler.cpp
2
3#include "StdAfx.h"
4
5#include "../../../C/CpuArch.h"
6
7#include "../../Common/ComTry.h"
8
9#include "../../Windows/PropVariantUtils.h"
10
11#include "../Common/RegisterArc.h"
12#include "../Common/StreamUtils.h"
13
14#include "HandlerCont.h"
15
16#define Get16(p) GetUi16(p)
17#define Get32(p) GetUi32(p)
18
19#define G16(_offs_, dest) dest = Get16(p + (_offs_));
20#define G32(_offs_, dest) dest = Get32(p + (_offs_));
21
22using namespace NWindows;
23
24namespace NArchive {
25namespace NSparse {
26
27// libsparse and simg2img
28
29struct CHeader
30{
31 // UInt32 magic; /* 0xed26ff3a */
32 // UInt16 major_version; /* (0x1) - reject images with higher major versions */
33 // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */
34 UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */
35 UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
36 UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */
37 UInt32 NumBlocks; /* total blocks in the non-sparse output image */
38 UInt32 NumChunks; /* total chunks in the sparse input image */
39 // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */
40
41 void Parse(const Byte *p)
42 {
43 // G16 (4, major_version);
44 // G16 (6, minor_version);
45 G16 (8, file_hdr_sz);
46 G16 (10, chunk_hdr_sz);
47 G32 (12, BlockSize);
48 G32 (16, NumBlocks);
49 G32 (20, NumChunks);
50 // G32 (24, image_checksum);
51 }
52};
53
54// #define SPARSE_HEADER_MAGIC 0xed26ff3a
55
56#define CHUNK_TYPE_RAW 0xCAC1
57#define CHUNK_TYPE_FILL 0xCAC2
58#define CHUNK_TYPE_DONT_CARE 0xCAC3
59#define CHUNK_TYPE_CRC32 0xCAC4
60
61#define MY__CHUNK_TYPE_FILL 0
62#define MY__CHUNK_TYPE_DONT_CARE 1
63#define MY__CHUNK_TYPE_RAW__START 2
64
65static const char * const g_Methods[] =
66{
67 "RAW"
68 , "FILL"
69 , "SPARSE" // "DONT_CARE"
70 , "CRC32"
71};
72
73static const unsigned kFillSize = 4;
74
75struct CChunk
76{
77 UInt32 VirtBlock;
78 Byte Fill [kFillSize];
79 UInt64 PhyOffset;
80};
81
82static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 };
83
84
85class CHandler: public CHandlerImg
86{
87 CRecordVector<CChunk> Chunks;
88 UInt64 _virtSize_fromChunks;
89 unsigned _blockSizeLog;
90 UInt32 _chunkIndexPrev;
91
92 UInt64 _packSizeProcessed;
93 UInt64 _phySize;
94 UInt32 _methodFlags;
95 bool _isArc;
96 bool _headersError;
97 bool _unexpectedEnd;
98 // bool _unsupported;
99 UInt32 NumChunks; // from header
100
101 HRESULT Seek2(UInt64 offset)
102 {
103 _posInArc = offset;
104 return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
105 }
106
107 void InitSeekPositions()
108 {
109 /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()).
110 So we must reset these variables before first call of Read() */
111 Reset_VirtPos();
112 Reset_PosInArc();
113 _chunkIndexPrev = 0;
114 _packSizeProcessed = 0;
115 }
116
117 // virtual functions
118 bool Init_PackSizeProcessed()
119 {
120 _packSizeProcessed = 0;
121 return true;
122 }
123 bool Get_PackSizeProcessed(UInt64 &size)
124 {
125 size = _packSizeProcessed;
126 return true;
127 }
128
129 HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback);
130 HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed);
131
132public:
133 INTERFACE_IInArchive_Img(;)
134
135 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
136 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
137};
138
139
140
141static const Byte kProps[] =
142{
143 kpidSize,
144 kpidPackSize
145};
146
147static const Byte kArcProps[] =
148{
149 kpidClusterSize,
150 kpidNumBlocks,
151 kpidMethod
152};
153
154IMP_IInArchive_Props
155IMP_IInArchive_ArcProps
156
157STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
158{
159 COM_TRY_BEGIN
160 NCOM::CPropVariant prop;
161
162 switch (propID)
163 {
164 case kpidMainSubfile: prop = (UInt32)0; break;
165 case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break;
166 case kpidNumBlocks: prop = (UInt32)NumChunks; break;
167 case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
168
169 case kpidMethod:
170 {
171 FLAGS_TO_PROP(g_Methods, _methodFlags, prop);
172 break;
173 }
174
175 case kpidErrorFlags:
176 {
177 UInt32 v = 0;
178 if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
179 if (_headersError) v |= kpv_ErrorFlags_HeadersError;
180 if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
181 // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
182 if (!Stream && v == 0 && _isArc)
183 v = kpv_ErrorFlags_HeadersError;
184 if (v != 0)
185 prop = v;
186 break;
187 }
188 }
189
190 prop.Detach(value);
191 return S_OK;
192 COM_TRY_END
193}
194
195
196STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
197{
198 COM_TRY_BEGIN
199 NCOM::CPropVariant prop;
200
201 switch (propID)
202 {
203 case kpidSize: prop = _size; break;
204 case kpidPackSize: prop = _phySize; break;
205 case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
206 }
207
208 prop.Detach(value);
209 return S_OK;
210 COM_TRY_END
211}
212
213
214static unsigned GetLogSize(UInt32 size)
215{
216 unsigned k;
217 for (k = 0; k < 32; k++)
218 if (((UInt32)1 << k) == size)
219 return k;
220 return k;
221}
222
223
224HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
225{
226 const unsigned kHeaderSize = 28;
227 const unsigned kChunkHeaderSize = 12;
228 CHeader h;
229 {
230 Byte buf[kHeaderSize];
231 RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
232 if (memcmp(buf, k_Signature, 6) != 0)
233 return S_FALSE;
234 h.Parse(buf);
235 }
236
237 if (h.file_hdr_sz != kHeaderSize ||
238 h.chunk_hdr_sz != kChunkHeaderSize)
239 return S_FALSE;
240
241 NumChunks = h.NumChunks;
242
243 const unsigned logSize = GetLogSize(h.BlockSize);
244 if (logSize < 2 || logSize >= 32)
245 return S_FALSE;
246 _blockSizeLog = logSize;
247
248 _size = (UInt64)h.NumBlocks << logSize;
249
250 if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit
251 return S_FALSE;
252
253 _isArc = true;
254 Chunks.Reserve(h.NumChunks + 1);
255 UInt64 offset = kHeaderSize;
256 UInt32 virtBlock = 0;
257 UInt32 i;
258
259 for (i = 0; i < h.NumChunks; i++)
260 {
261 {
262 const UInt32 mask = ((UInt32)1 << 16) - 1;
263 if ((i & mask) == mask && openCallback)
264 {
265 RINOK(openCallback->SetCompleted(NULL, &offset));
266 }
267 }
268 Byte buf[kChunkHeaderSize];
269 {
270 size_t processed = kChunkHeaderSize;
271 RINOK(ReadStream(stream, buf, &processed));
272 if (kChunkHeaderSize != processed)
273 {
274 offset += kChunkHeaderSize;
275 break;
276 }
277 }
278 const UInt32 type = Get32(&buf[0]);
279 const UInt32 numBlocks = Get32(&buf[4]);
280 UInt32 size = Get32(&buf[8]);
281
282 if (type < CHUNK_TYPE_RAW ||
283 type > CHUNK_TYPE_CRC32)
284 return S_FALSE;
285 if (size < kChunkHeaderSize)
286 return S_FALSE;
287 CChunk c;
288 c.PhyOffset = offset + kChunkHeaderSize;
289 c.VirtBlock = virtBlock;
290 offset += size;
291 size -= kChunkHeaderSize;
292 _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW));
293
294 if (numBlocks > h.NumBlocks - virtBlock)
295 return S_FALSE;
296
297 if (type == CHUNK_TYPE_CRC32)
298 {
299 // crc chunk must be last chunk (i == h.NumChunks -1);
300 if (size != kFillSize || numBlocks != 0)
301 return S_FALSE;
302 {
303 size_t processed = kFillSize;
304 RINOK(ReadStream(stream, c.Fill, &processed));
305 if (kFillSize != processed)
306 break;
307 }
308 continue;
309 }
310 // else
311 {
312 if (numBlocks == 0)
313 return S_FALSE;
314
315 if (type == CHUNK_TYPE_DONT_CARE)
316 {
317 if (size != 0)
318 return S_FALSE;
319 c.PhyOffset = MY__CHUNK_TYPE_DONT_CARE;
320 }
321 else if (type == CHUNK_TYPE_FILL)
322 {
323 if (size != kFillSize)
324 return S_FALSE;
325 c.PhyOffset = MY__CHUNK_TYPE_FILL;
326 size_t processed = kFillSize;
327 RINOK(ReadStream(stream, c.Fill, &processed));
328 if (kFillSize != processed)
329 break;
330 }
331 else if (type == CHUNK_TYPE_RAW)
332 {
333 /* Here we require (size == virtSize).
334 Probably original decoder also requires it.
335 But maybe size of last chunk can be non-aligned with blockSize ? */
336 const UInt32 virtSize = (numBlocks << _blockSizeLog);
337 if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog))
338 return S_FALSE;
339 }
340 else
341 return S_FALSE;
342
343 virtBlock += numBlocks;
344 Chunks.AddInReserved(c);
345 if (type == CHUNK_TYPE_RAW)
346 RINOK(stream->Seek(offset, STREAM_SEEK_SET, NULL));
347 }
348 }
349
350 if (i != h.NumChunks)
351 _unexpectedEnd = true;
352 else if (virtBlock != h.NumBlocks)
353 _headersError = true;
354
355 _phySize = offset;
356
357 {
358 CChunk c;
359 c.VirtBlock = virtBlock;
360 c.PhyOffset = offset;
361 Chunks.AddInReserved(c);
362 }
363 _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog;
364
365 Stream = stream;
366 return S_OK;
367}
368
369
370STDMETHODIMP CHandler::Close()
371{
372 Chunks.Clear();
373 _isArc = false;
374 _virtSize_fromChunks = 0;
375 // _unsupported = false;
376 _headersError = false;
377 _unexpectedEnd = false;
378 _phySize = 0;
379 _methodFlags = 0;
380
381 _chunkIndexPrev = 0;
382 _packSizeProcessed = 0;
383
384 // CHandlerImg:
385 Clear_HandlerImg_Vars();
386 Stream.Release();
387 return S_OK;
388}
389
390
391STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
392{
393 COM_TRY_BEGIN
394 *stream = NULL;
395 if (Chunks.Size() < 1)
396 return S_FALSE;
397 if (Chunks.Size() < 2 && _virtSize_fromChunks != 0)
398 return S_FALSE;
399 // if (_unsupported) return S_FALSE;
400 InitSeekPositions();
401 CMyComPtr<ISequentialInStream> streamTemp = this;
402 *stream = streamTemp.Detach();
403 return S_OK;
404 COM_TRY_END
405}
406
407
408
409HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed)
410{
411 processed = 0;
412 if (offset > _phySize || offset + size > _phySize)
413 {
414 // we don't expect these cases, if (_phySize) was set correctly.
415 return S_FALSE;
416 }
417 if (offset != _posInArc)
418 {
419 const HRESULT res = Seek2(offset);
420 if (res != S_OK)
421 {
422 Reset_PosInArc(); // we don't trust seek_pos in case of error
423 return res;
424 }
425 }
426 {
427 size_t size2 = size;
428 const HRESULT res = ReadStream(Stream, data, &size2);
429 processed = (UInt32)size2;
430 _packSizeProcessed += size2;
431 _posInArc += size2;
432 if (res != S_OK)
433 Reset_PosInArc(); // we don't trust seek_pos in case of reading error
434 return res;
435 }
436}
437
438
439STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
440{
441 if (processedSize)
442 *processedSize = 0;
443 // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug
444 if (_virtPos >= _virtSize_fromChunks)
445 return S_OK;
446 {
447 const UInt64 rem = _virtSize_fromChunks - _virtPos;
448 if (size > rem)
449 size = (UInt32)rem;
450 if (size == 0)
451 return S_OK;
452 }
453
454 UInt32 chunkIndex = _chunkIndexPrev;
455 if (chunkIndex + 1 >= Chunks.Size())
456 return S_FALSE;
457 {
458 const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog);
459 if (blockIndex < Chunks[chunkIndex ].VirtBlock ||
460 blockIndex >= Chunks[chunkIndex + 1].VirtBlock)
461 {
462 unsigned left = 0, right = Chunks.Size() - 1;
463 for (;;)
464 {
465 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
466 if (mid == left)
467 break;
468 if (blockIndex < Chunks[mid].VirtBlock)
469 right = mid;
470 else
471 left = mid;
472 }
473 chunkIndex = left;
474 _chunkIndexPrev = chunkIndex;
475 }
476 }
477
478 const CChunk &c = Chunks[chunkIndex];
479 const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog);
480 {
481 const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock;
482 const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset;
483 if (size > rem)
484 size = (UInt32)rem;
485 }
486
487 const UInt64 phyOffset = c.PhyOffset;
488
489 if (phyOffset >= MY__CHUNK_TYPE_RAW__START)
490 {
491 UInt32 processed = 0;
492 const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed);
493 if (processedSize)
494 *processedSize = processed;
495 _virtPos += processed;
496 return res;
497 }
498
499 unsigned b = 0;
500
501 if (phyOffset == MY__CHUNK_TYPE_FILL)
502 {
503 const Byte b0 = c.Fill [0];
504 const Byte b1 = c.Fill [1];
505 const Byte b2 = c.Fill [2];
506 const Byte b3 = c.Fill [3];
507 if (b0 != b1 ||
508 b0 != b2 ||
509 b0 != b3)
510 {
511 if (processedSize)
512 *processedSize = size;
513 _virtPos += size;
514 Byte *dest = (Byte *)data;
515 while (size >= 4)
516 {
517 dest[0] = b0;
518 dest[1] = b1;
519 dest[2] = b2;
520 dest[3] = b3;
521 dest += 4;
522 size -= 4;
523 }
524 if (size > 0) dest[0] = b0;
525 if (size > 1) dest[1] = b1;
526 if (size > 2) dest[2] = b2;
527 return S_OK;
528 }
529 b = b0;
530 }
531 else if (phyOffset != MY__CHUNK_TYPE_DONT_CARE)
532 return S_FALSE;
533
534 memset(data, b, size);
535 _virtPos += size;
536 if (processedSize)
537 *processedSize = size;
538 return S_OK;
539}
540
541REGISTER_ARC_I(
542 "Sparse", "simg img", NULL, 0xc2,
543 k_Signature,
544 0,
545 0,
546 NULL)
547
548}}
diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp
index 6705aee..6bddfb8 100644
--- a/CPP/7zip/Archive/SplitHandler.cpp
+++ b/CPP/7zip/Archive/SplitHandler.cpp
@@ -162,7 +162,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
162 numLetters++; 162 numLetters++;
163 } 163 }
164 } 164 }
165 else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01")) 165 else if (ext2.Len() >= 2 && (
166 StringsAreEqual_Ascii(ext2.RightPtr(2), "01")
167 || StringsAreEqual_Ascii(ext2.RightPtr(2), "00")
168 ))
166 { 169 {
167 while (numLetters < ext2.Len()) 170 while (numLetters < ext2.Len())
168 { 171 {
@@ -170,7 +173,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
170 break; 173 break;
171 numLetters++; 174 numLetters++;
172 } 175 }
173 if (numLetters != ext.Len()) 176 if (numLetters != ext2.Len())
174 return S_FALSE; 177 return S_FALSE;
175 } 178 }
176 else 179 else
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp
index 74bc8fb..fe271bc 100644
--- a/CPP/7zip/Archive/SquashfsHandler.cpp
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -76,7 +76,7 @@ static const char * const k_Methods[] =
76 , "XZ" 76 , "XZ"
77}; 77};
78 78
79static const UInt32 kMetadataBlockSizeLog = 13; 79static const unsigned kMetadataBlockSizeLog = 13;
80static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog); 80static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
81 81
82enum 82enum
@@ -408,7 +408,7 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
408 408
409UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) 409UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
410{ 410{
411 bool be = _h.be; 411 const bool be = _h.be;
412 if (size < 4) 412 if (size < 4)
413 return 0; 413 return 0;
414 { 414 {
@@ -541,7 +541,7 @@ UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
541 541
542UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) 542UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
543{ 543{
544 bool be = _h.be; 544 const bool be = _h.be;
545 if (size < 12) 545 if (size < 12)
546 return 0; 546 return 0;
547 547
@@ -843,8 +843,8 @@ class CHandler:
843 CData _inodesData; 843 CData _inodesData;
844 CData _dirs; 844 CData _dirs;
845 CRecordVector<CFrag> _frags; 845 CRecordVector<CFrag> _frags;
846 // CByteBuffer _uids; 846 CByteBuffer _uids;
847 // CByteBuffer _gids; 847 CByteBuffer _gids;
848 CHeader _h; 848 CHeader _h;
849 bool _noPropsLZMA; 849 bool _noPropsLZMA;
850 bool _needCheckLzma; 850 bool _needCheckLzma;
@@ -891,14 +891,20 @@ class CHandler:
891 _cachedUnpackBlockSize = 0; 891 _cachedUnpackBlockSize = 0;
892 } 892 }
893 893
894 HRESULT Seek2(UInt64 offset)
895 {
896 return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
897 }
898
894 HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, 899 HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
895 UInt32 inSize, UInt32 outSizeMax); 900 UInt32 inSize, UInt32 outSizeMax);
896 HRESULT ReadMetadataBlock(UInt32 &packSize); 901 HRESULT ReadMetadataBlock(UInt32 &packSize);
902 HRESULT ReadMetadataBlock2();
897 HRESULT ReadData(CData &data, UInt64 start, UInt64 end); 903 HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
898 904
899 HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); 905 HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
900 HRESULT ScanInodes(UInt64 ptr); 906 HRESULT ScanInodes(UInt64 ptr);
901 // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); 907 HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
902 HRESULT Open2(IInStream *inStream); 908 HRESULT Open2(IInStream *inStream);
903 AString GetPath(int index) const; 909 AString GetPath(int index) const;
904 bool GetPackSize(int index, UInt64 &res, bool fillOffsets); 910 bool GetPackSize(int index, UInt64 &res, bool fillOffsets);
@@ -938,9 +944,9 @@ static const Byte kProps[] =
938 kpidSize, 944 kpidSize,
939 kpidPackSize, 945 kpidPackSize,
940 kpidMTime, 946 kpidMTime,
941 kpidPosixAttrib 947 kpidPosixAttrib,
942 // kpidUser, 948 kpidUserId,
943 // kpidGroup, 949 kpidGroupId
944 // kpidLinks, 950 // kpidLinks,
945 // kpidOffset 951 // kpidOffset
946}; 952};
@@ -1280,14 +1286,14 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool
1280HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize) 1286HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
1281{ 1287{
1282 Byte temp[3]; 1288 Byte temp[3];
1283 unsigned offset = _h.NeedCheckData() ? 3 : 2; 1289 const unsigned offset = _h.NeedCheckData() ? 3 : 2;
1284 if (offset > packSize) 1290 if (offset > packSize)
1285 return S_FALSE; 1291 return S_FALSE;
1286 RINOK(ReadStream_FALSE(_stream, temp, offset)); 1292 RINOK(ReadStream_FALSE(_stream, temp, offset));
1287 // if (NeedCheckData && Major < 4) checkByte must be = 0xFF 1293 // if (NeedCheckData && Major < 4) checkByte must be = 0xFF
1288 bool be = _h.be; 1294 const bool be = _h.be;
1289 UInt32 size = Get16(temp); 1295 UInt32 size = Get16(temp);
1290 bool isCompressed = ((size & kNotCompressedBit16) == 0); 1296 const bool isCompressed = ((size & kNotCompressedBit16) == 0);
1291 if (size != kNotCompressedBit16) 1297 if (size != kNotCompressedBit16)
1292 size &= ~kNotCompressedBit16; 1298 size &= ~kNotCompressedBit16;
1293 1299
@@ -1311,12 +1317,20 @@ HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
1311 return S_OK; 1317 return S_OK;
1312} 1318}
1313 1319
1320
1321HRESULT CHandler::ReadMetadataBlock2()
1322{
1323 _dynOutStreamSpec->Init();
1324 UInt32 packSize = kMetadataBlockSize + 3; // check it
1325 return ReadMetadataBlock(packSize);
1326}
1327
1314HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) 1328HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end)
1315{ 1329{
1316 if (end < start || end - start >= ((UInt64)1 << 32)) 1330 if (end < start || end - start >= ((UInt64)1 << 32))
1317 return S_FALSE; 1331 return S_FALSE;
1318 const UInt32 size = (UInt32)(end - start); 1332 const UInt32 size = (UInt32)(end - start);
1319 RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); 1333 RINOK(Seek2(start));
1320 _dynOutStreamSpec->Init(); 1334 _dynOutStreamSpec->Init();
1321 UInt32 packPos = 0; 1335 UInt32 packPos = 0;
1322 while (packPos != size) 1336 while (packPos != size)
@@ -1395,7 +1409,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
1395 CRecordVector<CTempItem> tempItems; 1409 CRecordVector<CTempItem> tempItems;
1396 while (rem != 0) 1410 while (rem != 0)
1397 { 1411 {
1398 bool be = _h.be; 1412 const bool be = _h.be;
1399 UInt32 count; 1413 UInt32 count;
1400 CTempItem tempItem; 1414 CTempItem tempItem;
1401 if (_h.Major <= 2) 1415 if (_h.Major <= 2)
@@ -1519,15 +1533,15 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
1519 return S_OK; 1533 return S_OK;
1520} 1534}
1521 1535
1522/*
1523HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) 1536HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids)
1524{ 1537{
1525 size_t size = num * 4; 1538 const size_t size = (size_t)num * 4;
1526 ids.SetCapacity(size); 1539 ids.Alloc(size);
1527 RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); 1540 if (num == 0)
1541 return S_OK;
1542 RINOK(Seek2(start));
1528 return ReadStream_FALSE(_stream, ids, size); 1543 return ReadStream_FALSE(_stream, ids, size);
1529} 1544}
1530*/
1531 1545
1532HRESULT CHandler::Open2(IInStream *inStream) 1546HRESULT CHandler::Open2(IInStream *inStream)
1533{ 1547{
@@ -1560,24 +1574,22 @@ HRESULT CHandler::Open2(IInStream *inStream)
1560 if (_h.NumFrags > kNumFilesMax) 1574 if (_h.NumFrags > kNumFilesMax)
1561 return S_FALSE; 1575 return S_FALSE;
1562 _frags.ClearAndReserve(_h.NumFrags); 1576 _frags.ClearAndReserve(_h.NumFrags);
1563 unsigned bigFrag = (_h.Major > 2); 1577 const unsigned bigFrag = (_h.Major > 2);
1564 1578
1565 unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); 1579 const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
1566 UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; 1580 const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
1567 size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); 1581 const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
1568 CByteBuffer data(numBlocksBytes); 1582 CByteBuffer data(numBlocksBytes);
1569 RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); 1583 RINOK(Seek2(_h.FragTable));
1570 RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); 1584 RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
1571 bool be = _h.be; 1585 const bool be = _h.be;
1572 1586
1573 for (UInt32 i = 0; i < numBlocks; i++) 1587 for (UInt32 i = 0; i < numBlocks; i++)
1574 { 1588 {
1575 UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); 1589 const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
1576 RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); 1590 RINOK(Seek2(offset));
1577 _dynOutStreamSpec->Init(); 1591 RINOK(ReadMetadataBlock2());
1578 UInt32 packSize = kMetadataBlockSize + 3; 1592 const UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
1579 RINOK(ReadMetadataBlock(packSize));
1580 UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
1581 if (unpackSize != kMetadataBlockSize) 1593 if (unpackSize != kMetadataBlockSize)
1582 if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) 1594 if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
1583 return S_FALSE; 1595 return S_FALSE;
@@ -1605,8 +1617,6 @@ HRESULT CHandler::Open2(IInStream *inStream)
1605 return S_FALSE; 1617 return S_FALSE;
1606 } 1618 }
1607 1619
1608 // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL));
1609
1610 RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)); 1620 RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable));
1611 RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)); 1621 RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable));
1612 1622
@@ -1655,7 +1665,6 @@ HRESULT CHandler::Open2(IInStream *inStream)
1655 int rootNodeIndex; 1665 int rootNodeIndex;
1656 RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex)); 1666 RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex));
1657 1667
1658 /*
1659 if (_h.Major < 4) 1668 if (_h.Major < 4)
1660 { 1669 {
1661 RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids)); 1670 RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids));
@@ -1663,33 +1672,34 @@ HRESULT CHandler::Open2(IInStream *inStream)
1663 } 1672 }
1664 else 1673 else
1665 { 1674 {
1666 UInt32 size = _h.NumIDs * 4; 1675 const UInt32 size = (UInt32)_h.NumIDs * 4;
1667 _uids.SetCapacity(size); 1676 _uids.Alloc(size);
1668 1677
1669 UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; 1678 const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
1670 UInt32 numBlocksBytes = numBlocks << 3; 1679 const UInt32 numBlocksBytes = numBlocks << 3;
1671 CByteBuffer data; 1680 CByteBuffer data;
1672 data.SetCapacity(numBlocksBytes); 1681 data.Alloc(numBlocksBytes);
1673 RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL)); 1682 RINOK(Seek2(_h.UidTable));
1674 RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); 1683 RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
1675 1684
1676 for (UInt32 i = 0; i < numBlocks; i++) 1685 for (UInt32 i = 0; i < numBlocks; i++)
1677 { 1686 {
1678 UInt64 offset = GetUi64(data + i * 8); 1687 const UInt64 offset = GetUi64(data + i * 8);
1679 UInt32 unpackSize, packSize; 1688 RINOK(Seek2(offset));
1680 RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); 1689 // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
1681 RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); 1690 RINOK(ReadMetadataBlock2());
1691 const size_t unpackSize = _dynOutStreamSpec->GetSize();
1682 if (unpackSize != kMetadataBlockSize) 1692 if (unpackSize != kMetadataBlockSize)
1683 if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1))) 1693 if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1)))
1684 return S_FALSE; 1694 return S_FALSE;
1695 memcpy(_uids + kMetadataBlockSize * i, _dynOutStreamSpec->GetBuffer(), unpackSize);
1685 } 1696 }
1686 } 1697 }
1687 */
1688 1698
1689 { 1699 {
1690 const UInt32 alignSize = 1 << 12; 1700 const UInt32 alignSize = 1 << 12;
1691 Byte buf[alignSize]; 1701 Byte buf[alignSize];
1692 RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL)); 1702 RINOK(Seek2(_h.Size));
1693 UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); 1703 UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
1694 _sizeCalculated = _h.Size; 1704 _sizeCalculated = _h.Size;
1695 if (rem != 0) 1705 if (rem != 0)
@@ -1710,7 +1720,7 @@ AString CHandler::GetPath(int index) const
1710{ 1720{
1711 unsigned len = 0; 1721 unsigned len = 0;
1712 int indexMem = index; 1722 int indexMem = index;
1713 bool be = _h.be; 1723 const bool be = _h.be;
1714 do 1724 do
1715 { 1725 {
1716 const CItem &item = _items[index]; 1726 const CItem &item = _items[index];
@@ -1804,9 +1814,9 @@ bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
1804 totalPack = 0; 1814 totalPack = 0;
1805 const CItem &item = _items[index]; 1815 const CItem &item = _items[index];
1806 const CNode &node = _nodes[item.Node]; 1816 const CNode &node = _nodes[item.Node];
1807 UInt32 ptr = _nodesPos[item.Node]; 1817 const UInt32 ptr = _nodesPos[item.Node];
1808 const Byte *p = _inodesData.Data + ptr; 1818 const Byte *p = _inodesData.Data + ptr;
1809 bool be = _h.be; 1819 const bool be = _h.be;
1810 1820
1811 UInt32 type = node.Type; 1821 UInt32 type = node.Type;
1812 UInt32 offset; 1822 UInt32 offset;
@@ -1936,11 +1946,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
1936 case kpidBigEndian: prop = _h.be; break; 1946 case kpidBigEndian: prop = _h.be; break;
1937 case kpidCTime: 1947 case kpidCTime:
1938 if (_h.CTime != 0) 1948 if (_h.CTime != 0)
1939 { 1949 PropVariant_SetFrom_UnixTime(prop, _h.CTime);
1940 FILETIME ft;
1941 NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft);
1942 prop = ft;
1943 }
1944 break; 1950 break;
1945 case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; 1951 case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
1946 // case kpidNumBlocks: prop = _h.NumFrags; break; 1952 // case kpidNumBlocks: prop = _h.NumFrags; break;
@@ -1979,8 +1985,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
1979 NWindows::NCOM::CPropVariant prop; 1985 NWindows::NCOM::CPropVariant prop;
1980 const CItem &item = _items[index]; 1986 const CItem &item = _items[index];
1981 const CNode &node = _nodes[item.Node]; 1987 const CNode &node = _nodes[item.Node];
1982 bool isDir = node.IsDir(); 1988 const bool isDir = node.IsDir();
1983 bool be = _h.be; 1989 const bool be = _h.be;
1984 1990
1985 switch (propID) 1991 switch (propID)
1986 { 1992 {
@@ -2031,9 +2037,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
2031 if (offset != 0) 2037 if (offset != 0)
2032 { 2038 {
2033 const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset; 2039 const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
2034 FILETIME ft; 2040 PropVariant_SetFrom_UnixTime(prop, Get32(p));
2035 NWindows::NTime::UnixTimeToFileTime(Get32(p), ft);
2036 prop = ft;
2037 } 2041 }
2038 break; 2042 break;
2039 } 2043 }
@@ -2043,31 +2047,38 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
2043 prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; 2047 prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
2044 break; 2048 break;
2045 } 2049 }
2046 /* 2050 case kpidUserId:
2047 case kpidUser:
2048 { 2051 {
2049 UInt32 offset = node.Uid * 4; 2052 const UInt32 offset = (UInt32)node.Uid * 4;
2050 if (offset < _uids.Size()) 2053 if (offset < _uids.Size())
2051 prop = (UInt32)Get32(_uids + offset); 2054 prop = (UInt32)Get32(_uids + offset);
2052 break; 2055 break;
2053 } 2056 }
2054 case kpidGroup: 2057 case kpidGroupId:
2055 { 2058 {
2056 if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) 2059 if (_h.Major < 4)
2057 { 2060 {
2058 UInt32 offset = node.Uid * 4; 2061 if (node.Gid == _h.GetSpecGuidIndex())
2059 if (offset < _uids.Size()) 2062 {
2060 prop = (UInt32)Get32(_uids + offset); 2063 const UInt32 offset = (UInt32)node.Uid * 4;
2064 if (offset < _uids.Size())
2065 prop = (UInt32)Get32(_uids + offset);
2066 }
2067 else
2068 {
2069 const UInt32 offset = (UInt32)node.Gid * 4;
2070 if (offset < _gids.Size())
2071 prop = (UInt32)Get32(_gids + offset);
2072 }
2061 } 2073 }
2062 else 2074 else
2063 { 2075 {
2064 UInt32 offset = node.Gid * 4; 2076 const UInt32 offset = (UInt32)node.Gid * 4;
2065 if (offset < _gids.Size()) 2077 if (offset < _uids.Size())
2066 prop = (UInt32)Get32(_gids + offset); 2078 prop = (UInt32)Get32(_uids + offset);
2067 } 2079 }
2068 break; 2080 break;
2069 } 2081 }
2070 */
2071 /* 2082 /*
2072 case kpidLinks: 2083 case kpidLinks:
2073 if (_h.Major >= 3 && node.Type != kType_FILE) 2084 if (_h.Major >= 3 && node.Type != kType_FILE)
@@ -2128,7 +2139,7 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
2128 packBlockSize != _cachedPackBlockSize) 2139 packBlockSize != _cachedPackBlockSize)
2129 { 2140 {
2130 ClearCache(); 2141 ClearCache();
2131 RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL)); 2142 RINOK(Seek2(blockOffset));
2132 _limitedInStreamSpec->Init(packBlockSize); 2143 _limitedInStreamSpec->Init(packBlockSize);
2133 2144
2134 if (compressed) 2145 if (compressed)
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
index 2f23dd8..bd04bd7 100644
--- a/CPP/7zip/Archive/Tar/TarHandler.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -36,22 +36,34 @@ static const Byte kProps[] =
36 kpidSize, 36 kpidSize,
37 kpidPackSize, 37 kpidPackSize,
38 kpidMTime, 38 kpidMTime,
39 kpidCTime,
40 kpidATime,
39 kpidPosixAttrib, 41 kpidPosixAttrib,
40 kpidUser, 42 kpidUser,
41 kpidGroup, 43 kpidGroup,
44 kpidUserId,
45 kpidGroupId,
42 kpidSymLink, 46 kpidSymLink,
43 kpidHardLink, 47 kpidHardLink,
44 kpidCharacts 48 kpidCharacts,
45 // kpidLinkType 49 kpidComment
50 , kpidDeviceMajor
51 , kpidDeviceMinor
52 // , kpidDevice
53 // , kpidHeadersSize // for debug
54 // , kpidOffset // for debug
46}; 55};
47 56
48static const Byte kArcProps[] = 57static const Byte kArcProps[] =
49{ 58{
50 kpidHeadersSize, 59 kpidHeadersSize,
51 kpidCodePage, 60 kpidCodePage,
52 kpidCharacts 61 kpidCharacts,
62 kpidComment
53}; 63};
54 64
65static const char *k_Characts_Prefix = "PREFIX";
66
55IMP_IInArchive_Props 67IMP_IInArchive_Props
56IMP_IInArchive_ArcProps 68IMP_IInArchive_ArcProps
57 69
@@ -60,14 +72,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
60 NCOM::CPropVariant prop; 72 NCOM::CPropVariant prop;
61 switch (propID) 73 switch (propID)
62 { 74 {
63 case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; 75 case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break;
64 case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; 76 case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break;
65 case kpidErrorFlags: 77 case kpidErrorFlags:
66 { 78 {
67 UInt32 flags = 0; 79 UInt32 flags = 0;
68 if (!_isArc) 80 if (!_isArc)
69 flags |= kpv_ErrorFlags_IsNotArc; 81 flags |= kpv_ErrorFlags_IsNotArc;
70 else switch (_error) 82 else switch (_arc._error)
71 { 83 {
72 case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; 84 case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
73 case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; 85 case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
@@ -82,7 +94,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
82 94
83 case kpidWarningFlags: 95 case kpidWarningFlags:
84 { 96 {
85 if (_warning) 97 if (_arc._is_Warning)
86 prop = kpv_ErrorFlags_HeadersError; 98 prop = kpv_ErrorFlags_HeadersError;
87 break; 99 break;
88 } 100 }
@@ -107,37 +119,38 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
107 119
108 case kpidCharacts: 120 case kpidCharacts:
109 { 121 {
110 prop = _encodingCharacts.GetCharactsString(); 122 AString s;
123 if (_arc._are_Gnu) s.Add_OptSpaced("GNU");
124 if (_arc._are_Posix) s.Add_OptSpaced("POSIX");
125 if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM");
126 if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix);
127 if (_arc._are_LongName) s.Add_OptSpaced("LongName");
128 if (_arc._are_LongLink) s.Add_OptSpaced("LongLink");
129 if (_arc._are_Pax) s.Add_OptSpaced("PAX");
130 if (_arc._are_pax_path) s.Add_OptSpaced("path");
131 if (_arc._are_pax_link) s.Add_OptSpaced("linkpath");
132 if (_arc._are_mtime) s.Add_OptSpaced("mtime");
133 if (_arc._are_atime) s.Add_OptSpaced("atime");
134 if (_arc._are_ctime) s.Add_OptSpaced("ctime");
135 if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR");
136 s.Add_OptSpaced(_encodingCharacts.GetCharactsString());
137 prop = s;
111 break; 138 break;
112 } 139 }
113 }
114 prop.Detach(value);
115 return S_OK;
116}
117 140
118HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) 141 case kpidComment:
119{ 142 {
120 item.HeaderPos = _phySize; 143 if (_arc.PaxGlobal_Defined)
121 EErrorType error; 144 {
122 HRESULT res = ReadItem(stream, filled, item, error); 145 AString s;
123 if (error == k_ErrorType_Warning) 146 _arc.PaxGlobal.Print_To_String(s);
124 _warning = true; 147 if (!s.IsEmpty())
125 else if (error != k_ErrorType_OK) 148 prop = s;
126 _error = error; 149 }
127 RINOK(res); 150 break;
128 if (filled) 151 }
129 {
130 /*
131 if (item.IsSparse())
132 _isSparse = true;
133 */
134 if (item.IsPaxExtendedHeader())
135 _thereIsPaxExtendedHeader = true;
136 if (item.IsThereWarning())
137 _warning = true;
138 } 152 }
139 _phySize += item.HeaderSize; 153 prop.Detach(value);
140 _headersSize += item.HeaderSize;
141 return S_OK; 154 return S_OK;
142} 155}
143 156
@@ -199,16 +212,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
199 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); 212 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
200 } 213 }
201 214
202 _phySizeDefined = true; 215 _arc._phySize_Defined = true;
203 216
204 // bool utf8_OK = true; 217 // bool utf8_OK = true;
205 218
219 _arc.SeqStream = stream;
220 _arc.InStream = stream;
221 _arc.OpenCallback = callback;
222
223 CItemEx item;
206 for (;;) 224 for (;;)
207 { 225 {
208 CItemEx item; 226 _arc.NumFiles = _items.Size();
209 bool filled; 227 RINOK(_arc.ReadItem(item));
210 RINOK(ReadItem2(stream, filled, item)); 228 if (!_arc.filled)
211 if (!filled)
212 break; 229 break;
213 230
214 _isArc = true; 231 _isArc = true;
@@ -228,10 +245,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
228 245
229 _items.Add(item); 246 _items.Add(item);
230 247
231 RINOK(stream->Seek((Int64)item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); 248 RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize));
232 if (_phySize > endPos) 249 if (_arc._phySize > endPos)
233 { 250 {
234 _error = k_ErrorType_UnexpectedEnd; 251 _arc._error = k_ErrorType_UnexpectedEnd;
235 break; 252 break;
236 } 253 }
237 /* 254 /*
@@ -241,6 +258,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
241 break; 258 break;
242 } 259 }
243 */ 260 */
261 /*
244 if (callback) 262 if (callback)
245 { 263 {
246 if (_items.Size() == 1) 264 if (_items.Size() == 1)
@@ -249,10 +267,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
249 } 267 }
250 if ((_items.Size() & 0x3FF) == 0) 268 if ((_items.Size() & 0x3FF) == 0)
251 { 269 {
252 UInt64 numFiles = _items.Size(); 270 const UInt64 numFiles = _items.Size();
253 RINOK(callback->SetCompleted(&numFiles, &_phySize)); 271 RINOK(callback->SetCompleted(&numFiles, &_phySize));
254 } 272 }
255 } 273 }
274 */
256 } 275 }
257 276
258 /* 277 /*
@@ -266,7 +285,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
266 285
267 if (_items.Size() == 0) 286 if (_items.Size() == 0)
268 { 287 {
269 if (_error != k_ErrorType_OK) 288 if (_arc._error != k_ErrorType_OK)
270 { 289 {
271 _isArc = false; 290 _isArc = false;
272 return S_FALSE; 291 return S_FALSE;
@@ -294,6 +313,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
294STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) 313STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)
295{ 314{
296 COM_TRY_BEGIN 315 COM_TRY_BEGIN
316 // for (int i = 0; i < 10; i++) // for debug
297 { 317 {
298 Close(); 318 Close();
299 RINOK(Open2(stream, openArchiveCallback)); 319 RINOK(Open2(stream, openArchiveCallback));
@@ -314,16 +334,11 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
314STDMETHODIMP CHandler::Close() 334STDMETHODIMP CHandler::Close()
315{ 335{
316 _isArc = false; 336 _isArc = false;
317 _warning = false;
318 _error = k_ErrorType_OK;
319 337
320 _phySizeDefined = false; 338 _arc.Clear();
321 _phySize = 0; 339
322 _headersSize = 0;
323 _curIndex = 0; 340 _curIndex = 0;
324 _latestIsRead = false; 341 _latestIsRead = false;
325 // _isSparse = false;
326 _thereIsPaxExtendedHeader = false;
327 _encodingCharacts.Clear(); 342 _encodingCharacts.Clear();
328 _items.Clear(); 343 _items.Clear();
329 _seqStream.Release(); 344 _seqStream.Release();
@@ -351,12 +366,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
351 { 366 {
352 if (_latestIsRead) 367 if (_latestIsRead)
353 { 368 {
354 UInt64 packSize = _latestItem.GetPackSizeAligned(); 369 const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
355 RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); 370 RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
356 _phySize += copyCoderSpec->TotalSize; 371 _arc._phySize += copyCoderSpec->TotalSize;
357 if (copyCoderSpec->TotalSize != packSize) 372 if (copyCoderSpec->TotalSize != packSize)
358 { 373 {
359 _error = k_ErrorType_UnexpectedEnd; 374 _arc._error = k_ErrorType_UnexpectedEnd;
360 return S_FALSE; 375 return S_FALSE;
361 } 376 }
362 _latestIsRead = false; 377 _latestIsRead = false;
@@ -364,11 +379,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
364 } 379 }
365 else 380 else
366 { 381 {
367 bool filled; 382 _arc.SeqStream = _seqStream;
368 RINOK(ReadItem2(_seqStream, filled, _latestItem)); 383 _arc.InStream = NULL;
369 if (!filled) 384 RINOK(_arc.ReadItem(_latestItem));
385 if (!_arc.filled)
370 { 386 {
371 _phySizeDefined = true; 387 _arc._phySize_Defined = true;
372 return E_INVALIDARG; 388 return E_INVALIDARG;
373 } 389 }
374 _latestIsRead = true; 390 _latestIsRead = true;
@@ -390,6 +406,69 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant
390 prop = dest; 406 prop = dest;
391} 407}
392 408
409
410static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop)
411{
412 UInt64 v;
413 if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v))
414 return;
415 if (pt.Ns != 0)
416 v += pt.Ns / 100;
417 FILETIME ft;
418 ft.dwLowDateTime = (DWORD)v;
419 ft.dwHighDateTime = (DWORD)(v >> 32);
420 prop.SetAsTimeFrom_FT_Prec_Ns100(ft,
421 k_PropVar_TimePrec_Base + pt.NumDigits, pt.Ns % 100);
422}
423
424
425#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
426
427static void AddByteToHex2(unsigned val, AString &s)
428{
429 unsigned t;
430 t = val >> 4;
431 s += ValToHex(t);
432 t = val & 0xF;
433 s += ValToHex(t);
434}
435
436static void AddSpecCharToString(const char c, AString &s)
437{
438 if ((Byte)c <= 0x20 || (Byte)c > 127)
439 {
440 s += '[';
441 AddByteToHex2((Byte)(c), s);
442 s += ']';
443 }
444 else
445 s += c;
446}
447
448static void AddSpecUInt64(AString &s, const char *name, UInt64 v)
449{
450 if (v != 0)
451 {
452 s.Add_OptSpaced(name);
453 if (v > 1)
454 {
455 s += ':';
456 s.Add_UInt64(v);
457 }
458 }
459}
460
461static void AddSpecBools(AString &s, const char *name, bool b1, bool b2)
462{
463 if (b1)
464 {
465 s.Add_OptSpaced(name);
466 if (b2)
467 s += '*';
468 }
469}
470
471
393STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 472STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
394{ 473{
395 COM_TRY_BEGIN 474 COM_TRY_BEGIN
@@ -413,49 +492,189 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
413 { 492 {
414 case kpidPath: TarStringToUnicode(item->Name, prop, true); break; 493 case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
415 case kpidIsDir: prop = item->IsDir(); break; 494 case kpidIsDir: prop = item->IsDir(); break;
416 case kpidSize: prop = item->GetUnpackSize(); break; 495 case kpidSize: prop = item->Get_UnpackSize(); break;
417 case kpidPackSize: prop = item->GetPackSizeAligned(); break; 496 case kpidPackSize: prop = item->Get_PackSize_Aligned(); break;
418 case kpidMTime: 497 case kpidMTime:
419 if (item->MTime != 0) 498 {
499 /*
500 // for debug:
501 PropVariant_SetFrom_UnixTime(prop, 1 << 30);
502 prop.wReserved1 = k_PropVar_TimePrec_Base + 1;
503 prop.wReserved2 = 12;
504 break;
505 */
506
507 if (item->PaxTimes.MTime.IsDefined())
508 PaxTimeToProp(item->PaxTimes.MTime, prop);
509 else
510 // if (item->MTime != 0)
420 { 511 {
512 // we allow (item->MTime == 0)
421 FILETIME ft; 513 FILETIME ft;
422 if (NTime::UnixTime64ToFileTime(item->MTime, ft)) 514 if (NTime::UnixTime64_To_FileTime(item->MTime, ft))
423 prop = ft; 515 {
516 unsigned prec = k_PropVar_TimePrec_Unix;
517 if (item->MTime_IsBin)
518 {
519 /* we report here that it's Int64-UnixTime
520 instead of basic UInt32-UnixTime range */
521 prec = k_PropVar_TimePrec_Base;
522 }
523 prop.SetAsTimeFrom_FT_Prec(ft, prec);
524 }
424 } 525 }
425 break; 526 break;
527 }
528 case kpidATime:
529 if (item->PaxTimes.ATime.IsDefined())
530 PaxTimeToProp(item->PaxTimes.ATime, prop);
531 break;
532 case kpidCTime:
533 if (item->PaxTimes.CTime.IsDefined())
534 PaxTimeToProp(item->PaxTimes.CTime, prop);
535 break;
426 case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; 536 case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break;
427 case kpidUser: TarStringToUnicode(item->User, prop); break; 537
428 case kpidGroup: TarStringToUnicode(item->Group, prop); break; 538 case kpidUser:
429 case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; 539 if (!item->User.IsEmpty())
430 case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; 540 TarStringToUnicode(item->User, prop);
431 // case kpidLinkType: prop = (int)item->LinkFlag; break; 541 break;
542 case kpidGroup:
543 if (!item->Group.IsEmpty())
544 TarStringToUnicode(item->Group, prop);
545 break;
546
547 case kpidUserId:
548 // if (item->UID != 0)
549 prop = (UInt32)item->UID;
550 break;
551 case kpidGroupId:
552 // if (item->GID != 0)
553 prop = (UInt32)item->GID;
554 break;
555
556 case kpidDeviceMajor:
557 if (item->DeviceMajor_Defined)
558 // if (item->DeviceMajor != 0)
559 prop = (UInt32)item->DeviceMajor;
560 break;
561
562 case kpidDeviceMinor:
563 if (item->DeviceMinor_Defined)
564 // if (item->DeviceMinor != 0)
565 prop = (UInt32)item->DeviceMinor;
566 break;
567 /*
568 case kpidDevice:
569 if (item->DeviceMajor_Defined)
570 if (item->DeviceMinor_Defined)
571 prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor);
572 break;
573 */
574
575 case kpidSymLink:
576 if (item->Is_SymLink())
577 if (!item->LinkName.IsEmpty())
578 TarStringToUnicode(item->LinkName, prop);
579 break;
580 case kpidHardLink:
581 if (item->Is_HardLink())
582 if (!item->LinkName.IsEmpty())
583 TarStringToUnicode(item->LinkName, prop);
584 break;
585
432 case kpidCharacts: 586 case kpidCharacts:
433 { 587 {
434 AString s = item->EncodingCharacts.GetCharactsString(); 588 AString s;
435 if (item->IsThereWarning())
436 { 589 {
437 s.Add_Space_if_NotEmpty(); 590 s.Add_Space_if_NotEmpty();
438 s += "HEADER_ERROR"; 591 AddSpecCharToString(item->LinkFlag, s);
439 } 592 }
440 prop = s; 593 if (item->IsMagic_GNU())
594 s.Add_OptSpaced("GNU");
595 else if (item->IsMagic_Posix_ustar_00())
596 s.Add_OptSpaced("POSIX");
597 else
598 {
599 s.Add_Space_if_NotEmpty();
600 for (unsigned i = 0; i < sizeof(item->Magic); i++)
601 AddSpecCharToString(item->Magic[i], s);
602 }
603
604 if (item->IsSignedChecksum)
605 s.Add_OptSpaced("SignedChecksum");
606
607 if (item->Prefix_WasUsed)
608 s.Add_OptSpaced(k_Characts_Prefix);
609
610 s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString());
611
612 // AddSpecUInt64(s, "LongName", item->Num_LongName_Records);
613 // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records);
614 AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2);
615 AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2);
616
617 if (item->MTime_IsBin)
618 s.Add_OptSpaced("bin_mtime");
619 if (item->PackSize_IsBin)
620 s.Add_OptSpaced("bin_psize");
621 if (item->Size_IsBin)
622 s.Add_OptSpaced("bin_size");
623
624 AddSpecUInt64(s, "PAX", item->Num_Pax_Records);
625
626 if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime");
627 if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime");
628 if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime");
629
630 if (item->pax_path_WasUsed)
631 s.Add_OptSpaced("pax_path");
632 if (item->pax_link_WasUsed)
633 s.Add_OptSpaced("pax_linkpath");
634 if (item->pax_size_WasUsed)
635 s.Add_OptSpaced("pax_size");
636
637 if (item->IsThereWarning())
638 s.Add_OptSpaced("WARNING");
639 if (item->HeaderError)
640 s.Add_OptSpaced("ERROR");
641 if (item->Pax_Error)
642 s.Add_OptSpaced("PAX_error");
643 if (!item->PaxExtra.RawLines.IsEmpty())
644 s.Add_OptSpaced("PAX_unsupported_line");
645 if (item->Pax_Overflow)
646 s.Add_OptSpaced("PAX_overflow");
647 if (!s.IsEmpty())
648 prop = s;
441 break; 649 break;
442 } 650 }
651 case kpidComment:
652 {
653 AString s;
654 item->PaxExtra.Print_To_String(s);
655 if (!s.IsEmpty())
656 prop = s;
657 break;
658 }
659 // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug
660 // case kpidOffset: prop = item->HeaderPos; break; // for debug
443 } 661 }
444 prop.Detach(value); 662 prop.Detach(value);
445 return S_OK; 663 return S_OK;
446 COM_TRY_END 664 COM_TRY_END
447} 665}
448 666
667
449HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, 668HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
450 Int32 testMode, IArchiveExtractCallback *extractCallback) 669 Int32 testMode, IArchiveExtractCallback *extractCallback)
451{ 670{
452 COM_TRY_BEGIN 671 COM_TRY_BEGIN
453 ISequentialInStream *stream = _seqStream; 672 ISequentialInStream *stream = _seqStream;
454 bool seqMode = (_stream == NULL); 673 const bool seqMode = (_stream == NULL);
455 if (!seqMode) 674 if (!seqMode)
456 stream = _stream; 675 stream = _stream;
457 676
458 bool allFilesMode = (numItems == (UInt32)(Int32)-1); 677 const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
459 if (allFilesMode) 678 if (allFilesMode)
460 numItems = _items.Size(); 679 numItems = _items.Size();
461 if (_stream && numItems == 0) 680 if (_stream && numItems == 0)
@@ -463,7 +682,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
463 UInt64 totalSize = 0; 682 UInt64 totalSize = 0;
464 UInt32 i; 683 UInt32 i;
465 for (i = 0; i < numItems; i++) 684 for (i = 0; i < numItems; i++)
466 totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize(); 685 totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
467 extractCallback->SetTotal(totalSize); 686 extractCallback->SetTotal(totalSize);
468 687
469 UInt64 totalPackSize; 688 UInt64 totalPackSize;
@@ -503,9 +722,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
503 item = &_items[index]; 722 item = &_items[index];
504 723
505 RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); 724 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
506 UInt64 unpackSize = item->GetUnpackSize(); 725 const UInt64 unpackSize = item->Get_UnpackSize();
507 totalSize += unpackSize; 726 totalSize += unpackSize;
508 totalPackSize += item->GetPackSizeAligned(); 727 totalPackSize += item->Get_PackSize_Aligned();
509 if (item->IsDir()) 728 if (item->IsDir())
510 { 729 {
511 RINOK(extractCallback->PrepareOperation(askMode)); 730 RINOK(extractCallback->PrepareOperation(askMode));
@@ -539,7 +758,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
539 758
540 Int32 opRes = NExtract::NOperationResult::kOK; 759 Int32 opRes = NExtract::NOperationResult::kOK;
541 CMyComPtr<ISequentialInStream> inStream2; 760 CMyComPtr<ISequentialInStream> inStream2;
542 if (!item->IsSparse()) 761 if (!item->Is_Sparse())
543 inStream2 = inStream; 762 inStream2 = inStream;
544 else 763 else
545 { 764 {
@@ -549,7 +768,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
549 } 768 }
550 769
551 { 770 {
552 if (item->IsSymLink()) 771 if (item->Is_SymLink())
553 { 772 {
554 RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); 773 RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
555 } 774 }
@@ -557,9 +776,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
557 { 776 {
558 if (!seqMode) 777 if (!seqMode)
559 { 778 {
560 RINOK(_stream->Seek((Int64)item->GetDataPosition(), STREAM_SEEK_SET, NULL)); 779 RINOK(_stream->Seek((Int64)item->Get_DataPos(), STREAM_SEEK_SET, NULL));
561 } 780 }
562 streamSpec->Init(item->GetPackSizeAligned()); 781 streamSpec->Init(item->Get_PackSize_Aligned());
563 RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress)); 782 RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
564 } 783 }
565 if (outStreamSpec->GetRem() != 0) 784 if (outStreamSpec->GetRem() != 0)
@@ -628,7 +847,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
628 unsigned left = 0, right = item.SparseBlocks.Size(); 847 unsigned left = 0, right = item.SparseBlocks.Size();
629 for (;;) 848 for (;;)
630 { 849 {
631 unsigned mid = (left + right) / 2; 850 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
632 if (mid == left) 851 if (mid == left)
633 break; 852 break;
634 if (_virtPos < item.SparseBlocks[mid].Offset) 853 if (_virtPos < item.SparseBlocks[mid].Offset)
@@ -648,7 +867,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
648 UInt64 phyPos = PhyOffsets[left] + relat; 867 UInt64 phyPos = PhyOffsets[left] + relat;
649 if (_needStartSeek || _phyPos != phyPos) 868 if (_needStartSeek || _phyPos != phyPos)
650 { 869 {
651 RINOK(Handler->_stream->Seek((Int64)(item.GetDataPosition() + phyPos), STREAM_SEEK_SET, NULL)); 870 RINOK(Handler->_stream->Seek((Int64)(item.Get_DataPos() + phyPos), STREAM_SEEK_SET, NULL));
652 _needStartSeek = false; 871 _needStartSeek = false;
653 _phyPos = phyPos; 872 _phyPos = phyPos;
654 } 873 }
@@ -698,7 +917,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
698 917
699 const CItemEx &item = _items[index]; 918 const CItemEx &item = _items[index];
700 919
701 if (item.IsSparse()) 920 if (item.Is_Sparse())
702 { 921 {
703 CSparseStream *streamSpec = new CSparseStream; 922 CSparseStream *streamSpec = new CSparseStream;
704 CMyComPtr<IInStream> streamTemp = streamSpec; 923 CMyComPtr<IInStream> streamTemp = streamSpec;
@@ -718,24 +937,30 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
718 return S_OK; 937 return S_OK;
719 } 938 }
720 939
721 if (item.IsSymLink()) 940 if (item.Is_SymLink())
722 { 941 {
723 Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); 942 Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream);
724 return S_OK; 943 return S_OK;
725 } 944 }
726 945
727 return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); 946 return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream);
728 947
729 COM_TRY_END 948 COM_TRY_END
730} 949}
731 950
951
732void CHandler::Init() 952void CHandler::Init()
733{ 953{
734 _forceCodePage = false; 954 _forceCodePage = false;
735 _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; 955 _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
736 _thereIsPaxExtendedHeader = false; 956 _posixMode = false;
957 _posixMode_WasForced = false;
958 // TimeOptions.Clear();
959 _handlerTimeOptions.Init();
960 // _handlerTimeOptions.Write_MTime.Val = true; // it's default already
737} 961}
738 962
963
739STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) 964STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
740{ 965{
741 Init(); 966 Init();
@@ -768,8 +993,54 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
768 else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) 993 else if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
769 { 994 {
770 } 995 }
996 else if (name.IsEqualTo("m"))
997 {
998 if (prop.vt != VT_BSTR)
999 return E_INVALIDARG;
1000 const UString s = prop.bstrVal;
1001 if (s.IsEqualTo_Ascii_NoCase("pax") ||
1002 s.IsEqualTo_Ascii_NoCase("posix"))
1003 _posixMode = true;
1004 else if (s.IsEqualTo_Ascii_NoCase("gnu"))
1005 _posixMode = false;
1006 else
1007 return E_INVALIDARG;
1008 _posixMode_WasForced = true;
1009 }
771 else 1010 else
1011 {
1012 /*
1013 if (name.IsPrefixedBy_Ascii_NoCase("td"))
1014 {
1015 name.Delete(0, 3);
1016 if (prop.vt == VT_EMPTY)
1017 {
1018 if (name.IsEqualTo_Ascii_NoCase("n"))
1019 {
1020 // TimeOptions.UseNativeDigits = true;
1021 }
1022 else if (name.IsEqualTo_Ascii_NoCase("r"))
1023 {
1024 // TimeOptions.RemoveZeroDigits = true;
1025 }
1026 else
1027 return E_INVALIDARG;
1028 }
1029 else
1030 {
1031 UInt32 numTimeDigits = 0;
1032 RINOK(ParsePropToUInt32(name, prop, numTimeDigits));
1033 TimeOptions.NumDigits_WasForced = true;
1034 TimeOptions.NumDigits = numTimeDigits;
1035 }
1036 }
1037 */
1038 bool processed = false;
1039 RINOK(_handlerTimeOptions.Parse(name, prop, processed));
1040 if (processed)
1041 continue;
772 return E_INVALIDARG; 1042 return E_INVALIDARG;
1043 }
773 } 1044 }
774 return S_OK; 1045 return S_OK;
775} 1046}
diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h
index 4834c2a..44a9980 100644
--- a/CPP/7zip/Archive/Tar/TarHandler.h
+++ b/CPP/7zip/Archive/Tar/TarHandler.h
@@ -9,7 +9,7 @@
9 9
10#include "../../Compress/CopyCoder.h" 10#include "../../Compress/CopyCoder.h"
11 11
12#include "../IArchive.h" 12#include "../Common/HandlerOut.h"
13 13
14#include "TarIn.h" 14#include "TarIn.h"
15 15
@@ -29,31 +29,26 @@ public:
29 CMyComPtr<IInStream> _stream; 29 CMyComPtr<IInStream> _stream;
30 CMyComPtr<ISequentialInStream> _seqStream; 30 CMyComPtr<ISequentialInStream> _seqStream;
31private: 31private:
32 UInt32 _curIndex;
33 bool _latestIsRead;
34 CItemEx _latestItem;
35
36 UInt64 _phySize;
37 UInt64 _headersSize;
38 bool _phySizeDefined;
39 EErrorType _error;
40 bool _warning;
41 bool _isArc; 32 bool _isArc;
42 33 bool _posixMode_WasForced;
43 // bool _isSparse; 34 bool _posixMode;
44 bool _thereIsPaxExtendedHeader;
45
46 bool _forceCodePage; 35 bool _forceCodePage;
47 UInt32 _specifiedCodePage; 36 UInt32 _specifiedCodePage;
48 UInt32 _curCodePage; 37 UInt32 _curCodePage;
49 UInt32 _openCodePage; 38 UInt32 _openCodePage;
50 39 // CTimeOptions TimeOptions;
40 CHandlerTimeOptions _handlerTimeOptions;
51 CEncodingCharacts _encodingCharacts; 41 CEncodingCharacts _encodingCharacts;
52 42
43 UInt32 _curIndex;
44 bool _latestIsRead;
45 CItemEx _latestItem;
46
47 CArchive _arc;
48
53 NCompress::CCopyCoder *copyCoderSpec; 49 NCompress::CCopyCoder *copyCoderSpec;
54 CMyComPtr<ICompressCoder> copyCoder; 50 CMyComPtr<ICompressCoder> copyCoder;
55 51
56 HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
57 HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); 52 HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
58 HRESULT SkipTo(UInt32 index); 53 HRESULT SkipTo(UInt32 index);
59 void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; 54 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 5ddb4b2..53255e4 100644
--- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -2,15 +2,16 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5// #include <stdio.h>
6
5#include "../../../Common/ComTry.h" 7#include "../../../Common/ComTry.h"
6#include "../../../Common/Defs.h"
7#include "../../../Common/MyLinux.h" 8#include "../../../Common/MyLinux.h"
8#include "../../../Common/StringConvert.h" 9#include "../../../Common/StringConvert.h"
9#include "../../../Common/UTFConvert.h"
10 10
11#include "../../../Windows/PropVariant.h"
12#include "../../../Windows/TimeUtils.h" 11#include "../../../Windows/TimeUtils.h"
13 12
13#include "../Common/ItemNameUtils.h"
14
14#include "TarHandler.h" 15#include "TarHandler.h"
15#include "TarUpdate.h" 16#include "TarUpdate.h"
16 17
@@ -21,10 +22,35 @@ namespace NTar {
21 22
22STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) 23STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
23{ 24{
24 *type = NFileTimeType::kUnix; 25 UInt32 t = NFileTimeType::kUnix;
26 const UInt32 prec = _handlerTimeOptions.Prec;
27 if (prec != (UInt32)(Int32)-1)
28 {
29 t = NFileTimeType::kWindows;
30 if (prec == k_PropVar_TimePrec_0 ||
31 prec == k_PropVar_TimePrec_100ns)
32 t = NFileTimeType::kWindows;
33 else if (prec == k_PropVar_TimePrec_HighPrec)
34 t = k_PropVar_TimePrec_1ns;
35 else if (prec >= k_PropVar_TimePrec_Base)
36 t = prec;
37 }
38 // 7-Zip before 22.00 fails, if unknown typeType.
39 *type = t;
25 return S_OK; 40 return S_OK;
26} 41}
27 42
43
44void Get_AString_From_UString(const UString &s, AString &res,
45 UINT codePage, unsigned utfFlags)
46{
47 if (codePage == CP_UTF8)
48 ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
49 else
50 UnicodeStringToMultiByte2(res, s, codePage);
51}
52
53
28HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, 54HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
29 UINT codePage, unsigned utfFlags, bool convertSlash) 55 UINT codePage, unsigned utfFlags, bool convertSlash)
30{ 56{
@@ -36,14 +62,7 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
36 UString s = prop.bstrVal; 62 UString s = prop.bstrVal;
37 if (convertSlash) 63 if (convertSlash)
38 NItemName::ReplaceSlashes_OsToUnix(s); 64 NItemName::ReplaceSlashes_OsToUnix(s);
39 65 Get_AString_From_UString(s, res, codePage, utfFlags);
40 if (codePage == CP_UTF8)
41 {
42 ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
43 // if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG;
44 }
45 else
46 UnicodeStringToMultiByte2(res, s, codePage);
47 } 66 }
48 else if (prop.vt != VT_EMPTY) 67 else if (prop.vt != VT_EMPTY)
49 return E_INVALIDARG; 68 return E_INVALIDARG;
@@ -70,12 +89,106 @@ static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
70} 89}
71 90
72 91
92static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback,
93 CPaxTime &pt)
94{
95 pt.Clear();
96 NCOM::CPropVariant prop;
97 RINOK(callback->GetProperty(i, pid, &prop));
98 return Prop_To_PaxTime(prop, pt);
99}
100
101
102/*
103static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
104 UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
105{
106 NWindows::NCOM::CPropVariant prop;
107 RINOK(callback->GetProperty(i, kpidDevice, &prop));
108 if (prop.vt == VT_EMPTY)
109 return S_OK;
110 if (prop.vt != VT_UI8)
111 return E_INVALIDARG;
112 {
113 const UInt64 v = prop.uhVal.QuadPart;
114 majo = MY_dev_major(v);
115 mino = MY_dev_minor(v);
116 majo_defined = true;
117 mino_defined = true;
118 }
119 return S_OK;
120}
121*/
122
123static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
124 UInt32 pid, UInt32 &id, bool &defined)
125{
126 defined = false;
127 NWindows::NCOM::CPropVariant prop;
128 RINOK(callback->GetProperty(i, pid, &prop));
129 if (prop.vt == VT_EMPTY)
130 return S_OK;
131 if (prop.vt == VT_UI4)
132 {
133 id = prop.ulVal;
134 defined = true;
135 return S_OK;
136 }
137 return E_INVALIDARG;
138}
139
140
141static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i,
142 UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
143 UINT codePage, unsigned utfFlags)
144{
145 // printf("\ncallback->GetProperty(i, pidId, &prop))\n");
146
147 bool isSet = false;
148 {
149 NWindows::NCOM::CPropVariant prop;
150 RINOK(callback->GetProperty(i, pidId, &prop));
151 if (prop.vt == VT_UI4)
152 {
153 isSet = true;
154 id = prop.ulVal;
155 // printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id);
156 name.Empty();
157 }
158 else if (prop.vt != VT_EMPTY)
159 return E_INVALIDARG;
160 }
161 {
162 NWindows::NCOM::CPropVariant prop;
163 RINOK(callback->GetProperty(i, pidName, &prop));
164 if (prop.vt == VT_BSTR)
165 {
166 const UString s = prop.bstrVal;
167 Get_AString_From_UString(s, name, codePage, utfFlags);
168 if (!isSet)
169 id = 0;
170 }
171 else if (prop.vt == VT_UI4)
172 {
173 id = prop.ulVal;
174 name.Empty();
175 }
176 else if (prop.vt != VT_EMPTY)
177 return E_INVALIDARG;
178 }
179 return S_OK;
180}
181
182
183
73STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, 184STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
74 IArchiveUpdateCallback *callback) 185 IArchiveUpdateCallback *callback)
75{ 186{
76 COM_TRY_BEGIN 187 COM_TRY_BEGIN
77 188
78 if ((_stream && (_error != k_ErrorType_OK || _warning /* || _isSparse */)) || _seqStream) 189 if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning
190 /* || _isSparse */
191 )) || _seqStream)
79 return E_NOTIMPL; 192 return E_NOTIMPL;
80 CObjectVector<CUpdateItem> updateItems; 193 CObjectVector<CUpdateItem> updateItems;
81 const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); 194 const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
@@ -131,25 +244,30 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
131 else 244 else
132 ui.Mode = prop.ulVal; 245 ui.Mode = prop.ulVal;
133 // 21.07 : we clear high file type bits as GNU TAR. 246 // 21.07 : we clear high file type bits as GNU TAR.
134 ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; 247 // we will clear it later
248 // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
135 } 249 }
136 250
137 { 251 if (_handlerTimeOptions.Write_MTime.Val)
138 NCOM::CPropVariant prop; 252 RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime))
139 RINOK(callback->GetProperty(i, kpidMTime, &prop)); 253 if (_handlerTimeOptions.Write_ATime.Val)
140 if (prop.vt == VT_EMPTY) 254 RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime))
141 ui.MTime = 0; 255 if (_handlerTimeOptions.Write_CTime.Val)
142 else if (prop.vt != VT_FILETIME) 256 RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime))
143 return E_INVALIDARG; 257
144 else
145 ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
146 }
147
148 RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true)); 258 RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true));
149 if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') 259 if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
150 ui.Name += '/'; 260 ui.Name += '/';
151 RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage, utfFlags, false)); 261 // ui.Name += '/'; // for debug
152 RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage, utfFlags, false)); 262
263 if (_posixMode)
264 {
265 RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined));
266 RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined));
267 }
268
269 RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags));
270 RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags));
153 } 271 }
154 272
155 if (IntToBool(newData)) 273 if (IntToBool(newData))
@@ -169,13 +287,44 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
169 updateItems.Add(ui); 287 updateItems.Add(ui);
170 } 288 }
171 289
172 if (_thereIsPaxExtendedHeader) 290 if (_arc._are_Pax_Items)
173 { 291 {
174 // we restore original order of files, if there is pax header block 292 // we restore original order of files, if there are pax items
175 updateItems.Sort(CompareUpdateItems, NULL); 293 updateItems.Sort(CompareUpdateItems, NULL);
176 } 294 }
295
296 CUpdateOptions options;
297
298 options.CodePage = codePage;
299 options.UtfFlags = utfFlags;
300 options.PosixMode = _posixMode;
301
302 options.Write_MTime = _handlerTimeOptions.Write_MTime;
303 options.Write_ATime = _handlerTimeOptions.Write_ATime;
304 options.Write_CTime = _handlerTimeOptions.Write_CTime;
177 305
178 return UpdateArchive(_stream, outStream, _items, updateItems, codePage, utfFlags, callback); 306 // options.TimeOptions = TimeOptions;
307
308 const UInt32 prec = _handlerTimeOptions.Prec;
309 if (prec != (UInt32)(Int32)-1)
310 {
311 unsigned numDigits = 0;
312 if (prec == 0)
313 numDigits = 7;
314 else if (prec == k_PropVar_TimePrec_HighPrec
315 || prec >= k_PropVar_TimePrec_1ns)
316 numDigits = 9;
317 else if (prec >= k_PropVar_TimePrec_Base)
318 numDigits = prec - k_PropVar_TimePrec_Base;
319 options.TimeOptions.NumDigitsMax = numDigits;
320 // options.TimeOptions.RemoveZeroMode =
321 // k_PaxTimeMode_DontRemoveZero; // pure for debug
322 // k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code
323 // k_PaxTimeMode_RemoveZero_Always; // original pax code
324 }
325
326 return UpdateArchive(_stream, outStream, _items, updateItems,
327 options, callback);
179 328
180 COM_TRY_END 329 COM_TRY_END
181} 330}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp
index 9c16c89..f1efddb 100644
--- a/CPP/7zip/Archive/Tar/TarHeader.cpp
+++ b/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -18,9 +18,82 @@ namespace NFileHeader {
18 // const char * const kGNUTar = "GNUtar "; // 7 chars and a null 18 // const char * const kGNUTar = "GNUtar "; // 7 chars and a null
19 // const char * const kEmpty = "\0\0\0\0\0\0\0\0"; 19 // const char * const kEmpty = "\0\0\0\0\0\0\0\0";
20 // 7-Zip used kUsTar_00 before 21.07: 20 // 7-Zip used kUsTar_00 before 21.07:
21 // const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; 21 const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
22 // GNU TAR uses such header: 22 // GNU TAR uses such header:
23 const char kUsTar_GNU[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ; 23 const char k_GNU_ustar__[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ;
24 } 24 }
25 25
26/*
27pre-POSIX.1-1988 (i.e. v7) tar header:
28-----
29Link indicator:
30'0' or 0 : Normal file
31'1' : Hard link
32'2' : Symbolic link
33Some pre-POSIX.1-1988 tar implementations indicated a directory by having
34a trailing slash (/) in the name.
35
36Numeric values : octal with leading zeroes.
37For historical reasons, a final NUL or space character should also be used.
38Thus only 11 octal digits can be stored from 12 bytes field.
39
402001 star : introduced a base-256 coding that is indicated by
41setting the high-order bit of the leftmost byte of a numeric field.
42GNU-tar and BSD-tar followed this idea.
43
44versions of tar from before the first POSIX standard from 1988
45pad the values with spaces instead of zeroes.
46
47UStar
48-----
49UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988.
50 257 signature: "ustar", 0, "00"
51 265 32 Owner user name
52 297 32 Owner group name
53 329 8 Device major number
54 337 8 Device minor number
55 345 155 Filename prefix
56
57POSIX.1-2001/pax
58----
59format is known as extended tar format or pax format
60vendor-tagged vendor-specific enhancements.
61tags Defined by the POSIX standard:
62 atime, mtime, path, linkpath, uname, gname, size, uid, gid, ...
63
64
65PAX EXTENSION
66-----------
67Hard links
68A further difference from the ustar header block is that data blocks
69for files of typeflag 1 (hard link) may be included,
70which means that the size field may be greater than zero.
71Archives created by pax -o linkdata shall include these data
72blocks with the hard links.
73*
74
75compatiblity
76------------
77 7-Zip 16.03 supports "PaxHeader/"
78 7-Zip 20.01 supports "PaxHeaders.X/" with optional "./"
79 7-Zip 21.02 supports "@PaxHeader" with optional "./" "./"
80
81 GNU tar --format=posix uses "PaxHeaders/" in folder of file
82
83
84GNU TAR format
85==============
86v7 - Unix V7
87oldgnu - GNU tar <=1.12 : writes zero in last character in name
88gnu - GNU tar 1.13 : doesn't write zero in last character in name
89 as 7-zip 21.07
90ustar - POSIX.1-1988
91posix (pax) - POSIX.1-2001
92
93 gnu tar:
94 if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) {
95 major_t devmajor = major (st->stat.st_rdev);
96 minor_t devminor = minor (st->stat.st_rdev); }
97*/
98
26}}} 99}}}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h
index b0f0ec3..1af3093 100644
--- a/CPP/7zip/Archive/Tar/TarHeader.h
+++ b/CPP/7zip/Archive/Tar/TarHeader.h
@@ -59,6 +59,9 @@ namespace NFileHeader
59 const char kGnu_LongName = 'L'; 59 const char kGnu_LongName = 'L';
60 const char kSparse = 'S'; 60 const char kSparse = 'S';
61 const char kLabel = 'V'; 61 const char kLabel = 'V';
62 const char kPax = 'x'; // Extended header with meta data for the next file in the archive (POSIX.1-2001)
63 const char kPax_2 = 'X';
64 const char kGlobal = 'g'; // Global extended header with meta data (POSIX.1-2001)
62 const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR. 65 const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
63 data: list of files created by the --incremental (-G) option 66 data: list of files created by the --incremental (-G) option
64 Each file name is preceded by either 67 Each file name is preceded by either
@@ -66,6 +69,7 @@ namespace NFileHeader
66 - 'N' (file is a directory, or is not stored in the archive.) 69 - 'N' (file is a directory, or is not stored in the archive.)
67 Each file name is terminated by a null + an additional null after 70 Each file name is terminated by a null + an additional null after
68 the last file name. */ 71 the last file name. */
72 // 'A'-'Z' Vendor specific extensions (POSIX.1-1988)
69 } 73 }
70 74
71 extern const char * const kLongLink; // = "././@LongLink"; 75 extern const char * const kLongLink; // = "././@LongLink";
@@ -76,8 +80,8 @@ namespace NFileHeader
76 // extern const char * const kUsTar; // = "ustar"; // 5 chars 80 // extern const char * const kUsTar; // = "ustar"; // 5 chars
77 // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null 81 // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null
78 // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0" 82 // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0"
79 // extern const char kUsTar_00[8]; 83 extern const char k_Posix_ustar_00[8];
80 extern const char kUsTar_GNU[8]; 84 extern const char k_GNU_ustar__[8];
81 } 85 }
82} 86}
83 87
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
index 58399d0..4fd8c5b 100644
--- a/CPP/7zip/Archive/Tar/TarIn.cpp
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -12,6 +12,45 @@
12 12
13#include "TarIn.h" 13#include "TarIn.h"
14 14
15#define NUM_UNROLL_BYTES (8 * 4)
16
17MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size);
18MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size)
19{
20 const Byte *p = (const Byte *)data;
21
22 for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--)
23 if (*p++ != 0)
24 return true;
25
26 if (size >= NUM_UNROLL_BYTES)
27 {
28 const Byte *lim = p + size;
29 size &= (NUM_UNROLL_BYTES - 1);
30 lim -= size;
31 do
32 {
33 if (*(const UInt64 *)(const void *)(p ) != 0) return true;
34 if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true;
35 if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true;
36 if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true;
37 // if (*(const UInt32 *)(const void *)(p ) != 0) return true;
38 // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true;
39 // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true;
40 // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true;
41 p += NUM_UNROLL_BYTES;
42 }
43 while (p != lim);
44 }
45
46 for (; size != 0; size--)
47 if (*p++ != 0)
48 return true;
49
50 return false;
51}
52
53
15namespace NArchive { 54namespace NArchive {
16namespace NTar { 55namespace NTar {
17 56
@@ -41,10 +80,11 @@ static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, boo
41 return (*end == ' ' || *end == 0); 80 return (*end == ' ' || *end == 0);
42} 81}
43 82
44static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, bool allowEmpty = false) 83static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false)
45{ 84{
85 const unsigned kSize = 8;
46 UInt64 res64; 86 UInt64 res64;
47 if (!OctalToNumber(srcString, size, res64, allowEmpty)) 87 if (!OctalToNumber(srcString, kSize, res64, allowEmpty))
48 return false; 88 return false;
49 res = (UInt32)res64; 89 res = (UInt32)res64;
50 return (res64 <= 0xFFFFFFFF); 90 return (res64 <= 0xFFFFFFFF);
@@ -52,68 +92,61 @@ static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, b
52 92
53#define RIF(x) { if (!(x)) return S_OK; } 93#define RIF(x) { if (!(x)) return S_OK; }
54 94
55/*
56static bool IsEmptyData(const char *buf, size_t size)
57{
58 for (unsigned i = 0; i < size; i++)
59 if (buf[i] != 0)
60 return false;
61 return true;
62}
63*/
64
65static bool IsRecordLast(const char *buf)
66{
67 for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
68 if (buf[i] != 0)
69 return false;
70 return true;
71}
72
73static void ReadString(const char *s, unsigned size, AString &result) 95static void ReadString(const char *s, unsigned size, AString &result)
74{ 96{
75 result.SetFrom_CalcLen(s, size); 97 result.SetFrom_CalcLen(s, size);
76} 98}
77 99
78static bool ParseInt64(const char *p, Int64 &val) 100static bool ParseInt64(const char *p, Int64 &val, bool &isBin)
79{ 101{
80 UInt32 h = GetBe32(p); 102 const UInt32 h = GetBe32(p);
81 val = (Int64)GetBe64(p + 4); 103 val = (Int64)GetBe64(p + 4);
104 isBin = true;
82 if (h == (UInt32)1 << 31) 105 if (h == (UInt32)1 << 31)
83 return ((val >> 63) & 1) == 0; 106 return ((val >> 63) & 1) == 0;
84 if (h == (UInt32)(Int32)-1) 107 if (h == (UInt32)(Int32)-1)
85 return ((val >> 63) & 1) != 0; 108 return ((val >> 63) & 1) != 0;
86 UInt64 uv; 109 isBin = false;
87 bool res = OctalToNumber(p, 12, uv); 110 UInt64 u;
88 val = (Int64)uv; 111 const bool res = OctalToNumber(p, 12, u);
112 val = (Int64)u;
89 return res; 113 return res;
90} 114}
91 115
92static bool ParseInt64_MTime(const char *p, Int64 &val) 116static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin)
93{ 117{
94 // rare case tar : ZEROs in Docker-Windows TARs 118 // rare case tar : ZEROs in Docker-Windows TARs
95 // rare case tar : spaces 119 // rare case tar : spaces
120 isBin = false;
96 if (GetUi32(p) != 0) 121 if (GetUi32(p) != 0)
97 for (unsigned i = 0; i < 12; i++) 122 for (unsigned i = 0; i < 12; i++)
98 if (p[i] != ' ') 123 if (p[i] != ' ')
99 return ParseInt64(p, val); 124 return ParseInt64(p, val, isBin);
100 val = 0; 125 val = 0;
101 return true; 126 return true;
102} 127}
103 128
104static bool ParseSize(const char *p, UInt64 &val) 129static bool ParseSize(const char *p, UInt64 &val, bool &isBin)
105{ 130{
106 if (GetBe32(p) == (UInt32)1 << 31) 131 if (GetBe32(p) == (UInt32)1 << 31)
107 { 132 {
108 // GNU extension 133 // GNU extension
134 isBin = true;
109 val = GetBe64(p + 4); 135 val = GetBe64(p + 4);
110 return ((val >> 63) & 1) == 0; 136 return ((val >> 63) & 1) == 0;
111 } 137 }
138 isBin = false;
112 return OctalToNumber(p, 12, val, 139 return OctalToNumber(p, 12, val,
113 true // 20.03: allow empty size for 'V' Label entry 140 true // 20.03: allow empty size for 'V' Label entry
114 ); 141 );
115} 142}
116 143
144static bool ParseSize(const char *p, UInt64 &val)
145{
146 bool isBin;
147 return ParseSize(p, val, isBin);
148}
149
117#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; } 150#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; }
118 151
119API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size) 152API_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)
126 159
127 UInt32 mode; 160 UInt32 mode;
128 // we allow empty Mode value for LongName prefix items 161 // we allow empty Mode value for LongName prefix items
129 CHECK(OctalToNumber32(p, 8, mode, true)); p += 8; 162 CHECK(OctalToNumber32(p, mode, true)); p += 8;
130 163
131 // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; 164 // if (!OctalToNumber32(p, item.UID)) item.UID = 0;
132 p += 8; 165 p += 8;
133 // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; 166 // if (!OctalToNumber32(p, item.GID)) item.GID = 0;
134 p += 8; 167 p += 8;
135 168
136 UInt64 packSize; 169 UInt64 packSize;
137 Int64 time; 170 Int64 time;
138 UInt32 checkSum; 171 UInt32 checkSum;
139 CHECK(ParseSize(p, packSize)); p += 12; 172 bool isBin;
140 CHECK(ParseInt64_MTime(p, time)); p += 12; 173 CHECK(ParseSize(p, packSize, isBin)); p += 12;
141 CHECK(OctalToNumber32(p, 8, checkSum)); 174 CHECK(ParseInt64_MTime(p, time, isBin)); p += 12;
175 CHECK(OctalToNumber32(p, checkSum));
142 return k_IsArc_Res_YES; 176 return k_IsArc_Res_YES;
143} 177}
144 178
145static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) 179
180HRESULT CArchive::GetNextItemReal(CItemEx &item)
146{ 181{
147 char buf[NFileHeader::kRecordSize]; 182 char buf[NFileHeader::kRecordSize];
148 char *p = buf;
149 183
150 error = k_ErrorType_OK; 184 error = k_ErrorType_OK;
151 filled = false; 185 filled = false;
@@ -154,7 +188,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
154 for (;;) 188 for (;;)
155 { 189 {
156 size_t processedSize = NFileHeader::kRecordSize; 190 size_t processedSize = NFileHeader::kRecordSize;
157 RINOK(ReadStream(stream, buf, &processedSize)); 191 RINOK(ReadStream(SeqStream, buf, &processedSize));
158 if (processedSize == 0) 192 if (processedSize == 0)
159 { 193 {
160 if (!thereAreEmptyRecords) 194 if (!thereAreEmptyRecords)
@@ -180,10 +214,14 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
180 214
181 return S_OK; 215 return S_OK;
182 } 216 }
183 if (!IsRecordLast(buf)) 217 if (IsBufNonZero(buf, NFileHeader::kRecordSize))
184 break; 218 break;
185 item.HeaderSize += NFileHeader::kRecordSize; 219 item.HeaderSize += NFileHeader::kRecordSize;
186 thereAreEmptyRecords = true; 220 thereAreEmptyRecords = true;
221 if (OpenCallback)
222 {
223 RINOK(Progress(item, 0));
224 }
187 } 225 }
188 if (thereAreEmptyRecords) 226 if (thereAreEmptyRecords)
189 { 227 {
@@ -191,52 +229,69 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
191 return S_OK; 229 return S_OK;
192 } 230 }
193 231
232 char *p = buf;
233
194 error = k_ErrorType_Corrupted; 234 error = k_ErrorType_Corrupted;
195 ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; 235
196 item.NameCouldBeReduced = 236 // ReadString(p, NFileHeader::kNameSize, item.Name);
237 p += NFileHeader::kNameSize;
238
239 /*
240 item.Name_CouldBeReduced =
197 (item.Name.Len() == NFileHeader::kNameSize || 241 (item.Name.Len() == NFileHeader::kNameSize ||
198 item.Name.Len() == NFileHeader::kNameSize - 1); 242 item.Name.Len() == NFileHeader::kNameSize - 1);
243 */
199 244
200 // we allow empty Mode value for LongName prefix items 245 // we allow empty Mode value for LongName prefix items
201 RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8; 246 RIF(OctalToNumber32(p, item.Mode, true)); p += 8;
202 247
203 if (!OctalToNumber32(p, 8, item.UID)) { item.UID = 0; } p += 8; 248 if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8;
204 if (!OctalToNumber32(p, 8, item.GID)) { item.GID = 0; } p += 8; 249 if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8;
205 250
206 RIF(ParseSize(p, item.PackSize)); 251 RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin));
207 item.Size = item.PackSize; 252 item.Size = item.PackSize;
253 item.Size_IsBin = item.PackSize_IsBin;
208 p += 12; 254 p += 12;
209 RIF(ParseInt64_MTime(p, item.MTime)); p += 12; 255 RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)); p += 12;
210 256
211 UInt32 checkSum; 257 UInt32 checkSum;
212 RIF(OctalToNumber32(p, 8, checkSum)); 258 RIF(OctalToNumber32(p, checkSum));
213 memset(p, ' ', 8); p += 8; 259 memset(p, ' ', 8); p += 8;
214 260
215 item.LinkFlag = *p++; 261 item.LinkFlag = *p++;
216 262
217 ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; 263 ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
218 item.LinkNameCouldBeReduced = 264
265 /*
266 item.LinkName_CouldBeReduced =
219 (item.LinkName.Len() == NFileHeader::kNameSize || 267 (item.LinkName.Len() == NFileHeader::kNameSize ||
220 item.LinkName.Len() == NFileHeader::kNameSize - 1); 268 item.LinkName.Len() == NFileHeader::kNameSize - 1);
269 */
221 270
222 memcpy(item.Magic, p, 8); p += 8; 271 memcpy(item.Magic, p, 8); p += 8;
223 272
224 ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize; 273 ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
225 ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize; 274 ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
226 275
227 item.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8; 276 item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)); } p += 8;
228 item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8; 277 item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)); } p += 8;
229 278
230 if (p[0] != 0) 279 if (p[0] != 0
280 && item.IsMagic_ustar_5chars()
281 && (item.LinkFlag != 'L' ))
231 { 282 {
232 AString prefix; 283 item.Prefix_WasUsed = true;
233 ReadString(p, NFileHeader::kPrefixSize, prefix); 284 ReadString(p, NFileHeader::kPrefixSize, item.Name);
234 if (!prefix.IsEmpty() 285 item.Name += '/';
235 && item.IsUstarMagic() 286 unsigned i;
236 && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) 287 for (i = 0; i < NFileHeader::kNameSize; i++)
237 item.Name = prefix + '/' + item.Name; 288 if (buf[i] == 0)
289 break;
290 item.Name.AddFrom(buf, i);
238 } 291 }
239 292 else
293 ReadString(buf, NFileHeader::kNameSize, item.Name);
294
240 p += NFileHeader::kPrefixSize; 295 p += NFileHeader::kPrefixSize;
241 296
242 if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) 297 if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink)
@@ -255,22 +310,25 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
255 310
256 /* 311 /*
257 TAR standard requires sum of unsigned byte values. 312 TAR standard requires sum of unsigned byte values.
258 But some TAR programs use sum of signed byte values. 313 But some old TAR programs use sum of signed byte values.
259 So we check both values. 314 So we check both values.
260 */ 315 */
261 UInt32 checkSumReal = 0; 316 // for (int y = 0; y < 100; y++) // for debug
262 Int32 checkSumReal_Signed = 0;
263 for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
264 { 317 {
265 char c = buf[i]; 318 UInt32 sum0 = 0;
266 checkSumReal_Signed += (signed char)c; 319 {
267 checkSumReal += (Byte)buf[i]; 320 for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
268 } 321 sum0 += (Byte)buf[i];
269 322 }
270 if (checkSumReal != checkSum) 323 if (sum0 != checkSum)
271 { 324 {
272 if ((UInt32)checkSumReal_Signed != checkSum) 325 Int32 sum = 0;
273 return S_OK; 326 for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
327 sum += (signed char)buf[i];
328 if ((UInt32)sum != checkSum)
329 return S_OK;
330 item.IsSignedChecksum = true;
331 }
274 } 332 }
275 333
276 item.HeaderSize += NFileHeader::kRecordSize; 334 item.HeaderSize += NFileHeader::kRecordSize;
@@ -280,7 +338,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
280 Byte isExtended = (Byte)buf[482]; 338 Byte isExtended = (Byte)buf[482];
281 if (isExtended != 0 && isExtended != 1) 339 if (isExtended != 0 && isExtended != 1)
282 return S_OK; 340 return S_OK;
283 RIF(ParseSize(buf + 483, item.Size)); 341 RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin));
284 UInt64 min = 0; 342 UInt64 min = 0;
285 for (unsigned i = 0; i < 4; i++) 343 for (unsigned i = 0; i < 4; i++)
286 { 344 {
@@ -309,7 +367,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
309 while (isExtended != 0) 367 while (isExtended != 0)
310 { 368 {
311 size_t processedSize = NFileHeader::kRecordSize; 369 size_t processedSize = NFileHeader::kRecordSize;
312 RINOK(ReadStream(stream, buf, &processedSize)); 370 RINOK(ReadStream(SeqStream, buf, &processedSize));
313 if (processedSize != NFileHeader::kRecordSize) 371 if (processedSize != NFileHeader::kRecordSize)
314 { 372 {
315 error = k_ErrorType_UnexpectedEnd; 373 error = k_ErrorType_UnexpectedEnd;
@@ -317,6 +375,12 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
317 } 375 }
318 376
319 item.HeaderSize += NFileHeader::kRecordSize; 377 item.HeaderSize += NFileHeader::kRecordSize;
378
379 if (OpenCallback)
380 {
381 RINOK(Progress(item, 0));
382 }
383
320 isExtended = (Byte)buf[21 * 24]; 384 isExtended = (Byte)buf[21 * 24];
321 if (isExtended != 0 && isExtended != 1) 385 if (isExtended != 0 && isExtended != 1)
322 return S_OK; 386 return S_OK;
@@ -346,172 +410,711 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
346 return S_OK; 410 return S_OK;
347 } 411 }
348 412
413 if (item.PackSize >= (UInt64)1 << 63)
414 return S_OK;
415
349 filled = true; 416 filled = true;
350 error = k_ErrorType_OK; 417 error = k_ErrorType_OK;
351 return S_OK; 418 return S_OK;
352} 419}
353 420
354 421
355static HRESULT ReadDataToString(ISequentialInStream *stream, CItemEx &item, AString &s, EErrorType &error) 422HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset)
356{ 423{
357 const unsigned packSize = (unsigned)item.GetPackSizeAligned(); 424 const UInt64 pos = item.Get_DataPos() + posOffset;
358 size_t processedSize = packSize; 425 if (NumFiles - NumFiles_Prev < (1 << 16)
359 HRESULT res = ReadStream(stream, s.GetBuf(packSize), &processedSize); 426 // && NumRecords - NumRecords_Prev < (1 << 16)
360 item.HeaderSize += (unsigned)processedSize; 427 && pos - Pos_Prev < ((UInt32)1 << 28))
361 s.ReleaseBuf_CalcLen((unsigned)item.PackSize); 428 return S_OK;
362 RINOK(res); 429 {
363 if (processedSize != packSize) 430 Pos_Prev = pos;
364 error = k_ErrorType_UnexpectedEnd; 431 NumFiles_Prev = NumFiles;
432 // NumRecords_Prev = NumRecords;
433 // Sleep(100); // for debug
434 return OpenCallback->SetCompleted(&NumFiles, &pos);
435 }
436}
437
438
439HRESULT CArchive::ReadDataToBuffer(const CItemEx &item,
440 CTempBuffer &tb, size_t stringLimit)
441{
442 tb.Init();
443 UInt64 packSize = item.Get_PackSize_Aligned();
444 if (packSize == 0)
445 return S_OK;
446
447 UInt64 pos;
448
449 {
450 size_t size = stringLimit;
451 if (size > packSize)
452 size = (size_t)packSize;
453 tb.Buffer.AllocAtLeast(size);
454 size_t processedSize = size;
455 const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize);
456 pos = processedSize;
457 if (processedSize != size)
458 {
459 error = k_ErrorType_UnexpectedEnd;
460 return res;
461 }
462 RINOK(res);
463
464 packSize -= size;
465
466 size_t i;
467 const Byte *p = tb.Buffer;
468 for (i = 0; i < size; i++)
469 if (p[i] == 0)
470 break;
471 if (i >= item.PackSize)
472 tb.StringSize_IsConfirmed = true;
473 if (i > item.PackSize)
474 {
475 tb.StringSize = (size_t)item.PackSize;
476 tb.IsNonZeroTail = true;
477 }
478 else
479 {
480 tb.StringSize = i;
481 if (i != size)
482 {
483 tb.StringSize_IsConfirmed = true;
484 if (IsBufNonZero(p + i, size - i))
485 tb.IsNonZeroTail = true;
486 }
487 }
488
489 if (packSize == 0)
490 return S_OK;
491 }
492
493 if (InStream)
494 {
495 RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL));
496 return S_OK;
497 }
498 const unsigned kBufSize = 1 << 15;
499 Buffer.AllocAtLeast(kBufSize);
500
501 do
502 {
503 if (OpenCallback)
504 {
505 RINOK(Progress(item, pos));
506 }
507
508 unsigned size = kBufSize;
509 if (size > packSize)
510 size = (unsigned)packSize;
511 size_t processedSize = size;
512 const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize);
513 if (processedSize != size)
514 {
515 error = k_ErrorType_UnexpectedEnd;
516 return res;
517 }
518 if (!tb.IsNonZeroTail)
519 {
520 if (IsBufNonZero(Buffer, size))
521 tb.IsNonZeroTail = true;
522 }
523 packSize -= size;
524 pos += size;
525 }
526 while (packSize != 0);
365 return S_OK; 527 return S_OK;
366} 528}
529
367 530
368static bool ParsePaxLongName(const AString &src, AString &dest) 531
532struct CPaxInfo: public CPaxTimes
369{ 533{
370 dest.Empty(); 534 bool DoubleTagError;
371 for (unsigned pos = 0;;) 535 bool TagParsingError;
536 bool UnknownLines_Overflow;
537 bool Size_Defined;
538 bool UID_Defined;
539 bool GID_Defined;
540 bool Path_Defined;
541 bool Link_Defined;
542 bool User_Defined;
543 bool Group_Defined;
544
545 UInt64 Size;
546 UInt32 UID;
547 UInt32 GID;
548
549 AString Path;
550 AString Link;
551 AString User;
552 AString Group;
553 AString UnknownLines;
554
555 bool ParseID(const AString &val, bool &defined, UInt32 &res)
372 { 556 {
373 if (pos >= src.Len()) 557 if (defined)
558 DoubleTagError = true;
559 if (val.IsEmpty())
374 return false; 560 return false;
375 const char *start = src.Ptr(pos); 561 const char *end2;
376 const char *end; 562 res = ConvertStringToUInt32(val.Ptr(), &end2);
377 const UInt32 lineLen = ConvertStringToUInt32(start, &end); 563 if (*end2 != 0)
378 if (end == start)
379 return false; 564 return false;
380 if (*end != ' ') 565 defined = true;
566 return true;
567 }
568
569 bool ParsePax(const CTempBuffer &tb, bool isFile);
570};
571
572
573static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError)
574{
575 if (pt.IsDefined())
576 doubleTagError = true;
577 pt.Clear();
578 const char *s = src.Ptr();
579 bool isNegative = false;
580 if (*s == '-')
581 {
582 isNegative = true;
583 s++;
584 }
585 const char *end;
586 {
587 UInt64 sec = ConvertStringToUInt64(s, &end);
588 if (s == end)
381 return false; 589 return false;
382 if (lineLen > src.Len() - pos) 590 if (sec >= ((UInt64)1 << 63))
383 return false; 591 return false;
384 unsigned offset = (unsigned)(end - start) + 1; 592 if (isNegative)
385 if (lineLen < offset) 593 sec = -(Int64)sec;
594 pt.Sec = sec;
595 }
596 if (*end == 0)
597 {
598 pt.Ns = 0;
599 pt.NumDigits = 0;
600 return true;
601 }
602 if (*end != '.')
603 return false;
604 s = end + 1;
605
606 UInt32 ns = 0;
607 unsigned i;
608 const unsigned kNsDigits = 9;
609 for (i = 0;; i++)
610 {
611 const char c = s[i];
612 if (c == 0)
613 break;
614 if (c < '0' || c > '9')
386 return false; 615 return false;
387 if (IsString1PrefixedByString2(src.Ptr(pos + offset), "path=")) 616 // we ignore digits after 9 digits as GNU TAR
617 if (i < kNsDigits)
618 {
619 ns *= 10;
620 ns += c - '0';
621 }
622 }
623 pt.NumDigits = (i < kNsDigits ? i : kNsDigits);
624 while (i < kNsDigits)
625 {
626 ns *= 10;
627 i++;
628 }
629 if (isNegative && ns != 0)
630 {
631 pt.Sec--;
632 ns = (UInt32)1000 * 1000 * 1000 - ns;
633 }
634 pt.Ns = ns;
635 return true;
636}
637
638
639bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile)
640{
641 DoubleTagError = false;
642 TagParsingError = false;
643 UnknownLines_Overflow = false;
644 Size_Defined = false;
645 UID_Defined = false;
646 GID_Defined = false;
647 Path_Defined = false;
648 Link_Defined = false;
649 User_Defined = false;
650 Group_Defined = false;
651
652 // CPaxTimes::Clear();
653
654 const char *s = (const char *)(const void *)(const Byte *)tb.Buffer;
655 size_t rem = tb.StringSize;
656
657 Clear();
658
659 AString name, val;
660
661 while (rem != 0)
662 {
663 unsigned i;
664 for (i = 0;; i++)
388 { 665 {
389 offset += 5; // "path=" 666 if (i > 24 || i >= rem) // we use limitation for size of (size) field
390 dest = src.Mid(pos + offset, lineLen - offset);
391 if (dest.IsEmpty())
392 return false; 667 return false;
393 if (dest.Back() != '\n') 668 if (s[i] == ' ')
669 break;
670 }
671 if (i == 0)
672 return false;
673 const char *end;
674 const UInt32 size = ConvertStringToUInt32(s, &end);
675 const unsigned offset = (unsigned)(end - s) + 1;
676 if (size > rem
677 || size <= offset + 1
678 || offset != i + 1
679 || s[size - 1] != '\n')
680 return false;
681
682 for (i = offset; i < size; i++)
683 if (s[i] == 0)
394 return false; 684 return false;
395 dest.DeleteBack(); 685
396 return true; 686 for (i = offset; i < size - 1; i++)
687 if (s[i] == '=')
688 break;
689 if (i == size - 1)
690 return false;
691
692 name.SetFrom(s + offset, i - offset);
693 val.SetFrom(s + i + 1, size - 1 - (i + 1));
694
695 bool parsed = false;
696 if (isFile)
697 {
698 bool isDetectedName = true;
699 // only lower case (name) is supported
700 if (name.IsEqualTo("path"))
701 {
702 if (Path_Defined)
703 DoubleTagError = true;
704 Path = val;
705 Path_Defined = true;
706 parsed = true;
707 }
708 else if (name.IsEqualTo("linkpath"))
709 {
710 if (Link_Defined)
711 DoubleTagError = true;
712 Link = val;
713 Link_Defined = true;
714 parsed = true;
715 }
716 else if (name.IsEqualTo("uname"))
717 {
718 if (User_Defined)
719 DoubleTagError = true;
720 User = val;
721 User_Defined = true;
722 parsed = true;
723 }
724 else if (name.IsEqualTo("gname"))
725 {
726 if (Group_Defined)
727 DoubleTagError = true;
728 Group = val;
729 Group_Defined = true;
730 parsed = true;
731 }
732 else if (name.IsEqualTo("uid"))
733 {
734 parsed = ParseID(val, UID_Defined, UID);
735 }
736 else if (name.IsEqualTo("gid"))
737 {
738 parsed = ParseID(val, GID_Defined, GID);
739 }
740 else if (name.IsEqualTo("size"))
741 {
742 if (Size_Defined)
743 DoubleTagError = true;
744 Size_Defined = false;
745 if (!val.IsEmpty())
746 {
747 const char *end2;
748 Size = ConvertStringToUInt64(val.Ptr(), &end2);
749 if (*end2 == 0)
750 {
751 Size_Defined = true;
752 parsed = true;
753 }
754 }
755 }
756 else if (name.IsEqualTo("mtime"))
757 { parsed = ParsePaxTime(val, MTime, DoubleTagError); }
758 else if (name.IsEqualTo("atime"))
759 { parsed = ParsePaxTime(val, ATime, DoubleTagError); }
760 else if (name.IsEqualTo("ctime"))
761 { parsed = ParsePaxTime(val, CTime, DoubleTagError); }
762 else
763 isDetectedName = false;
764 if (isDetectedName && !parsed)
765 TagParsingError = true;
397 } 766 }
398 pos += lineLen; 767 if (!parsed)
768 {
769 if (!UnknownLines_Overflow)
770 {
771 const unsigned addSize = size - offset;
772 if (UnknownLines.Len() + addSize < (1 << 16))
773 UnknownLines.AddFrom(s + offset, addSize);
774 else
775 UnknownLines_Overflow = true;
776 }
777 }
778
779 s += size;
780 rem -= size;
399 } 781 }
782 return true;
400} 783}
401 784
402HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) 785
786HRESULT CArchive::ReadItem2(CItemEx &item)
403{ 787{
788 // CItem
789
790 item.SparseBlocks.Clear();
791 item.PaxTimes.Clear();
792
793 // CItemEx
794
404 item.HeaderSize = 0; 795 item.HeaderSize = 0;
796 item.Num_Pax_Records = 0;
405 797
406 bool flagL = false; 798 item.LongName_WasUsed = false;
407 bool flagK = false; 799 item.LongName_WasUsed_2 = false;
408 AString nameL; 800
409 AString nameK; 801 item.LongLink_WasUsed = false;
410 AString pax; 802 item.LongLink_WasUsed_2 = false;
803
804 item.HeaderError = false;
805 item.IsSignedChecksum = false;
806 item.Prefix_WasUsed = false;
411 807
412 for (;;) 808 item.Pax_Error = false;
809 item.Pax_Overflow = false;
810 item.pax_path_WasUsed = false;
811 item.pax_link_WasUsed = false;
812 item.pax_size_WasUsed = false;
813
814 item.PaxExtra.Clear();
815
816 item.EncodingCharacts.Clear();
817
818 // CArchive temp variable
819
820 NameBuf.Init();
821 LinkBuf.Init();
822 PaxBuf.Init();
823 PaxBuf_global.Init();
824
825 for (unsigned recordIndex = 0;; recordIndex++)
413 { 826 {
414 RINOK(GetNextItemReal(stream, filled, item, error)); 827 if (OpenCallback)
828 {
829 RINOK(Progress(item, 0));
830 }
831
832 RINOK(GetNextItemReal(item));
833
834 // NumRecords++;
835
415 if (!filled) 836 if (!filled)
416 { 837 {
417 if (error == k_ErrorType_OK && (flagL || flagK)) 838 if (error == k_ErrorType_OK)
839 if (item.LongName_WasUsed ||
840 item.LongLink_WasUsed ||
841 item.Num_Pax_Records != 0)
418 error = k_ErrorType_Corrupted; 842 error = k_ErrorType_Corrupted;
419 return S_OK;
420 } 843 }
421 844
422 if (error != k_ErrorType_OK) 845 if (error != k_ErrorType_OK)
423 return S_OK; 846 return S_OK;
424 847
425 if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name 848 const char lf = item.LinkFlag;
426 item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname 849 if (lf == NFileHeader::NLinkFlag::kGnu_LongName ||
850 lf == NFileHeader::NLinkFlag::kGnu_LongLink)
427 { 851 {
428 AString *name; 852 // GNU tar ignores item.Name after LinkFlag test
429 if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName) 853 // 22.00 : now we also ignore item.Name here
430 { if (flagL) return S_OK; flagL = true; name = &nameL; } 854 /*
431 else
432 { if (flagK) return S_OK; flagK = true; name = &nameK; }
433
434 if (item.Name != NFileHeader::kLongLink && 855 if (item.Name != NFileHeader::kLongLink &&
435 item.Name != NFileHeader::kLongLink2) 856 item.Name != NFileHeader::kLongLink2)
857 {
858 break;
859 // return S_OK;
860 }
861 */
862
863 CTempBuffer *tb =
864 lf == NFileHeader::NLinkFlag::kGnu_LongName ?
865 &NameBuf :
866 &LinkBuf;
867
868 /*
869 if (item.PackSize > (1 << 29))
870 {
871 // break;
436 return S_OK; 872 return S_OK;
437 if (item.PackSize > (1 << 14)) 873 }
438 return S_OK; 874 */
439 875
440 RINOK(ReadDataToString(stream, item, *name, error)); 876 const unsigned kLongNameSizeMax = (unsigned)1 << 14;
877 RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax));
441 if (error != k_ErrorType_OK) 878 if (error != k_ErrorType_OK)
442 return S_OK; 879 return S_OK;
443 880
881 if (lf == NFileHeader::NLinkFlag::kGnu_LongName)
882 {
883 item.LongName_WasUsed_2 =
884 item.LongName_WasUsed;
885 item.LongName_WasUsed = true;
886 }
887 else
888 {
889 item.LongLink_WasUsed_2 =
890 item.LongLink_WasUsed;
891 item.LongLink_WasUsed = true;
892 }
893
894 if (!tb->StringSize_IsConfirmed)
895 tb->StringSize = 0;
896 item.HeaderSize += item.Get_PackSize_Aligned();
897 if (tb->StringSize == 0 ||
898 tb->StringSize + 1 != item.PackSize)
899 item.HeaderError = true;
900 if (tb->IsNonZeroTail)
901 item.HeaderError = true;
444 continue; 902 continue;
445 } 903 }
446 904
447 switch (item.LinkFlag) 905 if (lf == NFileHeader::NLinkFlag::kGlobal ||
906 lf == NFileHeader::NLinkFlag::kPax ||
907 lf == NFileHeader::NLinkFlag::kPax_2)
448 { 908 {
449 case 'g': 909 // GNU tar ignores item.Name after LinkFlag test
450 case 'x': 910 // 22.00 : now we also ignore item.Name here
451 case 'X': 911 /*
912 if (item.PackSize > (UInt32)1 << 26)
452 { 913 {
453 const char *s = item.Name.Ptr(); 914 break; // we don't want big PaxBuf files
454 if (IsString1PrefixedByString2(s, "./")) 915 // return S_OK;
455 s += 2;
456 if (IsString1PrefixedByString2(s, "./"))
457 s += 2;
458 if ( IsString1PrefixedByString2(s, "PaxHeader/")
459 || IsString1PrefixedByString2(s, "PaxHeaders.X/")
460 || IsString1PrefixedByString2(s, "PaxHeaders.4467/")
461 || StringsAreEqual_Ascii(s, "@PaxHeader")
462 )
463 {
464 RINOK(ReadDataToString(stream, item, pax, error));
465 if (error != k_ErrorType_OK)
466 return S_OK;
467 continue;
468 }
469 break;
470 } 916 }
471 case NFileHeader::NLinkFlag::kDumpDir: 917 */
918 const unsigned kParsingPaxSizeMax = (unsigned)1 << 26;
919
920 const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize);
921
922 CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf);
923
924 RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax));
925 if (error != k_ErrorType_OK)
926 return S_OK;
927
928 item.HeaderSize += item.Get_PackSize_Aligned();
929
930 if (tb->StringSize != item.PackSize
931 || tb->StringSize == 0
932 || tb->IsNonZeroTail)
933 item.Pax_Error = true;
934
935 item.Num_Pax_Records++;
936 if (lf != NFileHeader::NLinkFlag::kGlobal)
472 { 937 {
473 break; 938 item.PaxExtra.RecordPath = item.Name;
474 // GNU Extensions to the Archive Format 939 continue;
475 } 940 }
476 case NFileHeader::NLinkFlag::kSparse: 941 // break; // for debug
477 { 942 {
478 break; 943 if (PaxGlobal_Defined)
479 // GNU Extensions to the Archive Format 944 _is_PaxGlobal_Error = true;
945 CPaxInfo paxInfo;
946 if (paxInfo.ParsePax(PaxBuf_global, false))
947 {
948 PaxGlobal.RawLines = paxInfo.UnknownLines;
949 PaxGlobal.RecordPath = item.Name;
950 PaxGlobal_Defined = true;
951 }
952 else
953 _is_PaxGlobal_Error = true;
954 if (isStartHeader)
955 {
956 // we skip global pax header info after parsing
957 item.HeaderPos += item.HeaderSize;
958 item.HeaderSize = 0;
959 }
480 } 960 }
481 default: 961 continue;
482 if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
483 return S_OK;
484 } 962 }
485 963
486 if (flagL) 964 /*
965 if (lf == NFileHeader::NLinkFlag::kDumpDir ||
966 lf == NFileHeader::NLinkFlag::kSparse)
487 { 967 {
488 item.Name = nameL; 968 // GNU Extensions to the Archive Format
489 item.NameCouldBeReduced = false; 969 break;
490 } 970 }
491 971 if (lf > '7' || (lf < '0' && lf != 0))
492 if (flagK)
493 { 972 {
494 item.LinkName = nameK; 973 break;
495 item.LinkNameCouldBeReduced = false; 974 // return S_OK;
496 } 975 }
497 976 */
498 error = k_ErrorType_OK; 977 break;
499 978 }
500 if (!pax.IsEmpty()) 979
980 // we still use name from main header, if long_name is bad
981 if (item.LongName_WasUsed && NameBuf.StringSize != 0)
982 {
983 NameBuf.CopyToString(item.Name);
984 // item.Name_CouldBeReduced = false;
985 }
986
987 if (item.LongLink_WasUsed)
988 {
989 // we use empty link, if long_link is bad
990 LinkBuf.CopyToString(item.LinkName);
991 // item.LinkName_CouldBeReduced = false;
992 }
993
994 error = k_ErrorType_OK;
995
996 if (PaxBuf.StringSize != 0)
997 {
998 CPaxInfo paxInfo;
999 if (!paxInfo.ParsePax(PaxBuf, true))
1000 item.Pax_Error = true;
1001 else
501 { 1002 {
502 AString name; 1003 if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty())
503 if (ParsePaxLongName(pax, name)) 1004 {
504 item.Name = name; 1005 item.Name = paxInfo.Path;
505 else 1006 item.pax_path_WasUsed = true;
1007 }
1008 if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty())
1009 {
1010 item.LinkName = paxInfo.Link;
1011 item.pax_link_WasUsed = true;
1012 }
1013 if (paxInfo.User_Defined)
1014 {
1015 item.User = paxInfo.User;
1016 // item.pax_uname_WasUsed = true;
1017 }
1018 if (paxInfo.Group_Defined)
1019 {
1020 item.Group = paxInfo.Group;
1021 // item.pax_gname_WasUsed = true;
1022 }
1023 if (paxInfo.UID_Defined)
506 { 1024 {
507 // no "path" property is allowed in pax4467 1025 item.UID = (UInt32)paxInfo.UID;
508 // error = k_ErrorType_Warning;
509 } 1026 }
510 pax.Empty(); 1027 if (paxInfo.GID_Defined)
1028 {
1029 item.GID = (UInt32)paxInfo.GID;
1030 }
1031
1032 if (paxInfo.Size_Defined)
1033 {
1034 const UInt64 piSize = paxInfo.Size;
1035 // GNU TAR ignores (item.Size) in that case
1036 if (item.Size != 0 && item.Size != piSize)
1037 item.Pax_Error = true;
1038 item.Size = piSize;
1039 item.PackSize = piSize;
1040 item.pax_size_WasUsed = true;
1041 }
1042
1043 item.PaxTimes = paxInfo;
1044 item.PaxExtra.RawLines = paxInfo.UnknownLines;
1045 if (paxInfo.UnknownLines_Overflow)
1046 item.Pax_Overflow = true;
1047 if (paxInfo.TagParsingError)
1048 item.Pax_Error = true;
1049 if (paxInfo.DoubleTagError)
1050 item.Pax_Error = true;
511 } 1051 }
1052 }
512 1053
513 return S_OK; 1054 return S_OK;
1055}
1056
1057
1058
1059HRESULT CArchive::ReadItem(CItemEx &item)
1060{
1061 item.HeaderPos = _phySize;
1062
1063 const HRESULT res = ReadItem2(item);
1064
1065 /*
1066 if (error == k_ErrorType_Warning)
1067 _is_Warning = true;
1068 else
1069 */
1070
1071 if (error != k_ErrorType_OK)
1072 _error = error;
1073
1074 RINOK(res);
1075
1076 if (filled)
1077 {
1078 if (item.IsMagic_GNU())
1079 _are_Gnu = true;
1080 else if (item.IsMagic_Posix_ustar_00())
1081 _are_Posix = true;
1082
1083 if (item.Num_Pax_Records != 0)
1084 _are_Pax = true;
1085
1086 if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true;
1087 if (item.PaxTimes.ATime.IsDefined()) _are_atime = true;
1088 if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true;
1089
1090 if (item.pax_path_WasUsed)
1091 _are_pax_path = true;
1092 if (item.pax_link_WasUsed)
1093 _are_pax_link = true;
1094 if (item.LongName_WasUsed)
1095 _are_LongName = true;
1096 if (item.LongLink_WasUsed)
1097 _are_LongLink = true;
1098 if (item.Prefix_WasUsed)
1099 _pathPrefix_WasUsed = true;
1100 /*
1101 if (item.IsSparse())
1102 _isSparse = true;
1103 */
1104 if (item.Is_PaxExtendedHeader())
1105 _are_Pax_Items = true;
1106 if (item.IsThereWarning()
1107 || item.HeaderError
1108 || item.Pax_Error)
1109 _is_Warning = true;
514 } 1110 }
1111
1112 const UInt64 headerEnd = item.HeaderPos + item.HeaderSize;
1113 // _headersSize += headerEnd - _phySize;
1114 // we don't count skipped records
1115 _headersSize += item.HeaderSize;
1116 _phySize = headerEnd;
1117 return S_OK;
515} 1118}
516 1119
517}} 1120}}
diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h
index 1c508bc..e99599a 100644
--- a/CPP/7zip/Archive/Tar/TarIn.h
+++ b/CPP/7zip/Archive/Tar/TarIn.h
@@ -3,7 +3,7 @@
3#ifndef __ARCHIVE_TAR_IN_H 3#ifndef __ARCHIVE_TAR_IN_H
4#define __ARCHIVE_TAR_IN_H 4#define __ARCHIVE_TAR_IN_H
5 5
6#include "../../IStream.h" 6#include "../IArchive.h"
7 7
8#include "TarItem.h" 8#include "TarItem.h"
9 9
@@ -14,11 +14,133 @@ enum EErrorType
14{ 14{
15 k_ErrorType_OK, 15 k_ErrorType_OK,
16 k_ErrorType_Corrupted, 16 k_ErrorType_Corrupted,
17 k_ErrorType_UnexpectedEnd, 17 k_ErrorType_UnexpectedEnd
18 k_ErrorType_Warning 18 // , k_ErrorType_Warning
19};
20
21
22struct CTempBuffer
23{
24 CByteBuffer Buffer;
25 size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize)
26 bool IsNonZeroTail;
27 bool StringSize_IsConfirmed;
28
29 void CopyToString(AString &s)
30 {
31 s.Empty();
32 if (StringSize != 0)
33 s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize);
34 }
35
36 void Init()
37 {
38 StringSize = 0;
39 IsNonZeroTail = false;
40 StringSize_IsConfirmed = false;
41 }
42};
43
44
45class CArchive
46{
47public:
48 bool _phySize_Defined;
49 bool _is_Warning;
50 bool PaxGlobal_Defined;
51 bool _is_PaxGlobal_Error;
52 bool _are_Pax_Items;
53 bool _are_Gnu;
54 bool _are_Posix;
55 bool _are_Pax;
56 bool _are_mtime;
57 bool _are_atime;
58 bool _are_ctime;
59 bool _are_pax_path;
60 bool _are_pax_link;
61 bool _are_LongName;
62 bool _are_LongLink;
63 bool _pathPrefix_WasUsed;
64 // bool _isSparse;
65
66 // temp internal vars for ReadItem():
67 bool filled;
68private:
69 EErrorType error;
70
71public:
72 UInt64 _phySize;
73 UInt64 _headersSize;
74 EErrorType _error;
75
76 ISequentialInStream *SeqStream;
77 IInStream *InStream;
78 IArchiveOpenCallback *OpenCallback;
79 UInt64 NumFiles;
80 UInt64 NumFiles_Prev;
81 UInt64 Pos_Prev;
82 // UInt64 NumRecords;
83 // UInt64 NumRecords_Prev;
84
85 CPaxExtra PaxGlobal;
86
87 void Clear()
88 {
89 SeqStream = NULL;
90 InStream = NULL;
91 OpenCallback = NULL;
92 NumFiles = 0;
93 NumFiles_Prev = 0;
94 Pos_Prev = 0;
95 // NumRecords = 0;
96 // NumRecords_Prev = 0;
97
98 PaxGlobal.Clear();
99 PaxGlobal_Defined = false;
100 _is_PaxGlobal_Error = false;
101 _are_Pax_Items = false; // if there are final paxItems
102 _are_Gnu = false;
103 _are_Posix = false;
104 _are_Pax = false;
105 _are_mtime = false;
106 _are_atime = false;
107 _are_ctime = false;
108 _are_pax_path = false;
109 _are_pax_link = false;
110 _are_LongName = false;
111 _are_LongLink = false;
112 _pathPrefix_WasUsed = false;
113 // _isSparse = false;
114
115 _is_Warning = false;
116 _error = k_ErrorType_OK;
117
118 _phySize_Defined = false;
119 _phySize = 0;
120 _headersSize = 0;
121 }
122
123private:
124 CTempBuffer NameBuf;
125 CTempBuffer LinkBuf;
126 CTempBuffer PaxBuf;
127 CTempBuffer PaxBuf_global;
128
129 CByteBuffer Buffer;
130
131 HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit);
132 HRESULT Progress(const CItemEx &item, UInt64 posOffset);
133 HRESULT GetNextItemReal(CItemEx &item);
134 HRESULT ReadItem2(CItemEx &itemInfo);
135public:
136 CArchive()
137 {
138 // we will call Clear() in CHandler::Close().
139 // Clear(); // it's not required here
140 }
141 HRESULT ReadItem(CItemEx &itemInfo);
19}; 142};
20 143
21HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
22 144
23API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size); 145API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
24 146
diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h
index f947786..738618f 100644
--- a/CPP/7zip/Archive/Tar/TarItem.h
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -6,8 +6,6 @@
6#include "../../../Common/MyLinux.h" 6#include "../../../Common/MyLinux.h"
7#include "../../../Common/UTFConvert.h" 7#include "../../../Common/UTFConvert.h"
8 8
9#include "../Common/ItemNameUtils.h"
10
11#include "TarHeader.h" 9#include "TarHeader.h"
12 10
13namespace NArchive { 11namespace NArchive {
@@ -19,50 +17,149 @@ struct CSparseBlock
19 UInt64 Size; 17 UInt64 Size;
20}; 18};
21 19
20
21enum EPaxTimeRemoveZeroMode
22{
23 k_PaxTimeMode_DontRemoveZero,
24 k_PaxTimeMode_RemoveZero_if_PureSecondOnly,
25 k_PaxTimeMode_RemoveZero_Always
26};
27
28struct CTimeOptions
29{
30 EPaxTimeRemoveZeroMode RemoveZeroMode;
31 unsigned NumDigitsMax;
32
33 void Init()
34 {
35 RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly;
36 NumDigitsMax = 0;
37 }
38 CTimeOptions() { Init(); }
39};
40
41
42struct CPaxTime
43{
44 Int32 NumDigits; // -1 means undefined
45 UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files.
46 Int64 Sec; // can be negative
47
48 Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; }
49
50 bool IsDefined() const { return NumDigits != -1; }
51 // bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); }
52
53 void Clear()
54 {
55 NumDigits = -1;
56 Ns = 0;
57 Sec = 0;
58 }
59 CPaxTime() { Clear(); }
60
61 /*
62 void ReducePrecison(int numDigits)
63 {
64 // we don't use this->NumDigits here
65 if (numDigits > 0)
66 {
67 if (numDigits >= 9)
68 return;
69 UInt32 r = 1;
70 for (unsigned i = numDigits; i < 9; i++)
71 r *= 10;
72 Ns /= r;
73 Ns *= r;
74 return;
75 }
76 Ns = 0;
77 if (numDigits == 0)
78 return;
79 UInt32 r;
80 if (numDigits == -1) r = 60;
81 else if (numDigits == -2) r = 60 * 60;
82 else if (numDigits == -3) r = 60 * 60 * 24;
83 else return;
84 Sec /= r;
85 Sec *= r;
86 }
87 */
88};
89
90
91struct CPaxTimes
92{
93 CPaxTime MTime;
94 CPaxTime ATime;
95 CPaxTime CTime;
96
97 void Clear()
98 {
99 MTime.Clear();
100 ATime.Clear();
101 CTime.Clear();
102 }
103
104 /*
105 void ReducePrecison(int numDigits)
106 {
107 MTime.ReducePrecison(numDigits);
108 CTime.ReducePrecison(numDigits);
109 ATime.ReducePrecison(numDigits);
110 }
111 */
112};
113
114
22struct CItem 115struct CItem
23{ 116{
24 AString Name;
25 UInt64 PackSize; 117 UInt64 PackSize;
26 UInt64 Size; 118 UInt64 Size;
27 Int64 MTime; 119 Int64 MTime;
28 120
121 char LinkFlag;
122 bool DeviceMajor_Defined;
123 bool DeviceMinor_Defined;
124
29 UInt32 Mode; 125 UInt32 Mode;
30 UInt32 UID; 126 UInt32 UID;
31 UInt32 GID; 127 UInt32 GID;
32 UInt32 DeviceMajor; 128 UInt32 DeviceMajor;
33 UInt32 DeviceMinor; 129 UInt32 DeviceMinor;
34 130
131 AString Name;
35 AString LinkName; 132 AString LinkName;
36 AString User; 133 AString User;
37 AString Group; 134 AString Group;
38 135
39 char Magic[8]; 136 char Magic[8];
40 char LinkFlag; 137
41 bool DeviceMajorDefined; 138 CPaxTimes PaxTimes;
42 bool DeviceMinorDefined;
43 139
44 CRecordVector<CSparseBlock> SparseBlocks; 140 CRecordVector<CSparseBlock> SparseBlocks;
45 141
46 void SetDefaultWriteFields() 142 void SetMagic_Posix(bool posixMode)
47 { 143 {
48 DeviceMajorDefined = false; 144 memcpy(Magic, posixMode ?
49 DeviceMinorDefined = false; 145 NFileHeader::NMagic::k_Posix_ustar_00 :
50 UID = 0; 146 NFileHeader::NMagic::k_GNU_ustar__,
51 GID = 0; 147 8);
52 memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 8);
53 } 148 }
54 149
55 bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } 150 bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
56 bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } 151 bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
57 bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } 152 bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
58 UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; } 153
59 bool IsPaxExtendedHeader() const 154 UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; }
155
156 bool Is_PaxExtendedHeader() const
60 { 157 {
61 switch (LinkFlag) 158 switch (LinkFlag)
62 { 159 {
63 case 'g': 160 case NFileHeader::NLinkFlag::kPax:
64 case 'x': 161 case NFileHeader::NLinkFlag::kPax_2:
65 case 'X': // Check it 162 case NFileHeader::NLinkFlag::kGlobal:
66 return true; 163 return true;
67 } 164 }
68 return false; 165 return false;
@@ -72,6 +169,17 @@ struct CItem
72 { 169 {
73 return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); 170 return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag();
74 } 171 }
172
173 void Set_LinkFlag_for_File(UInt32 mode)
174 {
175 Byte lf = NFileHeader::NLinkFlag::kNormal;
176 if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter;
177 else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock;
178 else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO;
179 // else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory;
180 // else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink;
181 LinkFlag = lf;
182 }
75 183
76 UInt32 Get_FileTypeMode_from_LinkFlag() const 184 UInt32 Get_FileTypeMode_from_LinkFlag() const
77 { 185 {
@@ -82,10 +190,10 @@ struct CItem
82 case NFileHeader::NLinkFlag::kDumpDir: 190 case NFileHeader::NLinkFlag::kDumpDir:
83 return MY_LIN_S_IFDIR; 191 return MY_LIN_S_IFDIR;
84 */ 192 */
85 case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; 193 case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
86 case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; 194 case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
87 case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; 195 case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
88 case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; 196 case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
89 // case return MY_LIN_S_IFSOCK; 197 // case return MY_LIN_S_IFSOCK;
90 } 198 }
91 199
@@ -104,20 +212,41 @@ struct CItem
104 case NFileHeader::NLinkFlag::kOldNormal: 212 case NFileHeader::NLinkFlag::kOldNormal:
105 case NFileHeader::NLinkFlag::kNormal: 213 case NFileHeader::NLinkFlag::kNormal:
106 case NFileHeader::NLinkFlag::kSymLink: 214 case NFileHeader::NLinkFlag::kSymLink:
107 return NItemName::HasTailSlash(Name, CP_OEMCP); 215 if (Name.IsEmpty())
216 return false;
217 // GNU TAR uses last character as directory marker
218 // we also do it
219 return Name.Back() == '/';
220 // return NItemName::HasTailSlash(Name, CP_OEMCP);
108 } 221 }
109 return false; 222 return false;
110 } 223 }
111 224
112 bool IsUstarMagic() const 225 bool IsMagic_ustar_5chars() const
226 {
227 for (unsigned i = 0; i < 5; i++)
228 if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
229 return false;
230 return true;
231 }
232
233 bool IsMagic_Posix_ustar_00() const
234 {
235 for (unsigned i = 0; i < 8; i++)
236 if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i])
237 return false;
238 return true;
239 }
240
241 bool IsMagic_GNU() const
113 { 242 {
114 for (int i = 0; i < 5; i++) 243 for (unsigned i = 0; i < 8; i++)
115 if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i]) 244 if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
116 return false; 245 return false;
117 return true; 246 return true;
118 } 247 }
119 248
120 UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } 249 UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
121 250
122 bool IsThereWarning() const 251 bool IsThereWarning() const
123 { 252 {
@@ -163,18 +292,67 @@ struct CEncodingCharacts
163}; 292};
164 293
165 294
295struct CPaxExtra
296{
297 AString RecordPath;
298 AString RawLines;
299
300 void Clear()
301 {
302 RecordPath.Empty();
303 RawLines.Empty();
304 }
305
306 void Print_To_String(AString &s) const
307 {
308 if (!RecordPath.IsEmpty())
309 {
310 s += RecordPath;
311 s.Add_LF();
312 }
313 if (!RawLines.IsEmpty())
314 s += RawLines;
315 }
316};
317
166 318
167struct CItemEx: public CItem 319struct CItemEx: public CItem
168{ 320{
321 bool HeaderError;
322
323 bool IsSignedChecksum;
324 bool Prefix_WasUsed;
325
326 bool Pax_Error;
327 bool Pax_Overflow;
328 bool pax_path_WasUsed;
329 bool pax_link_WasUsed;
330 bool pax_size_WasUsed;
331
332 bool MTime_IsBin;
333 bool PackSize_IsBin;
334 bool Size_IsBin;
335
336 bool LongName_WasUsed;
337 bool LongName_WasUsed_2;
338
339 bool LongLink_WasUsed;
340 bool LongLink_WasUsed_2;
341
342 // bool Name_CouldBeReduced;
343 // bool LinkName_CouldBeReduced;
344
169 UInt64 HeaderPos; 345 UInt64 HeaderPos;
170 unsigned HeaderSize; 346 UInt64 HeaderSize;
171 bool NameCouldBeReduced; 347
172 bool LinkNameCouldBeReduced; 348 UInt64 Num_Pax_Records;
349 CPaxExtra PaxExtra;
173 350
174 CEncodingCharacts EncodingCharacts; 351 CEncodingCharacts EncodingCharacts;
175 352
176 UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } 353 UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; }
177 UInt64 GetFullSize() const { return HeaderSize + PackSize; } 354 // UInt64 GetFullSize() const { return HeaderSize + PackSize; }
355 UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); }
178}; 356};
179 357
180}} 358}}
diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp
index 271b854..f73c625 100644
--- a/CPP/7zip/Archive/Tar/TarOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -2,6 +2,10 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#include "../../../../C/7zCrc.h"
6
7#include "../../../Common/IntToString.h"
8
5#include "../../Common/StreamUtils.h" 9#include "../../Common/StreamUtils.h"
6 10
7#include "TarOut.h" 11#include "TarOut.h"
@@ -9,23 +13,27 @@
9namespace NArchive { 13namespace NArchive {
10namespace NTar { 14namespace NTar {
11 15
12HRESULT COutArchive::WriteBytes(const void *data, unsigned size) 16using namespace NFileHeader;
13{ 17
14 Pos += size; 18// it's path prefix assigned by 7-Zip to show that file path was cut
15 return WriteStream(m_Stream, data, size); 19#define K_PREFIX_PATH_CUT "@PathCut"
16} 20
21static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1;
17 22
18static bool WriteOctal_8(char *s, UInt32 val) 23static void WriteOctal_8(char *s, UInt32 val)
19{ 24{
20 const unsigned kNumDigits = 8 - 1; 25 const unsigned kNumDigits = 8 - 1;
21 if (val >= ((UInt32)1 << (kNumDigits * 3))) 26 if (val >= ((UInt32)1 << (kNumDigits * 3)))
22 return false; 27 {
28 val = 0;
29 // return false;
30 }
23 for (unsigned i = 0; i < kNumDigits; i++) 31 for (unsigned i = 0; i < kNumDigits; i++)
24 { 32 {
25 s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); 33 s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
26 val >>= 3; 34 val >>= 3;
27 } 35 }
28 return true; 36 // return true;
29} 37}
30 38
31static void WriteBin_64bit(char *s, UInt64 val) 39static void WriteBin_64bit(char *s, UInt64 val)
@@ -68,61 +76,93 @@ static void CopyString(char *dest, const AString &src, unsigned maxSize)
68 unsigned len = src.Len(); 76 unsigned len = src.Len();
69 if (len == 0) 77 if (len == 0)
70 return; 78 return;
71 // 21.07: we don't require additional 0 character at the end 79 // 21.07: new gnu : we don't require additional 0 character at the end
80 // if (len >= maxSize)
72 if (len > maxSize) 81 if (len > maxSize)
73 { 82 {
74 len = maxSize; 83 len = maxSize;
75 // return false; 84 /*
85 // oldgnu needs 0 character at the end
86 len = maxSize - 1;
87 dest[len] = 0;
88 */
76 } 89 }
77 memcpy(dest, src.Ptr(), len); 90 memcpy(dest, src.Ptr(), len);
78 // return true;
79} 91}
80 92
81#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; } 93// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; }
94#define RETURN_IF_NOT_TRUE(x) { x; }
82 95
83#define COPY_STRING_CHECK(dest, src, size) \ 96#define COPY_STRING_CHECK(dest, src, size) \
84 CopyString(dest, src, size); dest += (size); 97 CopyString(dest, src, size); dest += (size);
85 98
86#define WRITE_OCTAL_8_CHECK(dest, src) \ 99#define WRITE_OCTAL_8_CHECK(dest, src) \
87 RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src)); 100 RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src))
88 101
89 102
90HRESULT COutArchive::WriteHeaderReal(const CItem &item) 103HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax
104 // , bool zero_PackSize
105 // , bool zero_MTime
106 )
91{ 107{
92 char record[NFileHeader::kRecordSize]; 108 /*
93 memset(record, 0, NFileHeader::kRecordSize); 109 if (isPax) { we don't use Glob_Name and Prefix }
110 if (!isPax)
111 {
112 we use Glob_Name if it's not empty
113 we use Prefix if it's not empty
114 }
115 */
116 char record[kRecordSize];
117 memset(record, 0, kRecordSize);
94 char *cur = record; 118 char *cur = record;
95 119
96 COPY_STRING_CHECK (cur, item.Name, NFileHeader::kNameSize); 120 COPY_STRING_CHECK (cur,
121 (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name,
122 kNameSize);
97 123
98 WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; 124 WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; // & k_7_oct_digits_Val_Max
99 WRITE_OCTAL_8_CHECK (cur, item.UID); cur += 8; 125 WRITE_OCTAL_8_CHECK (cur, item.UID); cur += 8;
100 WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8; 126 WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8;
101 127
102 WriteOctal_12(cur, item.PackSize); cur += 12; 128 WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12;
103 WriteOctal_12_Signed(cur, item.MTime); cur += 12; 129 WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12;
104 130
105 memset(cur, ' ', 8); // checksum field 131 // we will use binary init for checksum instead of memset
132 // checksum field:
133 // memset(cur, ' ', 8);
106 cur += 8; 134 cur += 8;
107 135
108 *cur++ = item.LinkFlag; 136 *cur++ = item.LinkFlag;
109 137
110 COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize); 138 COPY_STRING_CHECK (cur, item.LinkName, kNameSize);
111 139
112 memcpy(cur, item.Magic, 8); 140 memcpy(cur, item.Magic, 8);
113 cur += 8; 141 cur += 8;
114 142
115 COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize); 143 COPY_STRING_CHECK (cur, item.User, kUserNameSize);
116 COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize); 144 COPY_STRING_CHECK (cur, item.Group, kGroupNameSize);
117 145
118 if (item.DeviceMajorDefined) 146 const bool needDevice = (IsPosixMode && !isPax);
119 WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor); 147
148 if (item.DeviceMajor_Defined)
149 WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor)
150 else if (needDevice)
151 WRITE_OCTAL_8_CHECK (cur, 0)
120 cur += 8; 152 cur += 8;
121 if (item.DeviceMinorDefined) 153
122 WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor); 154 if (item.DeviceMinor_Defined)
155 WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
156 else if (needDevice)
157 WRITE_OCTAL_8_CHECK (cur, 0)
123 cur += 8; 158 cur += 8;
124 159
125 if (item.IsSparse()) 160 if (!isPax && !Prefix.IsEmpty())
161 {
162 COPY_STRING_CHECK (cur, Prefix, kPrefixSize);
163 }
164
165 if (item.Is_Sparse())
126 { 166 {
127 record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); 167 record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
128 WriteOctal_12(record + 483, item.Size); 168 WriteOctal_12(record + 483, item.Size);
@@ -136,31 +176,31 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
136 } 176 }
137 177
138 { 178 {
139 UInt32 checkSum = 0; 179 UInt32 sum = (unsigned)(' ') * 8; // we use binary init
140 { 180 {
141 for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) 181 for (unsigned i = 0; i < kRecordSize; i++)
142 checkSum += (Byte)record[i]; 182 sum += (Byte)record[i];
143 } 183 }
144 /* we use GNU TAR scheme: 184 /* checksum field is formatted differently from the
145 checksum field is formatted differently from the
146 other fields: it has [6] digits, a null, then a space. */ 185 other fields: it has [6] digits, a null, then a space. */
147 // WRITE_OCTAL_8_CHECK(record + 148, checkSum); 186 // WRITE_OCTAL_8_CHECK(record + 148, sum);
148 const unsigned kNumDigits = 6; 187 const unsigned kNumDigits = 6;
149 for (unsigned i = 0; i < kNumDigits; i++) 188 for (unsigned i = 0; i < kNumDigits; i++)
150 { 189 {
151 record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); 190 record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7));
152 checkSum >>= 3; 191 sum >>= 3;
153 } 192 }
154 record[148 + 6] = 0; 193 // record[148 + 6] = 0; // we need it, if we use memset(' ') init
194 record[148 + 7] = ' '; // we need it, if we use binary init
155 } 195 }
156 196
157 RINOK(WriteBytes(record, NFileHeader::kRecordSize)); 197 RINOK(Write_Data(record, kRecordSize));
158 198
159 if (item.IsSparse()) 199 if (item.Is_Sparse())
160 { 200 {
161 for (unsigned i = 4; i < item.SparseBlocks.Size();) 201 for (unsigned i = 4; i < item.SparseBlocks.Size();)
162 { 202 {
163 memset(record, 0, NFileHeader::kRecordSize); 203 memset(record, 0, kRecordSize);
164 for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++) 204 for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
165 { 205 {
166 const CSparseBlock &sb = item.SparseBlocks[i]; 206 const CSparseBlock &sb = item.SparseBlocks[i];
@@ -169,7 +209,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
169 WriteOctal_12(p + 12, sb.Size); 209 WriteOctal_12(p + 12, sb.Size);
170 } 210 }
171 record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); 211 record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
172 RINOK(WriteBytes(record, NFileHeader::kRecordSize)); 212 RINOK(Write_Data(record, kRecordSize));
173 } 213 }
174 } 214 }
175 215
@@ -177,101 +217,426 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
177} 217}
178 218
179 219
180/* OLD_GNU_TAR: writes short name with zero at the end 220static void AddPaxLine(AString &s, const char *name, const AString &val)
181 NEW_GNU_TAR: writes short name without zero at the end */ 221{
222 // s.Add_LF(); // for debug
223 const unsigned len = 3 + (unsigned)strlen(name) + val.Len();
224 AString n;
225 for (unsigned numDigits = 1;; numDigits++)
226 {
227 n.Empty();
228 n.Add_UInt32(numDigits + len);
229 if (numDigits == n.Len())
230 break;
231 }
232 s += n;
233 s.Add_Space();
234 s += name;
235 s += '=';
236 s += val;
237 s.Add_LF();
238}
239
240
241static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt,
242 const CTimeOptions &options)
243{
244 unsigned numDigits = pt.NumDigits;
245 if (numDigits > options.NumDigitsMax)
246 numDigits = options.NumDigitsMax;
247
248 bool needNs = false;
249 UInt32 ns = 0;
250 if (numDigits != 0)
251 {
252 ns = pt.Ns;
253 // if (ns != 0) before reduction, we show all digits after digits reduction
254 needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero);
255 UInt32 d = 1;
256 for (unsigned k = numDigits; k < 9; k++)
257 d *= 10;
258 ns /= d;
259 ns *= d;
260 }
261
262 AString v;
263 {
264 Int64 sec = pt.Sec;
265 if (pt.Sec < 0)
266 {
267 sec = -sec;
268 v += '-';
269 if (ns != 0)
270 {
271 ns = 1000*1000*1000 - ns;
272 sec--;
273 }
274 }
275 v.Add_UInt64(sec);
276 }
277
278 if (needNs)
279 {
280 AString d;
281 d.Add_UInt32(ns);
282 while (d.Len() < 9)
283 d.InsertAtFront('0');
284 // here we have precision
285 while (d.Len() > (unsigned)numDigits)
286 d.DeleteBack();
287 // GNU TAR reduces '0' digits.
288 if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always)
289 while (!d.IsEmpty() && d.Back() == '0')
290 d.DeleteBack();
291
292 if (!d.IsEmpty())
293 {
294 v += '.';
295 v += d;
296 // v += "1234567009999"; // for debug
297 // for (int y = 0; y < 1000; y++) v += '8'; // for debug
298 }
299 }
300
301 AddPaxLine(s, name, v);
302}
303
304
305static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v)
306{
307 if (v > k_7_oct_digits_Val_Max)
308 {
309 AString s2;
310 s2.Add_UInt32(v);
311 AddPaxLine(s, name, s2);
312 }
313}
314
315
316/* OLD_GNU_TAR: writes name with zero at the end
317 NEW_GNU_TAR: can write name filled with all kNameSize characters */
182 318
183static const unsigned kNameSize_Max = 319static const unsigned kNameSize_Max =
184 NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 320 kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
185 // NFileHeader::kNameSize - 1; // OLD_GNU_TAR / old 7-Zip 321 // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
186 322
187#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max) 323#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max)
188 324
325
189HRESULT COutArchive::WriteHeader(const CItem &item) 326HRESULT COutArchive::WriteHeader(const CItem &item)
190{ 327{
191 if (DOES_NAME_FIT_IN_FIELD(item.Name) && 328 Glob_Name.Empty();
192 DOES_NAME_FIT_IN_FIELD(item.LinkName)) 329 Prefix.Empty();
193 return WriteHeaderReal(item);
194 330
195 // here we can get all fields from main (item) or create new empty item 331 unsigned namePos = 0;
196 /* 332 bool needPathCut = false;
197 CItem mi; 333 bool allowPrefix = false;
198 mi.SetDefaultWriteFields(); 334
199 */ 335 if (!DOES_NAME_FIT_IN_FIELD(item.Name))
200 336 {
201 CItem mi = item; 337 const char *s = item.Name;
202 mi.LinkName.Empty(); 338 const char *p = s + item.Name.Len() - 1;
203 // SparseBlocks will be ignored by IsSparse() 339 for (; *p == '/' && p != s; p--)
204 // mi.SparseBlocks.Clear(); 340 {}
341 for (; p != s && p[-1] != '/'; p--)
342 {}
343 namePos = (unsigned)(p - s);
344 needPathCut = true;
345 }
205 346
206 mi.Name = NFileHeader::kLongLink; 347 if (IsPosixMode)
207 // 21.07 : we set Mode and MTime props as in GNU TAR: 348 {
208 mi.Mode = 0644; // octal 349 AString s;
209 mi.MTime = 0; 350
351 if (needPathCut)
352 {
353 const unsigned nameLen = item.Name.Len() - namePos;
354 if ( item.LinkFlag >= NLinkFlag::kNormal
355 && item.LinkFlag <= NLinkFlag::kDirectory
356 && namePos > 1
357 && nameLen != 0
358 // && IsPrefixAllowed
359 && item.IsMagic_Posix_ustar_00())
360 {
361 /* GNU TAR decoder supports prefix field, only if (magic)
362 signature matches 6-bytes "ustar\0".
363 so here we use prefix field only in posix mode with posix signature */
364
365 allowPrefix = true;
366 // allowPrefix = false; // for debug
367 if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max)
368 {
369 needPathCut = false;
370 /* we will set Prefix and Glob_Name later, for such conditions:
371 if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */
372 }
373 }
210 374
211 for (int i = 0; i < 2; i++) 375 if (needPathCut)
376 AddPaxLine(s, "path", item.Name);
377 }
378
379 // AddPaxLine(s, "testname", AString("testval")); // for debug
380
381 if (item.LinkName.Len() > kNameSize_Max)
382 AddPaxLine(s, "linkpath", item.LinkName);
383
384 const UInt64 kPaxSize_Limit = ((UInt64)1 << 33);
385 // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug
386 // bool zero_PackSize = false;
387 if (item.PackSize >= kPaxSize_Limit)
388 {
389 /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB
390 But old 7-Zip doesn't detect "size" property from pax header.
391 So we write real size (>= 8 GiB) to main record in binary format,
392 and old 7-Zip can decode size correctly */
393 // zero_PackSize = true;
394 AString v;
395 v.Add_UInt64(item.PackSize);
396 AddPaxLine(s, "size", v);
397 }
398
399 /* GNU TAR encoder can set "devmajor" / "devminor" attributes,
400 but GNU TAR decoder doesn't parse "devmajor" / "devminor" */
401 if (item.DeviceMajor_Defined)
402 AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor);
403 if (item.DeviceMinor_Defined)
404 AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor);
405
406 AddPax_UInt32_ifBig(s, "uid", item.UID);
407 AddPax_UInt32_ifBig(s, "gid", item.GID);
408
409 const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33);
410 const bool zero_MTime = (
411 item.MTime < 0 ||
412 item.MTime >= (Int64)kPax_MTime_Limit);
413
414 const CPaxTime &mtime = item.PaxTimes.MTime;
415 if (mtime.IsDefined())
416 {
417 bool needPax = false;
418 if (zero_MTime)
419 needPax = true;
420 else if (TimeOptions.NumDigitsMax > 0)
421 if (mtime.Ns != 0 ||
422 (mtime.NumDigits != 0 &&
423 TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero))
424 needPax = true;
425 if (needPax)
426 AddPaxTime(s, "mtime", mtime, TimeOptions);
427 }
428
429 if (item.PaxTimes.ATime.IsDefined())
430 AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions);
431 if (item.PaxTimes.CTime.IsDefined())
432 AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions);
433
434 if (item.User.Len() > kUserNameSize)
435 AddPaxLine(s, "uname", item.User);
436 if (item.Group.Len() > kGroupNameSize)
437 AddPaxLine(s, "gname", item.Group);
438
439 /*
440 // for debug
441 AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a);
442 */
443
444 const unsigned paxSize = s.Len();
445 if (paxSize != 0)
446 {
447 CItem mi = item;
448 mi.LinkName.Empty();
449 // SparseBlocks will be ignored by Is_Sparse()
450 // mi.SparseBlocks.Clear();
451 // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder
452
453 // GNU TAR writes empty for these fields;
454 mi.User.Empty();
455 mi.Group.Empty();
456 mi.UID = 0;
457 mi.GID = 0;
458
459 mi.DeviceMajor_Defined = false;
460 mi.DeviceMinor_Defined = false;
461
462 mi.Name = "PaxHeader/@PaxHeader";
463 mi.Mode = 0644; // octal
464 if (zero_MTime)
465 mi.MTime = 0;
466 mi.LinkFlag = NLinkFlag::kPax;
467 // mi.LinkFlag = 'Z'; // for debug
468 mi.PackSize = paxSize;
469 // for (unsigned y = 0; y < 1; y++) { // for debug
470 RINOK(WriteHeaderReal(mi, true)); // isPax
471 RINOK(Write_Data_And_Residual(s, paxSize));
472 // } // for debug
473 /*
474 we can send (zero_MTime) for compatibility with gnu tar output.
475 we can send (zero_MTime = false) for better compatibility with old 7-Zip
476 */
477 // return WriteHeaderReal(item);
478 /*
479 false, // isPax
480 false, // zero_PackSize
481 false); // zero_MTime
482 */
483 }
484 }
485 else // !PosixMode
486 if (!DOES_NAME_FIT_IN_FIELD(item.Name) ||
487 !DOES_NAME_FIT_IN_FIELD(item.LinkName))
212 { 488 {
213 const AString *name; 489 // here we can get all fields from main (item) or create new empty item
214 // We suppose that GNU TAR also writes item for long link before item for LongName? 490 /*
215 if (i == 0) 491 CItem mi;
492 mi.SetDefaultWriteFields();
493 */
494 CItem mi = item;
495 mi.LinkName.Empty();
496 // SparseBlocks will be ignored by Is_Sparse()
497 // mi.SparseBlocks.Clear();
498 mi.Name = kLongLink;
499 // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug
500 // 21.07 : we set Mode and MTime props as in GNU TAR:
501 mi.Mode = 0644; // octal
502 mi.MTime = 0;
503
504 mi.User.Empty();
505 mi.Group.Empty();
506 /*
507 gnu tar sets "root" for such items:
508 uid_to_uname (0, &uname);
509 gid_to_gname (0, &gname);
510 */
511 /*
512 mi.User = "root";
513 mi.Group = "root";
514 */
515 mi.UID = 0;
516 mi.GID = 0;
517 mi.DeviceMajor_Defined = false;
518 mi.DeviceMinor_Defined = false;
519
520
521 for (unsigned i = 0; i < 2; i++)
216 { 522 {
217 mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink; 523 const AString *name;
218 name = &item.LinkName; 524 // We suppose that GNU TAR also writes item for long link before item for LongName?
525 if (i == 0)
526 {
527 mi.LinkFlag = NLinkFlag::kGnu_LongLink;
528 name = &item.LinkName;
529 }
530 else
531 {
532 mi.LinkFlag = NLinkFlag::kGnu_LongName;
533 name = &item.Name;
534 }
535 if (DOES_NAME_FIT_IN_FIELD(*name))
536 continue;
537 // GNU TAR writes null character after NAME to file. We do same here:
538 const unsigned nameStreamSize = name->Len() + 1;
539 mi.PackSize = nameStreamSize;
540 // for (unsigned y = 0; y < 3; y++) { // for debug
541 RINOK(WriteHeaderReal(mi));
542 RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize));
543 // }
544
545 // for debug
546 /*
547 const unsigned kSize = (1 << 29) + 16;
548 CByteBuffer buf;
549 buf.Alloc(kSize);
550 memset(buf, 0, kSize);
551 memcpy(buf, name->Ptr(), name->Len());
552 const unsigned nameStreamSize = kSize;
553 mi.PackSize = nameStreamSize;
554 // for (unsigned y = 0; y < 3; y++) { // for debug
555 RINOK(WriteHeaderReal(mi));
556 RINOK(WriteBytes(buf, nameStreamSize));
557 RINOK(FillDataResidual(nameStreamSize));
558 */
219 } 559 }
560 }
561
562 // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR
563
564 if (!DOES_NAME_FIT_IN_FIELD(item.Name))
565 {
566 const unsigned nameLen = item.Name.Len() - namePos;
567 if (!needPathCut)
568 Prefix.SetFrom(item.Name, namePos - 1);
220 else 569 else
221 { 570 {
222 mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; 571 Glob_Name = K_PREFIX_PATH_CUT "/_pc_";
223 name = &item.Name; 572
573 if (namePos == 0)
574 Glob_Name += "root";
575 else
576 {
577 Glob_Name += "crc32/";
578 char temp[12];
579 ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp);
580 Glob_Name += temp;
581 }
582
583 if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max)
584 Glob_Name.Add_Slash();
585 else
586 {
587 Prefix = Glob_Name;
588 Glob_Name.Empty();
589 }
224 } 590 }
225 if (DOES_NAME_FIT_IN_FIELD(*name)) 591 Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen);
226 continue;
227 // GNU TAR writes null character after NAME to file. We do same here:
228 const unsigned nameStreamSize = name->Len() + 1;
229 mi.PackSize = nameStreamSize;
230 RINOK(WriteHeaderReal(mi));
231 RINOK(WriteBytes(name->Ptr(), nameStreamSize));
232 RINOK(FillDataResidual(nameStreamSize));
233 } 592 }
234 593
235 // 21.07: WriteHeaderReal() writes short part of (Name) and (LinkName).
236 return WriteHeaderReal(item); 594 return WriteHeaderReal(item);
237 /*
238 mi = item;
239 if (!DOES_NAME_FIT_IN_FIELD(mi.Name))
240 mi.Name.SetFrom(item.Name, kNameSize_Max);
241 if (!DOES_NAME_FIT_IN_FIELD(mi.LinkName))
242 mi.LinkName.SetFrom(item.LinkName, kNameSize_Max);
243 return WriteHeaderReal(mi);
244 */
245} 595}
246 596
247HRESULT COutArchive::FillDataResidual(UInt64 dataSize) 597
598HRESULT COutArchive::Write_Data(const void *data, unsigned size)
248{ 599{
249 unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1)); 600 Pos += size;
250 if (lastRecordSize == 0) 601 return WriteStream(Stream, data, size);
602}
603
604HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize)
605{
606 const unsigned v = ((unsigned)dataSize & (kRecordSize - 1));
607 if (v == 0)
251 return S_OK; 608 return S_OK;
252 unsigned rem = NFileHeader::kRecordSize - lastRecordSize; 609 const unsigned rem = kRecordSize - v;
253 Byte buf[NFileHeader::kRecordSize]; 610 Byte buf[kRecordSize];
254 memset(buf, 0, rem); 611 memset(buf, 0, rem);
255 return WriteBytes(buf, rem); 612 return Write_Data(buf, rem);
613}
614
615
616HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size)
617{
618 RINOK(Write_Data(data, size));
619 return Write_AfterDataResidual(size);
256} 620}
257 621
622
258HRESULT COutArchive::WriteFinishHeader() 623HRESULT COutArchive::WriteFinishHeader()
259{ 624{
260 Byte record[NFileHeader::kRecordSize]; 625 Byte record[kRecordSize];
261 memset(record, 0, NFileHeader::kRecordSize); 626 memset(record, 0, kRecordSize);
262 627
263 const unsigned kNumFinishRecords = 2; 628 const unsigned kNumFinishRecords = 2;
264 629
265 /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB) 630 /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB)
266 we also can use cluster alignment: 631 we also can use cluster alignment:
267 const unsigned numBlocks = (unsigned)(Pos / NFileHeader::kRecordSize) + kNumFinishRecords; 632 const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords;
268 const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB 633 const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB
269 const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1)); 634 const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1));
270 */ 635 */
271 636
272 for (unsigned i = 0; i < kNumFinishRecords; i++) 637 for (unsigned i = 0; i < kNumFinishRecords; i++)
273 { 638 {
274 RINOK(WriteBytes(record, NFileHeader::kRecordSize)); 639 RINOK(Write_Data(record, kRecordSize));
275 } 640 }
276 return S_OK; 641 return S_OK;
277} 642}
diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h
index ee9b965..34af20a 100644
--- a/CPP/7zip/Archive/Tar/TarOut.h
+++ b/CPP/7zip/Archive/Tar/TarOut.h
@@ -14,21 +14,38 @@ namespace NTar {
14 14
15class COutArchive 15class COutArchive
16{ 16{
17 CMyComPtr<ISequentialOutStream> m_Stream; 17 CMyComPtr<ISequentialOutStream> Stream;
18
19 AString Glob_Name;
20 AString Prefix;
21
22 HRESULT WriteHeaderReal(const CItem &item, bool isPax = false
23 // , bool zero_PackSize = false
24 // , bool zero_MTime = false
25 );
26
27 HRESULT Write_Data(const void *data, unsigned size);
28 HRESULT Write_Data_And_Residual(const void *data, unsigned size);
18 29
19 HRESULT WriteBytes(const void *data, unsigned size);
20 HRESULT WriteHeaderReal(const CItem &item);
21public: 30public:
22 UInt64 Pos; 31 UInt64 Pos;
23 32 bool IsPosixMode;
33 // bool IsPrefixAllowed; // it's used only if (IsPosixMode == true)
34 CTimeOptions TimeOptions;
35
24 void Create(ISequentialOutStream *outStream) 36 void Create(ISequentialOutStream *outStream)
25 { 37 {
26 m_Stream = outStream; 38 Stream = outStream;
27 } 39 }
28
29 HRESULT WriteHeader(const CItem &item); 40 HRESULT WriteHeader(const CItem &item);
30 HRESULT FillDataResidual(UInt64 dataSize); 41 HRESULT Write_AfterDataResidual(UInt64 dataSize);
31 HRESULT WriteFinishHeader(); 42 HRESULT WriteFinishHeader();
43
44 COutArchive():
45 Pos(0),
46 IsPosixMode(false)
47 // , IsPrefixAllowed(true)
48 {}
32}; 49};
33 50
34}} 51}}
diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp
index 5014f04..a78c376 100644
--- a/CPP/7zip/Archive/Tar/TarRegister.cpp
+++ b/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -15,9 +15,17 @@ REGISTER_ARC_IO(
15 "tar", "tar ova", 0, 0xEE, 15 "tar", "tar ova", 0, 0xEE,
16 k_Signature, 16 k_Signature,
17 NFileHeader::kUstarMagic_Offset, 17 NFileHeader::kUstarMagic_Offset,
18 NArcInfoFlags::kStartOpen | 18 NArcInfoFlags::kStartOpen
19 NArcInfoFlags::kSymLinks | 19 | NArcInfoFlags::kSymLinks
20 NArcInfoFlags::kHardLinks, 20 | NArcInfoFlags::kHardLinks
21 IsArc_Tar) 21 | NArcInfoFlags::kMTime
22 | NArcInfoFlags::kMTime_Default
23 // | NArcInfoTimeFlags::kCTime
24 // | NArcInfoTimeFlags::kATime
25 , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
26 | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
27 | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns)
28 | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
29 , IsArc_Tar)
22 30
23}} 31}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp
index 295e16b..caa0a82 100644
--- a/CPP/7zip/Archive/Tar/TarUpdate.cpp
+++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -2,6 +2,8 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5// #include <stdio.h>
6
5#include "../../../Windows/TimeUtils.h" 7#include "../../../Windows/TimeUtils.h"
6 8
7#include "../../Common/LimitedStreams.h" 9#include "../../Common/LimitedStreams.h"
@@ -15,18 +17,161 @@
15namespace NArchive { 17namespace NArchive {
16namespace NTar { 18namespace NTar {
17 19
20static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt)
21{
22 UInt32 ns;
23 pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns);
24 pt.Ns = ns * 100;
25 pt.NumDigits = 7;
26}
27
28
29HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt)
30{
31 pt.Clear();
32 if (prop.vt == VT_EMPTY)
33 {
34 // pt.Sec = 0;
35 return S_OK;
36 }
37 if (prop.vt != VT_FILETIME)
38 return E_INVALIDARG;
39 {
40 UInt32 ns;
41 pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns);
42 ns *= 100;
43 pt.NumDigits = 7;
44 const unsigned prec = prop.wReserved1;
45 if (prec >= k_PropVar_TimePrec_Base)
46 {
47 pt.NumDigits = prec - k_PropVar_TimePrec_Base;
48 if (prop.wReserved2 < 100)
49 ns += prop.wReserved2;
50 }
51 pt.Ns = ns;
52 return S_OK;
53 }
54}
55
56
57static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt)
58{
59 pt.Clear();
60 NWindows::NCOM::CPropVariant prop;
61 RINOK(getProp->GetProperty(pid, &prop));
62 return Prop_To_PaxTime(prop, pt);
63}
64
65
66static HRESULT GetUser(IStreamGetProp *getProp,
67 UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
68 UINT codePage, unsigned utfFlags)
69{
70 // printf("\nGetUser\n");
71 // we keep old values, if both GetProperty() return VT_EMPTY
72 // we clear old values, if any of GetProperty() returns non-VT_EMPTY;
73 bool isSet = false;
74 {
75 NWindows::NCOM::CPropVariant prop;
76 RINOK(getProp->GetProperty(pidId, &prop));
77 if (prop.vt == VT_UI4)
78 {
79 isSet = true;
80 id = prop.ulVal;
81 name.Empty();
82 }
83 else if (prop.vt != VT_EMPTY)
84 return E_INVALIDARG;
85 }
86 {
87 NWindows::NCOM::CPropVariant prop;
88 RINOK(getProp->GetProperty(pidName, &prop));
89 if (prop.vt == VT_BSTR)
90 {
91 const UString s = prop.bstrVal;
92 Get_AString_From_UString(s, name, codePage, utfFlags);
93 // printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr());
94 if (!isSet)
95 id = 0;
96 }
97 else if (prop.vt == VT_UI4)
98 {
99 id = prop.ulVal;
100 name.Empty();
101 }
102 else if (prop.vt != VT_EMPTY)
103 return E_INVALIDARG;
104 }
105 return S_OK;
106}
107
108
109/*
110static HRESULT GetDevice(IStreamGetProp *getProp,
111 UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
112{
113 NWindows::NCOM::CPropVariant prop;
114 RINOK(getProp->GetProperty(kpidDevice, &prop));
115 if (prop.vt == VT_EMPTY)
116 return S_OK;
117 if (prop.vt != VT_UI8)
118 return E_INVALIDARG;
119 {
120 printf("\nTarUpdate.cpp :: GetDevice()\n");
121 const UInt64 v = prop.uhVal.QuadPart;
122 majo = MY_dev_major(v);
123 mino = MY_dev_minor(v);
124 majo_defined = true;
125 mino_defined = true;
126 }
127 return S_OK;
128}
129*/
130
131static HRESULT GetDevice(IStreamGetProp *getProp,
132 UInt32 pid, UInt32 &id, bool &defined)
133{
134 defined = false;
135 NWindows::NCOM::CPropVariant prop;
136 RINOK(getProp->GetProperty(pid, &prop));
137 if (prop.vt == VT_EMPTY)
138 return S_OK;
139 if (prop.vt == VT_UI4)
140 {
141 id = prop.ulVal;
142 defined = true;
143 return S_OK;
144 }
145 return E_INVALIDARG;
146}
147
148
18HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, 149HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
19 const CObjectVector<NArchive::NTar::CItemEx> &inputItems, 150 const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
20 const CObjectVector<CUpdateItem> &updateItems, 151 const CObjectVector<CUpdateItem> &updateItems,
21 UINT codePage, unsigned utfFlags, 152 const CUpdateOptions &options,
22 IArchiveUpdateCallback *updateCallback) 153 IArchiveUpdateCallback *updateCallback)
23{ 154{
24 COutArchive outArchive; 155 COutArchive outArchive;
25 outArchive.Create(outStream); 156 outArchive.Create(outStream);
26 outArchive.Pos = 0; 157 outArchive.Pos = 0;
158 outArchive.IsPosixMode = options.PosixMode;
159 outArchive.TimeOptions = options.TimeOptions;
27 160
28 CMyComPtr<IOutStream> outSeekStream; 161 CMyComPtr<IOutStream> outSeekStream;
29 outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); 162 outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
163 if (outSeekStream)
164 {
165 /*
166 // for debug
167 Byte buf[1 << 14];
168 memset (buf, 0, sizeof(buf));
169 RINOK(outStream->Write(buf, sizeof(buf), NULL));
170 */
171 // we need real outArchive.Pos, if outSeekStream->SetSize() will be used.
172 RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos));
173 }
174
30 175
31 CMyComPtr<IArchiveUpdateCallbackFile> opCallback; 176 CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
32 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); 177 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
@@ -40,7 +185,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
40 if (ui.NewData) 185 if (ui.NewData)
41 complexity += ui.Size; 186 complexity += ui.Size;
42 else 187 else
43 complexity += inputItems[(unsigned)ui.IndexInArc].GetFullSize(); 188 complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned();
44 } 189 }
45 190
46 RINOK(updateCallback->SetTotal(complexity)); 191 RINOK(updateCallback->SetTotal(complexity));
@@ -58,21 +203,31 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
58 203
59 complexity = 0; 204 complexity = 0;
60 205
61 for (i = 0; i < updateItems.Size(); i++) 206 // const int kNumReduceDigits = -1; // for debug
207
208 for (i = 0;; i++)
62 { 209 {
63 lps->InSize = lps->OutSize = complexity; 210 lps->InSize = lps->OutSize = complexity;
64 RINOK(lps->SetCur()); 211 RINOK(lps->SetCur());
65 212
213 if (i == updateItems.Size())
214 return outArchive.WriteFinishHeader();
215
66 const CUpdateItem &ui = updateItems[i]; 216 const CUpdateItem &ui = updateItems[i];
67 CItem item; 217 CItem item;
68 218
69 if (ui.NewProps) 219 if (ui.NewProps)
70 { 220 {
71 item.SetDefaultWriteFields(); 221 item.SetMagic_Posix(options.PosixMode);
72 item.Mode = ui.Mode;
73 item.Name = ui.Name; 222 item.Name = ui.Name;
74 item.User = ui.User; 223 item.User = ui.User;
75 item.Group = ui.Group; 224 item.Group = ui.Group;
225 item.UID = ui.UID;
226 item.GID = ui.GID;
227 item.DeviceMajor = ui.DeviceMajor;
228 item.DeviceMinor = ui.DeviceMinor;
229 item.DeviceMajor_Defined = ui.DeviceMajor_Defined;
230 item.DeviceMinor_Defined = ui.DeviceMinor_Defined;
76 231
77 if (ui.IsDir) 232 if (ui.IsDir)
78 { 233 {
@@ -81,11 +236,15 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
81 } 236 }
82 else 237 else
83 { 238 {
84 item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
85 item.PackSize = ui.Size; 239 item.PackSize = ui.Size;
240 item.Set_LinkFlag_for_File(ui.Mode);
86 } 241 }
87 242
88 item.MTime = ui.MTime; 243 // 22.00
244 item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT;
245 item.PaxTimes = ui.PaxTimes;
246 // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
247 item.MTime = ui.PaxTimes.MTime.GetSec();
89 } 248 }
90 else 249 else
91 item = inputItems[(unsigned)ui.IndexInArc]; 250 item = inputItems[(unsigned)ui.IndexInArc];
@@ -93,7 +252,8 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
93 AString symLink; 252 AString symLink;
94 if (ui.NewData || ui.NewProps) 253 if (ui.NewData || ui.NewProps)
95 { 254 {
96 RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, utfFlags, true)); 255 RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink,
256 options.CodePage, options.UtfFlags, true));
97 if (!symLink.IsEmpty()) 257 if (!symLink.IsEmpty())
98 { 258 {
99 item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; 259 item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
@@ -120,7 +280,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
120 } 280 }
121 else 281 else
122 { 282 {
123 HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); 283 const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
124 284
125 if (res == S_FALSE) 285 if (res == S_FALSE)
126 needWrite = false; 286 needWrite = false;
@@ -128,31 +288,105 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
128 { 288 {
129 RINOK(res); 289 RINOK(res);
130 290
131 if (fileInStream) 291 if (!fileInStream)
292 {
293 item.PackSize = 0;
294 item.Size = 0;
295 }
296 else
132 { 297 {
133 CMyComPtr<IStreamGetProps> getProps; 298 CMyComPtr<IStreamGetProps> getProps;
134 fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); 299 CMyComPtr<IStreamGetProp> getProp;
135 if (getProps) 300 fileInStream->QueryInterface(IID_IStreamGetProp, (void **)&getProp);
301 if (getProp)
302 {
303 if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime))
304 if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime))
305 if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime))
306
307 if (options.PosixMode)
308 {
309 /*
310 RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor,
311 item.DeviceMajor_Defined, item.DeviceMinor_Defined));
312 */
313 bool defined = false;
314 UInt32 val = 0;
315 RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined));
316 if (defined)
317 {
318 item.DeviceMajor = val;
319 item.DeviceMajor_Defined = true;
320 item.DeviceMinor = 0;
321 item.DeviceMinor_Defined = false;
322 RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined));
323 }
324 }
325
326 RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags));
327 RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags));
328
329 {
330 NWindows::NCOM::CPropVariant prop;
331 RINOK(getProp->GetProperty(kpidPosixAttrib, &prop));
332 if (prop.vt == VT_EMPTY)
333 item.Mode =
334 MY_LIN_S_IRWXO
335 | MY_LIN_S_IRWXG
336 | MY_LIN_S_IRWXU
337 | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
338 else if (prop.vt != VT_UI4)
339 return E_INVALIDARG;
340 else
341 item.Mode = prop.ulVal;
342 // 21.07 : we clear high file type bits as GNU TAR.
343 item.Set_LinkFlag_for_File(item.Mode);
344 item.Mode &= ~(UInt32)MY_LIN_S_IFMT;
345 }
346
347 {
348 NWindows::NCOM::CPropVariant prop;
349 RINOK(getProp->GetProperty(kpidSize, &prop));
350 if (prop.vt != VT_UI8)
351 return E_INVALIDARG;
352 const UInt64 size = prop.uhVal.QuadPart;
353 item.PackSize = size;
354 item.Size = size;
355 }
356 /*
357 printf("\nNum digits = %d %d\n",
358 (int)item.PaxTimes.MTime.NumDigits,
359 (int)item.PaxTimes.MTime.Ns);
360 */
361 }
362 else
136 { 363 {
137 FILETIME mTime; 364 fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
138 UInt64 size2; 365 if (getProps)
139 if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
140 { 366 {
141 item.PackSize = size2; 367 FILETIME mTime, aTime, cTime;
142 item.Size = size2; 368 UInt64 size2;
143 item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; 369 if (getProps->GetProps(&size2,
370 options.Write_CTime.Val ? &cTime : NULL,
371 options.Write_ATime.Val ? &aTime : NULL,
372 options.Write_MTime.Val ? &mTime : NULL,
373 NULL) == S_OK)
374 {
375 item.PackSize = size2;
376 item.Size = size2;
377 if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime);
378 if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime);
379 if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime);
380 }
144 } 381 }
145 } 382 }
146 } 383 }
147 else
148 {
149 item.PackSize = 0;
150 item.Size = 0;
151 }
152 384
153 { 385 {
386 // we must request kpidHardLink after updateCallback->GetStream()
154 AString hardLink; 387 AString hardLink;
155 RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, utfFlags, true)); 388 RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink,
389 options.CodePage, options.UtfFlags, true));
156 if (!hardLink.IsEmpty()) 390 if (!hardLink.IsEmpty())
157 { 391 {
158 item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; 392 item.LinkFlag = NFileHeader::NLinkFlag::kHardLink;
@@ -165,37 +399,98 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
165 } 399 }
166 } 400 }
167 401
402 // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
403
404 if (ui.NewProps)
405 item.MTime = item.PaxTimes.MTime.GetSec();
406
168 if (needWrite) 407 if (needWrite)
169 { 408 {
170 UInt64 fileHeaderStartPos = outArchive.Pos; 409 const UInt64 headerPos = outArchive.Pos;
410 // item.PackSize = ((UInt64)1 << 33); // for debug
171 RINOK(outArchive.WriteHeader(item)); 411 RINOK(outArchive.WriteHeader(item));
172 if (fileInStream) 412 if (fileInStream)
173 { 413 {
174 RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); 414 for (unsigned numPasses = 0;; numPasses++)
175 outArchive.Pos += copyCoderSpec->TotalSize;
176 if (copyCoderSpec->TotalSize != item.PackSize)
177 { 415 {
416 /* we support 2 attempts to write header:
417 pass-0: main pass:
418 pass-1: additional pass, if size_of_file and size_of_header are changed */
419 if (numPasses >= 2)
420 {
421 // opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged;
422 // break;
423 return E_FAIL;
424 }
425
426 const UInt64 dataPos = outArchive.Pos;
427 RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
428 outArchive.Pos += copyCoderSpec->TotalSize;
429 RINOK(outArchive.Write_AfterDataResidual(copyCoderSpec->TotalSize));
430
431 // if (numPasses >= 10) // for debug
432 if (copyCoderSpec->TotalSize == item.PackSize)
433 break;
434
435 if (opCallback)
436 {
437 RINOK(opCallback->ReportOperation(
438 NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient,
439 NUpdateNotifyOp::kInFileChanged))
440 }
441
178 if (!outSeekStream) 442 if (!outSeekStream)
179 return E_FAIL; 443 return E_FAIL;
180 UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; 444 const UInt64 nextPos = outArchive.Pos;
181 RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); 445 RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL));
182 outArchive.Pos = fileHeaderStartPos; 446 outArchive.Pos = headerPos;
183 item.PackSize = copyCoderSpec->TotalSize; 447 item.PackSize = copyCoderSpec->TotalSize;
448
184 RINOK(outArchive.WriteHeader(item)); 449 RINOK(outArchive.WriteHeader(item));
185 RINOK(outSeekStream->Seek((Int64)item.PackSize, STREAM_SEEK_CUR, NULL)); 450
186 outArchive.Pos += item.PackSize; 451 // if (numPasses >= 10) // for debug
452 if (outArchive.Pos == dataPos)
453 {
454 const UInt64 alignedSize = nextPos - dataPos;
455 if (alignedSize != 0)
456 {
457 RINOK(outSeekStream->Seek(alignedSize, STREAM_SEEK_CUR, NULL));
458 outArchive.Pos += alignedSize;
459 }
460 break;
461 }
462
463 // size of header was changed.
464 // we remove data after header and try new attempt, if required
465 CMyComPtr<IInStream> fileSeekStream;
466 fileInStream->QueryInterface(IID_IInStream, (void **)&fileSeekStream);
467 if (!fileSeekStream)
468 return E_FAIL;
469 RINOK(fileSeekStream->Seek(0, STREAM_SEEK_SET, NULL));
470 RINOK(outSeekStream->SetSize(outArchive.Pos));
471 if (item.PackSize == 0)
472 break;
187 } 473 }
188 RINOK(outArchive.FillDataResidual(item.PackSize));
189 } 474 }
190 } 475 }
191 476
192 complexity += item.PackSize; 477 complexity += item.PackSize;
478 fileInStream.Release();
193 RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); 479 RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
194 } 480 }
195 else 481 else
196 { 482 {
483 // (ui.NewData == false)
484
485 if (opCallback)
486 {
487 RINOK(opCallback->ReportOperation(
488 NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
489 NUpdateNotifyOp::kReplicate))
490 }
491
197 const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc]; 492 const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc];
198 UInt64 size; 493 UInt64 size, pos;
199 494
200 if (ui.NewProps) 495 if (ui.NewProps)
201 { 496 {
@@ -216,44 +511,37 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
216 item.PackSize = existItem.PackSize; 511 item.PackSize = existItem.PackSize;
217 } 512 }
218 513
219 item.DeviceMajorDefined = existItem.DeviceMajorDefined; 514 item.DeviceMajor_Defined = existItem.DeviceMajor_Defined;
220 item.DeviceMinorDefined = existItem.DeviceMinorDefined; 515 item.DeviceMinor_Defined = existItem.DeviceMinor_Defined;
221 item.DeviceMajor = existItem.DeviceMajor; 516 item.DeviceMajor = existItem.DeviceMajor;
222 item.DeviceMinor = existItem.DeviceMinor; 517 item.DeviceMinor = existItem.DeviceMinor;
223 item.UID = existItem.UID; 518 item.UID = existItem.UID;
224 item.GID = existItem.GID; 519 item.GID = existItem.GID;
225 520
226 RINOK(outArchive.WriteHeader(item)); 521 RINOK(outArchive.WriteHeader(item));
227 RINOK(inStream->Seek((Int64)existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); 522 size = existItem.Get_PackSize_Aligned();
228 size = existItem.PackSize; 523 pos = existItem.Get_DataPos();
229 } 524 }
230 else 525 else
231 { 526 {
232 RINOK(inStream->Seek((Int64)existItem.HeaderPos, STREAM_SEEK_SET, NULL)); 527 size = existItem.Get_FullSize_Aligned();
233 size = existItem.GetFullSize(); 528 pos = existItem.HeaderPos;
234 } 529 }
235
236 streamSpec->Init(size);
237 530
238 if (opCallback) 531 if (size != 0)
239 { 532 {
240 RINOK(opCallback->ReportOperation( 533 RINOK(inStream->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
241 NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, 534 streamSpec->Init(size);
242 NUpdateNotifyOp::kReplicate)) 535 // 22.00 : we copy Residual data from old archive to new archive instead of zeroing
536 RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
537 if (copyCoderSpec->TotalSize != size)
538 return E_FAIL;
539 outArchive.Pos += size;
540 // RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize));
541 complexity += size;
243 } 542 }
244
245 RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
246 if (copyCoderSpec->TotalSize != size)
247 return E_FAIL;
248 outArchive.Pos += size;
249 RINOK(outArchive.FillDataResidual(existItem.PackSize));
250 complexity += size;
251 } 543 }
252 } 544 }
253
254 lps->InSize = lps->OutSize = complexity;
255 RINOK(lps->SetCur());
256 return outArchive.WriteFinishHeader();
257} 545}
258 546
259}} 547}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h
index 1e3d021..ca0976d 100644
--- a/CPP/7zip/Archive/Tar/TarUpdate.h
+++ b/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -15,27 +15,60 @@ struct CUpdateItem
15 int IndexInArc; 15 int IndexInArc;
16 unsigned IndexInClient; 16 unsigned IndexInClient;
17 UInt64 Size; 17 UInt64 Size;
18 Int64 MTime; 18 // Int64 MTime;
19 UInt32 Mode; 19 UInt32 Mode;
20 bool NewData; 20 bool NewData;
21 bool NewProps; 21 bool NewProps;
22 bool IsDir; 22 bool IsDir;
23 bool DeviceMajor_Defined;
24 bool DeviceMinor_Defined;
25 UInt32 UID;
26 UInt32 GID;
27 UInt32 DeviceMajor;
28 UInt32 DeviceMinor;
23 AString Name; 29 AString Name;
24 AString User; 30 AString User;
25 AString Group; 31 AString Group;
26 32
27 CUpdateItem(): Size(0), IsDir(false) {} 33 CPaxTimes PaxTimes;
34
35 CUpdateItem():
36 Size(0),
37 IsDir(false),
38 DeviceMajor_Defined(false),
39 DeviceMinor_Defined(false),
40 UID(0),
41 GID(0)
42 {}
43};
44
45
46struct CUpdateOptions
47{
48 UINT CodePage;
49 unsigned UtfFlags;
50 bool PosixMode;
51 CBoolPair Write_MTime;
52 CBoolPair Write_ATime;
53 CBoolPair Write_CTime;
54 CTimeOptions TimeOptions;
28}; 55};
29 56
57
30HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, 58HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
31 const CObjectVector<CItemEx> &inputItems, 59 const CObjectVector<CItemEx> &inputItems,
32 const CObjectVector<CUpdateItem> &updateItems, 60 const CObjectVector<CUpdateItem> &updateItems,
33 UINT codePage, unsigned utfFlags, 61 const CUpdateOptions &options,
34 IArchiveUpdateCallback *updateCallback); 62 IArchiveUpdateCallback *updateCallback);
35 63
36HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, 64HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
37 UINT codePage, unsigned utfFlags, bool convertSlash); 65 UINT codePage, unsigned utfFlags, bool convertSlash);
38 66
67HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt);
68
69void Get_AString_From_UString(const UString &s, AString &res,
70 UINT codePage, unsigned utfFlags);
71
39}} 72}}
40 73
41#endif 74#endif
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
index 74ec0be..2232c64 100644
--- 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
27 return; 27 return;
28 if (t.IsLocal()) 28 if (t.IsLocal())
29 numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60); 29 numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60);
30 FILETIME ft; 30 const UInt32 m0 = d[9];
31 UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10; 31 const UInt32 m1 = d[10];
32 ft.dwLowDateTime = (UInt32)v; 32 const UInt32 m2 = d[11];
33 ft.dwHighDateTime = (UInt32)(v >> 32); 33 unsigned numDigits = 0;
34 prop = ft; 34 UInt64 v = numSecs * 10000000;
35 if (m0 < 100 && m1 < 100 && m2 < 100)
36 {
37 v += m0 * 100000 + m1 * 1000 + m2 * 10;
38 numDigits = 6;
39 }
40 prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits);
35} 41}
36 42
37static const Byte kProps[] = 43static const Byte kProps[] =
@@ -41,7 +47,8 @@ static const Byte kProps[] =
41 kpidSize, 47 kpidSize,
42 kpidPackSize, 48 kpidPackSize,
43 kpidMTime, 49 kpidMTime,
44 kpidATime 50 kpidATime,
51 kpidChangeTime
45}; 52};
46 53
47static const Byte kArcProps[] = 54static const Byte kArcProps[] =
@@ -205,6 +212,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
205 case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; 212 case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
206 case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; 213 case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
207 case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; 214 case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
215 case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
208 } 216 }
209 } 217 }
210 prop.Detach(value); 218 prop.Detach(value);
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index 04d9228..d2d2b20 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -333,7 +333,7 @@ void CItem::Parse(const Byte *p)
333 NumLogBlockRecorded = Get64(p + 64); 333 NumLogBlockRecorded = Get64(p + 64);
334 ATime.Parse(p + 72); 334 ATime.Parse(p + 72);
335 MTime.Parse(p + 84); 335 MTime.Parse(p + 84);
336 // AttrtTime.Parse(p + 96); 336 AttribTime.Parse(p + 96);
337 // CheckPoint = Get32(p + 108); 337 // CheckPoint = Get32(p + 108);
338 // ExtendedAttrIcb.Parse(p + 112); 338 // ExtendedAttrIcb.Parse(p + 112);
339 // ImplId.Parse(p + 128); 339 // ImplId.Parse(p + 128);
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
index c26f609..4e7dfa1 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.h
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -243,7 +243,7 @@ struct CItem
243 UInt64 NumLogBlockRecorded; 243 UInt64 NumLogBlockRecorded;
244 CTime ATime; 244 CTime ATime;
245 CTime MTime; 245 CTime MTime;
246 // CTime AttrtTime; 246 CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of.
247 // UInt32 CheckPoint; 247 // UInt32 CheckPoint;
248 // CLongAllocDesc ExtendedAttrIcb; 248 // CLongAllocDesc ExtendedAttrIcb;
249 // CRegId ImplId; 249 // CRegId ImplId;
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
index 8b9af45..60bc3d3 100644
--- a/CPP/7zip/Archive/VhdHandler.cpp
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -921,7 +921,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
921 CLimitedInStream *streamSpec = new CLimitedInStream; 921 CLimitedInStream *streamSpec = new CLimitedInStream;
922 CMyComPtr<ISequentialInStream> streamTemp = streamSpec; 922 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
923 streamSpec->SetStream(Stream); 923 streamSpec->SetStream(Stream);
924 streamSpec->InitAndSeek(0, Footer.CurrentSize); 924 // fixme : check (startOffset = 0)
925 streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize);
925 RINOK(streamSpec->SeekToStart()); 926 RINOK(streamSpec->SeekToStart());
926 *stream = streamTemp.Detach(); 927 *stream = streamTemp.Detach();
927 return S_OK; 928 return S_OK;
diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp
index e1e4692..0fc83ac 100644
--- a/CPP/7zip/Archive/VhdxHandler.cpp
+++ b/CPP/7zip/Archive/VhdxHandler.cpp
@@ -171,6 +171,20 @@ struct CHeader
171 UInt64 LogOffset; 171 UInt64 LogOffset;
172 CGuid Guids[3]; 172 CGuid Guids[3];
173 173
174 bool IsEqualTo(const CHeader &h) const
175 {
176 if (SequenceNumber != h.SequenceNumber)
177 return false;
178 if (LogLength != h.LogLength)
179 return false;
180 if (LogOffset != h.LogOffset)
181 return false;
182 for (unsigned i = 0; i < 3; i++)
183 if (!Guids[i].IsEqualTo(h.Guids[i]))
184 return false;
185 return true;
186 };
187
174 bool Parse(Byte *p); 188 bool Parse(Byte *p);
175}; 189};
176 190
@@ -1174,7 +1188,18 @@ HRESULT CHandler::Open3()
1174 unsigned mainIndex; 1188 unsigned mainIndex;
1175 if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0; 1189 if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
1176 else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1; 1190 else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1;
1177 else return S_FALSE; 1191 else
1192 {
1193 /* Disk2vhd v2.02 can create image with 2 full copies of headers.
1194 It's violation of VHDX specification:
1195 "A header is current if it is the only valid header
1196 or if it is valid and its SequenceNumber field is
1197 greater than the other header's SequenceNumber".
1198 but we support such Disk2vhd archives. */
1199 if (!headers[0].IsEqualTo(headers[1]))
1200 return S_FALSE;
1201 mainIndex = 0;
1202 }
1178 1203
1179 const CHeader &h = headers[mainIndex]; 1204 const CHeader &h = headers[mainIndex];
1180 Header = h; 1205 Header = h;
@@ -1567,6 +1592,7 @@ static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
1567 1592
1568void CHandler::AddComment(UString &s) const 1593void CHandler::AddComment(UString &s) const
1569{ 1594{
1595 AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
1570 AddComment_UInt64(s, "PhysicalSize", _phySize); 1596 AddComment_UInt64(s, "PhysicalSize", _phySize);
1571 1597
1572 if (!_errorMessage.IsEmpty()) 1598 if (!_errorMessage.IsEmpty())
diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp
index fb5bb1f..40f5613 100644
--- 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)
138 int eq = s.Find('='); 138 int eq = s.Find('=');
139 if (eq < 0 || (qu >= 0 && eq > qu)) 139 if (eq < 0 || (qu >= 0 && eq > qu))
140 return false; 140 return false;
141 name = s.Left(eq); 141 name.SetFrom(s.Ptr(), eq);
142 name.Trim(); 142 name.Trim();
143 val = s.Ptr(eq + 1); 143 val = s.Ptr(eq + 1);
144 val.Trim(); 144 val.Trim();
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
index 9e39d02..3b39455 100644
--- 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)
355 prop.vt = VT_FILETIME; 355 prop.vt = VT_FILETIME;
356 prop.filetime.dwLowDateTime = Get32(p); 356 prop.filetime.dwLowDateTime = Get32(p);
357 prop.filetime.dwHighDateTime = Get32(p + 4); 357 prop.filetime.dwHighDateTime = Get32(p + 4);
358 prop.Set_FtPrec(k_PropVar_TimePrec_100ns);
358} 359}
359 360
360 361
@@ -842,7 +843,7 @@ public:
842 int dotPos = name.ReverseFind_Dot(); 843 int dotPos = name.ReverseFind_Dot();
843 if (dotPos < 0) 844 if (dotPos < 0)
844 dotPos = name.Len(); 845 dotPos = name.Len();
845 _before = name.Left(dotPos); 846 _before.SetFrom(name.Ptr(), dotPos);
846 _after = name.Ptr(dotPos); 847 _after = name.Ptr(dotPos);
847 } 848 }
848 849
diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
index 6b4497f..5e8365a 100644
--- 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
32 unsigned left = 0, right = sorted.Size(); 32 unsigned left = 0, right = sorted.Size();
33 while (left != right) 33 while (left != right)
34 { 34 {
35 unsigned mid = (left + right) / 2; 35 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
36 unsigned index = sorted[mid]; 36 const unsigned index = sorted[mid];
37 const Byte *hash2 = streams[index].Hash; 37 const Byte *hash2 = streams[index].Hash;
38 38
39 unsigned i; 39 unsigned i;
@@ -124,9 +124,9 @@ static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned
124 unsigned left = 0, right = indexes.Size(); 124 unsigned left = 0, right = indexes.Size();
125 while (left != right) 125 while (left != right)
126 { 126 {
127 unsigned mid = (left + right) / 2; 127 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
128 unsigned index = indexes[mid]; 128 const unsigned index = indexes[mid];
129 int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); 129 const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]);
130 if (comp == 0) 130 if (comp == 0)
131 return index; 131 return index;
132 if (comp < 0) 132 if (comp < 0)
@@ -203,8 +203,8 @@ bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, u
203 unsigned left = 0, right = Dirs.Size(); 203 unsigned left = 0, right = Dirs.Size();
204 while (left != right) 204 while (left != right)
205 { 205 {
206 unsigned mid = (left + right) / 2; 206 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
207 int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); 207 const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
208 if (comp == 0) 208 if (comp == 0)
209 { 209 {
210 index = mid; 210 index = mid;
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
index fef6b34..f805521 100644
--- 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
567 for (unsigned i = 0; i < len; i++) 567 for (unsigned i = 0; i < len; i++)
568 { 568 {
569 wchar_t c = Get16(meta + i * 2); 569 wchar_t c = Get16(meta + i * 2);
570 // 18.06 570 if (c == L'/')
571 if (c == CHAR_PATH_SEPARATOR || c == '/') 571 c = L'_';
572 c = '_'; 572 #if WCHAR_PATH_SEPARATOR != L'/'
573 else if (c == L'\\')
574 c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme
575 #endif
573 dest[i] = c; 576 dest[i] = c;
574 } 577 }
575 } 578 }
diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp
index ecebe8d..e143f91 100644
--- a/CPP/7zip/Archive/Wim/WimRegister.cpp
+++ b/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -10,13 +10,20 @@ namespace NArchive {
10namespace NWim { 10namespace NWim {
11 11
12REGISTER_ARC_IO( 12REGISTER_ARC_IO(
13 "wim", "wim swm esd ppkg", 0, 0xE6, 13 "wim", "wim swm esd ppkg", NULL, 0xE6
14 kSignature, 14 , kSignature, 0
15 0, 15 , NArcInfoFlags::kAltStreams
16 NArcInfoFlags::kAltStreams | 16 | NArcInfoFlags::kNtSecure
17 NArcInfoFlags::kNtSecure | 17 | NArcInfoFlags::kSymLinks
18 NArcInfoFlags::kSymLinks | 18 | NArcInfoFlags::kHardLinks
19 NArcInfoFlags::kHardLinks 19 | NArcInfoFlags::kCTime
20 // | NArcInfoFlags::kCTime_Default
21 | NArcInfoFlags::kATime
22 // | NArcInfoFlags::kATime_Default
23 | NArcInfoFlags::kMTime
24 | NArcInfoFlags::kMTime_Default
25 , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
26 | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
20 , NULL) 27 , NULL)
21 28
22}} 29}}
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp
index f1afab6..d358ca5 100644
--- a/CPP/7zip/Archive/XzHandler.cpp
+++ b/CPP/7zip/Archive/XzHandler.cpp
@@ -1089,7 +1089,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1089 1089
1090STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) 1090STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
1091{ 1091{
1092 *timeType = NFileTimeType::kUnix; 1092 *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
1093 // *timeType = NFileTimeType::kUnix;
1093 return S_OK; 1094 return S_OK;
1094} 1095}
1095 1096
@@ -1136,7 +1137,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1136 if (prop.vt != VT_UI8) 1137 if (prop.vt != VT_UI8)
1137 return E_INVALIDARG; 1138 return E_INVALIDARG;
1138 dataSize = prop.uhVal.QuadPart; 1139 dataSize = prop.uhVal.QuadPart;
1139 RINOK(updateCallback->SetTotal(dataSize));
1140 } 1140 }
1141 1141
1142 NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder; 1142 NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
@@ -1266,15 +1266,28 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1266 } 1266 }
1267 } 1267 }
1268 1268
1269 CMyComPtr<ISequentialInStream> fileInStream; 1269 {
1270 RINOK(updateCallback->GetStream(0, &fileInStream)); 1270 CMyComPtr<ISequentialInStream> fileInStream;
1271 1271 RINOK(updateCallback->GetStream(0, &fileInStream));
1272 CLocalProgress *lps = new CLocalProgress; 1272 if (!fileInStream)
1273 CMyComPtr<ICompressProgressInfo> progress = lps; 1273 return S_FALSE;
1274 lps->Init(updateCallback, true); 1274 {
1275 1275 CMyComPtr<IStreamGetSize> streamGetSize;
1276 RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress)); 1276 fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
1277 1277 if (streamGetSize)
1278 {
1279 UInt64 size;
1280 if (streamGetSize->GetSize(&size) == S_OK)
1281 dataSize = size;
1282 }
1283 }
1284 RINOK(updateCallback->SetTotal(dataSize));
1285 CLocalProgress *lps = new CLocalProgress;
1286 CMyComPtr<ICompressProgressInfo> progress = lps;
1287 lps->Init(updateCallback, true);
1288 RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress));
1289 }
1290
1278 return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); 1291 return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
1279 } 1292 }
1280 1293
@@ -1415,9 +1428,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
1415 1428
1416REGISTER_ARC_IO( 1429REGISTER_ARC_IO(
1417 "xz", "xz txz", "* .tar", 0xC, 1430 "xz", "xz txz", "* .tar", 0xC,
1418 XZ_SIG, 1431 XZ_SIG, 0
1419 0, 1432 , NArcInfoFlags::kKeepName
1420 NArcInfoFlags::kKeepName, 1433 , 0
1421 NULL) 1434 , NULL)
1422 1435
1423}} 1436}}
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp
index d8168bb..1b3985f 100644
--- a/CPP/7zip/Archive/Zip/ZipHandler.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -190,6 +190,8 @@ static const Byte kProps[] =
190 kpidVolumeIndex, 190 kpidVolumeIndex,
191 kpidOffset 191 kpidOffset
192 // kpidIsAltStream 192 // kpidIsAltStream
193 // , kpidChangeTime // for debug
194 // , 255 // for debug
193}; 195};
194 196
195static const Byte kArcProps[] = 197static const Byte kArcProps[] =
@@ -347,6 +349,34 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
347 return S_OK; 349 return S_OK;
348} 350}
349 351
352
353static bool NtfsUnixTimeToProp(bool fromCentral,
354 const CExtraBlock &extra,
355 unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop)
356{
357 {
358 FILETIME ft;
359 if (extra.GetNtfsTime(ntfsIndex, ft))
360 {
361 PropVariant_SetFrom_NtfsTime(prop, ft);
362 return true;
363 }
364 }
365 {
366 UInt32 unixTime = 0;
367 if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime))
368 return false;
369 /*
370 // we allow unixTime == 0
371 if (unixTime == 0)
372 return false;
373 */
374 PropVariant_SetFrom_UnixTime(prop, unixTime);
375 return true;
376 }
377}
378
379
350STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 380STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
351{ 381{
352 COM_TRY_BEGIN 382 COM_TRY_BEGIN
@@ -392,6 +422,30 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
392 422
393 case kpidPackSize: prop = item.PackSize; break; 423 case kpidPackSize: prop = item.PackSize; break;
394 424
425 case kpidCTime:
426 NtfsUnixTimeToProp(item.FromCentral, extra,
427 NFileHeader::NNtfsExtra::kCTime,
428 NFileHeader::NUnixTime::kCTime, prop);
429 break;
430
431 case kpidATime:
432 NtfsUnixTimeToProp(item.FromCentral, extra,
433 NFileHeader::NNtfsExtra::kATime,
434 NFileHeader::NUnixTime::kATime, prop);
435 break;
436
437 case kpidMTime:
438 {
439 if (!NtfsUnixTimeToProp(item.FromCentral, extra,
440 NFileHeader::NNtfsExtra::kMTime,
441 NFileHeader::NUnixTime::kMTime, prop))
442 {
443 if (item.Time != 0)
444 PropVariant_SetFrom_DosTime(prop, item.Time);
445 }
446 break;
447 }
448
395 case kpidTimeType: 449 case kpidTimeType:
396 { 450 {
397 FILETIME ft; 451 FILETIME ft;
@@ -399,7 +453,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
399 UInt32 type; 453 UInt32 type;
400 if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) 454 if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
401 type = NFileTimeType::kWindows; 455 type = NFileTimeType::kWindows;
402 else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) 456 else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime))
403 type = NFileTimeType::kUnix; 457 type = NFileTimeType::kUnix;
404 else 458 else
405 type = NFileTimeType::kDOS; 459 type = NFileTimeType::kDOS;
@@ -407,64 +461,28 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
407 break; 461 break;
408 } 462 }
409 463
410 case kpidCTime: 464 /*
411 { 465 // for debug to get Dos time values:
412 FILETIME utc; 466 case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break;
413 bool defined = true; 467 // for debug
414 if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc)) 468 // time difference (dos - utc)
415 { 469 case 255:
416 UInt32 unixTime = 0;
417 if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime))
418 NTime::UnixTimeToFileTime(unixTime, utc);
419 else
420 defined = false;
421 }
422 if (defined)
423 prop = utc;
424 break;
425 }
426
427 case kpidATime:
428 {
429 FILETIME utc;
430 bool defined = true;
431 if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc))
432 {
433 UInt32 unixTime = 0;
434 if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime))
435 NTime::UnixTimeToFileTime(unixTime, utc);
436 else
437 defined = false;
438 }
439 if (defined)
440 prop = utc;
441
442 break;
443 }
444
445 case kpidMTime:
446 { 470 {
447 FILETIME utc; 471 if (NtfsUnixTimeToProp(item.FromCentral, extra,
448 bool defined = true; 472 NFileHeader::NNtfsExtra::kMTime,
449 if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) 473 NFileHeader::NUnixTime::kMTime, prop))
450 { 474 {
451 UInt32 unixTime = 0; 475 FILETIME localFileTime;
452 if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) 476 if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime))
453 NTime::UnixTimeToFileTime(unixTime, utc);
454 else
455 { 477 {
456 FILETIME localFileTime; 478 UInt64 t1 = FILETIME_To_UInt64(prop.filetime);
457 if (item.Time == 0) 479 UInt64 t2 = FILETIME_To_UInt64(localFileTime);
458 defined = false; 480 prop.Set_Int64(t2 - t1);
459 else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
460 !LocalFileTimeToFileTime(&localFileTime, &utc))
461 utc.dwHighDateTime = utc.dwLowDateTime = 0;
462 } 481 }
463 } 482 }
464 if (defined)
465 prop = utc;
466 break; 483 break;
467 } 484 }
485 */
468 486
469 case kpidAttrib: prop = item.GetWinAttrib(); break; 487 case kpidAttrib: prop = item.GetWinAttrib(); break;
470 488
@@ -1122,7 +1140,18 @@ HRESULT CZipDecoder::Decode(
1122 AString_Wipe charPassword; 1140 AString_Wipe charPassword;
1123 if (password) 1141 if (password)
1124 { 1142 {
1125 UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP); 1143 /*
1144 // 22.00: do we need UTF-8 passwords here ?
1145 if (item.IsUtf8()) // 22.00
1146 {
1147 // throw 1;
1148 ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword);
1149 }
1150 else
1151 */
1152 {
1153 UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
1154 }
1126 /* 1155 /*
1127 if (wzAesMode || pkAesMode) 1156 if (wzAesMode || pkAesMode)
1128 { 1157 {
@@ -1341,6 +1370,8 @@ HRESULT CZipDecoder::Decode(
1341 1370
1342 if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted()) 1371 if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted())
1343 { 1372 {
1373 // for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter
1374 // here we use filter without CopyCoder
1344 readFromFilter = false; 1375 readFromFilter = false;
1345 1376
1346 COutStreamWithPadPKCS7 *padStreamSpec = NULL; 1377 COutStreamWithPadPKCS7 *padStreamSpec = NULL;
@@ -1425,33 +1456,44 @@ HRESULT CZipDecoder::Decode(
1425 const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed); 1456 const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
1426 if (processed + padSize > coderPackSize) 1457 if (processed + padSize > coderPackSize)
1427 truncatedError = true; 1458 truncatedError = true;
1459 else if (processed + padSize < coderPackSize)
1460 dataAfterEnd = true;
1428 else 1461 else
1429 { 1462 {
1430 if (processed + padSize < coderPackSize)
1431 dataAfterEnd = true;
1432 else
1433 { 1463 {
1434 // here we can PKCS7 padding data from reminder (it can be inside stream buffer in coder). 1464 // here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder).
1435 CMyComPtr<ICompressReadUnusedFromInBuf> readInStream; 1465 CMyComPtr<ICompressReadUnusedFromInBuf> readInStream;
1436 coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream); 1466 coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream);
1437 if (readInStream) 1467 // CCopyCoder() for kStore doesn't read data outside of (item.Size)
1468 if (readInStream || id == NFileHeader::NCompressionMethod::kStore)
1438 { 1469 {
1439 // change pad size, it we support another block size in ZipStron 1470 // change pad size, if we support another block size in ZipStrong.
1440 // here we request more to detect error with data after end. 1471 // here we request more data to detect error with data after end.
1441 const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16; 1472 const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16;
1442 Byte buf[kBufSize]; 1473 Byte buf[kBufSize];
1443 UInt32 processedSize; 1474 UInt32 processedSize = 0;
1444 RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize)); 1475 if (readInStream)
1476 {
1477 RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
1478 }
1445 if (processedSize > padSize) 1479 if (processedSize > padSize)
1446 dataAfterEnd = true; 1480 dataAfterEnd = true;
1447 else 1481 else
1448 { 1482 {
1449 if (ReadStream_FALSE(filterStream, buf + processedSize, padSize - processedSize) != S_OK) 1483 size_t processedSize2 = kBufSize - processedSize;
1450 padError = true; 1484 result = ReadStream(filterStream, buf + processedSize, &processedSize2);
1451 else 1485 if (result == S_OK)
1452 for (unsigned i = 0; i < padSize; i++) 1486 {
1453 if (buf[i] != padSize) 1487 processedSize2 += processedSize;
1454 padError = true; 1488 if (processedSize2 > padSize)
1489 dataAfterEnd = true;
1490 else if (processedSize2 < padSize)
1491 truncatedError = true;
1492 else
1493 for (unsigned i = 0; i < padSize; i++)
1494 if (buf[i] != padSize)
1495 padError = true;
1496 }
1455 } 1497 }
1456 } 1498 }
1457 } 1499 }
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h
index 3043e41..a70a1a7 100644
--- a/CPP/7zip/Archive/Zip/ZipHandler.h
+++ b/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -57,7 +57,9 @@ private:
57 57
58 int m_MainMethod; 58 int m_MainMethod;
59 bool m_ForceAesMode; 59 bool m_ForceAesMode;
60 bool m_WriteNtfsTimeExtra; 60
61 CHandlerTimeOptions TimeOptions;
62
61 bool _removeSfxBlock; 63 bool _removeSfxBlock;
62 bool m_ForceLocal; 64 bool m_ForceLocal;
63 bool m_ForceUtf8; 65 bool m_ForceUtf8;
@@ -71,7 +73,8 @@ private:
71 _props.Init(); 73 _props.Init();
72 m_MainMethod = -1; 74 m_MainMethod = -1;
73 m_ForceAesMode = false; 75 m_ForceAesMode = false;
74 m_WriteNtfsTimeExtra = true; 76 TimeOptions.Init();
77 TimeOptions.Prec = k_PropVar_TimePrec_0;
75 _removeSfxBlock = false; 78 _removeSfxBlock = false;
76 m_ForceLocal = false; 79 m_ForceLocal = false;
77 m_ForceUtf8 = false; 80 m_ForceUtf8 = false;
diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
index a9b3eae..77a71df 100644
--- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -30,7 +30,7 @@ namespace NZip {
30 30
31STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) 31STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
32{ 32{
33 *timeType = NFileTimeType::kDOS; 33 *timeType = TimeOptions.Prec;
34 return S_OK; 34 return S_OK;
35} 35}
36 36
@@ -207,27 +207,58 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
207 } 207 }
208 */ 208 */
209 209
210 // 22.00 : kpidTimeType is useless here : the code was disabled
211 /*
210 { 212 {
211 CPropVariant prop; 213 CPropVariant prop;
212 RINOK(callback->GetProperty(i, kpidTimeType, &prop)); 214 RINOK(callback->GetProperty(i, kpidTimeType, &prop));
213 if (prop.vt == VT_UI4) 215 if (prop.vt == VT_UI4)
214 ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows); 216 ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows);
215 else 217 else
216 ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra; 218 ui.NtfsTime_IsDefined = _Write_NtfsTime;
217 } 219 }
218 RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime)); 220 */
219 RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime)); 221
220 RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime)); 222 if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime));
223 if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime));
224 if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime));
221 225
226 if (TimeOptions.Prec != k_PropVar_TimePrec_DOS)
222 { 227 {
223 FILETIME localFileTime = { 0, 0 }; 228 if (TimeOptions.Prec == k_PropVar_TimePrec_Unix ||
224 if (ui.Ntfs_MTime.dwHighDateTime != 0 || 229 TimeOptions.Prec == k_PropVar_TimePrec_Base)
225 ui.Ntfs_MTime.dwLowDateTime != 0) 230 ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime);
226 if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) 231 else
227 return E_INVALIDARG; 232 {
228 FileTimeToDosTime(localFileTime, ui.Time); 233 /*
234 // if we want to store zero timestamps as zero timestamp, use the following:
235 ui.Write_NtfsTime =
236 _Write_MTime ||
237 _Write_ATime ||
238 _Write_CTime;
239 */
240
241 // We treat zero timestamp as no timestamp
242 ui.Write_NtfsTime =
243 ! FILETIME_IsZero (ui.Ntfs_MTime) ||
244 ! FILETIME_IsZero (ui.Ntfs_ATime) ||
245 ! FILETIME_IsZero (ui.Ntfs_CTime);
246 }
229 } 247 }
230 248
249 /*
250 how 0 in dos time works:
251 win10 explorer extract : some random date 1601-04-25.
252 winrar 6.10 : write time.
253 7zip : MTime of archive is used
254 how 0 in tar works:
255 winrar 6.10 : 1970
256 0 in dos field can show that there is no timestamp.
257 we write correct 1970-01-01 in dos field, to support correct extraction in Win10.
258 */
259
260 UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time);
261
231 NItemName::ReplaceSlashes_OsToUnix(name); 262 NItemName::ReplaceSlashes_OsToUnix(name);
232 263
233 bool needSlash = ui.IsDir; 264 bool needSlash = ui.IsDir;
@@ -441,11 +472,21 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
441 if (mainMethod != NFileHeader::NCompressionMethod::kStore) 472 if (mainMethod != NFileHeader::NCompressionMethod::kStore)
442 options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore); 473 options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore);
443 474
475 CUpdateOptions uo;
476 uo.Write_MTime = TimeOptions.Write_MTime.Val;
477 uo.Write_ATime = TimeOptions.Write_ATime.Val;
478 uo.Write_CTime = TimeOptions.Write_CTime.Val;
479 /*
480 uo.Write_NtfsTime = _Write_NtfsTime &&
481 (_Write_MTime || _Write_ATime || _Write_CTime);
482 uo.Write_UnixTime = _Write_UnixTime;
483 */
484
444 return Update( 485 return Update(
445 EXTERNAL_CODECS_VARS 486 EXTERNAL_CODECS_VARS
446 m_Items, updateItems, outStream, 487 m_Items, updateItems, outStream,
447 m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, 488 m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
448 options, callback); 489 uo, options, callback);
449 490
450 COM_TRY_END2 491 COM_TRY_END2
451} 492}
@@ -494,10 +535,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
494 return E_INVALIDARG; 535 return E_INVALIDARG;
495 } 536 }
496 } 537 }
497 else if (name.IsEqualTo("tc")) 538
498 { 539
499 RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); 540
500 }
501 else if (name.IsEqualTo("cl")) 541 else if (name.IsEqualTo("cl"))
502 { 542 {
503 RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)); 543 RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal));
@@ -532,7 +572,12 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
532 } 572 }
533 else 573 else
534 { 574 {
535 RINOK(_props.SetProperty(name, prop)); 575 bool processed = false;
576 RINOK(TimeOptions.Parse(name, prop, processed));
577 if (!processed)
578 {
579 RINOK(_props.SetProperty(name, prop));
580 }
536 } 581 }
537 // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); 582 // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
538 } 583 }
diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h
index c47659a..34fa359 100644
--- a/CPP/7zip/Archive/Zip/ZipHeader.h
+++ b/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -88,14 +88,15 @@ namespace NFileHeader
88 { 88 {
89 kZip64 = 0x01, 89 kZip64 = 0x01,
90 kNTFS = 0x0A, 90 kNTFS = 0x0A,
91 kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK
91 kStrongEncrypt = 0x17, 92 kStrongEncrypt = 0x17,
92 kIzNtSecurityDescriptor = 0x4453, 93 kIzNtSecurityDescriptor = 0x4453,
93 kUnixTime = 0x5455, 94 kUnixTime = 0x5455, // "UT" (time) Info-ZIP
94 kUnixExtra = 0x5855, 95 kUnix1 = 0x5855, // Info-ZIP
95 kIzUnicodeComment = 0x6375, 96 kIzUnicodeComment = 0x6375,
96 kIzUnicodeName = 0x7075, 97 kIzUnicodeName = 0x7075,
97 kUnix2Extra = 0x7855, 98 kUnix2 = 0x7855, // Info-ZIP
98 kUnix3Extra = 0x7875, 99 kUnixN = 0x7875, // Info-ZIP
99 kWzAES = 0x9901, 100 kWzAES = 0x9901,
100 kApkAlign = 0xD935 101 kApkAlign = 0xD935
101 }; 102 };
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
index 076d6bb..f2b69a9 100644
--- 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
1045 1045
1046 if (cdItem) 1046 if (cdItem)
1047 { 1047 {
1048 if (isOK && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) 1048 if (isOK)
1049 { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} 1049 {
1050 1050 if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
1051 { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
1052 /*
1053 else if (size == 8)
1054 {
1055 size -= 8;
1056 const UInt64 v = ReadUInt64();
1057 // soong_zip, an AOSP tool (written in the Go) writes incorrect value.
1058 // we can ignore that minor error here
1059 if (v != cdItem->LocalHeaderPos)
1060 isOK = false; // ignore error
1061 // isOK = false; // force error
1062 }
1063 */
1064 }
1065
1051 if (isOK && ZIP64_IS_16_MAX(cdItem->Disk)) 1066 if (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
1052 { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }} 1067 { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }}
1053 } 1068 }
@@ -1926,7 +1941,7 @@ static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
1926 { 1941 {
1927 if (left >= right) 1942 if (left >= right)
1928 return -1; 1943 return -1;
1929 const unsigned index = (left + right) / 2; 1944 const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2);
1930 const CItemEx &item2 = items[index]; 1945 const CItemEx &item2 = items[index];
1931 if (item.Disk < item2.Disk) 1946 if (item.Disk < item2.Disk)
1932 right = index; 1947 right = index;
diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp
index be33648..cffbb78 100644
--- a/CPP/7zip/Archive/Zip/ZipItem.cpp
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -30,11 +30,12 @@ static const CUInt32PCharPair g_ExtraTypes[] =
30{ 30{
31 { NExtraID::kZip64, "Zip64" }, 31 { NExtraID::kZip64, "Zip64" },
32 { NExtraID::kNTFS, "NTFS" }, 32 { NExtraID::kNTFS, "NTFS" },
33 { NExtraID::kUnix0, "UNIX" },
33 { NExtraID::kStrongEncrypt, "StrongCrypto" }, 34 { NExtraID::kStrongEncrypt, "StrongCrypto" },
34 { NExtraID::kUnixTime, "UT" }, 35 { NExtraID::kUnixTime, "UT" },
35 { NExtraID::kUnixExtra, "UX" }, 36 { NExtraID::kUnix1, "UX" },
36 { NExtraID::kUnix2Extra, "Ux" }, 37 { NExtraID::kUnix2, "Ux" },
37 { NExtraID::kUnix3Extra, "ux" }, 38 { NExtraID::kUnixN, "ux" },
38 { NExtraID::kIzUnicodeComment, "uc" }, 39 { NExtraID::kIzUnicodeComment, "uc" },
39 { NExtraID::kIzUnicodeName, "up" }, 40 { NExtraID::kIzUnicodeName, "up" },
40 { NExtraID::kIzNtSecurityDescriptor, "SD" }, 41 { NExtraID::kIzNtSecurityDescriptor, "SD" },
@@ -50,6 +51,23 @@ void CExtraSubBlock::PrintInfo(AString &s) const
50 if (pair.Value == ID) 51 if (pair.Value == ID)
51 { 52 {
52 s += pair.Name; 53 s += pair.Name;
54 if (ID == NExtraID::kUnixTime)
55 {
56 if (Data.Size() >= 1)
57 {
58 s += ':';
59 const Byte flags = Data[0];
60 if (flags & 1) s += 'M';
61 if (flags & 2) s += 'A';
62 if (flags & 4) s += 'C';
63 const UInt32 size = (UInt32)(Data.Size()) - 1;
64 if (size % 4 == 0)
65 {
66 s += ':';
67 s.Add_UInt32(size / 4);
68 }
69 }
70 }
53 /* 71 /*
54 if (ID == NExtraID::kApkAlign && Data.Size() >= 2) 72 if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
55 { 73 {
@@ -133,14 +151,22 @@ bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
133 return false; 151 return false;
134} 152}
135 153
136bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const 154bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const
137{ 155{
156 /* Info-Zip :
157 The central-header extra field contains the modification
158 time only, or no timestamp at all.
159 Size of Data is used to flag its presence or absence
160 If "Flags" indicates that Modtime is present in the local header
161 field, it MUST be present in the central header field, too
162 */
163
138 res = 0; 164 res = 0;
139 UInt32 size = (UInt32)Data.Size(); 165 UInt32 size = (UInt32)Data.Size();
140 if (ID != NExtraID::kUnixTime || size < 5) 166 if (ID != NExtraID::kUnixTime || size < 5)
141 return false; 167 return false;
142 const Byte *p = (const Byte *)Data; 168 const Byte *p = (const Byte *)Data;
143 Byte flags = *p++; 169 const Byte flags = *p++;
144 size--; 170 size--;
145 if (isCentral) 171 if (isCentral)
146 { 172 {
@@ -168,18 +194,35 @@ bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res
168} 194}
169 195
170 196
171bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const 197// Info-ZIP's abandoned "Unix1 timestamps & owner ID info"
198
199bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const
172{ 200{
173 res = 0; 201 res = 0;
174 const size_t size = Data.Size(); 202 const unsigned offset = index * 4;
175 unsigned offset = index * 4; 203 if (Data.Size() < offset + 4)
176 if (ID != NExtraID::kUnixExtra || size < offset + 4) 204 return false;
205 if (ID != NExtraID::kUnix0 &&
206 ID != NExtraID::kUnix1)
177 return false; 207 return false;
178 const Byte *p = (const Byte *)Data + offset; 208 const Byte *p = (const Byte *)Data + offset;
179 res = GetUi32(p); 209 res = GetUi32(p);
180 return true; 210 return true;
181} 211}
182 212
213/*
214// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps"
215bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const
216{
217 res = 0;
218 const unsigned offset = index * 4;
219 if (ID != NExtraID::kUnix0 || Data.Size() < offset)
220 return false;
221 const Byte *p = (const Byte *)Data + offset;
222 res = GetUi32(p);
223 return true;
224}
225*/
183 226
184bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const 227bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
185{ 228{
@@ -199,7 +242,7 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
199 { 242 {
200 const CExtraSubBlock &sb = SubBlocks[i]; 243 const CExtraSubBlock &sb = SubBlocks[i];
201 if (sb.ID == NFileHeader::NExtraID::kUnixTime) 244 if (sb.ID == NFileHeader::NExtraID::kUnixTime)
202 return sb.ExtractUnixTime(isCentral, index, res); 245 return sb.Extract_UnixTime(isCentral, index, res);
203 } 246 }
204 } 247 }
205 248
@@ -214,8 +257,9 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
214 FOR_VECTOR (i, SubBlocks) 257 FOR_VECTOR (i, SubBlocks)
215 { 258 {
216 const CExtraSubBlock &sb = SubBlocks[i]; 259 const CExtraSubBlock &sb = SubBlocks[i];
217 if (sb.ID == NFileHeader::NExtraID::kUnixExtra) 260 if (sb.ID == NFileHeader::NExtraID::kUnix0 ||
218 return sb.ExtractUnixExtraTime(index, res); 261 sb.ID == NFileHeader::NExtraID::kUnix1)
262 return sb.Extract_Unix01_Time(index, res);
219 } 263 }
220 } 264 }
221 return false; 265 return false;
diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h
index 6ee8765..934d7ec 100644
--- a/CPP/7zip/Archive/Zip/ZipItem.h
+++ b/CPP/7zip/Archive/Zip/ZipItem.h
@@ -31,8 +31,9 @@ struct CExtraSubBlock
31 CByteBuffer Data; 31 CByteBuffer Data;
32 32
33 bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; 33 bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
34 bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; 34 bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
35 bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const; 35 bool Extract_Unix01_Time(unsigned index, UInt32 &res) const;
36 // bool Extract_Unix_Time(unsigned index, UInt32 &res) const;
36 37
37 bool CheckIzUnicode(const AString &s) const; 38 bool CheckIzUnicode(const AString &s) const;
38 39
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp
index efed0a4..8f3f43b 100644
--- a/CPP/7zip/Archive/Zip/ZipOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -4,6 +4,7 @@
4 4
5#include "../../../../C/7zCrc.h" 5#include "../../../../C/7zCrc.h"
6 6
7#include "../../../Windows/TimeUtils.h"
7#include "../../Common/OffsetStream.h" 8#include "../../Common/OffsetStream.h"
8 9
9#include "ZipOut.h" 10#include "ZipOut.h"
@@ -110,6 +111,40 @@ void COutArchive::WriteUtfName(const CItemOut &item)
110 WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size()); 111 WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
111} 112}
112 113
114
115static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8);
116static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4);
117
118void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
119{
120 if (writeNtfs)
121 {
122 // windows explorer ignores that extra
123 Write16(NFileHeader::NExtraID::kNTFS);
124 Write16(k_Ntfs_ExtraSize);
125 Write32(0); // reserved
126 Write16(NFileHeader::NNtfsExtra::kTagTime);
127 Write16(8 * 3);
128 WriteNtfsTime(item.Ntfs_MTime);
129 WriteNtfsTime(item.Ntfs_ATime);
130 WriteNtfsTime(item.Ntfs_CTime);
131 }
132
133 if (item.Write_UnixTime)
134 {
135 // windows explorer ignores that extra
136 // by specification : should we write to local header also?
137 Write16(NFileHeader::NExtraID::kUnixTime);
138 Write16(k_UnixTime_ExtraSize);
139 const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
140 Write8(flags);
141 UInt32 unixTime;
142 NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime);
143 Write32(unixTime);
144 }
145}
146
147
113void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck) 148void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
114{ 149{
115 m_LocalHeaderPos = m_CurPos; 150 m_LocalHeaderPos = m_CurPos;
@@ -122,8 +157,14 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
122 if (needCheck && m_IsZip64) 157 if (needCheck && m_IsZip64)
123 isZip64 = true; 158 isZip64 = true;
124 159
160 // Why don't we write NTFS timestamps to local header?
161 // Probably we want to reduce size of archive?
162 const bool writeNtfs = false; // do not write NTFS timestamp to local header
163 // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header
125 const UInt32 localExtraSize = (UInt32)( 164 const UInt32 localExtraSize = (UInt32)(
126 (isZip64 ? (4 + 8 + 8): 0) 165 (isZip64 ? (4 + 8 + 8): 0)
166 + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
167 + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
127 + item.Get_UtfName_ExtraSize() 168 + item.Get_UtfName_ExtraSize()
128 + item.LocalExtra.GetSize()); 169 + item.LocalExtra.GetSize());
129 if ((UInt16)localExtraSize != localExtraSize) 170 if ((UInt16)localExtraSize != localExtraSize)
@@ -168,13 +209,12 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
168 Write64(packSize); 209 Write64(packSize);
169 } 210 }
170 211
212 WriteTimeExtra(item, writeNtfs);
213
171 WriteUtfName(item); 214 WriteUtfName(item);
172 215
173 WriteExtra(item.LocalExtra); 216 WriteExtra(item.LocalExtra);
174 217
175 // Why don't we write NTFS timestamps to local header?
176 // Probably we want to reduce size of archive?
177
178 const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos); 218 const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
179 if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) 219 if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
180 throw CSystemException(E_FAIL); 220 throw CSystemException(E_FAIL);
@@ -231,10 +271,10 @@ void COutArchive::WriteDescriptor(const CItemOut &item)
231 271
232void COutArchive::WriteCentralHeader(const CItemOut &item) 272void COutArchive::WriteCentralHeader(const CItemOut &item)
233{ 273{
234 bool isUnPack64 = DOES_NEED_ZIP64(item.Size); 274 const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
235 bool isPack64 = DOES_NEED_ZIP64(item.PackSize); 275 const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
236 bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); 276 const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
237 bool isZip64 = isPack64 || isUnPack64 || isPosition64; 277 const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
238 278
239 Write32(NSignature::kCentralFileHeader); 279 Write32(NSignature::kCentralFileHeader);
240 Write8(item.MadeByVersion.Version); 280 Write8(item.MadeByVersion.Version);
@@ -249,10 +289,11 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
249 Write16((UInt16)item.Name.Len()); 289 Write16((UInt16)item.Name.Len());
250 290
251 const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); 291 const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
252 const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8); 292 const bool writeNtfs = item.Write_NtfsTime;
253 const size_t centralExtraSize = 293 const size_t centralExtraSize =
254 (isZip64 ? 4 + zip64ExtraSize : 0) 294 (isZip64 ? 4 + zip64ExtraSize : 0)
255 + (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) 295 + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
296 + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
256 + item.Get_UtfName_ExtraSize() 297 + item.Get_UtfName_ExtraSize()
257 + item.CentralExtra.GetSize(); 298 + item.CentralExtra.GetSize();
258 299
@@ -283,18 +324,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
283 Write64(item.LocalHeaderPos); 324 Write64(item.LocalHeaderPos);
284 } 325 }
285 326
286 if (item.NtfsTimeIsDefined) 327 WriteTimeExtra(item, writeNtfs);
287 {
288 Write16(NFileHeader::NExtraID::kNTFS);
289 Write16(kNtfsExtraSize);
290 Write32(0); // reserved
291 Write16(NFileHeader::NNtfsExtra::kTagTime);
292 Write16(8 * 3);
293 WriteNtfsTime(item.Ntfs_MTime);
294 WriteNtfsTime(item.Ntfs_ATime);
295 WriteNtfsTime(item.Ntfs_CTime);
296 }
297
298 WriteUtfName(item); 328 WriteUtfName(item);
299 329
300 WriteExtra(item.CentralExtra); 330 WriteExtra(item.CentralExtra);
@@ -304,15 +334,15 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
304 334
305void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment) 335void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
306{ 336{
307 UInt64 cdOffset = GetCurPos(); 337 const UInt64 cdOffset = GetCurPos();
308 FOR_VECTOR (i, items) 338 FOR_VECTOR (i, items)
309 WriteCentralHeader(items[i]); 339 WriteCentralHeader(items[i]);
310 UInt64 cd64EndOffset = GetCurPos(); 340 const UInt64 cd64EndOffset = GetCurPos();
311 UInt64 cdSize = cd64EndOffset - cdOffset; 341 const UInt64 cdSize = cd64EndOffset - cdOffset;
312 bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); 342 const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
313 bool cdSize64 = DOES_NEED_ZIP64(cdSize); 343 const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
314 bool items64 = items.Size() >= 0xFFFF; 344 const bool items64 = items.Size() >= 0xFFFF;
315 bool isZip64 = (cdOffset64 || cdSize64 || items64); 345 const bool isZip64 = (cdOffset64 || cdSize64 || items64);
316 346
317 // isZip64 = true; // to test Zip64 347 // isZip64 = true; // to test Zip64
318 348
diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h
index 3546411..a645d67 100644
--- a/CPP/7zip/Archive/Zip/ZipOut.h
+++ b/CPP/7zip/Archive/Zip/ZipOut.h
@@ -18,7 +18,8 @@ public:
18 FILETIME Ntfs_MTime; 18 FILETIME Ntfs_MTime;
19 FILETIME Ntfs_ATime; 19 FILETIME Ntfs_ATime;
20 FILETIME Ntfs_CTime; 20 FILETIME Ntfs_CTime;
21 bool NtfsTimeIsDefined; 21 bool Write_NtfsTime;
22 bool Write_UnixTime;
22 23
23 // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. 24 // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra.
24 25
@@ -32,7 +33,10 @@ public:
32 return 4 + 5 + size; 33 return 4 + 5 + size;
33 } 34 }
34 35
35 CItemOut(): NtfsTimeIsDefined(false) {} 36 CItemOut():
37 Write_NtfsTime(false),
38 Write_UnixTime(false)
39 {}
36}; 40};
37 41
38 42
@@ -62,6 +66,7 @@ class COutArchive
62 Write32(ft.dwHighDateTime); 66 Write32(ft.dwHighDateTime);
63 } 67 }
64 68
69 void WriteTimeExtra(const CItemOut &item, bool writeNtfs);
65 void WriteUtfName(const CItemOut &item); 70 void WriteUtfName(const CItemOut &item);
66 void WriteExtra(const CExtraBlock &extra); 71 void WriteExtra(const CExtraBlock &extra);
67 void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); 72 void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp
index e6929f1..3ad4715 100644
--- a/CPP/7zip/Archive/Zip/ZipRegister.cpp
+++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -20,9 +20,19 @@ REGISTER_ARC_IO(
20 "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1, 20 "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1,
21 k_Signature, 21 k_Signature,
22 0, 22 0,
23 NArcInfoFlags::kFindSignature | 23 NArcInfoFlags::kFindSignature
24 NArcInfoFlags::kMultiSignature | 24 | NArcInfoFlags::kMultiSignature
25 NArcInfoFlags::kUseGlobalOffset, 25 | NArcInfoFlags::kUseGlobalOffset
26 IsArc_Zip) 26 | NArcInfoFlags::kCTime
27 // | NArcInfoFlags::kCTime_Default
28 | NArcInfoFlags::kATime
29 // | NArcInfoFlags::kATime_Default
30 | NArcInfoFlags::kMTime
31 | NArcInfoFlags::kMTime_Default
32 , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
33 | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
34 | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS)
35 | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
36 , IsArc_Zip)
27 37
28}} 38}}
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
index 26636c7..7f13071 100644
--- 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
74 item.Ntfs_MTime = ui.Ntfs_MTime; 74 item.Ntfs_MTime = ui.Ntfs_MTime;
75 item.Ntfs_ATime = ui.Ntfs_ATime; 75 item.Ntfs_ATime = ui.Ntfs_ATime;
76 item.Ntfs_CTime = ui.Ntfs_CTime; 76 item.Ntfs_CTime = ui.Ntfs_CTime;
77 item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; 77
78 item.Write_UnixTime = ui.Write_UnixTime;
79 item.Write_NtfsTime = ui.Write_NtfsTime;
78} 80}
79 81
80static void SetFileHeader( 82static void SetFileHeader(
@@ -476,12 +478,9 @@ static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *o
476} 478}
477 479
478 480
479static inline bool IsZero_FILETIME(const FILETIME &ft) 481static void UpdatePropsFromStream(
480{ 482 const CUpdateOptions &options,
481 return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); 483 CUpdateItem &item, ISequentialInStream *fileInStream,
482}
483
484static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream,
485 IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) 484 IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
486{ 485{
487 CMyComPtr<IStreamGetProps> getProps; 486 CMyComPtr<IStreamGetProps> getProps;
@@ -505,36 +504,100 @@ static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileIn
505 } 504 }
506 item.Size = size; 505 item.Size = size;
507 } 506 }
508 507
509 if (!IsZero_FILETIME(mTime)) 508 if (options.Write_MTime)
510 { 509 if (!FILETIME_IsZero(mTime))
511 item.Ntfs_MTime = mTime;
512 FILETIME loc = { 0, 0 };
513 if (FileTimeToLocalFileTime(&mTime, &loc))
514 { 510 {
515 item.Time = 0; 511 item.Ntfs_MTime = mTime;
516 NTime::FileTimeToDosTime(loc, item.Time); 512 NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time);
517 } 513 }
518 }
519 514
520 if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime; 515 if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime;
521 if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime; 516 if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime;
522 517
523 item.Attrib = attrib; 518 item.Attrib = attrib;
524} 519}
525 520
526 521
522/*
523static HRESULT ReportProps(
524 IArchiveUpdateCallbackArcProp *reportArcProp,
525 UInt32 index,
526 const CItemOut &item,
527 bool isAesMode)
528{
529 PROPVARIANT prop;
530 prop.vt = VT_EMPTY;
531 prop.wReserved1 = 0;
532
533 NCOM::PropVarEm_Set_UInt64(&prop, item.Size);
534 RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
535
536 NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize);
537 RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop));
538
539 if (!isAesMode)
540 {
541 NCOM::PropVarEm_Set_UInt32(&prop, item.Crc);
542 RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
543 }
544
545 RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK));
546
547 // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished))
548
549 return S_OK;
550}
551*/
552
553/*
554struct CTotalStats
555{
556 UInt64 Size;
557 UInt64 PackSize;
558
559 void UpdateWithItem(const CItemOut &item)
560 {
561 Size += item.Size;
562 PackSize += item.PackSize;
563 }
564};
565
566static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
567 CTotalStats &st)
568{
569 PROPVARIANT prop;
570 prop.vt = VT_EMPTY;
571 prop.wReserved1 = 0;
572 {
573 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size);
574 RINOK(reportArcProp->ReportProp(
575 NEventIndexType::kArcProp, 0, kpidSize, &prop));
576 }
577 {
578 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize);
579 RINOK(reportArcProp->ReportProp(
580 NEventIndexType::kArcProp, 0, kpidPackSize, &prop));
581 }
582 return S_OK;
583}
584*/
585
586
527static HRESULT Update2St( 587static HRESULT Update2St(
528 DECL_EXTERNAL_CODECS_LOC_VARS 588 DECL_EXTERNAL_CODECS_LOC_VARS
529 COutArchive &archive, 589 COutArchive &archive,
530 CInArchive *inArchive, 590 CInArchive *inArchive,
531 const CObjectVector<CItemEx> &inputItems, 591 const CObjectVector<CItemEx> &inputItems,
532 CObjectVector<CUpdateItem> &updateItems, 592 CObjectVector<CUpdateItem> &updateItems,
593 const CUpdateOptions &updateOptions,
533 const CCompressionMethodMode *options, bool outSeqMode, 594 const CCompressionMethodMode *options, bool outSeqMode,
534 const CByteBuffer *comment, 595 const CByteBuffer *comment,
535 IArchiveUpdateCallback *updateCallback, 596 IArchiveUpdateCallback *updateCallback,
536 UInt64 &totalComplexity, 597 UInt64 &totalComplexity,
537 IArchiveUpdateCallbackFile *opCallback) 598 IArchiveUpdateCallbackFile *opCallback
599 // , IArchiveUpdateCallbackArcProp *reportArcProp
600 )
538{ 601{
539 CLocalProgress *lps = new CLocalProgress; 602 CLocalProgress *lps = new CLocalProgress;
540 CMyComPtr<ICompressProgressInfo> progress = lps; 603 CMyComPtr<ICompressProgressInfo> progress = lps;
@@ -575,7 +638,8 @@ static HRESULT Update2St(
575 } 638 }
576 else 639 else
577 { 640 {
578 CMyComPtr<ISequentialInStream> fileInStream; 641 CMyComPtr<ISequentialInStream> fileInStream;
642 {
579 HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); 643 HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
580 if (res == S_FALSE) 644 if (res == S_FALSE)
581 { 645 {
@@ -596,7 +660,7 @@ static HRESULT Update2St(
596 } 660 }
597 // seqMode = true; // to test seqMode 661 // seqMode = true; // to test seqMode
598 662
599 UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); 663 UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
600 664
601 CCompressingResult compressingResult; 665 CCompressingResult compressingResult;
602 666
@@ -629,10 +693,11 @@ static HRESULT Update2St(
629 SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); 693 SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
630 694
631 archive.WriteLocalHeader_Replace(item); 695 archive.WriteLocalHeader_Replace(item);
632 696 }
633 RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); 697 // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode()))
634 unpackSizeTotal += item.Size; 698 RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
635 packSizeTotal += item.PackSize; 699 unpackSizeTotal += item.Size;
700 packSizeTotal += item.PackSize;
636 } 701 }
637 } 702 }
638 else 703 else
@@ -656,6 +721,14 @@ static HRESULT Update2St(
656 721
657 archive.WriteCentralDir(items, comment); 722 archive.WriteCentralDir(items, comment);
658 723
724 /*
725 CTotalStats stat;
726 stat.Size = unpackSizeTotal;
727 stat.PackSize = packSizeTotal;
728 if (reportArcProp)
729 RINOK(ReportArcProps(reportArcProp, stat))
730 */
731
659 lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; 732 lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1;
660 return lps->SetCur(); 733 return lps->SetCur();
661} 734}
@@ -667,6 +740,7 @@ static HRESULT Update2(
667 CInArchive *inArchive, 740 CInArchive *inArchive,
668 const CObjectVector<CItemEx> &inputItems, 741 const CObjectVector<CItemEx> &inputItems,
669 CObjectVector<CUpdateItem> &updateItems, 742 CObjectVector<CUpdateItem> &updateItems,
743 const CUpdateOptions &updateOptions,
670 const CCompressionMethodMode &options, bool outSeqMode, 744 const CCompressionMethodMode &options, bool outSeqMode,
671 const CByteBuffer *comment, 745 const CByteBuffer *comment,
672 IArchiveUpdateCallback *updateCallback) 746 IArchiveUpdateCallback *updateCallback)
@@ -674,6 +748,11 @@ static HRESULT Update2(
674 CMyComPtr<IArchiveUpdateCallbackFile> opCallback; 748 CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
675 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); 749 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
676 750
751 /*
752 CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
753 updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
754 */
755
677 bool unknownComplexity = false; 756 bool unknownComplexity = false;
678 UInt64 complexity = 0; 757 UInt64 complexity = 0;
679 UInt64 numFilesToCompress = 0; 758 UInt64 numFilesToCompress = 0;
@@ -901,11 +980,23 @@ static HRESULT Update2(
901 return Update2St( 980 return Update2St(
902 EXTERNAL_CODECS_LOC_VARS 981 EXTERNAL_CODECS_LOC_VARS
903 archive, inArchive, 982 archive, inArchive,
904 inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback); 983 inputItems, updateItems,
984 updateOptions,
985 &options2, outSeqMode,
986 comment, updateCallback, totalComplexity,
987 opCallback
988 // , reportArcProp
989 );
905 990
906 991
907 #ifndef _7ZIP_ST 992 #ifndef _7ZIP_ST
908 993
994 /*
995 CTotalStats stat;
996 stat.Size = 0;
997 stat.PackSize = 0;
998 */
999
909 CObjectVector<CItemOut> items; 1000 CObjectVector<CItemOut> items;
910 1001
911 CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; 1002 CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
@@ -1021,7 +1112,7 @@ static HRESULT Update2(
1021 RINOK(res); 1112 RINOK(res);
1022 if (!fileInStream) 1113 if (!fileInStream)
1023 return E_INVALIDARG; 1114 return E_INVALIDARG;
1024 UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); 1115 UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
1025 RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); 1116 RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
1026 } 1117 }
1027 1118
@@ -1122,6 +1213,13 @@ static HRESULT Update2(
1122 memRef.WriteToStream(memManager.GetBlockSize(), outStream); 1213 memRef.WriteToStream(memManager.GetBlockSize(), outStream);
1123 archive.MoveCurPos(item.PackSize); 1214 archive.MoveCurPos(item.PackSize);
1124 memRef.FreeOpt(&memManager); 1215 memRef.FreeOpt(&memManager);
1216 /*
1217 if (reportArcProp)
1218 {
1219 stat.UpdateWithItem(item);
1220 RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
1221 }
1222 */
1125 } 1223 }
1126 else 1224 else
1127 { 1225 {
@@ -1202,6 +1300,14 @@ static HRESULT Update2(
1202 options.IsRealAesMode(), options.AesKeyMode, item); 1300 options.IsRealAesMode(), options.AesKeyMode, item);
1203 1301
1204 archive.WriteLocalHeader_Replace(item); 1302 archive.WriteLocalHeader_Replace(item);
1303
1304 /*
1305 if (reportArcProp)
1306 {
1307 stat.UpdateWithItem(item);
1308 RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
1309 }
1310 */
1205 } 1311 }
1206 else 1312 else
1207 { 1313 {
@@ -1230,7 +1336,14 @@ static HRESULT Update2(
1230 RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)); 1336 RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL));
1231 1337
1232 archive.WriteCentralDir(items, comment); 1338 archive.WriteCentralDir(items, comment);
1233 1339
1340 /*
1341 if (reportArcProp)
1342 {
1343 RINOK(ReportArcProps(reportArcProp, stat));
1344 }
1345 */
1346
1234 complexity += kCentralHeaderSize * updateItems.Size() + 1; 1347 complexity += kCentralHeaderSize * updateItems.Size() + 1;
1235 mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); 1348 mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
1236 return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); 1349 return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
@@ -1472,6 +1585,7 @@ HRESULT Update(
1472 CObjectVector<CUpdateItem> &updateItems, 1585 CObjectVector<CUpdateItem> &updateItems,
1473 ISequentialOutStream *seqOutStream, 1586 ISequentialOutStream *seqOutStream,
1474 CInArchive *inArchive, bool removeSfx, 1587 CInArchive *inArchive, bool removeSfx,
1588 const CUpdateOptions &updateOptions,
1475 const CCompressionMethodMode &compressionMethodMode, 1589 const CCompressionMethodMode &compressionMethodMode,
1476 IArchiveUpdateCallback *updateCallback) 1590 IArchiveUpdateCallback *updateCallback)
1477{ 1591{
@@ -1529,6 +1643,7 @@ HRESULT Update(
1529 EXTERNAL_CODECS_LOC_VARS 1643 EXTERNAL_CODECS_LOC_VARS
1530 outArchive, inArchive, 1644 outArchive, inArchive,
1531 inputItems, updateItems, 1645 inputItems, updateItems,
1646 updateOptions,
1532 compressionMethodMode, outSeqMode, 1647 compressionMethodMode, outSeqMode,
1533 inArchive ? &inArchive->ArcInfo.Comment : NULL, 1648 inArchive ? &inArchive->ArcInfo.Comment : NULL,
1534 updateCallback); 1649 updateCallback);
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h
index 95e72a4..d1e3534 100644
--- a/CPP/7zip/Archive/Zip/ZipUpdate.h
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -30,7 +30,9 @@ struct CUpdateItem
30 bool NewData; 30 bool NewData;
31 bool NewProps; 31 bool NewProps;
32 bool IsDir; 32 bool IsDir;
33 bool NtfsTimeIsDefined; 33 bool Write_NtfsTime;
34 bool Write_UnixTime;
35 // bool Write_UnixTime_ATime;
34 bool IsUtf8; 36 bool IsUtf8;
35 // bool IsAltStream; 37 // bool IsAltStream;
36 int IndexInArc; 38 int IndexInArc;
@@ -50,30 +52,50 @@ struct CUpdateItem
50 void Clear() 52 void Clear()
51 { 53 {
52 IsDir = false; 54 IsDir = false;
53 NtfsTimeIsDefined = false; 55
56 Write_NtfsTime = false;
57 Write_UnixTime = false;
58
54 IsUtf8 = false; 59 IsUtf8 = false;
55 // IsAltStream = false; 60 // IsAltStream = false;
61 Time = 0;
56 Size = 0; 62 Size = 0;
57 Name.Empty(); 63 Name.Empty();
58 Name_Utf.Free(); 64 Name_Utf.Free();
59 Comment.Free(); 65 Comment.Free();
66
67 FILETIME_Clear(Ntfs_MTime);
68 FILETIME_Clear(Ntfs_ATime);
69 FILETIME_Clear(Ntfs_CTime);
60 } 70 }
61 71
62 CUpdateItem(): 72 CUpdateItem():
63 IsDir(false), 73 IsDir(false),
64 NtfsTimeIsDefined(false), 74 Write_NtfsTime(false),
75 Write_UnixTime(false),
65 IsUtf8(false), 76 IsUtf8(false),
66 // IsAltStream(false), 77 // IsAltStream(false),
78 Time(0),
67 Size(0) 79 Size(0)
68 {} 80 {}
69}; 81};
70 82
83
84struct CUpdateOptions
85{
86 bool Write_MTime;
87 bool Write_ATime;
88 bool Write_CTime;
89};
90
91
71HRESULT Update( 92HRESULT Update(
72 DECL_EXTERNAL_CODECS_LOC_VARS 93 DECL_EXTERNAL_CODECS_LOC_VARS
73 const CObjectVector<CItemEx> &inputItems, 94 const CObjectVector<CItemEx> &inputItems,
74 CObjectVector<CUpdateItem> &updateItems, 95 CObjectVector<CUpdateItem> &updateItems,
75 ISequentialOutStream *seqOutStream, 96 ISequentialOutStream *seqOutStream,
76 CInArchive *inArchive, bool removeSfx, 97 CInArchive *inArchive, bool removeSfx,
98 const CUpdateOptions &updateOptions,
77 const CCompressionMethodMode &compressionMethodMode, 99 const CCompressionMethodMode &compressionMethodMode,
78 IArchiveUpdateCallback *updateCallback); 100 IArchiveUpdateCallback *updateCallback);
79 101
diff --git a/CPP/7zip/Bundles/Alone2/makefile b/CPP/7zip/Bundles/Alone2/makefile
index 56de5b2..357e78e 100644
--- a/CPP/7zip/Bundles/Alone2/makefile
+++ b/CPP/7zip/Bundles/Alone2/makefile
@@ -18,7 +18,6 @@ WIN_OBJS = $(WIN_OBJS) \
18 $O\FileLink.obj \ 18 $O\FileLink.obj \
19 $O\FileSystem.obj \ 19 $O\FileSystem.obj \
20 $O\MemoryLock.obj \ 20 $O\MemoryLock.obj \
21 $O\PropVariantConv.obj \
22 $O\Registry.obj \ 21 $O\Registry.obj \
23 $O\SystemInfo.obj \ 22 $O\SystemInfo.obj \
24 23
diff --git a/CPP/7zip/Bundles/Alone2/makefile.gcc b/CPP/7zip/Bundles/Alone2/makefile.gcc
index 1e7e17f..f8d31db 100644
--- a/CPP/7zip/Bundles/Alone2/makefile.gcc
+++ b/CPP/7zip/Bundles/Alone2/makefile.gcc
@@ -81,7 +81,6 @@ COMMON_OBJS_2 = \
81WIN_OBJS_2 = \ 81WIN_OBJS_2 = \
82 $O/ErrorMsg.o \ 82 $O/ErrorMsg.o \
83 $O/FileLink.o \ 83 $O/FileLink.o \
84 $O/PropVariantConv.o \
85 $O/SystemInfo.o \ 84 $O/SystemInfo.o \
86 85
877ZIP_COMMON_OBJS_2 = \ 867ZIP_COMMON_OBJS_2 = \
diff --git a/CPP/7zip/Bundles/Fm/makefile b/CPP/7zip/Bundles/Fm/makefile
index 2c80ca1..33813e8 100644
--- a/CPP/7zip/Bundles/Fm/makefile
+++ b/CPP/7zip/Bundles/Fm/makefile
@@ -20,7 +20,6 @@ WIN_OBJS = $(WIN_OBJS) \
20 $O\MemoryLock.obj \ 20 $O\MemoryLock.obj \
21 $O\Menu.obj \ 21 $O\Menu.obj \
22 $O\ProcessUtils.obj \ 22 $O\ProcessUtils.obj \
23 $O\PropVariantConv.obj \
24 $O\Registry.obj \ 23 $O\Registry.obj \
25 $O\ResourceString.obj \ 24 $O\ResourceString.obj \
26 $O\SystemInfo.obj \ 25 $O\SystemInfo.obj \
diff --git a/CPP/7zip/Bundles/Fm/resource.rc b/CPP/7zip/Bundles/Fm/resource.rc
index ffcff11..ebc2f74 100644
--- a/CPP/7zip/Bundles/Fm/resource.rc
+++ b/CPP/7zip/Bundles/Fm/resource.rc
@@ -3,5 +3,5 @@
3 3
4STRINGTABLE 4STRINGTABLE
5BEGIN 5BEGIN
6 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs" 6 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs apfs"
7END 7END
diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak
index d8468a6..209aea3 100644
--- a/CPP/7zip/Bundles/Format7zF/Arc.mak
+++ b/CPP/7zip/Bundles/Format7zF/Arc.mak
@@ -24,6 +24,7 @@ WIN_OBJS = \
24 $O\FileIO.obj \ 24 $O\FileIO.obj \
25 $O\FileName.obj \ 25 $O\FileName.obj \
26 $O\PropVariant.obj \ 26 $O\PropVariant.obj \
27 $O\PropVariantConv.obj \
27 $O\PropVariantUtils.obj \ 28 $O\PropVariantUtils.obj \
28 $O\Synchronization.obj \ 29 $O\Synchronization.obj \
29 $O\System.obj \ 30 $O\System.obj \
@@ -53,6 +54,7 @@ WIN_OBJS = \
53 $O\VirtThread.obj \ 54 $O\VirtThread.obj \
54 55
55AR_OBJS = \ 56AR_OBJS = \
57 $O\ApfsHandler.obj \
56 $O\ApmHandler.obj \ 58 $O\ApmHandler.obj \
57 $O\ArHandler.obj \ 59 $O\ArHandler.obj \
58 $O\ArjHandler.obj \ 60 $O\ArjHandler.obj \
@@ -72,6 +74,7 @@ AR_OBJS = \
72 $O\HandlerCont.obj \ 74 $O\HandlerCont.obj \
73 $O\HfsHandler.obj \ 75 $O\HfsHandler.obj \
74 $O\IhexHandler.obj \ 76 $O\IhexHandler.obj \
77 $O\LpHandler.obj \
75 $O\LzhHandler.obj \ 78 $O\LzhHandler.obj \
76 $O\LzmaHandler.obj \ 79 $O\LzmaHandler.obj \
77 $O\MachoHandler.obj \ 80 $O\MachoHandler.obj \
@@ -83,6 +86,7 @@ AR_OBJS = \
83 $O\PpmdHandler.obj \ 86 $O\PpmdHandler.obj \
84 $O\QcowHandler.obj \ 87 $O\QcowHandler.obj \
85 $O\RpmHandler.obj \ 88 $O\RpmHandler.obj \
89 $O\SparseHandler.obj \
86 $O\SplitHandler.obj \ 90 $O\SplitHandler.obj \
87 $O\SquashfsHandler.obj \ 91 $O\SquashfsHandler.obj \
88 $O\SwfHandler.obj \ 92 $O\SwfHandler.obj \
diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
index 8021f68..e5e1e21 100644
--- a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
+++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
@@ -59,6 +59,7 @@ WIN_OBJS = \
59 $O/FileIO.o \ 59 $O/FileIO.o \
60 $O/FileName.o \ 60 $O/FileName.o \
61 $O/PropVariant.o \ 61 $O/PropVariant.o \
62 $O/PropVariantConv.o \
62 $O/PropVariantUtils.o \ 63 $O/PropVariantUtils.o \
63 $O/System.o \ 64 $O/System.o \
64 $O/TimeUtils.o \ 65 $O/TimeUtils.o \
@@ -82,6 +83,7 @@ WIN_OBJS = \
82 $O/UniqBlocks.o \ 83 $O/UniqBlocks.o \
83 84
84AR_OBJS = \ 85AR_OBJS = \
86 $O/ApfsHandler.o \
85 $O/ApmHandler.o \ 87 $O/ApmHandler.o \
86 $O/ArHandler.o \ 88 $O/ArHandler.o \
87 $O/ArjHandler.o \ 89 $O/ArjHandler.o \
@@ -101,6 +103,7 @@ AR_OBJS = \
101 $O/HandlerCont.o \ 103 $O/HandlerCont.o \
102 $O/HfsHandler.o \ 104 $O/HfsHandler.o \
103 $O/IhexHandler.o \ 105 $O/IhexHandler.o \
106 $O/LpHandler.o \
104 $O/LzhHandler.o \ 107 $O/LzhHandler.o \
105 $O/LzmaHandler.o \ 108 $O/LzmaHandler.o \
106 $O/MachoHandler.o \ 109 $O/MachoHandler.o \
@@ -112,6 +115,7 @@ AR_OBJS = \
112 $O/PpmdHandler.o \ 115 $O/PpmdHandler.o \
113 $O/QcowHandler.o \ 116 $O/QcowHandler.o \
114 $O/RpmHandler.o \ 117 $O/RpmHandler.o \
118 $O/SparseHandler.o \
115 $O/SplitHandler.o \ 119 $O/SplitHandler.o \
116 $O/SquashfsHandler.o \ 120 $O/SquashfsHandler.o \
117 $O/SwfHandler.o \ 121 $O/SwfHandler.o \
diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
index 6b55e93..cf2d9e8 100644
--- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
@@ -2763,6 +2763,10 @@ SOURCE=..\..\Archive\Udf\UdfIn.h
2763# End Group 2763# End Group
2764# Begin Source File 2764# Begin Source File
2765 2765
2766SOURCE=..\..\Archive\ApfsHandler.cpp
2767# End Source File
2768# Begin Source File
2769
2766SOURCE=..\..\Archive\ApmHandler.cpp 2770SOURCE=..\..\Archive\ApmHandler.cpp
2767# End Source File 2771# End Source File
2768# Begin Source File 2772# Begin Source File
@@ -2851,6 +2855,10 @@ SOURCE=..\..\Archive\IhexHandler.cpp
2851# End Source File 2855# End Source File
2852# Begin Source File 2856# Begin Source File
2853 2857
2858SOURCE=..\..\Archive\LpHandler.cpp
2859# End Source File
2860# Begin Source File
2861
2854SOURCE=..\..\Archive\LzhHandler.cpp 2862SOURCE=..\..\Archive\LzhHandler.cpp
2855# End Source File 2863# End Source File
2856# Begin Source File 2864# Begin Source File
@@ -2905,6 +2913,10 @@ SOURCE=..\..\Archive\RpmHandler.cpp
2905# End Source File 2913# End Source File
2906# Begin Source File 2914# Begin Source File
2907 2915
2916SOURCE=..\..\Archive\SparseHandler.cpp
2917# End Source File
2918# Begin Source File
2919
2908SOURCE=..\..\Archive\SplitHandler.cpp 2920SOURCE=..\..\Archive\SplitHandler.cpp
2909# End Source File 2921# End Source File
2910# Begin Source File 2922# Begin Source File
@@ -3029,6 +3041,14 @@ SOURCE=..\..\..\Windows\PropVariant.h
3029# End Source File 3041# End Source File
3030# Begin Source File 3042# Begin Source File
3031 3043
3044SOURCE=..\..\..\Windows\PropVariantConv.cpp
3045# End Source File
3046# Begin Source File
3047
3048SOURCE=..\..\..\Windows\PropVariantConv.h
3049# End Source File
3050# Begin Source File
3051
3032SOURCE=..\..\..\Windows\PropVariantUtils.cpp 3052SOURCE=..\..\..\Windows\PropVariantUtils.cpp
3033# End Source File 3053# End Source File
3034# Begin Source File 3054# Begin Source File
diff --git a/CPP/7zip/Bundles/Format7zF/resource.rc b/CPP/7zip/Bundles/Format7zF/resource.rc
index aaaabea..9c797c1 100644
--- a/CPP/7zip/Bundles/Format7zF/resource.rc
+++ b/CPP/7zip/Bundles/Format7zF/resource.rc
@@ -28,10 +28,11 @@ MY_VERSION_INFO_DLL("7z Plugin" , "7z")
2822 ICON "../../Archive/Icons/ntfs.ico" 2822 ICON "../../Archive/Icons/ntfs.ico"
2923 ICON "../../Archive/Icons/xz.ico" 2923 ICON "../../Archive/Icons/xz.ico"
3024 ICON "../../Archive/Icons/squashfs.ico" 3024 ICON "../../Archive/Icons/squashfs.ico"
3125 ICON "../../Archive/Icons/apfs.ico"
31 32
32 33
33 34
34STRINGTABLE 35STRINGTABLE
35BEGIN 36BEGIN
36 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24" 37 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 apfs:25"
37END 38END
diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
index a08d9c0..71436f6 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
@@ -515,7 +515,7 @@ static int main2(int numArgs, const char *args[])
515 515
516 if (inStreamSpec) 516 if (inStreamSpec)
517 { 517 {
518 if (!inStreamSpec->File.GetLength(fileSize)) 518 if (!inStreamSpec->GetLength(fileSize))
519 throw "Cannot get file length"; 519 throw "Cannot get file length";
520 fileSizeDefined = true; 520 fileSizeDefined = true;
521 if (!stdOutMode) 521 if (!stdOutMode)
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp
index 9e0e79c..6862a9b 100644
--- a/CPP/7zip/Common/FileStreams.cpp
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -2,18 +2,30 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5// #include <stdio.h>
6
5#ifndef _WIN32 7#ifndef _WIN32
6#include <fcntl.h> 8#include <fcntl.h>
7#include <unistd.h> 9#include <unistd.h>
8#include <errno.h> 10#include <errno.h>
9#include "../../Windows/FileFind.h" 11#include <grp.h>
12#include <pwd.h>
13
14// for major minor
15// BSD: <sys/types.h>
16#include <sys/sysmacros.h>
17
10#endif 18#endif
11 19
20#include "../../Windows/FileFind.h"
21
12#ifdef SUPPORT_DEVICE_FILE 22#ifdef SUPPORT_DEVICE_FILE
13#include "../../../C/Alloc.h" 23#include "../../../C/Alloc.h"
14#include "../../Common/Defs.h" 24#include "../../Common/Defs.h"
15#endif 25#endif
16 26
27#include "../PropID.h"
28
17#include "FileStreams.h" 29#include "FileStreams.h"
18 30
19static inline HRESULT GetLastError_HRESULT() 31static inline HRESULT GetLastError_HRESULT()
@@ -37,12 +49,19 @@ static const UInt32 kClusterSize = 1 << 18;
37#endif 49#endif
38 50
39CInFileStream::CInFileStream(): 51CInFileStream::CInFileStream():
40 #ifdef SUPPORT_DEVICE_FILE 52 #ifdef SUPPORT_DEVICE_FILE
41 VirtPos(0), 53 VirtPos(0),
42 PhyPos(0), 54 PhyPos(0),
43 Buf(0), 55 Buf(0),
44 BufSize(0), 56 BufSize(0),
45 #endif 57 #endif
58 #ifndef _WIN32
59 _uid(0),
60 _gid(0),
61 StoreOwnerId(false),
62 StoreOwnerName(false),
63 #endif
64 _info_WasLoaded(false),
46 SupportHardLinks(false), 65 SupportHardLinks(false),
47 Callback(NULL), 66 Callback(NULL),
48 CallbackRef(0) 67 CallbackRef(0)
@@ -56,7 +75,7 @@ CInFileStream::~CInFileStream()
56 #endif 75 #endif
57 76
58 if (Callback) 77 if (Callback)
59 Callback->InFileStream_On_Destroy(CallbackRef); 78 Callback->InFileStream_On_Destroy(this, CallbackRef);
60} 79}
61 80
62STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) 81STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
@@ -306,8 +325,14 @@ STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
306 325
307STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) 326STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
308{ 327{
328 if (!_info_WasLoaded)
329 RINOK(ReloadProps());
330 const BY_HANDLE_FILE_INFORMATION &info = _info;
331 /*
309 BY_HANDLE_FILE_INFORMATION info; 332 BY_HANDLE_FILE_INFORMATION info;
310 if (File.GetFileInformation(&info)) 333 if (!File.GetFileInformation(&info))
334 return GetLastError_HRESULT();
335 */
311 { 336 {
312 if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; 337 if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
313 if (cTime) *cTime = info.ftCreationTime; 338 if (cTime) *cTime = info.ftCreationTime;
@@ -316,13 +341,18 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
316 if (attrib) *attrib = info.dwFileAttributes; 341 if (attrib) *attrib = info.dwFileAttributes;
317 return S_OK; 342 return S_OK;
318 } 343 }
319 return GetLastError_HRESULT();
320} 344}
321 345
322STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) 346STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
323{ 347{
348 if (!_info_WasLoaded)
349 RINOK(ReloadProps());
350 const BY_HANDLE_FILE_INFORMATION &info = _info;
351 /*
324 BY_HANDLE_FILE_INFORMATION info; 352 BY_HANDLE_FILE_INFORMATION info;
325 if (File.GetFileInformation(&info)) 353 if (!File.GetFileInformation(&info))
354 return GetLastError_HRESULT();
355 */
326 { 356 {
327 props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; 357 props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
328 props->VolID = info.dwVolumeSerialNumber; 358 props->VolID = info.dwVolumeSerialNumber;
@@ -335,27 +365,114 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
335 props->MTime = info.ftLastWriteTime; 365 props->MTime = info.ftLastWriteTime;
336 return S_OK; 366 return S_OK;
337 } 367 }
338 return GetLastError_HRESULT();
339} 368}
340 369
370STDMETHODIMP CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)
371{
372 if (!_info_WasLoaded)
373 RINOK(ReloadProps());
374
375 if (!_info_WasLoaded)
376 return S_OK;
377
378 NWindows::NCOM::CPropVariant prop;
379
380 #ifdef SUPPORT_DEVICE_FILE
381 if (File.IsDeviceFile)
382 {
383 switch (propID)
384 {
385 case kpidSize:
386 if (File.SizeDefined)
387 prop = File.Size;
388 break;
389 // case kpidAttrib: prop = (UInt32)0; break;
390 case kpidPosixAttrib:
391 {
392 prop = (UInt32)NWindows::NFile::NFind::NAttributes::
393 Get_PosixMode_From_WinAttrib(0);
394 /* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute
395 so we don't use MY_LIN_S_IFBLK here */
396 // prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug
397 break;
398 }
399 /*
400 case kpidDeviceMajor:
401 prop = (UInt32)8; // id for SCSI type device (sda)
402 break;
403 case kpidDeviceMinor:
404 prop = (UInt32)0;
405 break;
406 */
407 }
408 }
409 else
410 #endif
411 {
412 switch (propID)
413 {
414 case kpidSize:
415 {
416 const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow;
417 prop = size;
418 break;
419 }
420 case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break;
421 case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break;
422 case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break;
423 case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break;
424 case kpidPosixAttrib:
425 prop = (UInt32)NWindows::NFile::NFind::NAttributes::
426 Get_PosixMode_From_WinAttrib(_info.dwFileAttributes);
427 // | (UInt32)(1 << 21); // for debug
428 break;
429 }
430 }
431 prop.Detach(value);
432 return S_OK;
433}
434
435
436STDMETHODIMP CInFileStream::ReloadProps()
437{
438 #ifdef SUPPORT_DEVICE_FILE
439 if (File.IsDeviceFile)
440 {
441 memset(&_info, 0, sizeof(_info));
442 if (File.SizeDefined)
443 {
444 _info.nFileSizeHigh = (DWORD)(File.Size >> 32);
445 _info.nFileSizeLow = (DWORD)(File.Size);
446 }
447 _info.nNumberOfLinks = 1;
448 _info_WasLoaded = true;
449 return S_OK;
450 }
451 #endif
452 _info_WasLoaded = File.GetFileInformation(&_info);
453 if (!_info_WasLoaded)
454 return GetLastError_HRESULT();
455 return S_OK;
456}
457
458
341#elif !defined(_WIN32) 459#elif !defined(_WIN32)
342 460
343STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) 461STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
344{ 462{
463 if (!_info_WasLoaded)
464 RINOK(ReloadProps());
465 const struct stat &st = _info;
466 /*
345 struct stat st; 467 struct stat st;
346 if (File.my_fstat(&st) != 0) 468 if (File.my_fstat(&st) != 0)
347 return GetLastError_HRESULT(); 469 return GetLastError_HRESULT();
348 470 */
471
349 if (size) *size = (UInt64)st.st_size; 472 if (size) *size = (UInt64)st.st_size;
350 #ifdef __APPLE__ 473 if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime);
351 if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, *cTime); 474 if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime);
352 if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, *aTime); 475 if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime);
353 if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, *mTime);
354 #else
355 if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, *cTime);
356 if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, *aTime);
357 if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, *mTime);
358 #endif
359 if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); 476 if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
360 477
361 return S_OK; 478 return S_OK;
@@ -365,9 +482,14 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
365 482
366STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) 483STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
367{ 484{
485 if (!_info_WasLoaded)
486 RINOK(ReloadProps());
487 const struct stat &st = _info;
488 /*
368 struct stat st; 489 struct stat st;
369 if (File.my_fstat(&st) != 0) 490 if (File.my_fstat(&st) != 0)
370 return GetLastError_HRESULT(); 491 return GetLastError_HRESULT();
492 */
371 493
372 props->Size = (UInt64)st.st_size; 494 props->Size = (UInt64)st.st_size;
373 /* 495 /*
@@ -381,15 +503,9 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
381 props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long) 503 props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long)
382 props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); 504 props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
383 505
384 #ifdef __APPLE__ 506 FiTime_To_FILETIME (ST_CTIME(st), props->CTime);
385 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, props->CTime); 507 FiTime_To_FILETIME (ST_ATIME(st), props->ATime);
386 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, props->ATime); 508 FiTime_To_FILETIME (ST_MTIME(st), props->MTime);
387 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, props->MTime);
388 #else
389 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, props->CTime);
390 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, props->ATime);
391 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, props->MTime);
392 #endif
393 509
394 /* 510 /*
395 printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n" 511 printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
@@ -402,8 +518,130 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
402 return S_OK; 518 return S_OK;
403} 519}
404 520
521STDMETHODIMP CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)
522{
523 if (!_info_WasLoaded)
524 RINOK(ReloadProps());
525
526 if (!_info_WasLoaded)
527 return S_OK;
528
529 const struct stat &st = _info;
530
531 NWindows::NCOM::CPropVariant prop;
532 {
533 switch (propID)
534 {
535 case kpidSize: prop = (UInt64)st.st_size; break;
536 case kpidAttrib:
537 prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
538 break;
539 case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break;
540 case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break;
541 case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break;
542 case kpidPosixAttrib: prop = (UInt32)st.st_mode; break;
543
544 case kpidDeviceMajor:
545 {
546 // printf("\nst.st_rdev = %d\n", st.st_rdev);
547 if (S_ISCHR(st.st_mode) ||
548 S_ISBLK(st.st_mode))
549 prop = (UInt32)(major(st.st_rdev)); // + 1000);
550 // prop = (UInt32)12345678; // for debug
551 break;
552 }
553
554 case kpidDeviceMinor:
555 if (S_ISCHR(st.st_mode) ||
556 S_ISBLK(st.st_mode))
557 prop = (UInt32)(minor(st.st_rdev)); // + 100);
558 // prop = (UInt32)(st.st_rdev); // for debug
559 // printf("\nst.st_rdev = %d\n", st.st_rdev);
560 // prop = (UInt32)123456789; // for debug
561 break;
562
563 /*
564 case kpidDevice:
565 if (S_ISCHR(st.st_mode) ||
566 S_ISBLK(st.st_mode))
567 prop = (UInt64)(st.st_rdev);
568 break;
569 */
570
571 case kpidUserId:
572 {
573 if (StoreOwnerId)
574 prop = (UInt32)st.st_uid;
575 break;
576 }
577 case kpidGroupId:
578 {
579 if (StoreOwnerId)
580 prop = (UInt32)st.st_gid;
581 break;
582 }
583 case kpidUser:
584 {
585 if (StoreOwnerName)
586 {
587 const uid_t uid = st.st_uid;
588 {
589 if (!OwnerName.IsEmpty() && _uid == uid)
590 prop = OwnerName;
591 else
592 {
593 const passwd *pw = getpwuid(uid);
594 if (pw)
595 {
596 // we can use utf-8 here.
597 // prop = pw->pw_name;
598 }
599 }
600 }
601 }
602 break;
603 }
604 case kpidGroup:
605 {
606 if (StoreOwnerName)
607 {
608 const uid_t gid = st.st_gid;
609 {
610 if (!OwnerGroup.IsEmpty() && _gid == gid)
611 prop = OwnerGroup;
612 else
613 {
614 const group *gr = getgrgid(gid);
615 if (gr)
616 {
617 // we can use utf-8 here.
618 // prop = gr->gr_name;
619 }
620 }
621 }
622 }
623 break;
624 }
625 }
626 }
627 prop.Detach(value);
628 return S_OK;
629}
630
631
632STDMETHODIMP CInFileStream::ReloadProps()
633{
634 _info_WasLoaded = (File.my_fstat(&_info) == 0);
635 if (!_info_WasLoaded)
636 return GetLastError_HRESULT();
637 return S_OK;
638}
639
405#endif 640#endif
406 641
642
643
644
407////////////////////////// 645//////////////////////////
408// COutFileStream 646// COutFileStream
409 647
diff --git a/CPP/7zip/Common/FileStreams.h b/CPP/7zip/Common/FileStreams.h
index fe9f4c1..f2c19ee 100644
--- a/CPP/7zip/Common/FileStreams.h
+++ b/CPP/7zip/Common/FileStreams.h
@@ -14,10 +14,14 @@
14 14
15#include "../IStream.h" 15#include "../IStream.h"
16 16
17#include "UniqBlocks.h"
18
19
20class CInFileStream;
17struct IInFileStream_Callback 21struct IInFileStream_Callback
18{ 22{
19 virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0; 23 virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0;
20 virtual void InFileStream_On_Destroy(UINT_PTR val) = 0; 24 virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0;
21}; 25};
22 26
23class CInFileStream: 27class CInFileStream:
@@ -25,10 +29,11 @@ class CInFileStream:
25 public IStreamGetSize, 29 public IStreamGetSize,
26 public IStreamGetProps, 30 public IStreamGetProps,
27 public IStreamGetProps2, 31 public IStreamGetProps2,
32 public IStreamGetProp,
28 public CMyUnknownImp 33 public CMyUnknownImp
29{ 34{
30public:
31 NWindows::NFile::NIO::CInFile File; 35 NWindows::NFile::NIO::CInFile File;
36public:
32 37
33 #ifdef USE_WIN_FILE 38 #ifdef USE_WIN_FILE
34 39
@@ -42,22 +47,46 @@ public:
42 47
43 #endif 48 #endif
44 49
50 #ifdef _WIN32
51 BY_HANDLE_FILE_INFORMATION _info;
52 #else
53 struct stat _info;
54 UInt32 _uid;
55 UInt32 _gid;
56 UString OwnerName;
57 UString OwnerGroup;
58 bool StoreOwnerId;
59 bool StoreOwnerName;
60 #endif
61
62 bool _info_WasLoaded;
45 bool SupportHardLinks; 63 bool SupportHardLinks;
46
47 IInFileStream_Callback *Callback; 64 IInFileStream_Callback *Callback;
48 UINT_PTR CallbackRef; 65 UINT_PTR CallbackRef;
49 66
50 virtual ~CInFileStream(); 67 virtual ~CInFileStream();
51 68
52 CInFileStream(); 69 CInFileStream();
70
71 void Set_PreserveATime(bool v)
72 {
73 File.PreserveATime = v;
74 }
75
76 bool GetLength(UInt64 &length) const throw()
77 {
78 return File.GetLength(length);
79 }
53 80
54 bool Open(CFSTR fileName) 81 bool Open(CFSTR fileName)
55 { 82 {
83 _info_WasLoaded = false;
56 return File.Open(fileName); 84 return File.Open(fileName);
57 } 85 }
58 86
59 bool OpenShared(CFSTR fileName, bool shareForWrite) 87 bool OpenShared(CFSTR fileName, bool shareForWrite)
60 { 88 {
89 _info_WasLoaded = false;
61 return File.OpenShared(fileName, shareForWrite); 90 return File.OpenShared(fileName, shareForWrite);
62 } 91 }
63 92
@@ -65,6 +94,7 @@ public:
65 MY_QUERYINTERFACE_ENTRY(IStreamGetSize) 94 MY_QUERYINTERFACE_ENTRY(IStreamGetSize)
66 MY_QUERYINTERFACE_ENTRY(IStreamGetProps) 95 MY_QUERYINTERFACE_ENTRY(IStreamGetProps)
67 MY_QUERYINTERFACE_ENTRY(IStreamGetProps2) 96 MY_QUERYINTERFACE_ENTRY(IStreamGetProps2)
97 MY_QUERYINTERFACE_ENTRY(IStreamGetProp)
68 MY_QUERYINTERFACE_END 98 MY_QUERYINTERFACE_END
69 MY_ADDREF_RELEASE 99 MY_ADDREF_RELEASE
70 100
@@ -74,6 +104,8 @@ public:
74 STDMETHOD(GetSize)(UInt64 *size); 104 STDMETHOD(GetSize)(UInt64 *size);
75 STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib); 105 STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib);
76 STDMETHOD(GetProps2)(CStreamFileProps *props); 106 STDMETHOD(GetProps2)(CStreamFileProps *props);
107 STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
108 STDMETHOD(ReloadProps)();
77}; 109};
78 110
79class CStdInFileStream: 111class CStdInFileStream:
@@ -110,11 +142,11 @@ public:
110 142
111 UInt64 ProcessedSize; 143 UInt64 ProcessedSize;
112 144
113 bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) 145 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
114 { 146 {
115 return File.SetTime(cTime, aTime, mTime); 147 return File.SetTime(cTime, aTime, mTime);
116 } 148 }
117 bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); } 149 bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); }
118 150
119 MY_UNKNOWN_IMP1(IOutStream) 151 MY_UNKNOWN_IMP1(IOutStream)
120 152
diff --git a/CPP/7zip/Common/InBuffer.cpp b/CPP/7zip/Common/InBuffer.cpp
index 6f6eeca..fe6d149 100644
--- a/CPP/7zip/Common/InBuffer.cpp
+++ b/CPP/7zip/Common/InBuffer.cpp
@@ -77,7 +77,8 @@ bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
77{ 77{
78 if (!ReadBlock()) 78 if (!ReadBlock())
79 { 79 {
80 NumExtraBytes++; 80 // 22.00: we don't increment (NumExtraBytes) here
81 // NumExtraBytes++;
81 b = 0xFF; 82 b = 0xFF;
82 return false; 83 return false;
83 } 84 }
diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp
index add6636..980c795 100644
--- a/CPP/7zip/Common/LimitedStreams.cpp
+++ b/CPP/7zip/Common/LimitedStreams.cpp
@@ -154,44 +154,70 @@ STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize
154{ 154{
155 if (processedSize) 155 if (processedSize)
156 *processedSize = 0; 156 *processedSize = 0;
157 if (_virtPos >= Extents.Back().Virt) 157 const UInt64 virt = _virtPos;
158 if (virt >= Extents.Back().Virt)
158 return S_OK; 159 return S_OK;
159 if (size == 0) 160 if (size == 0)
160 return S_OK; 161 return S_OK;
161 162
162 unsigned left = 0, right = Extents.Size() - 1; 163 unsigned left = _prevExtentIndex;
163 for (;;) 164 if (virt < Extents[left].Virt ||
165 virt >= Extents[left + 1].Virt)
164 { 166 {
165 unsigned mid = (left + right) / 2; 167 left = 0;
166 if (mid == left) 168 unsigned right = Extents.Size() - 1;
167 break; 169 for (;;)
168 if (_virtPos < Extents[mid].Virt) 170 {
169 right = mid; 171 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
170 else 172 if (mid == left)
171 left = mid; 173 break;
174 if (virt < Extents[mid].Virt)
175 right = mid;
176 else
177 left = mid;
178 }
179 _prevExtentIndex = left;
172 } 180 }
173 181
174 const CSeekExtent &extent = Extents[left];
175 UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
176 if (_needStartSeek || _phyPos != phyPos)
177 { 182 {
178 _needStartSeek = false; 183 const UInt64 rem = Extents[left + 1].Virt - virt;
179 _phyPos = phyPos; 184 if (size > rem)
180 RINOK(SeekToPhys()); 185 size = (UInt32)rem;
181 } 186 }
182 187
183 UInt64 rem = Extents[left + 1].Virt - _virtPos; 188 const CSeekExtent &extent = Extents[left];
184 if (size > rem)
185 size = (UInt32)rem;
186 189
187 HRESULT res = Stream->Read(data, size, &size); 190 if (extent.Is_ZeroFill())
188 _phyPos += size; 191 {
192 memset(data, 0, size);
193 _virtPos += size;
194 if (processedSize)
195 *processedSize = size;
196 return S_OK;
197 }
198
199 {
200 const UInt64 phy = extent.Phy + (virt - extent.Virt);
201 if (_phyPos != phy)
202 {
203 _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
204 RINOK(Stream->Seek((Int64)phy, STREAM_SEEK_SET, NULL));
205 _phyPos = phy;
206 }
207 }
208
209 const HRESULT res = Stream->Read(data, size, &size);
189 _virtPos += size; 210 _virtPos += size;
211 if (res == S_OK)
212 _phyPos += size;
213 else
214 _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
190 if (processedSize) 215 if (processedSize)
191 *processedSize = size; 216 *processedSize = size;
192 return res; 217 return res;
193} 218}
194 219
220
195STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 221STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
196{ 222{
197 switch (seekOrigin) 223 switch (seekOrigin)
diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h
index ade2993..50c7cd8 100644
--- a/CPP/7zip/Common/LimitedStreams.h
+++ b/CPP/7zip/Common/LimitedStreams.h
@@ -101,21 +101,26 @@ public:
101 STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); 101 STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
102}; 102};
103 103
104
105
106const UInt64 k_SeekExtent_Phy_Type_ZeroFill = (UInt64)(Int64)-1;
107
104struct CSeekExtent 108struct CSeekExtent
105{ 109{
106 UInt64 Phy;
107 UInt64 Virt; 110 UInt64 Virt;
111 UInt64 Phy;
112
113 void SetAs_ZeroFill() { Phy = k_SeekExtent_Phy_Type_ZeroFill; }
114 bool Is_ZeroFill() const { return Phy == k_SeekExtent_Phy_Type_ZeroFill; }
108}; 115};
109 116
110class CExtentsStream: 117class CExtentsStream:
111 public IInStream, 118 public IInStream,
112 public CMyUnknownImp 119 public CMyUnknownImp
113{ 120{
114 UInt64 _phyPos;
115 UInt64 _virtPos; 121 UInt64 _virtPos;
116 bool _needStartSeek; 122 UInt64 _phyPos;
117 123 unsigned _prevExtentIndex;
118 HRESULT SeekToPhys() { return Stream->Seek((Int64)_phyPos, STREAM_SEEK_SET, NULL); }
119 124
120public: 125public:
121 CMyComPtr<IInStream> Stream; 126 CMyComPtr<IInStream> Stream;
@@ -129,11 +134,13 @@ public:
129 void Init() 134 void Init()
130 { 135 {
131 _virtPos = 0; 136 _virtPos = 0;
132 _phyPos = 0; 137 _phyPos = (UInt64)0 - 1; // we need Seek() for Stream
133 _needStartSeek = true; 138 _prevExtentIndex = 0;
134 } 139 }
135}; 140};
136 141
142
143
137class CLimitedSequentialOutStream: 144class CLimitedSequentialOutStream:
138 public ISequentialOutStream, 145 public ISequentialOutStream,
139 public CMyUnknownImp 146 public CMyUnknownImp
diff --git a/CPP/7zip/Common/PropId.cpp b/CPP/7zip/Common/PropId.cpp
index 11d20d5..0e643e8 100644
--- a/CPP/7zip/Common/PropId.cpp
+++ b/CPP/7zip/Common/PropId.cpp
@@ -104,5 +104,12 @@ const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] =
104 VT_UI8, 104 VT_UI8,
105 VT_BOOL, 105 VT_BOOL,
106 VT_BSTR, 106 VT_BSTR,
107 VT_BSTR 107 VT_BSTR,
108 VT_BSTR,
109 VT_BOOL,
110 VT_FILETIME, // kpidChangeTime
111 VT_UI4,
112 VT_UI4,
113 VT_UI4,
114 VT_UI4 // kpidDeviceMinor
108}; 115};
diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h
index 3421ba1..a0384fa 100644
--- a/CPP/7zip/Common/RegisterArc.h
+++ b/CPP/7zip/Common/RegisterArc.h
@@ -7,7 +7,7 @@
7 7
8struct CArcInfo 8struct CArcInfo
9{ 9{
10 UInt16 Flags; 10 UInt32 Flags;
11 Byte Id; 11 Byte Id;
12 Byte SignatureSize; 12 Byte SignatureSize;
13 UInt16 SignatureOffset; 13 UInt16 SignatureOffset;
@@ -17,6 +17,8 @@ struct CArcInfo
17 const char *Ext; 17 const char *Ext;
18 const char *AddExt; 18 const char *AddExt;
19 19
20 UInt32 TimeFlags;
21
20 Func_CreateInArchive CreateInArchive; 22 Func_CreateInArchive CreateInArchive;
21 Func_CreateOutArchive CreateOutArchive; 23 Func_CreateOutArchive CreateOutArchive;
22 Func_IsArc IsArc; 24 Func_IsArc IsArc;
@@ -39,22 +41,22 @@ void RegisterArc(const CArcInfo *arcInfo) throw();
39 #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); } 41 #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); }
40#endif 42#endif
41 43
42#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \ 44#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
43 static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, crIn, crOut, isArc } ; \ 45 static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, tf, crIn, crOut, isArc } ; \
44 46
45#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \ 47#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
46 REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \ 48 REGISTER_ARC_V (n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
47 struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \ 49 struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \
48 static CRegisterArc g_RegisterArc; 50 static CRegisterArc g_RegisterArc;
49 51
50 52
51#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \ 53#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \
52 IMP_CreateArcIn_2(cls) \ 54 IMP_CreateArcIn_2(cls) \
53 REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, NULL, isArc) 55 REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, 0, CreateArc, NULL, isArc)
54 56
55#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \ 57#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \
56 IMP_CreateArcIn_2(cls) \ 58 IMP_CreateArcIn_2(cls) \
57 REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, CreateArc, NULL, isArc) 59 REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, 0, CreateArc, NULL, isArc)
58 60
59#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \ 61#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \
60 REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc) 62 REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc)
@@ -63,15 +65,15 @@ void RegisterArc(const CArcInfo *arcInfo) throw();
63 REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc) 65 REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc)
64 66
65 67
66#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, isArc) \ 68#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, tf, isArc) \
67 IMP_CreateArcIn \ 69 IMP_CreateArcIn \
68 IMP_CreateArcOut \ 70 IMP_CreateArcOut \
69 REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc) 71 REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc)
70 72
71#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, isArc) \ 73#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, tf, isArc) \
72 IMP_CreateArcIn \ 74 IMP_CreateArcIn \
73 IMP_CreateArcOut \ 75 IMP_CreateArcOut \
74 REGISTER_ARC_V(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc) \ 76 REGISTER_ARC_V(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) \
75 struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \ 77 struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \
76 static CRegisterArcDecSig g_RegisterArc; 78 static CRegisterArcDecSig g_RegisterArc;
77 79
diff --git a/CPP/7zip/Common/UniqBlocks.cpp b/CPP/7zip/Common/UniqBlocks.cpp
index 8f754e1..32dc276 100644
--- a/CPP/7zip/Common/UniqBlocks.cpp
+++ b/CPP/7zip/Common/UniqBlocks.cpp
@@ -11,10 +11,10 @@ unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)
11 unsigned left = 0, right = Sorted.Size(); 11 unsigned left = 0, right = Sorted.Size();
12 while (left != right) 12 while (left != right)
13 { 13 {
14 unsigned mid = (left + right) / 2; 14 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
15 unsigned index = Sorted[mid]; 15 const unsigned index = Sorted[mid];
16 const CByteBuffer &buf = Bufs[index]; 16 const CByteBuffer &buf = Bufs[index];
17 size_t sizeMid = buf.Size(); 17 const size_t sizeMid = buf.Size();
18 if (size < sizeMid) 18 if (size < sizeMid)
19 right = mid; 19 right = mid;
20 else if (size > sizeMid) 20 else if (size > sizeMid)
@@ -23,7 +23,7 @@ unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)
23 { 23 {
24 if (size == 0) 24 if (size == 0)
25 return index; 25 return index;
26 int cmp = memcmp(data, buf, size); 26 const int cmp = memcmp(data, buf, size);
27 if (cmp == 0) 27 if (cmp == 0)
28 return index; 28 return index;
29 if (cmp < 0) 29 if (cmp < 0)
diff --git a/CPP/7zip/Common/UniqBlocks.h b/CPP/7zip/Common/UniqBlocks.h
index d6cd372..8479d68 100644
--- a/CPP/7zip/Common/UniqBlocks.h
+++ b/CPP/7zip/Common/UniqBlocks.h
@@ -3,9 +3,24 @@
3#ifndef __UNIQ_BLOCKS_H 3#ifndef __UNIQ_BLOCKS_H
4#define __UNIQ_BLOCKS_H 4#define __UNIQ_BLOCKS_H
5 5
6#include "../../Common/MyTypes.h"
7#include "../../Common/MyBuffer.h" 6#include "../../Common/MyBuffer.h"
8#include "../../Common/MyVector.h" 7#include "../../Common/MyString.h"
8
9struct C_UInt32_UString_Map
10{
11 CRecordVector<UInt32> Numbers;
12 UStringVector Strings;
13
14 void Add_UInt32(const UInt32 n)
15 {
16 Numbers.AddToUniqueSorted(n);
17 }
18 int Find(const UInt32 n)
19 {
20 return Numbers.FindInSorted(n);
21 }
22};
23
9 24
10struct CUniqBlocks 25struct CUniqBlocks
11{ 26{
diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp
index 25c3f04..62c15d6 100644
--- a/CPP/7zip/Compress/BZip2Encoder.cpp
+++ b/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -98,8 +98,8 @@ THREAD_FUNC_RET_TYPE CThreadInfo::ThreadFunc()
98 bool needLeave = true; 98 bool needLeave = true;
99 try 99 try
100 { 100 {
101 UInt32 blockSize = Encoder->ReadRleBlock(m_Block); 101 const UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
102 m_PackSize = Encoder->m_InStream.GetProcessedSize(); 102 m_UnpackSize = Encoder->m_InStream.GetProcessedSize();
103 m_BlockIndex = Encoder->NextBlockIndex; 103 m_BlockIndex = Encoder->NextBlockIndex;
104 if (++Encoder->NextBlockIndex == Encoder->NumThreads) 104 if (++Encoder->NextBlockIndex == Encoder->NumThreads)
105 Encoder->NextBlockIndex = 0; 105 Encoder->NextBlockIndex = 0;
@@ -222,7 +222,8 @@ UInt32 CEncoder::ReadRleBlock(Byte *buffer)
222 Byte prevByte; 222 Byte prevByte;
223 if (m_InStream.ReadByte(prevByte)) 223 if (m_InStream.ReadByte(prevByte))
224 { 224 {
225 UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; 225 NumBlocks++;
226 const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1;
226 unsigned numReps = 1; 227 unsigned numReps = 1;
227 buffer[i++] = prevByte; 228 buffer[i++] = prevByte;
228 while (i < blockSize) // "- 1" to support RLE 229 while (i < blockSize) // "- 1" to support RLE
@@ -722,8 +723,8 @@ HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
722 723
723 if (Encoder->Progress) 724 if (Encoder->Progress)
724 { 725 {
725 UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize(); 726 const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
726 res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize); 727 res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
727 } 728 }
728 729
729 Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); 730 Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
@@ -744,6 +745,7 @@ void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
744HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, 745HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
745 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) 746 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
746{ 747{
748 NumBlocks = 0;
747 #ifndef _7ZIP_ST 749 #ifndef _7ZIP_ST
748 Progress = progress; 750 Progress = progress;
749 RINOK(Create()); 751 RINOK(Create());
@@ -831,9 +833,9 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
831 RINOK(ti.EncodeBlock3(blockSize)); 833 RINOK(ti.EncodeBlock3(blockSize));
832 if (progress) 834 if (progress)
833 { 835 {
834 UInt64 packSize = m_InStream.GetProcessedSize(); 836 const UInt64 unpackSize = m_InStream.GetProcessedSize();
835 UInt64 unpackSize = m_OutStream.GetProcessedSize(); 837 const UInt64 packSize = m_OutStream.GetProcessedSize();
836 RINOK(progress->SetRatioInfo(&packSize, &unpackSize)); 838 RINOK(progress->SetRatioInfo(&unpackSize, &packSize));
837 } 839 }
838 } 840 }
839 } 841 }
@@ -845,7 +847,10 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
845 WriteByte(kFinSig5); 847 WriteByte(kFinSig5);
846 848
847 WriteCrc(CombinedCrc.GetDigest()); 849 WriteCrc(CombinedCrc.GetDigest());
848 return Flush(); 850 RINOK(Flush());
851 if (!m_InStream.WasFinished())
852 return E_FAIL;
853 return S_OK;
849} 854}
850 855
851STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 856STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
diff --git a/CPP/7zip/Compress/BZip2Encoder.h b/CPP/7zip/Compress/BZip2Encoder.h
index 5e63a73..e2828a9 100644
--- a/CPP/7zip/Compress/BZip2Encoder.h
+++ b/CPP/7zip/Compress/BZip2Encoder.h
@@ -129,7 +129,7 @@ public:
129 // it's not member of this thread. We just need one event per thread 129 // it's not member of this thread. We just need one event per thread
130 NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; 130 NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
131 131
132 UInt64 m_PackSize; 132 UInt64 m_UnpackSize;
133 133
134 Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. 134 Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
135 HRESULT Create(); 135 HRESULT Create();
@@ -195,6 +195,10 @@ public:
195 CThreadInfo ThreadsInfo; 195 CThreadInfo ThreadsInfo;
196 #endif 196 #endif
197 197
198 UInt64 NumBlocks;
199
200 UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); }
201
198 UInt32 ReadRleBlock(Byte *buf); 202 UInt32 ReadRleBlock(Byte *buf);
199 void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); 203 void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
200 204
diff --git a/CPP/7zip/Compress/BitlDecoder.h b/CPP/7zip/Compress/BitlDecoder.h
index e85942c..825864d 100644
--- a/CPP/7zip/Compress/BitlDecoder.h
+++ b/CPP/7zip/Compress/BitlDecoder.h
@@ -155,6 +155,10 @@ public:
155 MY_FORCE_INLINE 155 MY_FORCE_INLINE
156 bool ReadAlignedByte_FromBuf(Byte &b) 156 bool ReadAlignedByte_FromBuf(Byte &b)
157 { 157 {
158 if (this->_stream.NumExtraBytes != 0)
159 if (this->_stream.NumExtraBytes >= 4
160 || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3))
161 return false;
158 if (this->_bitPos == kNumBigValueBits) 162 if (this->_bitPos == kNumBigValueBits)
159 return this->_stream.ReadByte_FromBuf(b); 163 return this->_stream.ReadByte_FromBuf(b);
160 b = (Byte)(_normalValue & 0xFF); 164 b = (Byte)(_normalValue & 0xFF);
diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp
index 0206ce8..e4f66b7 100644
--- a/CPP/7zip/Compress/DeflateDecoder.cpp
+++ b/CPP/7zip/Compress/DeflateDecoder.cpp
@@ -426,7 +426,6 @@ STDMETHODIMP CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *proces
426{ 426{
427 AlignToByte(); 427 AlignToByte();
428 UInt32 i = 0; 428 UInt32 i = 0;
429 if (!m_InBitStream.ExtraBitsWereRead())
430 { 429 {
431 for (i = 0; i < size; i++) 430 for (i = 0; i < size; i++)
432 { 431 {
diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp
index 4b3acd3..dabd77a 100644
--- a/CPP/7zip/Compress/LzmaEncoder.cpp
+++ b/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -9,14 +9,15 @@
9 9
10#include "LzmaEncoder.h" 10#include "LzmaEncoder.h"
11 11
12#include "../../Common/IntToString.h"
13#include "../../Windows/TimeUtils.h"
14
15// #define LOG_LZMA_THREADS 12// #define LOG_LZMA_THREADS
16 13
17#ifdef LOG_LZMA_THREADS 14#ifdef LOG_LZMA_THREADS
15
18#include <stdio.h> 16#include <stdio.h>
19 17
18#include "../../Common/IntToString.h"
19#include "../../Windows/TimeUtils.h"
20
20EXTERN_C_BEGIN 21EXTERN_C_BEGIN
21void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]); 22void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]);
22EXTERN_C_END 23EXTERN_C_END
diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt
index 3b654bc..8fcdd84 100644
--- a/CPP/7zip/Guid.txt
+++ b/CPP/7zip/Guid.txt
@@ -19,6 +19,7 @@
19 0F IOutFolderArchive 19 0F IOutFolderArchive
20 10 IFolderArchiveUpdateCallback2 20 10 IFolderArchiveUpdateCallback2
21 11 IFolderScanProgress 21 11 IFolderScanProgress
22 12 IFolderSetZoneIdMode
22 23
23 20 IFileExtractCallback.h::IGetProp 24 20 IFileExtractCallback.h::IGetProp
24 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old) 25 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old)
@@ -34,6 +35,7 @@
34 07 IOutStreamFinish 35 07 IOutStreamFinish
35 08 IStreamGetProps 36 08 IStreamGetProps
36 09 IStreamGetProps2 37 09 IStreamGetProps2
38 0A IStreamGetProp
37 39
38 40
3904 ICoder.h 4104 ICoder.h
@@ -106,6 +108,8 @@
106 82 IArchiveUpdateCallback2 108 82 IArchiveUpdateCallback2
107 83 IArchiveUpdateCallbackFile 109 83 IArchiveUpdateCallbackFile
108 84 IArchiveGetDiskProperty 110 84 IArchiveGetDiskProperty
111 85 IArchiveUpdateCallbackArcProp (Reserved)
112
109 113
110 A0 IOutArchive 114 A0 IOutArchive
111 115
@@ -169,6 +173,10 @@ Handler GUIDs:
169 0C xz 173 0C xz
170 0D ppmd 174 0D ppmd
171 175
176 C0 AVB
177 C1 LP
178 C2 Sparse
179 C3 APFS
172 C4 Vhdx 180 C4 Vhdx
173 C5 Base64 181 C5 Base64
174 C6 COFF 182 C6 COFF
diff --git a/CPP/7zip/IStream.h b/CPP/7zip/IStream.h
index 48c67c1..2793a1e 100644
--- a/CPP/7zip/IStream.h
+++ b/CPP/7zip/IStream.h
@@ -133,4 +133,11 @@ STREAM_INTERFACE(IStreamGetProps2, 0x09)
133 STDMETHOD(GetProps2)(CStreamFileProps *props) PURE; 133 STDMETHOD(GetProps2)(CStreamFileProps *props) PURE;
134}; 134};
135 135
136
137STREAM_INTERFACE(IStreamGetProp, 0x0a)
138{
139 STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) PURE;
140 STDMETHOD(ReloadProps)() PURE;
141};
142
136#endif 143#endif
diff --git a/CPP/7zip/PropID.h b/CPP/7zip/PropID.h
index b818954..2da636f 100644
--- a/CPP/7zip/PropID.h
+++ b/CPP/7zip/PropID.h
@@ -105,7 +105,11 @@ enum
105 kpidCopyLink, 105 kpidCopyLink,
106 kpidArcFileName, 106 kpidArcFileName,
107 kpidIsHash, 107 kpidIsHash,
108 108 kpidChangeTime,
109 kpidUserId,
110 kpidGroupId,
111 kpidDeviceMajor,
112 kpidDeviceMinor,
109 113
110 kpid_NUM_DEFINED, 114 kpid_NUM_DEFINED,
111 115
@@ -127,4 +131,46 @@ const UInt32 kpv_ErrorFlags_DataError = 1 << 9;
127const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; 131const UInt32 kpv_ErrorFlags_CrcError = 1 << 10;
128// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; 132// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11;
129 133
134/*
135linux ctime :
136 file metadata was last changed.
137 changing the file modification time
138 counts as a metadata change, so will also have the side effect of updating the ctime.
139
140PROPVARIANT for timestamps in 7-Zip:
141{
142 vt = VT_FILETIME
143 wReserved1: set precision level
144 0 : base value (backward compatibility value)
145 only filetime is used (7 digits precision).
146 wReserved2 and wReserved3 can contain random data
147 1 : Unix (1 sec)
148 2 : DOS (2 sec)
149 3 : High Precision (1 ns)
150 16 - 3 : (reserved) = 1 day
151 16 - 2 : (reserved) = 1 hour
152 16 - 1 : (reserved) = 1 minute
153 16 + 0 : 1 sec (0 digits after point)
154 16 + (1,2,3,4,5,6,7,8,9) : set subsecond precision level :
155 (number of decimal digits after point)
156 16 + 9 : 1 ns (9 digits after point)
157 wReserved2 = ns % 100 : if (8 or 9 digits pecision)
158 = 0 : if not (8 or 9 digits pecision)
159 wReserved3 = 0;
160 filetime
161}
162
163NOTE: TAR-PAX archives created by GNU TAR don't keep
164 whole information about original level of precision,
165 and timestamp are stored in reduced form, where tail zero
166 digits after point are removed.
167 So 7-Zip can return different precision levels for different items for such TAR archives.
168*/
169
170/*
171TimePrec returned by IOutArchive::GetFileTimeType()
172is used only for updating, when we compare MTime timestamp
173from archive with timestamp from directory.
174*/
175
130#endif 176#endif
diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp
index cdb0e5d..cc20c11 100644
--- a/CPP/7zip/UI/Agent/Agent.cpp
+++ b/CPP/7zip/UI/Agent/Agent.cpp
@@ -25,6 +25,10 @@ using namespace NWindows;
25 25
26CCodecs *g_CodecsObj; 26CCodecs *g_CodecsObj;
27 27
28static const bool k_keepEmptyDirPrefixes =
29 false; // 22.00
30 // true; // 21.07
31
28#ifdef EXTERNAL_CODECS 32#ifdef EXTERNAL_CODECS
29 CExternalCodecs g_ExternalCodecs; 33 CExternalCodecs g_ExternalCodecs;
30 const CExternalCodecs *g_ExternalCodecs_Ptr; 34 const CExternalCodecs *g_ExternalCodecs_Ptr;
@@ -114,9 +118,9 @@ void CAgentFolder::LoadFolder(unsigned proxyDirIndex)
114 item.Index = i; 118 item.Index = i;
115 _items.Add(item); 119 _items.Add(item);
116 const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; 120 const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
117 if (file.DirIndex >= 0) 121 if (file.DirIndex != -1)
118 LoadFolder(file.DirIndex); 122 LoadFolder(file.DirIndex);
119 if (_loadAltStreams && file.AltDirIndex >= 0) 123 if (_loadAltStreams && file.AltDirIndex != -1)
120 LoadFolder(file.AltDirIndex); 124 LoadFolder(file.AltDirIndex);
121 } 125 }
122 return; 126 return;
@@ -211,21 +215,21 @@ void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const
211 unsigned len = 0; 215 unsigned len = 0;
212 while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) 216 while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
213 { 217 {
214 const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[proxyIndex].ArcIndex]; 218 const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
215 len += file.NameLen + 1; 219 len += file.NameLen + 1;
216 proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream); 220 proxyIndex = (file.Parent == -1) ? 0 : _proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
217 } 221 }
218 222
219 wchar_t *p = prefix.GetBuf_SetEnd(len) + len; 223 wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
220 proxyIndex = item.DirIndex; 224 proxyIndex = item.DirIndex;
221 while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) 225 while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
222 { 226 {
223 const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[proxyIndex].ArcIndex]; 227 const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
224 p--; 228 p--;
225 *p = WCHAR_PATH_SEPARATOR; 229 *p = WCHAR_PATH_SEPARATOR;
226 p -= file.NameLen; 230 p -= file.NameLen;
227 wmemcpy(p, file.Name, file.NameLen); 231 wmemcpy(p, file.Name, file.NameLen);
228 proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream); 232 proxyIndex = (file.Parent == -1) ? 0 : _proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
229 } 233 }
230 } 234 }
231 else 235 else
@@ -327,7 +331,7 @@ STDMETHODIMP CAgentFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT
327 /* 331 /*
328 if (propID == kpidNumAltStreams) 332 if (propID == kpidNumAltStreams)
329 { 333 {
330 if (item.AltDirIndex >= 0) 334 if (item.AltDirIndex != -1)
331 prop = _proxy2->Dirs[item.AltDirIndex].Items.Size(); 335 prop = _proxy2->Dirs[item.AltDirIndex].Items.Size();
332 } 336 }
333 else 337 else
@@ -887,12 +891,12 @@ STDMETHODIMP CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **res
887 if (_proxy2) 891 if (_proxy2)
888 { 892 {
889 int index = _proxy2->FindItem(_proxyDirIndex, name, true); 893 int index = _proxy2->FindItem(_proxyDirIndex, name, true);
890 if (index < 0) 894 if (index == -1)
891 return E_INVALIDARG; 895 return E_INVALIDARG;
892 return BindToFolder_Internal(_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder); 896 return BindToFolder_Internal(_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder);
893 } 897 }
894 int index = _proxy->FindSubDir(_proxyDirIndex, name); 898 int index = _proxy->FindSubDir(_proxyDirIndex, name);
895 if (index < 0) 899 if (index == -1)
896 return E_INVALIDARG; 900 return E_INVALIDARG;
897 return BindToFolder_Internal(index, resultFolder); 901 return BindToFolder_Internal(index, resultFolder);
898 COM_TRY_END 902 COM_TRY_END
@@ -956,7 +960,7 @@ STDMETHODIMP CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **result
956 { 960 {
957 unsigned arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex; 961 unsigned arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex;
958 const CProxyFile2 &item = _proxy2->Files[arcIndex]; 962 const CProxyFile2 &item = _proxy2->Files[arcIndex];
959 if (item.AltDirIndex < 0) 963 if (item.AltDirIndex == -1)
960 return S_OK; 964 return S_OK;
961 altDirIndex = item.AltDirIndex; 965 altDirIndex = item.AltDirIndex;
962 // parentFolder = _parentFolder; 966 // parentFolder = _parentFolder;
@@ -972,7 +976,7 @@ STDMETHODIMP CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **result
972 SET_realIndex_AND_dir_2 976 SET_realIndex_AND_dir_2
973 unsigned arcIndex = dir->Items[realIndex]; 977 unsigned arcIndex = dir->Items[realIndex];
974 const CProxyFile2 &item = _proxy2->Files[arcIndex]; 978 const CProxyFile2 &item = _proxy2->Files[arcIndex];
975 if (item.AltDirIndex < 0) 979 if (item.AltDirIndex == -1)
976 return S_OK; 980 return S_OK;
977 return BindToAltStreams_Internal(item.AltDirIndex, resultFolder); 981 return BindToAltStreams_Internal(item.AltDirIndex, resultFolder);
978 } 982 }
@@ -1000,7 +1004,7 @@ STDMETHODIMP CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder *
1000 FOR_VECTOR (i, dir.Items) 1004 FOR_VECTOR (i, dir.Items)
1001 { 1005 {
1002 const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; 1006 const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
1003 if (file.AltDirIndex >= 0) 1007 if (file.AltDirIndex != -1)
1004 if (CompareFileNames(file.Name, name) == 0) 1008 if (CompareFileNames(file.Name, name) == 0)
1005 return BindToAltStreams_Internal(file.AltDirIndex, resultFolder); 1009 return BindToAltStreams_Internal(file.AltDirIndex, resultFolder);
1006 } 1010 }
@@ -1036,7 +1040,7 @@ STDMETHODIMP CAgentFolder::AreAltStreamsSupported(UInt32 index, Int32 *isSupport
1036 arcIndex = dir->Items[realIndex]; 1040 arcIndex = dir->Items[realIndex];
1037 } 1041 }
1038 1042
1039 if (_proxy2->Files[arcIndex].AltDirIndex >= 0) 1043 if (_proxy2->Files[arcIndex].AltDirIndex != -1)
1040 *isSupported = BoolToInt(true); 1044 *isSupported = BoolToInt(true);
1041 return S_OK; 1045 return S_OK;
1042} 1046}
@@ -1062,18 +1066,18 @@ STDMETHODIMP CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder)
1062 else 1066 else
1063 { 1067 {
1064 const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex]; 1068 const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex];
1065 const CProxyFile2 &file = _proxy2->Files[fold.ArcIndex]; 1069 const CProxyFile2 &file = _proxy2->Files[(unsigned)fold.ArcIndex];
1066 int parentIndex = file.Parent; 1070 const int parentIndex = file.Parent;
1067 if (parentIndex < 0) 1071 if (parentIndex == -1)
1068 proxyDirIndex = k_Proxy2_RootDirIndex; 1072 proxyDirIndex = k_Proxy2_RootDirIndex;
1069 else 1073 else
1070 proxyDirIndex = _proxy2->Files[parentIndex].DirIndex; 1074 proxyDirIndex = _proxy2->Files[(unsigned)parentIndex].DirIndex;
1071 } 1075 }
1072 } 1076 }
1073 else 1077 else
1074 { 1078 {
1075 int parent = _proxy->Dirs[_proxyDirIndex].ParentDir; 1079 int parent = _proxy->Dirs[_proxyDirIndex].ParentDir;
1076 if (parent < 0) 1080 if (parent == -1)
1077 return S_OK; 1081 return S_OK;
1078 proxyDirIndex = parent; 1082 proxyDirIndex = parent;
1079 } 1083 }
@@ -1239,8 +1243,8 @@ STDMETHODIMP CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)
1239 const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; 1243 const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
1240 if (propID == kpidName) 1244 if (propID == kpidName)
1241 { 1245 {
1242 if (dir.ArcIndex >= 0) 1246 if (dir.ArcIndex != -1)
1243 prop = _proxy2->Files[dir.ArcIndex].Name; 1247 prop = _proxy2->Files[(unsigned)dir.ArcIndex].Name;
1244 } 1248 }
1245 else if (propID == kpidPath) 1249 else if (propID == kpidPath)
1246 { 1250 {
@@ -1477,8 +1481,8 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices,
1477 false, // multiArchives 1481 false, // multiArchives
1478 pathMode, 1482 pathMode,
1479 overwriteMode, 1483 overwriteMode,
1480 true // keepEmptyDirPrefixes 1484 _zoneMode,
1481 ); 1485 k_keepEmptyDirPrefixes);
1482 1486
1483 if (extractCallback2) 1487 if (extractCallback2)
1484 extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); 1488 extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize());
@@ -1500,6 +1504,15 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices,
1500 1504
1501 extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon); 1505 extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon);
1502 1506
1507 extractCallbackSpec->InitBeforeNewArchive();
1508
1509 #if defined(_WIN32) && !defined(UNDER_CE)
1510 if (_zoneMode != NExtract::NZoneIdMode::kNone)
1511 {
1512 ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf);
1513 }
1514 #endif
1515
1503 extractCallbackSpec->Init( 1516 extractCallbackSpec->Init(
1504 extractNtOptions, 1517 extractNtOptions,
1505 NULL, &_agentSpec->GetArc(), 1518 NULL, &_agentSpec->GetArc(),
@@ -1645,8 +1658,8 @@ STDMETHODIMP CAgent::Open(
1645 CArc &arc = _archiveLink.Arcs.Back(); 1658 CArc &arc = _archiveLink.Arcs.Back();
1646 if (!inStream) 1659 if (!inStream)
1647 { 1660 {
1648 arc.MTimeDefined = !fi.IsDevice; 1661 arc.MTime.Set_From_FiTime(fi.MTime);
1649 arc.MTime = fi.MTime; 1662 arc.MTime.Def = !fi.IsDevice;
1650 } 1663 }
1651 1664
1652 ArchiveType = GetTypeOfArc(arc); 1665 ArchiveType = GetTypeOfArc(arc);
@@ -1783,8 +1796,8 @@ STDMETHODIMP CAgent::Extract(
1783 false, // multiArchives 1796 false, // multiArchives
1784 pathMode, 1797 pathMode,
1785 overwriteMode, 1798 overwriteMode,
1786 true // keepEmptyDirPrefixes 1799 NExtract::NZoneIdMode::kNone,
1787 ); 1800 k_keepEmptyDirPrefixes);
1788 1801
1789 CExtractNtOptions extractNtOptions; 1802 CExtractNtOptions extractNtOptions;
1790 extractNtOptions.AltStreams.Val = true; // change it!!! 1803 extractNtOptions.AltStreams.Val = true; // change it!!!
diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h
index e9fe410..8e8a4c7 100644
--- a/CPP/7zip/UI/Agent/Agent.h
+++ b/CPP/7zip/UI/Agent/Agent.h
@@ -58,7 +58,7 @@ class CAgentFolder:
58 public IArchiveFolder, 58 public IArchiveFolder,
59 public IArchiveFolderInternal, 59 public IArchiveFolderInternal,
60 public IInArchiveGetStream, 60 public IInArchiveGetStream,
61 // public IFolderSetReplaceAltStreamCharsMode, 61 public IFolderSetZoneIdMode,
62#ifdef NEW_FOLDER_INTERFACE 62#ifdef NEW_FOLDER_INTERFACE
63 public IFolderOperations, 63 public IFolderOperations,
64 public IFolderSetFlatMode, 64 public IFolderSetFlatMode,
@@ -78,7 +78,7 @@ public:
78 MY_QUERYINTERFACE_ENTRY(IArchiveFolder) 78 MY_QUERYINTERFACE_ENTRY(IArchiveFolder)
79 MY_QUERYINTERFACE_ENTRY(IArchiveFolderInternal) 79 MY_QUERYINTERFACE_ENTRY(IArchiveFolderInternal)
80 MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream) 80 MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
81 // MY_QUERYINTERFACE_ENTRY(IFolderSetReplaceAltStreamCharsMode) 81 MY_QUERYINTERFACE_ENTRY(IFolderSetZoneIdMode)
82 #ifdef NEW_FOLDER_INTERFACE 82 #ifdef NEW_FOLDER_INTERFACE
83 MY_QUERYINTERFACE_ENTRY(IFolderOperations) 83 MY_QUERYINTERFACE_ENTRY(IFolderOperations)
84 MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode) 84 MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode)
@@ -92,7 +92,7 @@ public:
92 void GetRealIndices(const UInt32 *indices, UInt32 numItems, 92 void GetRealIndices(const UInt32 *indices, UInt32 numItems,
93 bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const; 93 bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const;
94 94
95 // INTERFACE_FolderSetReplaceAltStreamCharsMode(;) 95 INTERFACE_IFolderSetZoneIdMode(;)
96 96
97 INTERFACE_FolderFolder(;) 97 INTERFACE_FolderFolder(;)
98 INTERFACE_FolderAltStreams(;) 98 INTERFACE_FolderAltStreams(;)
@@ -123,6 +123,7 @@ public:
123 _isAltStreamFolder(false), 123 _isAltStreamFolder(false),
124 _flatMode(false), 124 _flatMode(false),
125 _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now 125 _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now
126 , _zoneMode(NExtract::NZoneIdMode::kNone)
126 /* , _replaceAltStreamCharsMode(0) */ 127 /* , _replaceAltStreamCharsMode(0) */
127 {} 128 {}
128 129
@@ -169,6 +170,7 @@ public:
169 bool _flatMode; 170 bool _flatMode;
170 bool _loadAltStreams; // in Flat mode 171 bool _loadAltStreams; // in Flat mode
171 // Int32 _replaceAltStreamCharsMode; 172 // Int32 _replaceAltStreamCharsMode;
173 NExtract::NZoneIdMode::EEnum _zoneMode;
172}; 174};
173 175
174class CAgent: 176class CAgent:
diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp
index fae0e22..da8da6c 100644
--- a/CPP/7zip/UI/Agent/AgentOut.cpp
+++ b/CPP/7zip/UI/Agent/AgentOut.cpp
@@ -12,6 +12,8 @@
12 12
13#include "../../Common/FileStreams.h" 13#include "../../Common/FileStreams.h"
14 14
15#include "../../Archive/Common/ItemNameUtils.h"
16
15#include "Agent.h" 17#include "Agent.h"
16#include "UpdateCallbackAgent.h" 18#include "UpdateCallbackAgent.h"
17 19
@@ -67,8 +69,8 @@ static HRESULT EnumerateArchiveItems(CAgent *agent,
67 unsigned arcIndex = item.SubFiles[i]; 69 unsigned arcIndex = item.SubFiles[i];
68 const CProxyFile &fileItem = agent->_proxy->Files[arcIndex]; 70 const CProxyFile &fileItem = agent->_proxy->Files[arcIndex];
69 CArcItem ai; 71 CArcItem ai;
70 RINOK(agent->GetArc().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); 72 RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime));
71 RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); 73 RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined));
72 ai.IsDir = false; 74 ai.IsDir = false;
73 ai.Name = prefix + fileItem.Name; 75 ai.Name = prefix + fileItem.Name;
74 ai.Censored = true; // test it 76 ai.Censored = true; // test it
@@ -83,9 +85,9 @@ static HRESULT EnumerateArchiveItems(CAgent *agent,
83 if (dirItem.IsLeaf()) 85 if (dirItem.IsLeaf())
84 { 86 {
85 CArcItem ai; 87 CArcItem ai;
86 RINOK(agent->GetArc().GetItemMTime(dirItem.ArcIndex, ai.MTime, ai.MTimeDefined)); 88 RINOK(agent->GetArc().GetItem_MTime(dirItem.ArcIndex, ai.MTime));
87 ai.IsDir = true; 89 ai.IsDir = true;
88 ai.SizeDefined = false; 90 ai.Size_Defined = false;
89 ai.Name = fullName; 91 ai.Name = fullName;
90 ai.Censored = true; // test it 92 ai.Censored = true; // test it
91 ai.IndexInServer = dirItem.ArcIndex; 93 ai.IndexInServer = dirItem.ArcIndex;
@@ -111,18 +113,18 @@ static HRESULT EnumerateArchiveItems2(const CAgent *agent,
111 ai.IndexInServer = arcIndex; 113 ai.IndexInServer = arcIndex;
112 ai.Name = prefix + file.Name; 114 ai.Name = prefix + file.Name;
113 ai.Censored = true; // test it 115 ai.Censored = true; // test it
114 RINOK(agent->GetArc().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); 116 RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime));
115 ai.IsDir = file.IsDir(); 117 ai.IsDir = file.IsDir();
116 ai.SizeDefined = false; 118 ai.Size_Defined = false;
117 ai.IsAltStream = file.IsAltStream; 119 ai.IsAltStream = file.IsAltStream;
118 if (!ai.IsDir) 120 if (!ai.IsDir)
119 { 121 {
120 RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); 122 RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined));
121 ai.IsDir = false; 123 ai.IsDir = false;
122 } 124 }
123 arcItems.Add(ai); 125 arcItems.Add(ai);
124 126
125 if (file.AltDirIndex >= 0) 127 if (file.AltDirIndex != -1)
126 { 128 {
127 RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems)); 129 RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems));
128 } 130 }
@@ -264,10 +266,13 @@ STDMETHODIMP CAgent::DoOperation(
264 #endif 266 #endif
265 } 267 }
266 268
267 NFileTimeType::EEnum fileTimeType; 269 NFileTimeType::EEnum fileTimeType = NFileTimeType::kNotDefined;
268 UInt32 value; 270 UInt32 value;
269 RINOK(outArchive->GetFileTimeType(&value)); 271 RINOK(outArchive->GetFileTimeType(&value));
270 272 // we support any future fileType here.
273 // 22.00:
274 fileTimeType = (NFileTimeType::EEnum)value;
275 /*
271 switch (value) 276 switch (value)
272 { 277 {
273 case NFileTimeType::kWindows: 278 case NFileTimeType::kWindows:
@@ -276,8 +281,11 @@ STDMETHODIMP CAgent::DoOperation(
276 fileTimeType = NFileTimeType::EEnum(value); 281 fileTimeType = NFileTimeType::EEnum(value);
277 break; 282 break;
278 default: 283 default:
284 {
279 return E_FAIL; 285 return E_FAIL;
286 }
280 } 287 }
288 */
281 289
282 290
283 CObjectVector<CArcItem> arcItems; 291 CObjectVector<CArcItem> arcItems;
@@ -389,11 +397,11 @@ STDMETHODIMP CAgent::DoOperation(
389 FOR_VECTOR(i, updatePairs2) 397 FOR_VECTOR(i, updatePairs2)
390 { 398 {
391 const CUpdatePair2 &up = updatePairs2[i]; 399 const CUpdatePair2 &up = updatePairs2[i];
392 if (up.DirIndex >= 0 && up.NewData) 400 if (up.DirIndex != -1 && up.NewData)
393 { 401 {
394 const CDirItem &di = dirItems.Items[up.DirIndex]; 402 const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex];
395 if (!di.IsDir() && di.Size == 0) 403 if (!di.IsDir() && di.Size == 0)
396 processedItems[up.DirIndex] = 1; 404 processedItems[(unsigned)up.DirIndex] = 1;
397 } 405 }
398 } 406 }
399 } 407 }
@@ -452,7 +460,7 @@ STDMETHODIMP CAgent::DeleteItems(ISequentialOutStream *outArchiveStream,
452 if (curIndex < realIndices.Size()) 460 if (curIndex < realIndices.Size())
453 if (realIndices[curIndex] == i) 461 if (realIndices[curIndex] == i)
454 { 462 {
455 RINOK(GetArc().GetItemPath2(i, deletePath)); 463 RINOK(GetArc().GetItem_Path2(i, deletePath));
456 RINOK(updateCallback100->DeleteOperation(deletePath)); 464 RINOK(updateCallback100->DeleteOperation(deletePath));
457 465
458 curIndex++; 466 curIndex++;
@@ -548,11 +556,14 @@ HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream,
548 true, // includeFolderSubItemsInFlatMode 556 true, // includeFolderSubItemsInFlatMode
549 realIndices); 557 realIndices);
550 558
551 int mainRealIndex = _agentFolder->GetRealIndex(indices[0]); 559 const UInt32 ind0 = indices[0];
552 560 const int mainRealIndex = _agentFolder->GetRealIndex(ind0);
553 UString fullPrefix = _agentFolder->GetFullPrefix(indices[0]); 561 const UString fullPrefix = _agentFolder->GetFullPrefix(ind0);
554 UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]); 562 UString name = _agentFolder->GetName(ind0);
555 UString newItemPath = fullPrefix + newItemName; 563 // 22.00 : we normalize name
564 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
565 const UString oldItemPath = fullPrefix + name;
566 const UString newItemPath = fullPrefix + newItemName;
556 567
557 UStringVector newNames; 568 UStringVector newNames;
558 569
@@ -568,10 +579,10 @@ HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream,
568 if (realIndices[curIndex] == i) 579 if (realIndices[curIndex] == i)
569 { 580 {
570 up2.NewProps = true; 581 up2.NewProps = true;
571 RINOK(GetArc().IsItemAnti(i, up2.IsAnti)); // it must work without that line too. 582 RINOK(GetArc().IsItem_Anti(i, up2.IsAnti)); // it must work without that line too.
572 583
573 UString oldFullPath; 584 UString oldFullPath;
574 RINOK(GetArc().GetItemPath2(i, oldFullPath)); 585 RINOK(GetArc().GetItem_Path2(i, oldFullPath));
575 586
576 if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath)) 587 if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath))
577 return E_INVALIDARG; 588 return E_INVALIDARG;
diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp
index f0acd20..4c9c386 100644
--- a/CPP/7zip/UI/Agent/AgentProxy.cpp
+++ b/CPP/7zip/UI/Agent/AgentProxy.cpp
@@ -18,6 +18,8 @@
18#include "../../../Windows/PropVariant.h" 18#include "../../../Windows/PropVariant.h"
19#include "../../../Windows/PropVariantConv.h" 19#include "../../../Windows/PropVariantConv.h"
20 20
21#include "../../Archive/Common/ItemNameUtils.h"
22
21#include "AgentProxy.h" 23#include "AgentProxy.h"
22 24
23using namespace NWindows; 25using namespace NWindows;
@@ -33,12 +35,12 @@ int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &inse
33 insertPos = left; 35 insertPos = left;
34 return -1; 36 return -1;
35 } 37 }
36 unsigned mid = (left + right) / 2; 38 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
37 unsigned dirIndex2 = subDirs[mid]; 39 const unsigned dirIndex2 = subDirs[mid];
38 int compare = CompareFileNames(name, Dirs[dirIndex2].Name); 40 const int comp = CompareFileNames(name, Dirs[dirIndex2].Name);
39 if (compare == 0) 41 if (comp == 0)
40 return dirIndex2; 42 return dirIndex2;
41 if (compare < 0) 43 if (comp < 0)
42 right = mid; 44 right = mid;
43 else 45 else
44 left = mid + 1; 46 left = mid + 1;
@@ -67,12 +69,12 @@ unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name)
67{ 69{
68 unsigned insertPos; 70 unsigned insertPos;
69 int subDirIndex = FindSubDir(dirIndex, name, insertPos); 71 int subDirIndex = FindSubDir(dirIndex, name, insertPos);
70 if (subDirIndex >= 0) 72 if (subDirIndex != -1)
71 { 73 {
72 if (arcIndex >= 0) 74 if (arcIndex != -1)
73 { 75 {
74 CProxyDir &item = Dirs[subDirIndex]; 76 CProxyDir &item = Dirs[(unsigned)subDirIndex];
75 if (item.ArcIndex < 0) 77 if (item.ArcIndex == -1)
76 item.ArcIndex = arcIndex; 78 item.ArcIndex = arcIndex;
77 } 79 }
78 return subDirIndex; 80 return subDirIndex;
@@ -98,27 +100,31 @@ void CProxyDir::Clear()
98void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const 100void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const
99{ 101{
100 pathParts.Clear(); 102 pathParts.Clear();
101 while (dirIndex >= 0) 103 while (dirIndex != -1)
102 { 104 {
103 const CProxyDir &dir = Dirs[dirIndex]; 105 const CProxyDir &dir = Dirs[dirIndex];
104 dirIndex = dir.ParentDir; 106 dirIndex = dir.ParentDir;
105 if (dirIndex < 0) 107 if (dirIndex == -1)
106 break; 108 break;
107 pathParts.Insert(0, dir.Name); 109 pathParts.Insert(0, dir.Name);
110 // 22.00: we normalize name
111 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]);
108 } 112 }
109} 113}
110 114
111UString CProxyArc::GetDirPath_as_Prefix(int dirIndex) const 115UString CProxyArc::GetDirPath_as_Prefix(int dirIndex) const
112{ 116{
113 UString s; 117 UString s;
114 while (dirIndex >= 0) 118 while (dirIndex != -1)
115 { 119 {
116 const CProxyDir &dir = Dirs[dirIndex]; 120 const CProxyDir &dir = Dirs[dirIndex];
117 dirIndex = dir.ParentDir; 121 dirIndex = dir.ParentDir;
118 if (dirIndex < 0) 122 if (dirIndex == -1)
119 break; 123 break;
120 s.InsertAtFront(WCHAR_PATH_SEPARATOR); 124 s.InsertAtFront(WCHAR_PATH_SEPARATOR);
121 s.Insert(0, dir.Name); 125 s.Insert(0, dir.Name);
126 // 22.00: we normalize name
127 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name));
122 } 128 }
123 return s; 129 return s;
124} 130}
@@ -251,7 +257,7 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
251 { 257 {
252 if (progress && (i & 0xFFFF) == 0) 258 if (progress && (i & 0xFFFF) == 0)
253 { 259 {
254 UInt64 currentItemIndex = i; 260 const UInt64 currentItemIndex = i;
255 RINOK(progress->SetCompleted(&currentItemIndex)); 261 RINOK(progress->SetCompleted(&currentItemIndex));
256 } 262 }
257 263
@@ -259,9 +265,9 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
259 unsigned len = 0; 265 unsigned len = 0;
260 bool isPtrName = false; 266 bool isPtrName = false;
261 267
262 #if WCHAR_PATH_SEPARATOR != L'/' 268 #if WCHAR_PATH_SEPARATOR != L'/'
263 wchar_t replaceFromChar = 0; 269 wchar_t separatorChar = WCHAR_PATH_SEPARATOR;
264 #endif 270 #endif
265 271
266 #if defined(MY_CPU_LE) && defined(_WIN32) 272 #if defined(MY_CPU_LE) && defined(_WIN32)
267 // it works only if (sizeof(wchar_t) == 2) 273 // it works only if (sizeof(wchar_t) == 2)
@@ -278,9 +284,9 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
278 len = size / 2 - 1; 284 len = size / 2 - 1;
279 s = (const wchar_t *)p; 285 s = (const wchar_t *)p;
280 isPtrName = true; 286 isPtrName = true;
281 #if WCHAR_PATH_SEPARATOR != L'/' 287 #if WCHAR_PATH_SEPARATOR != L'/'
282 replaceFromChar = L'\\'; 288 separatorChar = L'/'; // 0
283 #endif 289 #endif
284 } 290 }
285 } 291 }
286 if (!s) 292 if (!s)
@@ -297,7 +303,7 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
297 return E_FAIL; 303 return E_FAIL;
298 if (len == 0) 304 if (len == 0)
299 { 305 {
300 RINOK(arc.GetDefaultItemPath(i, path)); 306 RINOK(arc.GetItem_DefaultPath(i, path));
301 len = path.Len(); 307 len = path.Len();
302 s = path; 308 s = path;
303 } 309 }
@@ -328,16 +334,12 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
328 for (unsigned j = 0; j < len; j++) 334 for (unsigned j = 0; j < len; j++)
329 { 335 {
330 const wchar_t c = s[j]; 336 const wchar_t c = s[j];
331 if (c == WCHAR_PATH_SEPARATOR || c == L'/') 337 if (c == L'/'
332 {
333 #if WCHAR_PATH_SEPARATOR != L'/' 338 #if WCHAR_PATH_SEPARATOR != L'/'
334 if (c == replaceFromChar) 339 || (c == separatorChar)
335 {
336 // s.ReplaceOneCharAtPos(j, WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT);
337 continue;
338 }
339 #endif 340 #endif
340 341 )
342 {
341 const unsigned kLevelLimit = 1 << 10; 343 const unsigned kLevelLimit = 1 << 10;
342 if (numLevels <= kLevelLimit) 344 if (numLevels <= kLevelLimit)
343 { 345 {
@@ -345,6 +347,8 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
345 name = "[LONG_PATH]"; 347 name = "[LONG_PATH]";
346 else 348 else
347 name.SetFrom(s + namePos, j - namePos); 349 name.SetFrom(s + namePos, j - namePos);
350 // 22.00: we can normalize dir here
351 // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
348 curItem = AddDir(curItem, -1, name); 352 curItem = AddDir(curItem, -1, name);
349 } 353 }
350 namePos = j + 1; 354 namePos = j + 1;
@@ -384,6 +388,8 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
384 if (isDir) 388 if (isDir)
385 { 389 {
386 name = s; 390 name = s;
391 // 22.00: we can normalize dir here
392 // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
387 AddDir(curItem, (int)i, name); 393 AddDir(curItem, (int)i, name);
388 } 394 }
389 else 395 else
@@ -418,14 +424,14 @@ void CProxyArc2::GetDirPathParts(int dirIndex, UStringVector &pathParts, bool &i
418 while (dirIndex >= (int)k_Proxy2_NumRootDirs) 424 while (dirIndex >= (int)k_Proxy2_NumRootDirs)
419 { 425 {
420 const CProxyDir2 &dir = Dirs[dirIndex]; 426 const CProxyDir2 &dir = Dirs[dirIndex];
421 const CProxyFile2 &file = Files[dir.ArcIndex]; 427 const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
422 if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex) 428 if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex)
423 isAltStreamDir = true; 429 isAltStreamDir = true;
424 pathParts.Insert(0, file.Name); 430 pathParts.Insert(0, file.Name);
425 int par = file.Parent; 431 int par = file.Parent;
426 if (par < 0) 432 if (par == -1)
427 break; 433 break;
428 dirIndex = Files[par].DirIndex; 434 dirIndex = Files[(unsigned)par].DirIndex;
429 } 435 }
430} 436}
431 437
@@ -436,7 +442,7 @@ bool CProxyArc2::IsAltDir(unsigned dirIndex) const
436 if (dirIndex == k_Proxy2_AltRootDirIndex) 442 if (dirIndex == k_Proxy2_AltRootDirIndex)
437 return true; 443 return true;
438 const CProxyDir2 &dir = Dirs[dirIndex]; 444 const CProxyDir2 &dir = Dirs[dirIndex];
439 const CProxyFile2 &file = Files[dir.ArcIndex]; 445 const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
440 return ((int)dirIndex == file.AltDirIndex); 446 return ((int)dirIndex == file.AltDirIndex);
441} 447}
442 448
@@ -448,7 +454,7 @@ UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir
448 isAltStreamDir = true; 454 isAltStreamDir = true;
449 else if (dirIndex >= k_Proxy2_NumRootDirs) 455 else if (dirIndex >= k_Proxy2_NumRootDirs)
450 { 456 {
451 const CProxyFile2 &file = Files[dir.ArcIndex]; 457 const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
452 isAltStreamDir = ((int)dirIndex == file.AltDirIndex); 458 isAltStreamDir = ((int)dirIndex == file.AltDirIndex);
453 } 459 }
454 return dir.PathPrefix; 460 return dir.PathPrefix;
@@ -458,9 +464,9 @@ void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStr
458{ 464{
459 realIndices.Add(arcIndex); 465 realIndices.Add(arcIndex);
460 const CProxyFile2 &file = Files[arcIndex]; 466 const CProxyFile2 &file = Files[arcIndex];
461 if (file.DirIndex >= 0) 467 if (file.DirIndex != -1)
462 AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices); 468 AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices);
463 if (includeAltStreams && file.AltDirIndex >= 0) 469 if (includeAltStreams && file.AltDirIndex != -1)
464 AddRealIndices_of_Dir(file.AltDirIndex, includeAltStreams, realIndices); 470 AddRealIndices_of_Dir(file.AltDirIndex, includeAltStreams, realIndices);
465} 471}
466 472
@@ -520,15 +526,18 @@ void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive)
520 } 526 }
521 527
522 const CProxyFile2 &subFile = Files[index]; 528 const CProxyFile2 &subFile = Files[index];
523 if (subFile.DirIndex < 0) 529 if (subFile.DirIndex == -1)
524 { 530 {
525 dir.NumSubFiles++; 531 dir.NumSubFiles++;
526 } 532 }
527 else 533 else
528 { 534 {
535 // 22.00: we normalize name
536 UString s = subFile.Name;
537 NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s);
529 dir.NumSubDirs++; 538 dir.NumSubDirs++;
530 CProxyDir2 &f = Dirs[subFile.DirIndex]; 539 CProxyDir2 &f = Dirs[subFile.DirIndex];
531 f.PathPrefix = dir.PathPrefix + subFile.Name + WCHAR_PATH_SEPARATOR; 540 f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR;
532 CalculateSizes(subFile.DirIndex, archive); 541 CalculateSizes(subFile.DirIndex, archive);
533 dir.Size += f.Size; 542 dir.Size += f.Size;
534 dir.PackSize += f.PackSize; 543 dir.PackSize += f.PackSize;
@@ -539,7 +548,7 @@ void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive)
539 dir.CrcIsDefined = false; 548 dir.CrcIsDefined = false;
540 } 549 }
541 550
542 if (subFile.AltDirIndex < 0) 551 if (subFile.AltDirIndex == -1)
543 { 552 {
544 // dir.NumSubFiles++; 553 // dir.NumSubFiles++;
545 } 554 }
@@ -688,12 +697,12 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
688 697
689 if (file.IsAltStream) 698 if (file.IsAltStream)
690 { 699 {
691 if (file.Parent < 0) 700 if (file.Parent == -1)
692 dirIndex = k_Proxy2_AltRootDirIndex; 701 dirIndex = k_Proxy2_AltRootDirIndex;
693 else 702 else
694 { 703 {
695 int &folderIndex2 = Files[file.Parent].AltDirIndex; 704 int &folderIndex2 = Files[(unsigned)file.Parent].AltDirIndex;
696 if (folderIndex2 < 0) 705 if (folderIndex2 == -1)
697 { 706 {
698 folderIndex2 = Dirs.Size(); 707 folderIndex2 = Dirs.Size();
699 CProxyDir2 &dir = Dirs.AddNew(); 708 CProxyDir2 &dir = Dirs.AddNew();
@@ -704,12 +713,12 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
704 } 713 }
705 else 714 else
706 { 715 {
707 if (file.Parent < 0) 716 if (file.Parent == -1)
708 dirIndex = k_Proxy2_RootDirIndex; 717 dirIndex = k_Proxy2_RootDirIndex;
709 else 718 else
710 { 719 {
711 dirIndex = Files[file.Parent].DirIndex; 720 dirIndex = Files[(unsigned)file.Parent].DirIndex;
712 if (dirIndex < 0) 721 if (dirIndex == -1)
713 return E_FAIL; 722 return E_FAIL;
714 } 723 }
715 } 724 }
@@ -731,7 +740,7 @@ int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnl
731 FOR_VECTOR (i, dir.Items) 740 FOR_VECTOR (i, dir.Items)
732 { 741 {
733 const CProxyFile2 &file = Files[dir.Items[i]]; 742 const CProxyFile2 &file = Files[dir.Items[i]];
734 if (foldersOnly && file.DirIndex < 0) 743 if (foldersOnly && file.DirIndex == -1)
735 continue; 744 continue;
736 if (CompareFileNames(file.Name, name) == 0) 745 if (CompareFileNames(file.Name, name) == 0)
737 return i; 746 return i;
diff --git a/CPP/7zip/UI/Agent/AgentProxy.h b/CPP/7zip/UI/Agent/AgentProxy.h
index f2cb3d7..233174b 100644
--- a/CPP/7zip/UI/Agent/AgentProxy.h
+++ b/CPP/7zip/UI/Agent/AgentProxy.h
@@ -38,7 +38,7 @@ struct CProxyDir
38 ~CProxyDir() { delete [](wchar_t *)(void *)Name; } 38 ~CProxyDir() { delete [](wchar_t *)(void *)Name; }
39 39
40 void Clear(); 40 void Clear();
41 bool IsLeaf() const { return ArcIndex >= 0; } 41 bool IsLeaf() const { return ArcIndex != -1; }
42}; 42};
43 43
44class CProxyArc 44class CProxyArc
@@ -82,7 +82,7 @@ struct CProxyFile2
82 82
83 int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; } 83 int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; }
84 84
85 bool IsDir() const { return DirIndex >= 0; } 85 bool IsDir() const { return DirIndex != -1; }
86 CProxyFile2(): 86 CProxyFile2():
87 DirIndex(-1), AltDirIndex(-1), Parent(-1), 87 DirIndex(-1), AltDirIndex(-1), Parent(-1),
88 Name(NULL), NameLen(0), 88 Name(NULL), NameLen(0),
@@ -145,7 +145,7 @@ public:
145 { 145 {
146 const CProxyFile2 &file = Files[arcIndex]; 146 const CProxyFile2 &file = Files[arcIndex];
147 147
148 if (file.Parent < 0) 148 if (file.Parent == -1)
149 return file.IsAltStream ? 149 return file.IsAltStream ?
150 k_Proxy2_AltRootDirIndex : 150 k_Proxy2_AltRootDirIndex :
151 k_Proxy2_RootDirIndex; 151 k_Proxy2_RootDirIndex;
diff --git a/CPP/7zip/UI/Agent/ArchiveFolder.cpp b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
index a20b4f2..eca02ba 100644
--- a/CPP/7zip/UI/Agent/ArchiveFolder.cpp
+++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
@@ -16,6 +16,12 @@ STDMETHODIMP CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCh
16} 16}
17*/ 17*/
18 18
19STDMETHODIMP CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)
20{
21 _zoneMode = zoneMode;
22 return S_OK;
23}
24
19STDMETHODIMP CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, 25STDMETHODIMP CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
20 Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, 26 Int32 includeAltStreams, Int32 replaceAltStreamCharsMode,
21 const wchar_t *path, IFolderOperationsExtractCallback *callback) 27 const wchar_t *path, IFolderOperationsExtractCallback *callback)
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
index 4a10ebe..cd18c99 100644
--- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
@@ -210,7 +210,7 @@ HRESULT CAgentFolder::CommonUpdateOperation(
210 FOR_VECTOR (i, pathParts) 210 FOR_VECTOR (i, pathParts)
211 { 211 {
212 int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]); 212 int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]);
213 if (next < 0) 213 if (next == -1)
214 break; 214 break;
215 _proxyDirIndex = next; 215 _proxyDirIndex = next;
216 } 216 }
@@ -226,7 +226,7 @@ HRESULT CAgentFolder::CommonUpdateOperation(
226 { 226 {
227 bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder); 227 bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder);
228 int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly); 228 int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly);
229 if (index < 0) 229 if (index == -1)
230 break; 230 break;
231 231
232 const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]]; 232 const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]];
@@ -235,7 +235,7 @@ HRESULT CAgentFolder::CommonUpdateOperation(
235 _proxyDirIndex = file.DirIndex; 235 _proxyDirIndex = file.DirIndex;
236 else 236 else
237 { 237 {
238 if (file.AltDirIndex >= 0) 238 if (file.AltDirIndex != -1)
239 _proxyDirIndex = file.AltDirIndex; 239 _proxyDirIndex = file.AltDirIndex;
240 break; 240 break;
241 } 241 }
@@ -351,7 +351,7 @@ STDMETHODIMP CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress
351 } 351 }
352 else 352 else
353 { 353 {
354 if (_proxy->FindSubDir(_proxyDirIndex, name) >= 0) 354 if (_proxy->FindSubDir(_proxyDirIndex, name) != -1)
355 return ERROR_ALREADY_EXISTS; 355 return ERROR_ALREADY_EXISTS;
356 } 356 }
357 357
diff --git a/CPP/7zip/UI/Agent/IFolderArchive.h b/CPP/7zip/UI/Agent/IFolderArchive.h
index 565e37b..92eb616 100644
--- a/CPP/7zip/UI/Agent/IFolderArchive.h
+++ b/CPP/7zip/UI/Agent/IFolderArchive.h
@@ -116,4 +116,13 @@ FOLDER_ARCHIVE_INTERFACE(IFolderScanProgress, 0x11)
116 INTERFACE_IFolderScanProgress(PURE) 116 INTERFACE_IFolderScanProgress(PURE)
117}; 117};
118 118
119
120#define INTERFACE_IFolderSetZoneIdMode(x) \
121 STDMETHOD(SetZoneIdMode)(NExtract::NZoneIdMode::EEnum zoneMode) x; \
122
123FOLDER_ARCHIVE_INTERFACE(IFolderSetZoneIdMode, 0x12)
124{
125 INTERFACE_IFolderSetZoneIdMode(PURE)
126};
127
119#endif 128#endif
diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp
index 0fa4cda..a55fa22 100644
--- a/CPP/7zip/UI/Client7z/Client7z.cpp
+++ b/CPP/7zip/UI/Client7z/Client7z.cpp
@@ -33,17 +33,29 @@ HINSTANCE g_hInstance;
33HINSTANCE g_hInstance = 0; 33HINSTANCE g_hInstance = 0;
34#endif 34#endif
35 35
36// You can find the list of all GUIDs in Guid.txt file. 36// You can find full list of all GUIDs supported by 7-Zip in Guid.txt file.
37// use another CLSIDs, if you want to support other formats (zip, rar, ...). 37// 7z format GUID: {23170F69-40C1-278A-1000-000110070000}
38// {23170F69-40C1-278A-1000-000110070000}
39 38
40DEFINE_GUID(CLSID_CFormat7z, 39#define DEFINE_GUID_ARC(name, id) DEFINE_GUID(name, \
41 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); 40 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00);
42DEFINE_GUID(CLSID_CFormatXz,
43 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x0C, 0x00, 0x00);
44 41
45#define CLSID_Format CLSID_CFormat7z 42enum
46// #define CLSID_Format CLSID_CFormatXz 43{
44 kId_Zip = 1,
45 kId_BZip2 = 2,
46 kId_7z = 7,
47 kId_Xz = 0xC,
48 kId_Tar = 0xEE,
49 kId_GZip = 0xEF
50};
51
52// use another id, if you want to support other formats (zip, Xz, ...).
53// DEFINE_GUID_ARC (CLSID_Format, kId_Zip)
54// DEFINE_GUID_ARC (CLSID_Format, kId_BZip2)
55// DEFINE_GUID_ARC (CLSID_Format, kId_Xz)
56// DEFINE_GUID_ARC (CLSID_Format, kId_Tar)
57// DEFINE_GUID_ARC (CLSID_Format, kId_GZip)
58DEFINE_GUID_ARC (CLSID_Format, kId_7z)
47 59
48using namespace NWindows; 60using namespace NWindows;
49using namespace NFile; 61using namespace NFile;
@@ -229,6 +241,86 @@ static const char * const kIsNotArc = "Is not archive";
229static const char * const kHeadersError = "Headers Error"; 241static const char * const kHeadersError = "Headers Error";
230 242
231 243
244struct CArcTime
245{
246 FILETIME FT;
247 UInt16 Prec;
248 Byte Ns100;
249 bool Def;
250
251 CArcTime()
252 {
253 Clear();
254 }
255
256 void Clear()
257 {
258 FT.dwHighDateTime = FT.dwLowDateTime = 0;
259 Prec = 0;
260 Ns100 = 0;
261 Def = false;
262 }
263
264 bool IsZero() const
265 {
266 return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
267 }
268
269 int GetNumDigits() const
270 {
271 if (Prec == k_PropVar_TimePrec_Unix ||
272 Prec == k_PropVar_TimePrec_DOS)
273 return 0;
274 if (Prec == k_PropVar_TimePrec_HighPrec)
275 return 9;
276 if (Prec == k_PropVar_TimePrec_0)
277 return 7;
278 int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
279 if (digits < 0)
280 digits = 0;
281 return digits;
282 }
283
284 void Write_To_FiTime(CFiTime &dest) const
285 {
286 #ifdef _WIN32
287 dest = FT;
288 #else
289 if (FILETIME_To_timespec(FT, dest))
290 if ((Prec == k_PropVar_TimePrec_Base + 8 ||
291 Prec == k_PropVar_TimePrec_Base + 9)
292 && Ns100 != 0)
293 {
294 dest.tv_nsec += Ns100;
295 }
296 #endif
297 }
298
299 void Set_From_Prop(const PROPVARIANT &prop)
300 {
301 FT = prop.filetime;
302 unsigned prec = 0;
303 unsigned ns100 = 0;
304 const unsigned prec_Temp = prop.wReserved1;
305 if (prec_Temp != 0
306 && prec_Temp <= k_PropVar_TimePrec_1ns
307 && prop.wReserved3 == 0)
308 {
309 const unsigned ns100_Temp = prop.wReserved2;
310 if (ns100_Temp < 100)
311 {
312 ns100 = ns100_Temp;
313 prec = prec_Temp;
314 }
315 }
316 Prec = (UInt16)prec;
317 Ns100 = (Byte)ns100;
318 Def = true;
319 }
320};
321
322
323
232class CArchiveExtractCallback: 324class CArchiveExtractCallback:
233 public IArchiveExtractCallback, 325 public IArchiveExtractCallback,
234 public ICryptoGetTextPassword, 326 public ICryptoGetTextPassword,
@@ -257,11 +349,10 @@ private:
257 bool _extractMode; 349 bool _extractMode;
258 struct CProcessedFileInfo 350 struct CProcessedFileInfo
259 { 351 {
260 FILETIME MTime; 352 CArcTime MTime;
261 UInt32 Attrib; 353 UInt32 Attrib;
262 bool isDir; 354 bool isDir;
263 bool AttribDefined; 355 bool Attrib_Defined;
264 bool MTimeDefined;
265 } _processedFileInfo; 356 } _processedFileInfo;
266 357
267 COutFileStream *_outFileStreamSpec; 358 COutFileStream *_outFileStreamSpec;
@@ -328,32 +419,31 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index,
328 if (prop.vt == VT_EMPTY) 419 if (prop.vt == VT_EMPTY)
329 { 420 {
330 _processedFileInfo.Attrib = 0; 421 _processedFileInfo.Attrib = 0;
331 _processedFileInfo.AttribDefined = false; 422 _processedFileInfo.Attrib_Defined = false;
332 } 423 }
333 else 424 else
334 { 425 {
335 if (prop.vt != VT_UI4) 426 if (prop.vt != VT_UI4)
336 return E_FAIL; 427 return E_FAIL;
337 _processedFileInfo.Attrib = prop.ulVal; 428 _processedFileInfo.Attrib = prop.ulVal;
338 _processedFileInfo.AttribDefined = true; 429 _processedFileInfo.Attrib_Defined = true;
339 } 430 }
340 } 431 }
341 432
342 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir)); 433 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir));
343 434
344 { 435 {
436 _processedFileInfo.MTime.Clear();
345 // Get Modified Time 437 // Get Modified Time
346 NCOM::CPropVariant prop; 438 NCOM::CPropVariant prop;
347 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)); 439 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
348 _processedFileInfo.MTimeDefined = false;
349 switch (prop.vt) 440 switch (prop.vt)
350 { 441 {
351 case VT_EMPTY: 442 case VT_EMPTY:
352 // _processedFileInfo.MTime = _utcMTimeDefault; 443 // _processedFileInfo.MTime = _utcMTimeDefault;
353 break; 444 break;
354 case VT_FILETIME: 445 case VT_FILETIME:
355 _processedFileInfo.MTime = prop.filetime; 446 _processedFileInfo.MTime.Set_From_Prop(prop);
356 _processedFileInfo.MTimeDefined = true;
357 break; 447 break;
358 default: 448 default:
359 return E_FAIL; 449 return E_FAIL;
@@ -483,12 +573,16 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
483 573
484 if (_outFileStream) 574 if (_outFileStream)
485 { 575 {
486 if (_processedFileInfo.MTimeDefined) 576 if (_processedFileInfo.MTime.Def)
487 _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); 577 {
578 CFiTime ft;
579 _processedFileInfo.MTime.Write_To_FiTime(ft);
580 _outFileStreamSpec->SetMTime(&ft);
581 }
488 RINOK(_outFileStreamSpec->Close()); 582 RINOK(_outFileStreamSpec->Close());
489 } 583 }
490 _outFileStream.Release(); 584 _outFileStream.Release();
491 if (_extractMode && _processedFileInfo.AttribDefined) 585 if (_extractMode && _processedFileInfo.Attrib_Defined)
492 SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib); 586 SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);
493 PrintNewLine(); 587 PrintNewLine();
494 return S_OK; 588 return S_OK;
@@ -513,17 +607,14 @@ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
513////////////////////////////////////////////////////////////// 607//////////////////////////////////////////////////////////////
514// Archive Creating callback class 608// Archive Creating callback class
515 609
516struct CDirItem 610struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
517{ 611{
518 UInt64 Size; 612 UString Path_For_Handler;
519 FILETIME CTime; 613 FString FullPath; // for filesystem
520 FILETIME ATime; 614
521 FILETIME MTime; 615 CDirItem(const NWindows::NFile::NFind::CFileInfo &fi):
522 UString Name; 616 CFileInfoBase(fi)
523 FString FullPath; 617 {}
524 UInt32 Attrib;
525
526 bool isDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
527}; 618};
528 619
529class CArchiveUpdateCallback: 620class CArchiveUpdateCallback:
@@ -618,16 +709,17 @@ STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
618 } 709 }
619 710
620 { 711 {
621 const CDirItem &dirItem = (*DirItems)[index]; 712 const CDirItem &di = (*DirItems)[index];
622 switch (propID) 713 switch (propID)
623 { 714 {
624 case kpidPath: prop = dirItem.Name; break; 715 case kpidPath: prop = di.Path_For_Handler; break;
625 case kpidIsDir: prop = dirItem.isDir(); break; 716 case kpidIsDir: prop = di.IsDir(); break;
626 case kpidSize: prop = dirItem.Size; break; 717 case kpidSize: prop = di.Size; break;
627 case kpidAttrib: prop = dirItem.Attrib; break; 718 case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
628 case kpidCTime: prop = dirItem.CTime; break; 719 case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
629 case kpidATime: prop = dirItem.ATime; break; 720 case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
630 case kpidMTime: prop = dirItem.MTime; break; 721 case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
722 case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
631 } 723 }
632 } 724 }
633 prop.Detach(value); 725 prop.Detach(value);
@@ -657,9 +749,9 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream
657 RINOK(Finilize()); 749 RINOK(Finilize());
658 750
659 const CDirItem &dirItem = (*DirItems)[index]; 751 const CDirItem &dirItem = (*DirItems)[index];
660 GetStream2(dirItem.Name); 752 GetStream2(dirItem.Path_For_Handler);
661 753
662 if (dirItem.isDir()) 754 if (dirItem.IsDir())
663 return S_OK; 755 return S_OK;
664 756
665 { 757 {
@@ -848,7 +940,6 @@ int MY_CDECL main(int numArgs, const char *args[])
848 unsigned i; 940 unsigned i;
849 for (i = 1; i < params.Size(); i++) 941 for (i = 1; i < params.Size(); i++)
850 { 942 {
851 CDirItem di;
852 const FString &name = params[i]; 943 const FString &name = params[i];
853 944
854 NFind::CFileInfo fi; 945 NFind::CFileInfo fi;
@@ -857,13 +948,10 @@ int MY_CDECL main(int numArgs, const char *args[])
857 PrintError("Can't find file", name); 948 PrintError("Can't find file", name);
858 return 1; 949 return 1;
859 } 950 }
951
952 CDirItem di(fi);
860 953
861 di.Attrib = fi.Attrib; 954 di.Path_For_Handler = fs2us(name);
862 di.Size = fi.Size;
863 di.CTime = fi.CTime;
864 di.ATime = fi.ATime;
865 di.MTime = fi.MTime;
866 di.Name = fs2us(name);
867 di.FullPath = name; 955 di.FullPath = name;
868 dirItems.Add(di); 956 dirItems.Add(di);
869 } 957 }
@@ -894,12 +982,14 @@ int MY_CDECL main(int numArgs, const char *args[])
894 { 982 {
895 const wchar_t *names[] = 983 const wchar_t *names[] =
896 { 984 {
985 L"m",
897 L"s", 986 L"s",
898 L"x" 987 L"x"
899 }; 988 };
900 const unsigned kNumProps = ARRAY_SIZE(names); 989 const unsigned kNumProps = ARRAY_SIZE(names);
901 NCOM::CPropVariant values[kNumProps] = 990 NCOM::CPropVariant values[kNumProps] =
902 { 991 {
992 L"lzma",
903 false, // solid mode OFF 993 false, // solid mode OFF
904 (UInt32)9 // compression level = 9 - ultra 994 (UInt32)9 // compression level = 9 - ultra
905 }; 995 };
@@ -910,7 +1000,11 @@ int MY_CDECL main(int numArgs, const char *args[])
910 PrintError("ISetProperties unsupported"); 1000 PrintError("ISetProperties unsupported");
911 return 1; 1001 return 1;
912 } 1002 }
913 RINOK(setProperties->SetProperties(names, values, kNumProps)); 1003 if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
1004 {
1005 PrintError("SetProperties() error");
1006 return 1;
1007 }
914 } 1008 }
915 */ 1009 */
916 1010
@@ -1035,7 +1129,13 @@ int MY_CDECL main(int numArgs, const char *args[])
1035 CMyComPtr<ISetProperties> setProperties; 1129 CMyComPtr<ISetProperties> setProperties;
1036 archive->QueryInterface(IID_ISetProperties, (void **)&setProperties); 1130 archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
1037 if (setProperties) 1131 if (setProperties)
1038 setProperties->SetProperties(names, values, kNumProps); 1132 {
1133 if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
1134 {
1135 PrintError("SetProperties() error");
1136 return 1;
1137 }
1138 }
1039 */ 1139 */
1040 1140
1041 HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback); 1141 HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
index 91ef038..d88c851 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -160,7 +160,11 @@ enum Enum
160 kSymLinks_AllowDangerous, 160 kSymLinks_AllowDangerous,
161 kSymLinks, 161 kSymLinks,
162 kNtSecurity, 162 kNtSecurity,
163
164 kStoreOwnerId,
165 kStoreOwnerName,
163 166
167 kZoneFile,
164 kAltStreams, 168 kAltStreams,
165 kReplaceColonForAltStream, 169 kReplaceColonForAltStream,
166 kWriteToAltStreamIfColon, 170 kWriteToAltStreamIfColon,
@@ -304,7 +308,11 @@ static const CSwitchForm kSwitchForms[] =
304 { "snld", SWFRM_MINUS }, 308 { "snld", SWFRM_MINUS },
305 { "snl", SWFRM_MINUS }, 309 { "snl", SWFRM_MINUS },
306 { "sni", SWFRM_SIMPLE }, 310 { "sni", SWFRM_SIMPLE },
311
312 { "snoi", SWFRM_MINUS },
313 { "snon", SWFRM_MINUS },
307 314
315 { "snz", SWFRM_STRING_SINGL(0) },
308 { "sns", SWFRM_MINUS }, 316 { "sns", SWFRM_MINUS },
309 { "snr", SWFRM_SIMPLE }, 317 { "snr", SWFRM_SIMPLE },
310 { "snc", SWFRM_SIMPLE }, 318 { "snc", SWFRM_SIMPLE },
@@ -1032,9 +1040,9 @@ void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
1032 1040
1033 if (parser[NKey::kCaseSensitive].ThereIs) 1041 if (parser[NKey::kCaseSensitive].ThereIs)
1034 { 1042 {
1043 options.CaseSensitive =
1035 g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; 1044 g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
1036 options.CaseSensitiveChange = true; 1045 options.CaseSensitive_Change = true;
1037 options.CaseSensitive = g_CaseSensitive;
1038 } 1046 }
1039 1047
1040 1048
@@ -1367,6 +1375,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1367 SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); 1375 SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
1368 SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); 1376 SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
1369 SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); 1377 SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
1378
1379 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
1380 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
1370 1381
1371 CBoolPair symLinks_AllowDangerous; 1382 CBoolPair symLinks_AllowDangerous;
1372 SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); 1383 SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
@@ -1420,12 +1431,28 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1420 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; 1431 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
1421 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; 1432 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
1422 1433
1434 nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName
1435
1423 if (parser[NKey::kPreserveATime].ThereIs) 1436 if (parser[NKey::kPreserveATime].ThereIs)
1424 nt.PreserveATime = true; 1437 nt.PreserveATime = true;
1425 if (parser[NKey::kShareForWrite].ThereIs) 1438 if (parser[NKey::kShareForWrite].ThereIs)
1426 nt.OpenShareForWrite = true; 1439 nt.OpenShareForWrite = true;
1427 } 1440 }
1428 1441
1442 if (parser[NKey::kZoneFile].ThereIs)
1443 {
1444 eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1445 const UString &s = parser[NKey::kZoneFile].PostStrings[0];
1446 if (!s.IsEmpty())
1447 {
1448 if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone;
1449 else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1450 else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
1451 else
1452 throw CArcCmdLineException("Unsupported -snz:", s);
1453 }
1454 }
1455
1429 options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); 1456 options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
1430 options.Censor.ExtendExclude(); 1457 options.Censor.ExtendExclude();
1431 1458
@@ -1549,6 +1576,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1549 updateOptions.NtSecurity = options.NtSecurity; 1576 updateOptions.NtSecurity = options.NtSecurity;
1550 updateOptions.HardLinks = options.HardLinks; 1577 updateOptions.HardLinks = options.HardLinks;
1551 updateOptions.SymLinks = options.SymLinks; 1578 updateOptions.SymLinks = options.SymLinks;
1579
1580 updateOptions.StoreOwnerId = options.StoreOwnerId;
1581 updateOptions.StoreOwnerName = options.StoreOwnerName;
1552 1582
1553 updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; 1583 updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
1554 if (updateOptions.EMailMode) 1584 if (updateOptions.EMailMode)
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h
index ff4f28c..745f999 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.h
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -51,7 +51,7 @@ struct CArcCmdLineOptions
51 bool HelpMode; 51 bool HelpMode;
52 52
53 // bool LargePages; 53 // bool LargePages;
54 bool CaseSensitiveChange; 54 bool CaseSensitive_Change;
55 bool CaseSensitive; 55 bool CaseSensitive;
56 56
57 bool IsInTerminal; 57 bool IsInTerminal;
@@ -97,6 +97,9 @@ struct CArcCmdLineOptions
97 CBoolPair AltStreams; 97 CBoolPair AltStreams;
98 CBoolPair HardLinks; 98 CBoolPair HardLinks;
99 CBoolPair SymLinks; 99 CBoolPair SymLinks;
100
101 CBoolPair StoreOwnerId;
102 CBoolPair StoreOwnerName;
100 103
101 CUpdateOptions UpdateOptions; 104 CUpdateOptions UpdateOptions;
102 CHashOptions HashOptions; 105 CHashOptions HashOptions;
@@ -117,7 +120,7 @@ struct CArcCmdLineOptions
117 CArcCmdLineOptions(): 120 CArcCmdLineOptions():
118 HelpMode(false), 121 HelpMode(false),
119 // LargePages(false), 122 // LargePages(false),
120 CaseSensitiveChange(false), 123 CaseSensitive_Change(false),
121 CaseSensitive(false), 124 CaseSensitive(false),
122 125
123 IsInTerminal(false), 126 IsInTerminal(false),
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index 73c191e..a574f13 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -95,6 +95,83 @@ bool InitLocalPrivileges()
95#endif // _USE_SECURITY_CODE 95#endif // _USE_SECURITY_CODE
96 96
97 97
98
99#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
100
101static const char * const kOfficeExtensions =
102 " doc dot wbk"
103 " docx docm dotx dotm docb wll wwl"
104 " xls xlt xlm"
105 " xlsx xlsm xltx xltm xlsb xla xlam"
106 " ppt pot pps ppa ppam"
107 " pptx pptm potx potm ppam ppsx ppsm sldx sldm"
108 " ";
109
110static bool FindExt2(const char *p, const UString &name)
111{
112 const int pathPos = name.ReverseFind_PathSepar();
113 const int dotPos = name.ReverseFind_Dot();
114 if (dotPos < 0
115 || dotPos < pathPos
116 || dotPos == (int)name.Len() - 1)
117 return false;
118
119 AString s;
120 for (unsigned pos = dotPos + 1;; pos++)
121 {
122 const wchar_t c = name[pos];
123 if (c <= 0)
124 break;
125 if (c >= 0x80)
126 return false;
127 s += (char)MyCharLower_Ascii((char)c);
128 }
129 for (unsigned i = 0; p[i] != 0;)
130 {
131 unsigned j;
132 for (j = i; p[j] != ' '; j++);
133 if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0)
134 return true;
135 i = j + 1;
136 }
137 return false;
138}
139
140
141static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier");
142
143void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf)
144{
145 FString fileName = fileName2;
146 fileName += k_ZoneId_StreamName;
147
148 buf.Free();
149 NIO::CInFile file;
150 if (!file.Open(fileName))
151 return;
152 UInt64 fileSize;
153 if (!file.GetLength(fileSize))
154 return;
155 if (fileSize == 0 || fileSize >= ((UInt32)1 << 16))
156 return;
157 buf.Alloc((size_t)fileSize);
158 size_t processed;
159 if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize)
160 return;
161 buf.Free();
162}
163
164static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
165{
166 NIO::COutFile file;
167 if (!file.Create(fileName, true))
168 return false;
169 return file.WriteFull(buf, buf.Size());
170}
171
172#endif
173
174
98#ifdef SUPPORT_LINKS 175#ifdef SUPPORT_LINKS
99 176
100int CHardLinkNode::Compare(const CHardLinkNode &a) const 177int CHardLinkNode::Compare(const CHardLinkNode &a) const
@@ -190,9 +267,9 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
190 267
191CArchiveExtractCallback::CArchiveExtractCallback(): 268CArchiveExtractCallback::CArchiveExtractCallback():
192 _arc(NULL), 269 _arc(NULL),
193 WriteCTime(true), 270 Write_CTime(true),
194 WriteATime(true), 271 Write_ATime(true),
195 WriteMTime(true), 272 Write_MTime(true),
196 _multiArchives(false) 273 _multiArchives(false)
197{ 274{
198 LocalProgressSpec = new CLocalProgress(); 275 LocalProgressSpec = new CLocalProgress();
@@ -204,6 +281,13 @@ CArchiveExtractCallback::CArchiveExtractCallback():
204} 281}
205 282
206 283
284void CArchiveExtractCallback::InitBeforeNewArchive()
285{
286 #if defined(_WIN32) && !defined(UNDER_CE)
287 ZoneBuf.Free();
288 #endif
289}
290
207void CArchiveExtractCallback::Init( 291void CArchiveExtractCallback::Init(
208 const CExtractNtOptions &ntOptions, 292 const CExtractNtOptions &ntOptions,
209 const NWildcard::CCensorNode *wildcardCensor, 293 const NWildcard::CCensorNode *wildcardCensor,
@@ -240,13 +324,19 @@ void CArchiveExtractCallback::Init(
240 _progressTotal_Defined = true; 324 _progressTotal_Defined = true;
241 325
242 _extractCallback2 = extractCallback2; 326 _extractCallback2 = extractCallback2;
327
243 _compressProgress.Release(); 328 _compressProgress.Release();
244 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); 329 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
330
331 _callbackMessage.Release();
245 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage); 332 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage);
333
334 _folderArchiveExtractCallback2.Release();
246 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); 335 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
247 336
248 #ifndef _SFX 337 #ifndef _SFX
249 338
339 ExtractToStreamCallback.Release();
250 _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); 340 _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback);
251 if (ExtractToStreamCallback) 341 if (ExtractToStreamCallback)
252 { 342 {
@@ -416,26 +506,22 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat
416} 506}
417 507
418 508
419HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) 509HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, CArcTime &ft)
420{ 510{
421 filetimeIsDefined = false; 511 ft.Clear();
422 filetime.dwLowDateTime = 0;
423 filetime.dwHighDateTime = 0;
424 NCOM::CPropVariant prop; 512 NCOM::CPropVariant prop;
425 RINOK(_arc->Archive->GetProperty(index, propID, &prop)); 513 RINOK(_arc->Archive->GetProperty(index, propID, &prop));
426 if (prop.vt == VT_FILETIME) 514 if (prop.vt == VT_FILETIME)
427 { 515 ft.Set_From_Prop(prop);
428 filetime = prop.filetime;
429 filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
430 }
431 else if (prop.vt != VT_EMPTY) 516 else if (prop.vt != VT_EMPTY)
432 return E_FAIL; 517 return E_FAIL;
433 return S_OK; 518 return S_OK;
434} 519}
435 520
521
436HRESULT CArchiveExtractCallback::GetUnpackSize() 522HRESULT CArchiveExtractCallback::GetUnpackSize()
437{ 523{
438 return _arc->GetItemSize(_index, _curSize, _curSizeDefined); 524 return _arc->GetItem_Size(_index, _curSize, _curSizeDefined);
439} 525}
440 526
441static void AddPathToMessage(UString &s, const FString &path) 527static void AddPathToMessage(UString &s, const FString &path)
@@ -454,8 +540,9 @@ HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FSt
454HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) 540HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path)
455{ 541{
456 DWORD errorCode = GetLastError(); 542 DWORD errorCode = GetLastError();
543 if (errorCode == 0)
544 errorCode = (DWORD)E_FAIL;
457 UString s (message); 545 UString s (message);
458 if (errorCode != 0)
459 { 546 {
460 s += " : "; 547 s += " : ";
461 s += NError::MyFormatMessage(errorCode); 548 s += NError::MyFormatMessage(errorCode);
@@ -843,13 +930,58 @@ HRESULT CArchiveExtractCallback::ReadLink()
843#endif // SUPPORT_LINKS 930#endif // SUPPORT_LINKS
844 931
845 932
933#ifndef _WIN32
934
935static HRESULT GetOwner(IInArchive *archive,
936 UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res)
937{
938 {
939 NWindows::NCOM::CPropVariant prop;
940 RINOK(archive->GetProperty(index, pidId, &prop));
941 if (prop.vt == VT_UI4)
942 {
943 res.Id_Defined = true;
944 res.Id = prop.ulVal; // for debug
945 // res.Id++; // for debug
946 // if (pidId == kpidGroupId) res.Id += 7; // for debug
947 // res.Id = 0; // for debug
948 }
949 else if (prop.vt != VT_EMPTY)
950 return E_INVALIDARG;
951 }
952 {
953 NWindows::NCOM::CPropVariant prop;
954 RINOK(archive->GetProperty(index, pidName, &prop));
955 if (prop.vt == VT_BSTR)
956 {
957 const UString s = prop.bstrVal;
958 ConvertUnicodeToUTF8(s, res.Name);
959 }
960 else if (prop.vt == VT_UI4)
961 {
962 res.Id_Defined = true;
963 res.Id = prop.ulVal;
964 }
965 else if (prop.vt != VT_EMPTY)
966 return E_INVALIDARG;
967 }
968 return S_OK;
969}
970
971#endif
972
846 973
847HRESULT CArchiveExtractCallback::Read_fi_Props() 974HRESULT CArchiveExtractCallback::Read_fi_Props()
848{ 975{
849 IInArchive *archive = _arc->Archive; 976 IInArchive *archive = _arc->Archive;
850 const UInt32 index = _index; 977 const UInt32 index = _index;
851 978
852 _fi.AttribDefined = false; 979 _fi.Attrib_Defined = false;
980
981 #ifndef _WIN32
982 _fi.Owner.Clear();
983 _fi.Group.Clear();
984 #endif
853 985
854 { 986 {
855 NCOM::CPropVariant prop; 987 NCOM::CPropVariant prop;
@@ -868,15 +1000,25 @@ HRESULT CArchiveExtractCallback::Read_fi_Props()
868 if (prop.vt == VT_UI4) 1000 if (prop.vt == VT_UI4)
869 { 1001 {
870 _fi.Attrib = prop.ulVal; 1002 _fi.Attrib = prop.ulVal;
871 _fi.AttribDefined = true; 1003 _fi.Attrib_Defined = true;
872 } 1004 }
873 else if (prop.vt != VT_EMPTY) 1005 else if (prop.vt != VT_EMPTY)
874 return E_FAIL; 1006 return E_FAIL;
875 } 1007 }
876 1008
877 RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); 1009 RINOK(GetTime(index, kpidCTime, _fi.CTime));
878 RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); 1010 RINOK(GetTime(index, kpidATime, _fi.ATime));
879 RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); 1011 RINOK(GetTime(index, kpidMTime, _fi.MTime));
1012
1013 #ifndef _WIN32
1014 if (_ntOptions.ExtractOwner)
1015 {
1016 // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath);
1017 GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner);
1018 GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group);
1019 }
1020 #endif
1021
880 return S_OK; 1022 return S_OK;
881} 1023}
882 1024
@@ -923,6 +1065,39 @@ void CArchiveExtractCallback::CorrectPathParts()
923} 1065}
924 1066
925 1067
1068void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt)
1069{
1070 pt.CTime_Defined = false;
1071 pt.ATime_Defined = false;
1072 pt.MTime_Defined = false;
1073
1074 if (Write_MTime)
1075 {
1076 if (_fi.MTime.Def)
1077 {
1078 _fi.MTime.Write_To_FiTime(pt.MTime);
1079 pt.MTime_Defined = true;
1080 }
1081 else if (_arc->MTime.Def)
1082 {
1083 _arc->MTime.Write_To_FiTime(pt.MTime);
1084 pt.MTime_Defined = true;
1085 }
1086 }
1087
1088 if (Write_CTime && _fi.CTime.Def)
1089 {
1090 _fi.CTime.Write_To_FiTime(pt.CTime);
1091 pt.CTime_Defined = true;
1092 }
1093
1094 if (Write_ATime && _fi.ATime.Def)
1095 {
1096 _fi.ATime.Write_To_FiTime(pt.ATime);
1097 pt.ATime_Defined = true;
1098 }
1099}
1100
926 1101
927void CArchiveExtractCallback::CreateFolders() 1102void CArchiveExtractCallback::CreateFolders()
928{ 1103{
@@ -948,30 +1123,9 @@ void CArchiveExtractCallback::CreateFolders()
948 return; 1123 return;
949 1124
950 CDirPathTime pt; 1125 CDirPathTime pt;
951 1126 GetFiTimesCAM(pt);
952 pt.CTime = _fi.CTime; 1127
953 pt.CTimeDefined = (WriteCTime && _fi.CTimeDefined); 1128 if (pt.IsSomeTimeDefined())
954
955 pt.ATime = _fi.ATime;
956 pt.ATimeDefined = (WriteATime && _fi.ATimeDefined);
957
958 pt.MTimeDefined = false;
959
960 if (WriteMTime)
961 {
962 if (_fi.MTimeDefined)
963 {
964 pt.MTime = _fi.MTime;
965 pt.MTimeDefined = true;
966 }
967 else if (_arc->MTimeDefined)
968 {
969 pt.MTime = _arc->MTime;
970 pt.MTimeDefined = true;
971 }
972 }
973
974 if (pt.MTimeDefined || pt.ATimeDefined || pt.CTimeDefined)
975 { 1129 {
976 pt.Path = fullPathNew; 1130 pt.Path = fullPathNew;
977 pt.SetDirTime(); 1131 pt.SetDirTime();
@@ -1006,10 +1160,13 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1006 /* (fileInfo) can be symbolic link. 1160 /* (fileInfo) can be symbolic link.
1007 we can show final file properties here. */ 1161 we can show final file properties here. */
1008 1162
1163 FILETIME ft1;
1164 FiTime_To_FILETIME(fileInfo.MTime, ft1);
1165
1009 Int32 overwriteResult; 1166 Int32 overwriteResult;
1010 RINOK(_extractCallback2->AskOverwrite( 1167 RINOK(_extractCallback2->AskOverwrite(
1011 fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path, 1168 fs2us(realFullProcessedPath), &ft1, &fileInfo.Size, _item.Path,
1012 _fi.MTimeDefined ? &_fi.MTime : NULL, 1169 _fi.MTime.Def ? &_fi.MTime.FT : NULL,
1013 _curSizeDefined ? &_curSize : NULL, 1170 _curSizeDefined ? &_curSize : NULL,
1014 &overwriteResult)) 1171 &overwriteResult))
1015 1172
@@ -1126,7 +1283,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1126 const UInt32 index = _index; 1283 const UInt32 index = _index;
1127 1284
1128 bool isAnti = false; 1285 bool isAnti = false;
1129 RINOK(_arc->IsItemAnti(index, isAnti)); 1286 RINOK(_arc->IsItem_Anti(index, isAnti));
1130 1287
1131 CorrectPathParts(); 1288 CorrectPathParts();
1132 UString processedPath (MakePathFromParts(_item.PathParts)); 1289 UString processedPath (MakePathFromParts(_item.PathParts));
@@ -1147,8 +1304,8 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1147 #ifdef SUPPORT_ALT_STREAMS 1304 #ifdef SUPPORT_ALT_STREAMS
1148 if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1) 1305 if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1)
1149 { 1306 {
1150 int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex)); 1307 const int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));
1151 if (renIndex >= 0) 1308 if (renIndex != -1)
1152 { 1309 {
1153 const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex]; 1310 const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex];
1154 fullProcessedPath = pair.Path; 1311 fullProcessedPath = pair.Path;
@@ -1224,8 +1381,8 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1224 RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)); 1381 RINOK(Archive_Get_HardLinkNode(archive, index, h, defined));
1225 if (defined) 1382 if (defined)
1226 { 1383 {
1227 int linkIndex = _hardLinks.IDs.FindInSorted2(h); 1384 const int linkIndex = _hardLinks.IDs.FindInSorted2(h);
1228 if (linkIndex >= 0) 1385 if (linkIndex != -1)
1229 { 1386 {
1230 FString &hl = _hardLinks.Links[(unsigned)linkIndex]; 1387 FString &hl = _hardLinks.Links[(unsigned)linkIndex];
1231 if (hl.IsEmpty()) 1388 if (hl.IsEmpty())
@@ -1733,11 +1890,34 @@ HRESULT CArchiveExtractCallback::CloseFile()
1733 _curSize = processedSize; 1890 _curSize = processedSize;
1734 _curSizeDefined = true; 1891 _curSizeDefined = true;
1735 1892
1893 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
1894 if (ZoneBuf.Size() != 0
1895 && !_item.IsAltStream)
1896 {
1897 // if (NFind::DoesFileExist_Raw(tempFilePath))
1898 if (ZoneMode != NExtract::NZoneIdMode::kOffice ||
1899 FindExt2(kOfficeExtensions, _diskFilePath))
1900 {
1901 // we must write zone file before setting of timestamps
1902 const FString path = _diskFilePath + k_ZoneId_StreamName;
1903 if (!WriteZoneFile(path, ZoneBuf))
1904 {
1905 // we can't write it in FAT
1906 // SendMessageError_with_LastError("Can't write Zone.Identifier stream", path);
1907 }
1908 }
1909 }
1910 #endif
1911
1912 CFiTimesCAM t;
1913 GetFiTimesCAM(t);
1914
1736 // #ifdef _WIN32 1915 // #ifdef _WIN32
1737 _outFileStreamSpec->SetTime( 1916 if (t.IsSomeTimeDefined())
1738 (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, 1917 _outFileStreamSpec->SetTime(
1739 (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, 1918 t.CTime_Defined ? &t.CTime : NULL,
1740 (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); 1919 t.ATime_Defined ? &t.ATime : NULL,
1920 t.MTime_Defined ? &t.MTime : NULL);
1741 // #endif 1921 // #endif
1742 1922
1743 RINOK(_outFileStreamSpec->Close()); 1923 RINOK(_outFileStreamSpec->Close());
@@ -2065,19 +2245,30 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2065 2245
2066void CArchiveExtractCallback::SetAttrib() 2246void CArchiveExtractCallback::SetAttrib()
2067{ 2247{
2068 #ifndef _WIN32 2248 #ifndef _WIN32
2069 // Linux now doesn't support permissions for symlinks 2249 // Linux now doesn't support permissions for symlinks
2070 if (_isSymLinkCreated) 2250 if (_isSymLinkCreated)
2071 return; 2251 return;
2072 #endif 2252 #endif
2073 2253
2074 if (_itemFailure 2254 if (_itemFailure
2075 || _diskFilePath.IsEmpty() 2255 || _diskFilePath.IsEmpty()
2076 || _stdOutMode 2256 || _stdOutMode
2077 || !_extractMode 2257 || !_extractMode)
2078 || !_fi.AttribDefined)
2079 return; 2258 return;
2080 2259
2260 #ifndef _WIN32
2261 if (_fi.Owner.Id_Defined &&
2262 _fi.Group.Id_Defined)
2263 {
2264 if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0)
2265 {
2266 SendMessageError_with_LastError("Cannot set owner", _diskFilePath);
2267 }
2268 }
2269 #endif
2270
2271 if (_fi.Attrib_Defined)
2081 { 2272 {
2082 // const AString s = GetAnsiString(_diskFilePath); 2273 // const AString s = GetAnsiString(_diskFilePath);
2083 // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); 2274 // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib);
@@ -2276,7 +2467,7 @@ STDMETHODIMP CArchiveExtractCallback::GetStream2(UInt32 index, ISequentialInStre
2276 2467
2277 CInFileStream *inStreamSpec = new CInFileStream; 2468 CInFileStream *inStreamSpec = new CInFileStream;
2278 CMyComPtr<ISequentialInStream> inStreamRef = inStreamSpec; 2469 CMyComPtr<ISequentialInStream> inStreamRef = inStreamSpec;
2279 inStreamSpec->File.PreserveATime = _ntOptions.PreserveATime; 2470 inStreamSpec->Set_PreserveATime(_ntOptions.PreserveATime);
2280 if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite)) 2471 if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite))
2281 { 2472 {
2282 RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath)); 2473 RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath));
@@ -2318,9 +2509,9 @@ void CDirPathSortPair::SetNumSlashes(const FChar *s)
2318bool CDirPathTime::SetDirTime() const 2509bool CDirPathTime::SetDirTime() const
2319{ 2510{
2320 return NDir::SetDirTime(Path, 2511 return NDir::SetDirTime(Path,
2321 CTimeDefined ? &CTime : NULL, 2512 CTime_Defined ? &CTime : NULL,
2322 ATimeDefined ? &ATime : NULL, 2513 ATime_Defined ? &ATime : NULL,
2323 MTimeDefined ? &MTime : NULL); 2514 MTime_Defined ? &MTime : NULL);
2324} 2515}
2325 2516
2326 2517
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
index fe9cb32..fe70bc9 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -60,6 +60,8 @@ struct CExtractNtOptions
60 bool ReplaceColonForAltStream; 60 bool ReplaceColonForAltStream;
61 bool WriteToAltStreamIfColon; 61 bool WriteToAltStreamIfColon;
62 62
63 bool ExtractOwner;
64
63 bool PreAllocateOutFile; 65 bool PreAllocateOutFile;
64 66
65 // used for hash arcs only, when we open external files 67 // used for hash arcs only, when we open external files
@@ -69,6 +71,7 @@ struct CExtractNtOptions
69 CExtractNtOptions(): 71 CExtractNtOptions():
70 ReplaceColonForAltStream(false), 72 ReplaceColonForAltStream(false),
71 WriteToAltStreamIfColon(false), 73 WriteToAltStreamIfColon(false),
74 ExtractOwner(false),
72 PreserveATime(false), 75 PreserveATime(false),
73 OpenShareForWrite(false) 76 OpenShareForWrite(false)
74 { 77 {
@@ -163,16 +166,27 @@ struct CIndexToPathPair
163 166
164 167
165 168
166struct CDirPathTime 169struct CFiTimesCAM
167{ 170{
168 FILETIME CTime; 171 CFiTime CTime;
169 FILETIME ATime; 172 CFiTime ATime;
170 FILETIME MTime; 173 CFiTime MTime;
174
175 bool CTime_Defined;
176 bool ATime_Defined;
177 bool MTime_Defined;
171 178
172 bool CTimeDefined; 179 bool IsSomeTimeDefined() const
173 bool ATimeDefined; 180 {
174 bool MTimeDefined; 181 return
182 CTime_Defined |
183 ATime_Defined |
184 MTime_Defined;
185 }
186};
175 187
188struct CDirPathTime: public CFiTimesCAM
189{
176 FString Path; 190 FString Path;
177 191
178 bool SetDirTime() const; 192 bool SetDirTime() const;
@@ -216,6 +230,25 @@ struct CLinkInfo
216#endif // SUPPORT_LINKS 230#endif // SUPPORT_LINKS
217 231
218 232
233#ifndef _WIN32
234
235struct COwnerInfo
236{
237 bool Id_Defined;
238 UInt32 Id;
239 AString Name;
240
241 void Clear()
242 {
243 Id_Defined = false;
244 Id = 0;
245 Name.Empty();
246 }
247};
248
249#endif
250
251
219class CArchiveExtractCallback: 252class CArchiveExtractCallback:
220 public IArchiveExtractCallback, 253 public IArchiveExtractCallback,
221 public IArchiveExtractCallbackMessage, 254 public IArchiveExtractCallbackMessage,
@@ -256,32 +289,33 @@ class CArchiveExtractCallback:
256 289
257 bool _extractMode; 290 bool _extractMode;
258 291
259 bool WriteCTime; 292 bool Write_CTime;
260 bool WriteATime; 293 bool Write_ATime;
261 bool WriteMTime; 294 bool Write_MTime;
262 295
263 bool _encrypted; 296 bool _encrypted;
264 297
265 struct CProcessedFileInfo 298 struct CProcessedFileInfo
266 { 299 {
267 FILETIME CTime; 300 CArcTime CTime;
268 FILETIME ATime; 301 CArcTime ATime;
269 FILETIME MTime; 302 CArcTime MTime;
270 UInt32 Attrib; 303 UInt32 Attrib;
271 304 bool Attrib_Defined;
272 bool CTimeDefined; 305
273 bool ATimeDefined; 306 #ifndef _WIN32
274 bool MTimeDefined; 307 COwnerInfo Owner;
275 bool AttribDefined; 308 COwnerInfo Group;
309 #endif
276 310
277 bool IsReparse() const 311 bool IsReparse() const
278 { 312 {
279 return (AttribDefined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); 313 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
280 } 314 }
281 315
282 bool IsLinuxSymLink() const 316 bool IsLinuxSymLink() const
283 { 317 {
284 return (AttribDefined && MY_LIN_S_ISLNK(Attrib >> 16)); 318 return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
285 } 319 }
286 320
287 void SetFromPosixAttrib(UInt32 a) 321 void SetFromPosixAttrib(UInt32 a)
@@ -294,10 +328,14 @@ class CArchiveExtractCallback:
294 FILE_ATTRIBUTE_ARCHIVE; 328 FILE_ATTRIBUTE_ARCHIVE;
295 if ((a & 0222) == 0) // (& S_IWUSR) in p7zip 329 if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
296 Attrib |= FILE_ATTRIBUTE_READONLY; 330 Attrib |= FILE_ATTRIBUTE_READONLY;
331 // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
332 a &= MY_LIN_S_IFMT;
333 if (a == MY_LIN_S_IFLNK)
334 Attrib |= (a << 16);
297 #else 335 #else
298 Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; 336 Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
299 #endif 337 #endif
300 AttribDefined = true; 338 Attrib_Defined = true;
301 } 339 }
302 } _fi; 340 } _fi;
303 341
@@ -359,7 +397,7 @@ class CArchiveExtractCallback:
359 #endif 397 #endif
360 398
361 void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); 399 void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
362 HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); 400 HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft);
363 HRESULT GetUnpackSize(); 401 HRESULT GetUnpackSize();
364 402
365 FString Hash_GetFullFilePath(); 403 FString Hash_GetFullFilePath();
@@ -372,6 +410,10 @@ public:
372 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); 410 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2);
373 411
374public: 412public:
413 #if defined(_WIN32) && !defined(UNDER_CE)
414 NExtract::NZoneIdMode::EEnum ZoneMode;
415 CByteBuffer ZoneBuf;
416 #endif
375 417
376 CLocalProgress *LocalProgressSpec; 418 CLocalProgress *LocalProgressSpec;
377 419
@@ -405,11 +447,17 @@ public:
405 void InitForMulti(bool multiArchives, 447 void InitForMulti(bool multiArchives,
406 NExtract::NPathMode::EEnum pathMode, 448 NExtract::NPathMode::EEnum pathMode,
407 NExtract::NOverwriteMode::EEnum overwriteMode, 449 NExtract::NOverwriteMode::EEnum overwriteMode,
450 NExtract::NZoneIdMode::EEnum zoneMode,
408 bool keepAndReplaceEmptyDirPrefixes) 451 bool keepAndReplaceEmptyDirPrefixes)
409 { 452 {
410 _multiArchives = multiArchives; 453 _multiArchives = multiArchives;
411 _pathMode = pathMode; 454 _pathMode = pathMode;
412 _overwriteMode = overwriteMode; 455 _overwriteMode = overwriteMode;
456 #if defined(_WIN32) && !defined(UNDER_CE)
457 ZoneMode = zoneMode;
458 #else
459 UNUSED_VAR(zoneMode)
460 #endif
413 _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes; 461 _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
414 NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; 462 NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
415 } 463 }
@@ -427,6 +475,8 @@ public:
427 475
428 #endif 476 #endif
429 477
478 void InitBeforeNewArchive();
479
430 void Init( 480 void Init(
431 const CExtractNtOptions &ntOptions, 481 const CExtractNtOptions &ntOptions,
432 const NWildcard::CCensorNode *wildcardCensor, 482 const NWildcard::CCensorNode *wildcardCensor,
@@ -483,6 +533,7 @@ private:
483 533
484 HRESULT Read_fi_Props(); 534 HRESULT Read_fi_Props();
485 void CorrectPathParts(); 535 void CorrectPathParts();
536 void GetFiTimesCAM(CFiTimesCAM &pt);
486 void CreateFolders(); 537 void CreateFolders();
487 538
488 bool _isRenamed; 539 bool _isRenamed;
@@ -533,4 +584,6 @@ struct CArchiveExtractCallback_Closer
533 584
534bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); 585bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
535 586
587void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf);
588
536#endif 589#endif
diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
index d5926f8..64aa987 100644
--- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -34,7 +34,8 @@ STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *b
34 return Callback->Open_SetCompleted(files, bytes); 34 return Callback->Open_SetCompleted(files, bytes);
35 COM_TRY_END 35 COM_TRY_END
36} 36}
37 37
38
38STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) 39STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
39{ 40{
40 COM_TRY_BEGIN 41 COM_TRY_BEGIN
@@ -51,10 +52,11 @@ STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
51 case kpidName: prop = fs2us(_fileInfo.Name); break; 52 case kpidName: prop = fs2us(_fileInfo.Name); break;
52 case kpidIsDir: prop = _fileInfo.IsDir(); break; 53 case kpidIsDir: prop = _fileInfo.IsDir(); break;
53 case kpidSize: prop = _fileInfo.Size; break; 54 case kpidSize: prop = _fileInfo.Size; break;
54 case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; 55 case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break;
55 case kpidCTime: prop = _fileInfo.CTime; break; 56 case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break;
56 case kpidATime: prop = _fileInfo.ATime; break; 57 case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break;
57 case kpidMTime: prop = _fileInfo.MTime; break; 58 case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break;
59 case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break;
58 } 60 }
59 prop.Detach(value); 61 prop.Detach(value);
60 return S_OK; 62 return S_OK;
diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp
index c7efa99..3ef047f 100644
--- a/CPP/7zip/UI/Common/CompressCall.cpp
+++ b/CPP/7zip/UI/Common/CompressCall.cpp
@@ -252,7 +252,7 @@ static void ExtractGroupCommand(const UStringVector &arcPaths, UString &params,
252 ErrorMessageHRESULT(result); 252 ErrorMessageHRESULT(result);
253} 253}
254 254
255void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup) 255void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone)
256{ 256{
257 MY_TRY_BEGIN 257 MY_TRY_BEGIN
258 UString params ('x'); 258 UString params ('x');
@@ -263,6 +263,11 @@ void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bo
263 } 263 }
264 if (elimDup) 264 if (elimDup)
265 params += " -spe"; 265 params += " -spe";
266 if (writeZone != (UInt32)(Int32)-1)
267 {
268 params += " -snz";
269 params.Add_UInt32(writeZone);
270 }
266 if (showDialog) 271 if (showDialog)
267 params += kShowDialogSwitch; 272 params += kShowDialogSwitch;
268 ExtractGroupCommand(arcPaths, params, false); 273 ExtractGroupCommand(arcPaths, params, false);
diff --git a/CPP/7zip/UI/Common/CompressCall.h b/CPP/7zip/UI/Common/CompressCall.h
index b817df0..2697fda 100644
--- a/CPP/7zip/UI/Common/CompressCall.h
+++ b/CPP/7zip/UI/Common/CompressCall.h
@@ -15,7 +15,7 @@ HRESULT CompressFiles(
15 const UStringVector &names, 15 const UStringVector &names,
16 bool email, bool showDialog, bool waitFinish); 16 bool email, bool showDialog, bool waitFinish);
17 17
18void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup); 18void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone);
19void TestArchives(const UStringVector &arcPaths, bool hashMode = false); 19void TestArchives(const UStringVector &arcPaths, bool hashMode = false);
20 20
21void CalcChecksum(const UStringVector &paths, 21void CalcChecksum(const UStringVector &paths,
diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp
index 762342d..5d617e1 100644
--- a/CPP/7zip/UI/Common/CompressCall2.cpp
+++ b/CPP/7zip/UI/Common/CompressCall2.cpp
@@ -152,19 +152,12 @@ HRESULT CompressFiles(
152 152
153 153
154static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, 154static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
155 bool showDialog, const UString &outFolder, bool testMode, bool elimDup = false, 155 bool showDialog, CExtractOptions &eo, const char *kType = NULL)
156 const char *kType = NULL)
157{ 156{
158 MY_TRY_BEGIN 157 MY_TRY_BEGIN
159 158
160 CREATE_CODECS 159 CREATE_CODECS
161 160
162 CExtractOptions eo;
163 eo.OutputDir = us2fs(outFolder);
164 eo.TestMode = testMode;
165 eo.ElimDup.Val = elimDup;
166 eo.ElimDup.Def = elimDup;
167
168 CExtractCallbackImp *ecs = new CExtractCallbackImp; 161 CExtractCallbackImp *ecs = new CExtractCallbackImp;
169 CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs; 162 CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
170 163
@@ -228,15 +221,26 @@ static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
228 return result; 221 return result;
229} 222}
230 223
231void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup) 224void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder,
225 bool showDialog, bool elimDup, UInt32 writeZone)
232{ 226{
233 ExtractGroupCommand(arcPaths, showDialog, outFolder, false, elimDup); 227 CExtractOptions eo;
228 eo.OutputDir = us2fs(outFolder);
229 eo.TestMode = false;
230 eo.ElimDup.Val = elimDup;
231 eo.ElimDup.Def = elimDup;
232 if (writeZone != (UInt32)(Int32)-1)
233 eo.ZoneMode = (NExtract::NZoneIdMode::EEnum)writeZone;
234 ExtractGroupCommand(arcPaths, showDialog, eo);
234} 235}
235 236
236void TestArchives(const UStringVector &arcPaths, bool hashMode) 237void TestArchives(const UStringVector &arcPaths, bool hashMode)
237{ 238{
238 ExtractGroupCommand(arcPaths, true, UString(), true, 239 CExtractOptions eo;
239 false, // elimDup 240 eo.TestMode = true;
241 ExtractGroupCommand(arcPaths,
242 true, // showDialog
243 eo,
240 hashMode ? "hash" : NULL); 244 hashMode ? "hash" : NULL);
241} 245}
242 246
diff --git a/CPP/7zip/UI/Common/DirItem.h b/CPP/7zip/UI/Common/DirItem.h
index e5f578d..86e385f 100644
--- a/CPP/7zip/UI/Common/DirItem.h
+++ b/CPP/7zip/UI/Common/DirItem.h
@@ -10,6 +10,8 @@
10#include "../../../Common/MyString.h" 10#include "../../../Common/MyString.h"
11 11
12#include "../../../Windows/FileFind.h" 12#include "../../../Windows/FileFind.h"
13#include "../../../Windows/PropVariant.h"
14#include "../../../Windows/TimeUtils.h"
13 15
14#include "../../Common/UniqBlocks.h" 16#include "../../Common/UniqBlocks.h"
15 17
@@ -80,50 +82,213 @@ struct IDirItemsCallback
80 INTERFACE_IDirItemsCallback(=0) 82 INTERFACE_IDirItemsCallback(=0)
81}; 83};
82 84
83struct CDirItem 85
86struct CArcTime
87{
88 FILETIME FT;
89 UInt16 Prec;
90 Byte Ns100;
91 bool Def;
92
93 CArcTime()
94 {
95 Clear();
96 }
97
98 void Clear()
99 {
100 FT.dwHighDateTime = FT.dwLowDateTime = 0;
101 Prec = 0;
102 Ns100 = 0;
103 Def = false;
104 }
105
106 bool IsZero() const
107 {
108 return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
109 }
110
111 int CompareWith(const CArcTime &a) const
112 {
113 const int res = CompareFileTime(&FT, &a.FT);
114 if (res != 0)
115 return res;
116 if (Ns100 < a.Ns100) return -1;
117 if (Ns100 > a.Ns100) return 1;
118 return 0;
119 }
120
121 UInt64 Get_FILETIME_as_UInt64() const
122 {
123 return (((UInt64)FT.dwHighDateTime) << 32) + FT.dwLowDateTime;
124 }
125
126 UInt32 Get_DosTime() const
127 {
128 FILETIME ft2 = FT;
129 if ((Prec == k_PropVar_TimePrec_Base + 8 ||
130 Prec == k_PropVar_TimePrec_Base + 9)
131 && Ns100 != 0)
132 {
133 UInt64 u64 = Get_FILETIME_as_UInt64();
134 // we round up even small (ns < 100ns) as FileTimeToDosTime()
135 if (u64 % 20000000 == 0)
136 {
137 u64++;
138 ft2.dwHighDateTime = (DWORD)(u64 >> 32);
139 ft2.dwHighDateTime = (DWORD)u64;
140 }
141 }
142 // FileTimeToDosTime() is expected to round up in Windows
143 UInt32 dosTime;
144 // we use simplified code with utctime->dos.
145 // do we need local time instead here?
146 NWindows::NTime::FileTime_To_DosTime(ft2, dosTime);
147 return dosTime;
148 }
149
150 int GetNumDigits() const
151 {
152 if (Prec == k_PropVar_TimePrec_Unix ||
153 Prec == k_PropVar_TimePrec_DOS)
154 return 0;
155 if (Prec == k_PropVar_TimePrec_HighPrec)
156 return 9;
157 if (Prec == k_PropVar_TimePrec_0)
158 return 7;
159 int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
160 if (digits < 0)
161 digits = 0;
162 return digits;
163 }
164
165 void Write_To_FiTime(CFiTime &dest) const
166 {
167 #ifdef _WIN32
168 dest = FT;
169 #else
170 if (FILETIME_To_timespec(FT, dest))
171 if ((Prec == k_PropVar_TimePrec_Base + 8 ||
172 Prec == k_PropVar_TimePrec_Base + 9)
173 && Ns100 != 0)
174 {
175 dest.tv_nsec += Ns100;
176 }
177 #endif
178 }
179
180 // (Def) is not set
181 void Set_From_FILETIME(const FILETIME &ft)
182 {
183 FT = ft;
184 // Prec = k_PropVar_TimePrec_CompatNTFS;
185 Prec = k_PropVar_TimePrec_Base + 7;
186 Ns100 = 0;
187 }
188
189 // (Def) is not set
190 // it set full form precision: k_PropVar_TimePrec_Base + numDigits
191 void Set_From_FiTime(const CFiTime &ts)
192 {
193 #ifdef _WIN32
194 FT = ts;
195 Prec = k_PropVar_TimePrec_Base + 7;
196 // Prec = k_PropVar_TimePrec_Base; // for debug
197 // Prec = 0; // for debug
198 Ns100 = 0;
199 #else
200 unsigned ns100;
201 FiTime_To_FILETIME_ns100(ts, FT, ns100);
202 Ns100 = (Byte)ns100;
203 Prec = k_PropVar_TimePrec_Base + 9;
204 #endif
205 }
206
207 void Set_From_Prop(const PROPVARIANT &prop)
208 {
209 FT = prop.filetime;
210 unsigned prec = 0;
211 unsigned ns100 = 0;
212 const unsigned prec_Temp = prop.wReserved1;
213 if (prec_Temp != 0
214 && prec_Temp <= k_PropVar_TimePrec_1ns
215 && prop.wReserved3 == 0)
216 {
217 const unsigned ns100_Temp = prop.wReserved2;
218 if (ns100_Temp < 100)
219 {
220 ns100 = ns100_Temp;
221 prec = prec_Temp;
222 }
223 }
224 Prec = (UInt16)prec;
225 Ns100 = (Byte)ns100;
226 Def = true;
227 }
228};
229
230
231struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
84{ 232{
85 UInt64 Size;
86 FILETIME CTime;
87 FILETIME ATime;
88 FILETIME MTime;
89 UString Name; 233 UString Name;
90 234
91 #ifndef UNDER_CE 235 #ifndef UNDER_CE
92 CByteBuffer ReparseData; 236 CByteBuffer ReparseData;
93 237
94 #ifdef _WIN32 238 #ifdef _WIN32
95 // UString ShortName; 239 // UString ShortName;
96 CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format 240 CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format
97 bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } 241 bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; }
98 #else 242 #else
99 bool AreReparseData() const { return ReparseData.Size() != 0; } 243 bool AreReparseData() const { return ReparseData.Size() != 0; }
100 #endif // _WIN32 244 #endif // _WIN32
101 245
102 #endif // !UNDER_CE 246 #endif // !UNDER_CE
103 247
104 UInt32 Attrib; 248 void Copy_From_FileInfoBase(const NWindows::NFile::NFind::CFileInfoBase &fi)
249 {
250 (NWindows::NFile::NFind::CFileInfoBase &)*this = fi;
251 }
252
105 int PhyParent; 253 int PhyParent;
106 int LogParent; 254 int LogParent;
107 int SecureIndex; 255 int SecureIndex;
108 256
109 bool IsAltStream; 257 #ifdef _WIN32
110 258 #else
111 CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {} 259 int OwnerNameIndex;
112 260 int OwnerGroupIndex;
113 bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } 261 #endif
114 bool IsReadOnly() const { return (Attrib & FILE_ATTRIBUTE_READONLY) != 0; } 262
115 bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } 263 CDirItem():
116 264 PhyParent(-1)
117 #ifdef _WIN32 265 , LogParent(-1)
118 UInt32 GetPosixAttrib() const 266 , SecureIndex(-1)
267 #ifdef _WIN32
268 #else
269 , OwnerNameIndex(-1)
270 , OwnerGroupIndex(-1)
271 #endif
119 { 272 {
120 UInt32 v = IsDir() ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG;
121 /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY).
122 So extracting at Linux will be allowed to write files inside (0777) directories. */
123 v |= ((IsReadOnly() && !IsDir()) ? 0555 : 0777);
124 return v;
125 } 273 }
126 #endif 274
275
276 CDirItem(const NWindows::NFile::NFind::CFileInfo &fi,
277 int phyParent, int logParent, int secureIndex):
278 CFileInfoBase(fi)
279 , Name(fs2us(fi.Name))
280 #if defined(_WIN32) && !defined(UNDER_CE)
281 // , ShortName(fs2us(fi.ShortName))
282 #endif
283 , PhyParent(phyParent)
284 , LogParent(logParent)
285 , SecureIndex(secureIndex)
286 #ifdef _WIN32
287 #else
288 , OwnerNameIndex(-1)
289 , OwnerGroupIndex(-1)
290 #endif
291 {}
127}; 292};
128 293
129 294
@@ -145,6 +310,7 @@ public:
145 bool ScanAltStreams; 310 bool ScanAltStreams;
146 bool ExcludeDirItems; 311 bool ExcludeDirItems;
147 bool ExcludeFileItems; 312 bool ExcludeFileItems;
313 bool ShareForWrite;
148 314
149 /* it must be called after anotrher checks */ 315 /* it must be called after anotrher checks */
150 bool CanIncludeItem(bool isDir) const 316 bool CanIncludeItem(bool isDir) const
@@ -160,7 +326,7 @@ public:
160 const FString &phyPrefix); 326 const FString &phyPrefix);
161 #endif 327 #endif
162 328
163 #if defined(_WIN32) && !defined(UNDER_CE) 329 #if defined(_WIN32) && !defined(UNDER_CE)
164 330
165 CUniqBlocks SecureBlocks; 331 CUniqBlocks SecureBlocks;
166 CByteBuffer TempSecureBuf; 332 CByteBuffer TempSecureBuf;
@@ -170,7 +336,17 @@ public:
170 HRESULT AddSecurityItem(const FString &path, int &secureIndex); 336 HRESULT AddSecurityItem(const FString &path, int &secureIndex);
171 HRESULT FillFixedReparse(); 337 HRESULT FillFixedReparse();
172 338
173 #endif 339 #endif
340
341 #ifndef _WIN32
342
343 C_UInt32_UString_Map OwnerNameMap;
344 C_UInt32_UString_Map OwnerGroupMap;
345 bool StoreOwnerName;
346
347 HRESULT FillDeviceSizes();
348
349 #endif
174 350
175 IDirItemsCallback *Callback; 351 IDirItemsCallback *Callback;
176 352
@@ -204,20 +380,25 @@ public:
204}; 380};
205 381
206 382
383
384
207struct CArcItem 385struct CArcItem
208{ 386{
209 UInt64 Size; 387 UInt64 Size;
210 FILETIME MTime;
211 UString Name; 388 UString Name;
389 CArcTime MTime; // it can be mtime of archive file, if MTime is not defined for item in archive
212 bool IsDir; 390 bool IsDir;
213 bool IsAltStream; 391 bool IsAltStream;
214 bool SizeDefined; 392 bool Size_Defined;
215 bool MTimeDefined;
216 bool Censored; 393 bool Censored;
217 UInt32 IndexInServer; 394 UInt32 IndexInServer;
218 int TimeType;
219 395
220 CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {} 396 CArcItem():
397 IsDir(false),
398 IsAltStream(false),
399 Size_Defined(false),
400 Censored(false)
401 {}
221}; 402};
222 403
223#endif 404#endif
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp
index 89cce2b..a4ac413 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -5,6 +5,12 @@
5#include <wchar.h> 5#include <wchar.h>
6// #include <stdio.h> 6// #include <stdio.h>
7 7
8#ifndef _WIN32
9#include <grp.h>
10#include <pwd.h>
11#include "../../../Common/UTFConvert.h"
12#endif
13
8#include "../../../Common/Wildcard.h" 14#include "../../../Common/Wildcard.h"
9 15
10#include "../../../Windows/FileDir.h" 16#include "../../../Windows/FileDir.h"
@@ -23,32 +29,60 @@ using namespace NWindows;
23using namespace NFile; 29using namespace NFile;
24using namespace NName; 30using namespace NName;
25 31
32
33static bool FindFile_KeepDots(NFile::NFind::CFileInfo &fi, const FString &path, bool followLink)
34{
35 const bool res = fi.Find(path, followLink);
36 if (!res)
37 return res;
38 if (path.IsEmpty())
39 return res;
40 // we keep name "." and "..", if it's without tail slash
41 const FChar *p = path.RightPtr(1);
42 if (*p != '.')
43 return res;
44 if (p != path.Ptr())
45 {
46 FChar c = p[-1];
47 if (!IS_PATH_SEPAR(c))
48 {
49 if (c != '.')
50 return res;
51 p--;
52 if (p != path.Ptr())
53 {
54 c = p[-1];
55 if (!IS_PATH_SEPAR(c))
56 return res;
57 }
58 }
59 }
60 fi.Name = p;
61 return res;
62}
63
64
26void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex, 65void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,
27 const NFind::CFileInfo &fi) 66 const NFind::CFileInfo &fi)
28{ 67{
29 CDirItem di; 68 /*
30 di.Size = fi.Size; 69 CDirItem di(fi);
31 di.CTime = fi.CTime;
32 di.ATime = fi.ATime;
33 di.MTime = fi.MTime;
34 di.Attrib = fi.Attrib;
35 di.IsAltStream = fi.IsAltStream;
36 di.PhyParent = phyParent; 70 di.PhyParent = phyParent;
37 di.LogParent = logParent; 71 di.LogParent = logParent;
38 di.SecureIndex = secureIndex; 72 di.SecureIndex = secureIndex;
39 di.Name = fs2us(fi.Name);
40 #if defined(_WIN32) && !defined(UNDER_CE)
41 // di.ShortName = fs2us(fi.ShortName);
42 #endif
43 Items.Add(di); 73 Items.Add(di);
74 */
75 VECTOR_ADD_NEW_OBJECT (Items, CDirItem(fi, phyParent, logParent, secureIndex))
44 76
45 if (fi.IsDir()) 77 if (fi.IsDir())
46 Stat.NumDirs++; 78 Stat.NumDirs++;
79 #ifdef _WIN32
47 else if (fi.IsAltStream) 80 else if (fi.IsAltStream)
48 { 81 {
49 Stat.NumAltStreams++; 82 Stat.NumAltStreams++;
50 Stat.AltStreamsSize += fi.Size; 83 Stat.AltStreamsSize += fi.Size;
51 } 84 }
85 #endif
52 else 86 else
53 { 87 {
54 Stat.NumFiles++; 88 Stat.NumFiles++;
@@ -148,9 +182,13 @@ CDirItems::CDirItems():
148 ScanAltStreams(false) 182 ScanAltStreams(false)
149 , ExcludeDirItems(false) 183 , ExcludeDirItems(false)
150 , ExcludeFileItems(false) 184 , ExcludeFileItems(false)
151 #ifdef _USE_SECURITY_CODE 185 , ShareForWrite(false)
186 #ifdef _USE_SECURITY_CODE
152 , ReadSecure(false) 187 , ReadSecure(false)
153 #endif 188 #endif
189 #ifndef _WIN32
190 , StoreOwnerName(true)
191 #endif
154 , Callback(NULL) 192 , Callback(NULL)
155{ 193{
156 #ifdef _USE_SECURITY_CODE 194 #ifdef _USE_SECURITY_CODE
@@ -379,7 +417,7 @@ HRESULT CDirItems::EnumerateItems2(
379 const FString &filePath = filePaths[i]; 417 const FString &filePath = filePaths[i];
380 NFind::CFileInfo fi; 418 NFind::CFileInfo fi;
381 const FString phyPath = phyPrefix + filePath; 419 const FString phyPath = phyPrefix + filePath;
382 if (!fi.Find(phyPath FOLLOW_LINK_PARAM)) 420 if (!FindFile_KeepDots(fi, phyPath FOLLOW_LINK_PARAM))
383 { 421 {
384 RINOK(AddError(phyPath)); 422 RINOK(AddError(phyPath));
385 continue; 423 continue;
@@ -658,15 +696,14 @@ static HRESULT EnumerateForItem(
658 if (!enterToSubFolders) 696 if (!enterToSubFolders)
659 return S_OK; 697 return S_OK;
660 698
661 #ifndef _WIN32 699 #ifndef _WIN32
662 if (fi.IsPosixLink()) 700 if (fi.IsPosixLink())
663 { 701 {
664 // here we can try to resolve posix link 702 // here we can try to resolve posix link
665 // if the link to dir, then can we follow it 703 // if the link to dir, then can we follow it
666 return S_OK; // we don't follow posix link 704 return S_OK; // we don't follow posix link
667 } 705 }
668 #endif 706 #else
669
670 if (dirItems.SymLinks && fi.HasReparsePoint()) 707 if (dirItems.SymLinks && fi.HasReparsePoint())
671 { 708 {
672 /* 20.03: in SymLinks mode: we don't enter to directory that 709 /* 20.03: in SymLinks mode: we don't enter to directory that
@@ -677,6 +714,7 @@ static HRESULT EnumerateForItem(
677 */ 714 */
678 return S_OK; 715 return S_OK;
679 } 716 }
717 #endif
680 nextNode = &curNode; 718 nextNode = &curNode;
681 } 719 }
682 720
@@ -826,7 +864,7 @@ static HRESULT EnumerateDirItems(
826 } 864 }
827 else 865 else
828 #endif 866 #endif
829 if (!fi.Find(fullPath FOLLOW_LINK_PARAM2)) 867 if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2))
830 { 868 {
831 RINOK(dirItems.AddError(fullPath)); 869 RINOK(dirItems.AddError(fullPath));
832 continue; 870 continue;
@@ -914,15 +952,14 @@ static HRESULT EnumerateDirItems(
914 } 952 }
915 else 953 else
916 { 954 {
917 #ifndef _WIN32 955 #ifndef _WIN32
918 if (fi.IsPosixLink()) 956 if (fi.IsPosixLink())
919 { 957 {
920 // here we can try to resolve posix link 958 // here we can try to resolve posix link
921 // if the link to dir, then can we follow it 959 // if the link to dir, then can we follow it
922 continue; // we don't follow posix link 960 continue; // we don't follow posix link
923 } 961 }
924 #endif 962 #else
925
926 if (dirItems.SymLinks) 963 if (dirItems.SymLinks)
927 { 964 {
928 if (fi.HasReparsePoint()) 965 if (fi.HasReparsePoint())
@@ -932,6 +969,7 @@ static HRESULT EnumerateDirItems(
932 continue; 969 continue;
933 } 970 }
934 } 971 }
972 #endif
935 nextNode = &curNode; 973 nextNode = &curNode;
936 newParts.Add(name); // don't change it to fi.Name. It's for shortnames support 974 newParts.Add(name); // don't change it to fi.Name. It's for shortnames support
937 } 975 }
@@ -973,7 +1011,7 @@ static HRESULT EnumerateDirItems(
973 } 1011 }
974 else 1012 else
975 { 1013 {
976 if (!fi.Find(fullPath FOLLOW_LINK_PARAM2)) 1014 if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2))
977 { 1015 {
978 if (!nextNode.AreThereIncludeItems()) 1016 if (!nextNode.AreThereIncludeItems())
979 continue; 1017 continue;
@@ -1136,15 +1174,18 @@ HRESULT EnumerateItems(
1136 } 1174 }
1137 dirItems.ReserveDown(); 1175 dirItems.ReserveDown();
1138 1176
1139 #if defined(_WIN32) && !defined(UNDER_CE) 1177 #if defined(_WIN32) && !defined(UNDER_CE)
1140 RINOK(dirItems.FillFixedReparse()); 1178 RINOK(dirItems.FillFixedReparse());
1141 #endif 1179 #endif
1180
1181 #ifndef _WIN32
1182 RINOK(dirItems.FillDeviceSizes());
1183 #endif
1142 1184
1143 return S_OK; 1185 return S_OK;
1144} 1186}
1145 1187
1146 1188
1147
1148#if defined(_WIN32) && !defined(UNDER_CE) 1189#if defined(_WIN32) && !defined(UNDER_CE)
1149 1190
1150HRESULT CDirItems::FillFixedReparse() 1191HRESULT CDirItems::FillFixedReparse()
@@ -1281,6 +1322,148 @@ HRESULT CDirItems::FillFixedReparse()
1281#endif 1322#endif
1282 1323
1283 1324
1325#ifndef _WIN32
1326
1327HRESULT CDirItems::FillDeviceSizes()
1328{
1329 {
1330 FOR_VECTOR (i, Items)
1331 {
1332 CDirItem &item = Items[i];
1333
1334 if (S_ISBLK(item.mode) && item.Size == 0)
1335 {
1336 const FString phyPath = GetPhyPath(i);
1337 NIO::CInFile inFile;
1338 inFile.PreserveATime = true;
1339 if (inFile.OpenShared(phyPath, ShareForWrite)) // fixme: OpenShared ??
1340 {
1341 UInt64 size = 0;
1342 if (inFile.GetLength(size))
1343 item.Size = size;
1344 }
1345 }
1346 if (StoreOwnerName)
1347 {
1348 OwnerNameMap.Add_UInt32(item.uid);
1349 OwnerGroupMap.Add_UInt32(item.gid);
1350 }
1351 }
1352 }
1353
1354 if (StoreOwnerName)
1355 {
1356 UString u;
1357 AString a;
1358 {
1359 FOR_VECTOR (i, OwnerNameMap.Numbers)
1360 {
1361 // 200K/sec speed
1362 u.Empty();
1363 const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]);
1364 if (pw)
1365 {
1366 a = pw->pw_name;
1367 ConvertUTF8ToUnicode(a, u);
1368 }
1369 OwnerNameMap.Strings.Add(u);
1370 }
1371 }
1372 {
1373 FOR_VECTOR (i, OwnerGroupMap.Numbers)
1374 {
1375 u.Empty();
1376 const group *gr = getgrgid(OwnerGroupMap.Numbers[i]);
1377 if (gr)
1378 {
1379 // printf("\ngetgrgid %d %s\n", OwnerGroupMap.Numbers[i], gr->gr_name);
1380 a = gr->gr_name;
1381 ConvertUTF8ToUnicode(a, u);
1382 }
1383 OwnerGroupMap.Strings.Add(u);
1384 }
1385 }
1386
1387 FOR_VECTOR (i, Items)
1388 {
1389 CDirItem &item = Items[i];
1390 {
1391 const int index = OwnerNameMap.Find(item.uid);
1392 if (index < 0) throw 1;
1393 item.OwnerNameIndex = index;
1394 }
1395 {
1396 const int index = OwnerGroupMap.Find(item.gid);
1397 if (index < 0) throw 1;
1398 item.OwnerGroupIndex = index;
1399 }
1400 }
1401 }
1402
1403
1404 // if (NeedOwnerNames)
1405 {
1406 /*
1407 {
1408 for (unsigned i = 0 ; i < 10000; i++)
1409 {
1410 const passwd *pw = getpwuid(i);
1411 if (pw)
1412 {
1413 UString u;
1414 ConvertUTF8ToUnicode(AString(pw->pw_name), u);
1415 OwnerNameMap.Add(i, u);
1416 OwnerNameMap.Add(i, u);
1417 OwnerNameMap.Add(i, u);
1418 }
1419 const group *gr = getgrgid(i);
1420 if (gr)
1421 {
1422 // we can use utf-8 here.
1423 UString u;
1424 ConvertUTF8ToUnicode(AString(gr->gr_name), u);
1425 OwnerGroupMap.Add(i, u);
1426 }
1427 }
1428 }
1429 */
1430 /*
1431 {
1432 FOR_VECTOR (i, OwnerNameMap.Strings)
1433 {
1434 AString s;
1435 ConvertUnicodeToUTF8(OwnerNameMap.Strings[i], s);
1436 printf("\n%5d %s", (unsigned)OwnerNameMap.Numbers[i], s.Ptr());
1437 }
1438 }
1439 {
1440 printf("\n\n=========Groups\n");
1441 FOR_VECTOR (i, OwnerGroupMap.Strings)
1442 {
1443 AString s;
1444 ConvertUnicodeToUTF8(OwnerGroupMap.Strings[i], s);
1445 printf("\n%5d %s", (unsigned)OwnerGroupMap.Numbers[i], s.Ptr());
1446 }
1447 }
1448 */
1449 }
1450 /*
1451 for (unsigned i = 0 ; i < 100000000; i++)
1452 {
1453 // const passwd *pw = getpwuid(1000);
1454 // pw = pw;
1455 int pos = OwnerNameMap.Find(1000);
1456 if (pos < 0 - (int)i)
1457 throw 1;
1458 }
1459 */
1460
1461 return S_OK;
1462}
1463
1464#endif
1465
1466
1284 1467
1285static const char * const kCannotFindArchive = "Cannot find archive"; 1468static const char * const kCannotFindArchive = "Cannot find archive";
1286 1469
@@ -1351,11 +1534,18 @@ HRESULT EnumerateDirItemsAndSort(
1351 1534
1352#ifdef _WIN32 1535#ifdef _WIN32
1353 1536
1537static bool IsDotsName(const wchar_t *s)
1538{
1539 return s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0));
1540}
1541
1354// This code converts all short file names to long file names. 1542// This code converts all short file names to long file names.
1355 1543
1356static void ConvertToLongName(const UString &prefix, UString &name) 1544static void ConvertToLongName(const UString &prefix, UString &name)
1357{ 1545{
1358 if (name.IsEmpty() || DoesNameContainWildcard(name)) 1546 if (name.IsEmpty()
1547 || DoesNameContainWildcard(name)
1548 || IsDotsName(name))
1359 return; 1549 return;
1360 NFind::CFileInfo fi; 1550 NFind::CFileInfo fi;
1361 const FString path (us2fs(prefix + name)); 1551 const FString path (us2fs(prefix + name));
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp
index de2aeb2..58f5218 100644
--- a/CPP/7zip/UI/Common/Extract.cpp
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -239,18 +239,18 @@ static HRESULT DecompressArchive(
239 Sorted list for file paths was sorted with case insensitive compare function. 239 Sorted list for file paths was sorted with case insensitive compare function.
240 But FindInSorted function did binary search via case sensitive compare function */ 240 But FindInSorted function did binary search via case sensitive compare function */
241 241
242int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name); 242int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name);
243int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name) 243int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name)
244{ 244{
245 unsigned left = 0, right = fileName.Size(); 245 unsigned left = 0, right = fileNames.Size();
246 while (left != right) 246 while (left != right)
247 { 247 {
248 unsigned mid = (left + right) / 2; 248 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
249 const UString &midValue = fileName[mid]; 249 const UString &midVal = fileNames[mid];
250 int compare = CompareFileNames(name, midValue); 250 const int comp = CompareFileNames(name, midVal);
251 if (compare == 0) 251 if (comp == 0)
252 return (int)mid; 252 return (int)mid;
253 if (compare < 0) 253 if (comp < 0)
254 right = mid; 254 right = mid;
255 else 255 else
256 left = mid + 1; 256 left = mid + 1;
@@ -314,8 +314,13 @@ HRESULT Extract(
314 314
315 CArchiveExtractCallback *ecs = new CArchiveExtractCallback; 315 CArchiveExtractCallback *ecs = new CArchiveExtractCallback;
316 CMyComPtr<IArchiveExtractCallback> ec(ecs); 316 CMyComPtr<IArchiveExtractCallback> ec(ecs);
317 bool multi = (numArcs > 1); 317
318 ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode, 318 const bool multi = (numArcs > 1);
319
320 ecs->InitForMulti(multi,
321 options.PathMode,
322 options.OverwriteMode,
323 options.ZoneMode,
319 false // keepEmptyDirParts 324 false // keepEmptyDirParts
320 ); 325 );
321 #ifndef _SFX 326 #ifndef _SFX
@@ -335,12 +340,18 @@ HRESULT Extract(
335 if (skipArcs[i]) 340 if (skipArcs[i])
336 continue; 341 continue;
337 342
343 ecs->InitBeforeNewArchive();
344
338 const UString &arcPath = arcPaths[i]; 345 const UString &arcPath = arcPaths[i];
339 NFind::CFileInfo fi; 346 NFind::CFileInfo fi;
340 if (options.StdInMode) 347 if (options.StdInMode)
341 { 348 {
342 fi.Size = 0; 349 // do we need ctime and mtime?
343 fi.Attrib = 0; 350 fi.ClearBase();
351 fi.Size = 0; // (UInt64)(Int64)-1;
352 fi.SetAsFile();
353 // NTime::GetCurUtc_FiTime(fi.MTime);
354 // fi.CTime = fi.ATime = fi.MTime;
344 } 355 }
345 else 356 else
346 { 357 {
@@ -417,6 +428,15 @@ HRESULT Extract(
417 continue; 428 continue;
418 } 429 }
419 430
431 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
432 if (options.ZoneMode != NExtract::NZoneIdMode::kNone
433 && !options.StdInMode)
434 {
435 ReadZoneFile_Of_BaseFile(us2fs(arcPath), ecs->ZoneBuf);
436 }
437 #endif
438
439
420 if (arcLink.Arcs.Size() != 0) 440 if (arcLink.Arcs.Size() != 0)
421 { 441 {
422 if (arcLink.GetArc()->IsHashHandler(op)) 442 if (arcLink.GetArc()->IsHashHandler(op))
@@ -490,11 +510,16 @@ HRESULT Extract(
490 */ 510 */
491 511
492 CArc &arc = arcLink.Arcs.Back(); 512 CArc &arc = arcLink.Arcs.Back();
493 arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); 513 arc.MTime.Def = !options.StdInMode
494 arc.MTime = fi.MTime; 514 #ifdef _WIN32
515 && !fi.IsDevice
516 #endif
517 ;
518 if (arc.MTime.Def)
519 arc.MTime.Set_From_FiTime(fi.MTime);
495 520
496 UInt64 packProcessed; 521 UInt64 packProcessed;
497 bool calcCrc = 522 const bool calcCrc =
498 #ifndef _SFX 523 #ifndef _SFX
499 (hash != NULL); 524 (hash != NULL);
500 #else 525 #else
diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h
index 10e06da..f3d1126 100644
--- a/CPP/7zip/UI/Common/Extract.h
+++ b/CPP/7zip/UI/Common/Extract.h
@@ -25,6 +25,7 @@ struct CExtractOptionsBase
25 bool OverwriteMode_Force; 25 bool OverwriteMode_Force;
26 NExtract::NPathMode::EEnum PathMode; 26 NExtract::NPathMode::EEnum PathMode;
27 NExtract::NOverwriteMode::EEnum OverwriteMode; 27 NExtract::NOverwriteMode::EEnum OverwriteMode;
28 NExtract::NZoneIdMode::EEnum ZoneMode;
28 29
29 FString OutputDir; 30 FString OutputDir;
30 CExtractNtOptions NtOptions; 31 CExtractNtOptions NtOptions;
@@ -36,7 +37,8 @@ struct CExtractOptionsBase
36 PathMode_Force(false), 37 PathMode_Force(false),
37 OverwriteMode_Force(false), 38 OverwriteMode_Force(false),
38 PathMode(NExtract::NPathMode::kFullPaths), 39 PathMode(NExtract::NPathMode::kFullPaths),
39 OverwriteMode(NExtract::NOverwriteMode::kAsk) 40 OverwriteMode(NExtract::NOverwriteMode::kAsk),
41 ZoneMode(NExtract::NZoneIdMode::kNone)
40 {} 42 {}
41}; 43};
42 44
diff --git a/CPP/7zip/UI/Common/ExtractMode.h b/CPP/7zip/UI/Common/ExtractMode.h
index 3b2b9a0..9ad831e 100644
--- a/CPP/7zip/UI/Common/ExtractMode.h
+++ b/CPP/7zip/UI/Common/ExtractMode.h
@@ -29,6 +29,16 @@ namespace NOverwriteMode
29 }; 29 };
30} 30}
31 31
32namespace NZoneIdMode
33{
34 enum EEnum
35 {
36 kNone,
37 kAll,
38 kOffice
39 };
40}
41
32} 42}
33 43
34#endif 44#endif
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
index 21a306d..a1282b7 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -34,10 +34,19 @@ static void ReplaceIncorrectChars(UString &s)
34 || 34 ||
35 #endif 35 #endif
36 c == WCHAR_PATH_SEPARATOR) 36 c == WCHAR_PATH_SEPARATOR)
37 {
38 #if WCHAR_PATH_SEPARATOR != L'/'
39 // 22.00 : WSL replacement for backslash
40 if (c == WCHAR_PATH_SEPARATOR)
41 c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT;
42 else
43 #endif
44 c = '_';
37 s.ReplaceOneCharAtPos(i, 45 s.ReplaceOneCharAtPos(i,
38 '_' // default 46 c
39 // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters 47 // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters
40 ); 48 );
49 }
41 } 50 }
42 } 51 }
43 52
diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp
index 2417708..f0aa4bd 100644
--- a/CPP/7zip/UI/Common/HashCalc.cpp
+++ b/CPP/7zip/UI/Common/HashCalc.cpp
@@ -15,6 +15,7 @@
15#include "../../Common/StreamUtils.h" 15#include "../../Common/StreamUtils.h"
16 16
17#include "../../Archive/Common/ItemNameUtils.h" 17#include "../../Archive/Common/ItemNameUtils.h"
18#include "../../Archive/IArchive.h"
18 19
19#include "EnumDirItems.h" 20#include "EnumDirItems.h"
20#include "HashCalc.h" 21#include "HashCalc.h"
@@ -309,8 +310,6 @@ static unsigned GetColumnWidth(unsigned digestSize)
309} 310}
310 311
311 312
312void HashHexToString(char *dest, const Byte *data, UInt32 size);
313
314static void AddHashResultLine( 313static void AddHashResultLine(
315 AString &_s, 314 AString &_s,
316 // bool showHash, 315 // bool showHash,
@@ -463,10 +462,7 @@ HRESULT HashCalc(
463 { 462 {
464 CDirItem di; 463 CDirItem di;
465 di.Size = (UInt64)(Int64)-1; 464 di.Size = (UInt64)(Int64)-1;
466 di.Attrib = 0; 465 di.SetAsFile();
467 di.MTime.dwLowDateTime = 0;
468 di.MTime.dwHighDateTime = 0;
469 di.CTime = di.ATime = di.MTime;
470 dirItems.Items.Add(di); 466 dirItems.Items.Add(di);
471 } 467 }
472 else 468 else
@@ -478,6 +474,8 @@ HRESULT HashCalc(
478 dirItems.ExcludeDirItems = censor.ExcludeDirItems; 474 dirItems.ExcludeDirItems = censor.ExcludeDirItems;
479 dirItems.ExcludeFileItems = censor.ExcludeFileItems; 475 dirItems.ExcludeFileItems = censor.ExcludeFileItems;
480 476
477 dirItems.ShareForWrite = options.OpenShareForWrite;
478
481 HRESULT res = EnumerateItems(censor, 479 HRESULT res = EnumerateItems(censor,
482 options.PathMode, 480 options.PathMode,
483 UString(), 481 UString(),
@@ -498,14 +496,16 @@ HRESULT HashCalc(
498 // hb.Init(); 496 // hb.Init();
499 497
500 hb.NumErrors = dirItems.Stat.NumErrors; 498 hb.NumErrors = dirItems.Stat.NumErrors;
501 499
500 UInt64 totalSize = 0;
502 if (options.StdInMode) 501 if (options.StdInMode)
503 { 502 {
504 RINOK(callback->SetNumFiles(1)); 503 RINOK(callback->SetNumFiles(1));
505 } 504 }
506 else 505 else
507 { 506 {
508 RINOK(callback->SetTotal(dirItems.Stat.GetTotalBytes())); 507 totalSize = dirItems.Stat.GetTotalBytes();
508 RINOK(callback->SetTotal(totalSize));
509 } 509 }
510 510
511 const UInt32 kBufSize = 1 << 15; 511 const UInt32 kBufSize = 1 << 15;
@@ -537,7 +537,9 @@ HRESULT HashCalc(
537 { 537 {
538 path = dirItems.GetLogPath(i); 538 path = dirItems.GetLogPath(i);
539 const CDirItem &di = dirItems.Items[i]; 539 const CDirItem &di = dirItems.Items[i];
540 #ifdef _WIN32
540 isAltStream = di.IsAltStream; 541 isAltStream = di.IsAltStream;
542 #endif
541 543
542 #ifndef UNDER_CE 544 #ifndef UNDER_CE
543 // if (di.AreReparseData()) 545 // if (di.AreReparseData())
@@ -551,7 +553,7 @@ HRESULT HashCalc(
551 #endif 553 #endif
552 { 554 {
553 CInFileStream *inStreamSpec = new CInFileStream; 555 CInFileStream *inStreamSpec = new CInFileStream;
554 inStreamSpec->File.PreserveATime = options.PreserveATime; 556 inStreamSpec->Set_PreserveATime(options.PreserveATime);
555 inStream = inStreamSpec; 557 inStream = inStreamSpec;
556 isDir = di.IsDir(); 558 isDir = di.IsDir();
557 if (!isDir) 559 if (!isDir)
@@ -565,6 +567,20 @@ HRESULT HashCalc(
565 return res; 567 return res;
566 continue; 568 continue;
567 } 569 }
570 if (!options.StdInMode)
571 {
572 UInt64 curSize = 0;
573 if (inStreamSpec->GetSize(&curSize) == S_OK)
574 {
575 if (curSize > di.Size)
576 {
577 totalSize += curSize - di.Size;
578 RINOK(callback->SetTotal(totalSize));
579 // printf("\ntotal = %d MiB\n", (unsigned)(totalSize >> 20));
580 }
581 }
582 }
583 // inStreamSpec->ReloadProps();
568 } 584 }
569 } 585 }
570 } 586 }
@@ -580,6 +596,7 @@ HRESULT HashCalc(
580 { 596 {
581 if ((step & 0xFF) == 0) 597 if ((step & 0xFF) == 0)
582 { 598 {
599 // printf("\ncompl = %d\n", (unsigned)(completeValue >> 20));
583 RINOK(callback->SetCompleted(&completeValue)); 600 RINOK(callback->SetCompleted(&completeValue));
584 } 601 }
585 UInt32 size; 602 UInt32 size;
@@ -1679,8 +1696,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1679 if (_isArc && !CanUpdate()) 1696 if (_isArc && !CanUpdate())
1680 return E_NOTIMPL; 1697 return E_NOTIMPL;
1681 1698
1682 // const UINT codePage = CP_UTF8; // // (_forceCodePage ? _specifiedCodePage : _openCodePage); 1699 /*
1683 // const unsigned utfFlags = g_Unicode_To_UTF8_Flags; 1700 CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
1701 callback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
1702 */
1703
1684 CObjectVector<CUpdateItem> updateItems; 1704 CObjectVector<CUpdateItem> updateItems;
1685 1705
1686 UInt64 complexity = 0; 1706 UInt64 complexity = 0;
@@ -1827,6 +1847,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1827 if (ui.NewData) 1847 if (ui.NewData)
1828 { 1848 {
1829 UInt64 currentComplexity = ui.Size; 1849 UInt64 currentComplexity = ui.Size;
1850 UInt64 fileSize = 0;
1851
1830 CMyComPtr<ISequentialInStream> fileInStream; 1852 CMyComPtr<ISequentialInStream> fileInStream;
1831 bool needWrite = true; 1853 bool needWrite = true;
1832 { 1854 {
@@ -1840,6 +1862,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1840 1862
1841 if (fileInStream) 1863 if (fileInStream)
1842 { 1864 {
1865 CMyComPtr<IStreamGetSize> streamGetSize;
1866 fileInStream->QueryInterface(IID_IStreamGetSize, (void **)&streamGetSize);
1867 if (streamGetSize)
1868 {
1869 UInt64 size;
1870 if (streamGetSize->GetSize(&size) == S_OK)
1871 currentComplexity = size;
1872 }
1873 /*
1843 CMyComPtr<IStreamGetProps> getProps; 1874 CMyComPtr<IStreamGetProps> getProps;
1844 fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); 1875 fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
1845 if (getProps) 1876 if (getProps)
@@ -1852,6 +1883,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1852 // item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; 1883 // item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
1853 } 1884 }
1854 } 1885 }
1886 */
1855 } 1887 }
1856 else 1888 else
1857 { 1889 {
@@ -1865,7 +1897,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1865 1897
1866 if (needWrite && fileInStream && !isDir) 1898 if (needWrite && fileInStream && !isDir)
1867 { 1899 {
1868 UInt64 fileSize = 0;
1869 for (UInt32 step = 0;; step++) 1900 for (UInt32 step = 0;; step++)
1870 { 1901 {
1871 if ((step & 0xFF) == 0) 1902 if ((step & 0xFF) == 0)
@@ -1901,6 +1932,36 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1901 } 1932 }
1902 1933
1903 complexity += currentComplexity; 1934 complexity += currentComplexity;
1935
1936 /*
1937 if (reportArcProp)
1938 {
1939 PROPVARIANT prop;
1940 prop.vt = VT_EMPTY;
1941 prop.wReserved1 = 0;
1942
1943 NCOM::PropVarEm_Set_UInt64(&prop, fileSize);
1944 RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidSize, &prop));
1945
1946 for (unsigned k = 0; k < hb.Hashers.Size(); k++)
1947 {
1948 const CHasherState &hs = hb.Hashers[k];
1949
1950 if (hs.DigestSize == 4 && hs.Name.IsEqualTo_Ascii_NoCase("crc32"))
1951 {
1952 NCOM::PropVarEm_Set_UInt32(&prop, GetUi32(hs.Digests[k_HashCalc_Index_Current]));
1953 RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidCRC, &prop));
1954 }
1955 else
1956 {
1957 RINOK(reportArcProp->ReportRawProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient,
1958 kpidChecksum, hs.Digests[k_HashCalc_Index_Current],
1959 hs.DigestSize, NPropDataType::kRaw));
1960 }
1961 RINOK(reportArcProp->ReportFinished(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, NArchive::NUpdate::NOperationResult::kOK));
1962 }
1963 }
1964 */
1904 RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); 1965 RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
1905 } 1966 }
1906 else 1967 else
diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h
index 80a5565..c566caa 100644
--- a/CPP/7zip/UI/Common/HashCalc.h
+++ b/CPP/7zip/UI/Common/HashCalc.h
@@ -16,6 +16,12 @@ const unsigned k_HashCalc_DigestSize_Max = 64;
16const unsigned k_HashCalc_ExtraSize = 8; 16const unsigned k_HashCalc_ExtraSize = 8;
17const unsigned k_HashCalc_NumGroups = 4; 17const unsigned k_HashCalc_NumGroups = 4;
18 18
19/*
20 if (size <= 8) : upper case : reversed byte order : it shows 32-bit/64-bit number, if data contains little-endian number
21 if (size > 8) : lower case : original byte order (as big-endian byte sequence)
22*/
23void HashHexToString(char *dest, const Byte *data, UInt32 size);
24
19enum 25enum
20{ 26{
21 k_HashCalc_Index_Current, 27 k_HashCalc_Index_Current,
diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp
index 377963a..b6a2073 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.cpp
+++ b/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -33,8 +33,6 @@ EXPORT_CODECS
33 33
34#include "StdAfx.h" 34#include "StdAfx.h"
35 35
36#include "../../../../C/7zVersion.h"
37
38#include "../../../Common/MyCom.h" 36#include "../../../Common/MyCom.h"
39#include "../../../Common/StringToInt.h" 37#include "../../../Common/StringToInt.h"
40#include "../../../Common/StringConvert.h" 38#include "../../../Common/StringConvert.h"
@@ -275,6 +273,9 @@ static HRESULT GetMethodBoolProp(Func_GetMethodProperty getMethodProperty, UInt3
275#define MY_GET_FUNC(dest, type, func) *(void **)(&dest) = (func); 273#define MY_GET_FUNC(dest, type, func) *(void **)(&dest) = (func);
276// #define MY_GET_FUNC(dest, type, func) dest = (type)(func); 274// #define MY_GET_FUNC(dest, type, func) dest = (type)(func);
277 275
276#define MY_GET_FUNC_LOC(dest, type, func) \
277 type dest; MY_GET_FUNC(dest, type, func)
278
278HRESULT CCodecs::LoadCodecs() 279HRESULT CCodecs::LoadCodecs()
279{ 280{
280 CCodecLib &lib = Libs.Back(); 281 CCodecLib &lib = Libs.Back();
@@ -286,8 +287,7 @@ HRESULT CCodecs::LoadCodecs()
286 if (lib.GetMethodProperty) 287 if (lib.GetMethodProperty)
287 { 288 {
288 UInt32 numMethods = 1; 289 UInt32 numMethods = 1;
289 Func_GetNumberOfMethods getNumberOfMethods; 290 MY_GET_FUNC_LOC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib.GetProc("GetNumberOfMethods"));
290 MY_GET_FUNC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib.GetProc("GetNumberOfMethods"));
291 if (getNumberOfMethods) 291 if (getNumberOfMethods)
292 { 292 {
293 RINOK(getNumberOfMethods(&numMethods)); 293 RINOK(getNumberOfMethods(&numMethods));
@@ -304,8 +304,7 @@ HRESULT CCodecs::LoadCodecs()
304 } 304 }
305 } 305 }
306 306
307 Func_GetHashers getHashers; 307 MY_GET_FUNC_LOC (getHashers, Func_GetHashers, lib.Lib.GetProc("GetHashers"));
308 MY_GET_FUNC (getHashers, Func_GetHashers, lib.Lib.GetProc("GetHashers"));
309 if (getHashers) 308 if (getHashers)
310 { 309 {
311 RINOK(getHashers(&lib.ComHashers)); 310 RINOK(getHashers(&lib.ComHashers));
@@ -414,17 +413,14 @@ HRESULT CCodecs::LoadFormats()
414 const NDLL::CLibrary &lib = Libs.Back().Lib; 413 const NDLL::CLibrary &lib = Libs.Back().Lib;
415 414
416 Func_GetHandlerProperty getProp = NULL; 415 Func_GetHandlerProperty getProp = NULL;
417 Func_GetHandlerProperty2 getProp2; 416 MY_GET_FUNC_LOC (getProp2, Func_GetHandlerProperty2, lib.GetProc("GetHandlerProperty2"));
418 MY_GET_FUNC (getProp2, Func_GetHandlerProperty2, lib.GetProc("GetHandlerProperty2")); 417 MY_GET_FUNC_LOC (getIsArc, Func_GetIsArc, lib.GetProc("GetIsArc"));
419 Func_GetIsArc getIsArc;
420 MY_GET_FUNC (getIsArc, Func_GetIsArc, lib.GetProc("GetIsArc"));
421 418
422 UInt32 numFormats = 1; 419 UInt32 numFormats = 1;
423 420
424 if (getProp2) 421 if (getProp2)
425 { 422 {
426 Func_GetNumberOfFormats getNumberOfFormats; 423 MY_GET_FUNC_LOC (getNumberOfFormats, Func_GetNumberOfFormats, lib.GetProc("GetNumberOfFormats"));
427 MY_GET_FUNC (getNumberOfFormats, Func_GetNumberOfFormats, lib.GetProc("GetNumberOfFormats"));
428 if (getNumberOfFormats) 424 if (getNumberOfFormats)
429 { 425 {
430 RINOK(getNumberOfFormats(&numFormats)); 426 RINOK(getNumberOfFormats(&numFormats));
@@ -477,6 +473,11 @@ HRESULT CCodecs::LoadFormats()
477 item.Flags |= kArcFlagsPars[j + 1]; 473 item.Flags |= kArcFlagsPars[j + 1];
478 } 474 }
479 } 475 }
476
477 {
478 bool defined = false;
479 RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kTimeFlags, item.TimeFlags, defined));
480 }
480 481
481 CByteBuffer sig; 482 CByteBuffer sig;
482 RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)); 483 RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig));
@@ -567,8 +568,7 @@ HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loaded
567 568
568 /* 569 /*
569 { 570 {
570 Func_LibStartup _LibStartup; 571 MY_GET_FUNC_LOC (_LibStartup, Func_LibStartup, lib.Lib.GetProc("LibStartup"));
571 MY_GET_FUNC (_LibStartup, Func_LibStartup, lib.Lib.GetProc("LibStartup"));
572 if (_LibStartup) 572 if (_LibStartup)
573 { 573 {
574 HRESULT res = _LibStartup(); 574 HRESULT res = _LibStartup();
@@ -585,21 +585,31 @@ HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loaded
585 #ifdef _7ZIP_LARGE_PAGES 585 #ifdef _7ZIP_LARGE_PAGES
586 if (g_LargePageSize != 0) 586 if (g_LargePageSize != 0)
587 { 587 {
588 Func_SetLargePageMode setLargePageMode; 588 MY_GET_FUNC_LOC (setLargePageMode, Func_SetLargePageMode, lib.Lib.GetProc("SetLargePageMode"));
589 MY_GET_FUNC (setLargePageMode, Func_SetLargePageMode, lib.Lib.GetProc("SetLargePageMode"));
590 if (setLargePageMode) 589 if (setLargePageMode)
591 setLargePageMode(); 590 setLargePageMode();
592 } 591 }
593 #endif 592 #endif
594 593
595 if (CaseSensitiveChange) 594 if (CaseSensitive_Change)
596 { 595 {
597 Func_SetCaseSensitive setCaseSensitive; 596 MY_GET_FUNC_LOC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib.GetProc("SetCaseSensitive"));
598 MY_GET_FUNC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib.GetProc("SetCaseSensitive"));
599 if (setCaseSensitive) 597 if (setCaseSensitive)
600 setCaseSensitive(CaseSensitive ? 1 : 0); 598 setCaseSensitive(CaseSensitive ? 1 : 0);
601 } 599 }
602 600
601 /*
602 {
603 MY_GET_FUNC_LOC (setClientVersion, Func_SetClientVersion, lib.Lib.GetProc("SetClientVersion"));
604 if (setClientVersion)
605 {
606 // const UInt32 kVersion = (MY_VER_MAJOR << 16) | MY_VER_MINOR;
607 setClientVersion(g_ClientVersion);
608 }
609 }
610 */
611
612
603 MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib.GetProc("CreateObject")); 613 MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib.GetProc("CreateObject"));
604 { 614 {
605 unsigned startSize = Codecs.Size() + Hashers.Size(); 615 unsigned startSize = Codecs.Size() + Hashers.Size();
diff --git a/CPP/7zip/UI/Common/LoadCodecs.h b/CPP/7zip/UI/Common/LoadCodecs.h
index 829472d..50fb9f8 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.h
+++ b/CPP/7zip/UI/Common/LoadCodecs.h
@@ -96,6 +96,7 @@ struct CArcExtInfo
96struct CArcInfoEx 96struct CArcInfoEx
97{ 97{
98 UInt32 Flags; 98 UInt32 Flags;
99 UInt32 TimeFlags;
99 100
100 Func_CreateInArchive CreateInArchive; 101 Func_CreateInArchive CreateInArchive;
101 Func_IsArc IsArcFunc; 102 Func_IsArc IsArcFunc;
@@ -142,7 +143,7 @@ struct CArcInfoEx
142 bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } 143 bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
143 144
144 bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } 145 bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
145 bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } 146 bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
146 bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } 147 bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
147 bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } 148 bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
148 149
@@ -154,6 +155,27 @@ struct CArcInfoEx
154 bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; } 155 bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; }
155 bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; } 156 bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; }
156 157
158 bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; }
159 bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; }
160 bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; }
161
162 bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; }
163 bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; }
164 bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; }
165
166 UInt32 Get_TimePrecFlags() const
167 {
168 return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) &
169 (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1);
170 }
171
172 UInt32 Get_DefaultTimePrec() const
173 {
174 return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) &
175 (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1);
176 }
177
178
157 UString GetMainExt() const 179 UString GetMainExt() const
158 { 180 {
159 if (Exts.IsEmpty()) 181 if (Exts.IsEmpty())
@@ -162,6 +184,15 @@ struct CArcInfoEx
162 } 184 }
163 int FindExtension(const UString &ext) const; 185 int FindExtension(const UString &ext) const;
164 186
187 bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); }
188 bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); }
189 bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); }
190 bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); }
191 bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); }
192 bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); }
193 bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); }
194 bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); }
195
165 /* 196 /*
166 UString GetAllExtensions() const 197 UString GetAllExtensions() const
167 { 198 {
@@ -178,11 +209,10 @@ struct CArcInfoEx
178 209
179 void AddExts(const UString &ext, const UString &addExt); 210 void AddExts(const UString &ext, const UString &addExt);
180 211
181 bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }
182 // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }
183 212
184 CArcInfoEx(): 213 CArcInfoEx():
185 Flags(0), 214 Flags(0),
215 TimeFlags(0),
186 CreateInArchive(NULL), 216 CreateInArchive(NULL),
187 IsArcFunc(NULL) 217 IsArcFunc(NULL)
188 #ifndef _SFX 218 #ifndef _SFX
@@ -333,14 +363,14 @@ public:
333 CRecordVector<CDllHasherInfo> Hashers; 363 CRecordVector<CDllHasherInfo> Hashers;
334 #endif 364 #endif
335 365
336 bool CaseSensitiveChange; 366 bool CaseSensitive_Change;
337 bool CaseSensitive; 367 bool CaseSensitive;
338 368
339 CCodecs(): 369 CCodecs():
340 #ifdef EXTERNAL_CODECS 370 #ifdef EXTERNAL_CODECS
341 NeedSetLibCodecs(true), 371 NeedSetLibCodecs(true),
342 #endif 372 #endif
343 CaseSensitiveChange(false), 373 CaseSensitive_Change(false),
344 CaseSensitive(false) 374 CaseSensitive(false)
345 {} 375 {}
346 376
diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp
index 331793f..4a91a26 100644
--- a/CPP/7zip/UI/Common/OpenArchive.cpp
+++ b/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -209,8 +209,8 @@ int CHandler::FindInsertPos(const CParseItem &item) const
209 unsigned left = 0, right = _items.Size(); 209 unsigned left = 0, right = _items.Size();
210 while (left != right) 210 while (left != right)
211 { 211 {
212 unsigned mid = (left + right) / 2; 212 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
213 const CParseItem & midItem = _items[mid]; 213 const CParseItem &midItem = _items[mid];
214 if (item.Offset < midItem.Offset) 214 if (item.Offset < midItem.Offset)
215 right = mid; 215 right = mid;
216 else if (item.Offset > midItem.Offset) 216 else if (item.Offset > midItem.Offset)
@@ -262,8 +262,8 @@ void CHandler::AddUnknownItem(UInt64 next)
262void CHandler::AddItem(const CParseItem &item) 262void CHandler::AddItem(const CParseItem &item)
263{ 263{
264 AddUnknownItem(item.Offset); 264 AddUnknownItem(item.Offset);
265 int pos = FindInsertPos(item); 265 const int pos = FindInsertPos(item);
266 if (pos >= 0) 266 if (pos != -1)
267 { 267 {
268 _items.Insert((unsigned)pos, item); 268 _items.Insert((unsigned)pos, item);
269 UInt64 next = item.Offset + item.Size; 269 UInt64 next = item.Offset + item.Size;
@@ -482,7 +482,7 @@ HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) thro
482 return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); 482 return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result);
483} 483}
484 484
485static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) throw() 485static HRESULT Archive_GetArcProp_Bool(IInArchive *arc, PROPID propid, bool &result) throw()
486{ 486{
487 NCOM::CPropVariant prop; 487 NCOM::CPropVariant prop;
488 result = false; 488 result = false;
@@ -532,7 +532,7 @@ static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &res
532 532
533#ifndef _SFX 533#ifndef _SFX
534 534
535HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const 535HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const
536{ 536{
537 if (!GetRawProps) 537 if (!GetRawProps)
538 return E_FAIL; 538 return E_FAIL;
@@ -616,7 +616,7 @@ HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &pa
616 616
617 617
618 618
619HRESULT CArc::GetItemPath(UInt32 index, UString &result) const 619HRESULT CArc::GetItem_Path(UInt32 index, UString &result) const
620{ 620{
621 #ifdef MY_CPU_LE 621 #ifdef MY_CPU_LE
622 if (GetRawProps) 622 if (GetRawProps)
@@ -752,13 +752,13 @@ HRESULT CArc::GetItemPath(UInt32 index, UString &result) const
752 } 752 }
753 753
754 if (result.IsEmpty()) 754 if (result.IsEmpty())
755 return GetDefaultItemPath(index, result); 755 return GetItem_DefaultPath(index, result);
756 756
757 Convert_UnicodeEsc16_To_UnicodeEscHigh(result); 757 Convert_UnicodeEsc16_To_UnicodeEscHigh(result);
758 return S_OK; 758 return S_OK;
759} 759}
760 760
761HRESULT CArc::GetDefaultItemPath(UInt32 index, UString &result) const 761HRESULT CArc::GetItem_DefaultPath(UInt32 index, UString &result) const
762{ 762{
763 result.Empty(); 763 result.Empty();
764 bool isDir; 764 bool isDir;
@@ -779,9 +779,9 @@ HRESULT CArc::GetDefaultItemPath(UInt32 index, UString &result) const
779 return S_OK; 779 return S_OK;
780} 780}
781 781
782HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const 782HRESULT CArc::GetItem_Path2(UInt32 index, UString &result) const
783{ 783{
784 RINOK(GetItemPath(index, result)); 784 RINOK(GetItem_Path(index, result));
785 if (Ask_Deleted) 785 if (Ask_Deleted)
786 { 786 {
787 bool isDeleted = false; 787 bool isDeleted = false;
@@ -833,7 +833,7 @@ HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
833 RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir)); 833 RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir));
834 item.MainIsDir = item.IsDir; 834 item.MainIsDir = item.IsDir;
835 835
836 RINOK(GetItemPath2(index, item.Path)); 836 RINOK(GetItem_Path2(index, item.Path));
837 837
838 #ifndef _SFX 838 #ifndef _SFX
839 UInt32 mainIndex = index; 839 UInt32 mainIndex = index;
@@ -885,7 +885,7 @@ HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
885 } 885 }
886 else 886 else
887 { 887 {
888 RINOK(GetItemPath2(parentIndex, item.MainPath)); 888 RINOK(GetItem_Path2(parentIndex, item.MainPath));
889 RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir)); 889 RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir));
890 } 890 }
891 } 891 }
@@ -911,7 +911,7 @@ HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
911 #ifndef _SFX 911 #ifndef _SFX
912 if (item._use_baseParentFolder_mode) 912 if (item._use_baseParentFolder_mode)
913 { 913 {
914 RINOK(GetItemPathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts)); 914 RINOK(GetItem_PathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts));
915 915
916 #ifdef SUPPORT_ALT_STREAMS 916 #ifdef SUPPORT_ALT_STREAMS
917 if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty()) 917 if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty())
@@ -970,7 +970,7 @@ static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &s
970 970
971#endif 971#endif
972 972
973HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const 973HRESULT CArc::GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const
974{ 974{
975 NCOM::CPropVariant prop; 975 NCOM::CPropVariant prop;
976 defined = false; 976 defined = false;
@@ -989,24 +989,52 @@ HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const
989 return S_OK; 989 return S_OK;
990} 990}
991 991
992HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const 992HRESULT CArc::GetItem_MTime(UInt32 index, CArcTime &at) const
993{ 993{
994 at.Clear();
994 NCOM::CPropVariant prop; 995 NCOM::CPropVariant prop;
995 defined = false;
996 ft.dwHighDateTime = ft.dwLowDateTime = 0;
997 RINOK(Archive->GetProperty(index, kpidMTime, &prop)); 996 RINOK(Archive->GetProperty(index, kpidMTime, &prop));
997
998 if (prop.vt == VT_FILETIME) 998 if (prop.vt == VT_FILETIME)
999 { 999 {
1000 ft = prop.filetime; 1000 /*
1001 defined = true; 1001 // for debug
1002 if (FILETIME_IsZero(prop.at) && MTime.Def)
1003 {
1004 at = MTime;
1005 return S_OK;
1006 }
1007 */
1008 at.Set_From_Prop(prop);
1009 if (at.Prec == 0)
1010 {
1011 // (at.Prec == 0) before version 22.
1012 // so kpidTimeType is required for that code
1013 prop.Clear();
1014 RINOK(Archive->GetProperty(index, kpidTimeType, &prop));
1015 if (prop.vt == VT_UI4)
1016 {
1017 UInt32 val = prop.ulVal;
1018 if (val == NFileTimeType::kWindows)
1019 val = k_PropVar_TimePrec_100ns;
1020 /*
1021 else if (val > k_PropVar_TimePrec_1ns)
1022 {
1023 val = k_PropVar_TimePrec_100ns;
1024 // val = k_PropVar_TimePrec_1ns;
1025 // return E_FAIL; // for debug
1026 }
1027 */
1028 at.Prec = (UInt16)val;
1029 }
1030 }
1031 return S_OK;
1002 } 1032 }
1003 else if (prop.vt != VT_EMPTY) 1033
1034 if (prop.vt != VT_EMPTY)
1004 return E_FAIL; 1035 return E_FAIL;
1005 else if (MTimeDefined) 1036 if (MTime.Def)
1006 { 1037 at = MTime;
1007 ft = MTime;
1008 defined = true;
1009 }
1010 return S_OK; 1038 return S_OK;
1011} 1039}
1012 1040
@@ -1020,6 +1048,7 @@ static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
1020 return true; 1048 return true;
1021} 1049}
1022 1050
1051
1023static void MakeCheckOrder(CCodecs *codecs, 1052static void MakeCheckOrder(CCodecs *codecs,
1024 CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, 1053 CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2,
1025 const Byte *data, size_t dataSize) 1054 const Byte *data, size_t dataSize)
@@ -1034,7 +1063,7 @@ static void MakeCheckOrder(CCodecs *codecs,
1034 { 1063 {
1035 if (ai.Signatures.IsEmpty()) 1064 if (ai.Signatures.IsEmpty())
1036 { 1065 {
1037 if (dataSize != 0) // 21.04: no Sinature means Empty Signature 1066 if (dataSize != 0) // 21.04: no Signature means Empty Signature
1038 continue; 1067 continue;
1039 } 1068 }
1040 else 1069 else
@@ -1229,7 +1258,7 @@ void CArcErrorInfo::ClearErrors()
1229HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) 1258HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes)
1230{ 1259{
1231 // OkPhySize_Defined = false; 1260 // OkPhySize_Defined = false;
1232 PhySizeDefined = false; 1261 PhySize_Defined = false;
1233 PhySize = 0; 1262 PhySize = 0;
1234 Offset = 0; 1263 Offset = 0;
1235 AvailPhySize = FileSize - startPos; 1264 AvailPhySize = FileSize - startPos;
@@ -1262,12 +1291,12 @@ HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openR
1262 1291
1263 if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) 1292 if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen())
1264 { 1293 {
1265 RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined)); 1294 RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySize_Defined));
1266 /* 1295 /*
1267 RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); 1296 RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined));
1268 if (!OkPhySize_Defined) 1297 if (!OkPhySize_Defined)
1269 { 1298 {
1270 OkPhySize_Defined = PhySizeDefined; 1299 OkPhySize_Defined = PhySize_Defined;
1271 OkPhySize = PhySize; 1300 OkPhySize = PhySize;
1272 } 1301 }
1273 */ 1302 */
@@ -1277,7 +1306,7 @@ HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openR
1277 1306
1278 Int64 globalOffset = (Int64)startPos + Offset; 1307 Int64 globalOffset = (Int64)startPos + Offset;
1279 AvailPhySize = (UInt64)((Int64)FileSize - globalOffset); 1308 AvailPhySize = (UInt64)((Int64)FileSize - globalOffset);
1280 if (PhySizeDefined) 1309 if (PhySize_Defined)
1281 { 1310 {
1282 UInt64 endPos = (UInt64)(globalOffset + (Int64)PhySize); 1311 UInt64 endPos = (UInt64)(globalOffset + (Int64)PhySize);
1283 if (endPos < FileSize) 1312 if (endPos < FileSize)
@@ -1378,9 +1407,9 @@ static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NAr
1378 pi.FileTime_Defined = false; 1407 pi.FileTime_Defined = false;
1379 pi.ArcType = ai.Name; 1408 pi.ArcType = ai.Name;
1380 1409
1381 RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType)); 1410 RINOK(Archive_GetArcProp_Bool(archive, kpidIsNotArcType, pi.IsNotArcType));
1382 1411
1383 // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe)); 1412 // RINOK(Archive_GetArcProp_Bool(archive, kpidIsSelfExe, pi.IsSelfExe));
1384 pi.IsSelfExe = ai.Flags_PreArc(); 1413 pi.IsSelfExe = ai.Flags_PreArc();
1385 1414
1386 { 1415 {
@@ -1584,7 +1613,7 @@ static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize,
1584 return S_OK; 1613 return S_OK;
1585 1614
1586 bool phySizeCantBeDetected = false; 1615 bool phySizeCantBeDetected = false;
1587 RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); 1616 RINOK(Archive_GetArcProp_Bool(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected));
1588 1617
1589 if (!phySizeCantBeDetected) 1618 if (!phySizeCantBeDetected)
1590 { 1619 {
@@ -1724,7 +1753,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
1724 const CArcInfoEx &ai = op.codecs->Formats[i]; 1753 const CArcInfoEx &ai = op.codecs->Formats[i];
1725 1754
1726 if (IgnoreSplit || !op.openType.CanReturnArc) 1755 if (IgnoreSplit || !op.openType.CanReturnArc)
1727 if (ai.IsSplit()) 1756 if (ai.Is_Split())
1728 continue; 1757 continue;
1729 if (op.excludedFormats->FindInSorted((int)i) >= 0) 1758 if (op.excludedFormats->FindInSorted((int)i) >= 0)
1730 continue; 1759 continue;
@@ -1736,8 +1765,8 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
1736 1765
1737 if (ai.FindExtension(extension) >= 0 1766 if (ai.FindExtension(extension) >= 0
1738 #ifndef _SFX 1767 #ifndef _SFX
1739 || (isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip")) 1768 || (isZip && ai.Is_Zip())
1740 || (isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar")) 1769 || (isRar && ai.Is_Rar())
1741 #endif 1770 #endif
1742 ) 1771 )
1743 { 1772 {
@@ -1811,11 +1840,27 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
1811 1840
1812 /* 1841 /*
1813 check type order: 1842 check type order:
1814 1) matched extension, no signuature 1843 0) matched_extension && Backward
1815 2) matched extension, matched signuature 1844 1) matched_extension && (no_signuature || SignatureOffset != 0)
1845 2) matched_extension && (matched_signature)
1816 // 3) no signuature 1846 // 3) no signuature
1817 // 4) matched signuature 1847 // 4) matched signuature
1818 */ 1848 */
1849 // we move index from orderIndices to orderIndices2 for priority handlers.
1850
1851 for (unsigned i = 0; i < numFinded; i++)
1852 {
1853 const int index = orderIndices[i];
1854 if (index < 0)
1855 continue;
1856 const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index];
1857 if (ai.Flags_BackwardOpen())
1858 {
1859 // backward doesn't need start signatures
1860 orderIndices2.Add(index);
1861 orderIndices[i] = -1;
1862 }
1863 }
1819 1864
1820 MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); 1865 MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0);
1821 MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); 1866 MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize);
@@ -1906,6 +1951,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
1906 // OutputDebugStringW(ai.Name); 1951 // OutputDebugStringW(ai.Name);
1907 if (i >= numMainTypes) 1952 if (i >= numMainTypes)
1908 { 1953 {
1954 // here we allow mismatched extension only for backward handlers
1909 if (!ai.Flags_BackwardOpen() 1955 if (!ai.Flags_BackwardOpen()
1910 // && !ai.Flags_PureStartOpen() 1956 // && !ai.Flags_PureStartOpen()
1911 ) 1957 )
@@ -2125,7 +2171,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2125 2171
2126 const CArcInfoEx &ai = op.codecs->Formats[form]; 2172 const CArcInfoEx &ai = op.codecs->Formats[form];
2127 2173
2128 if (ai.IsSplit()) 2174 if (ai.Is_Split())
2129 { 2175 {
2130 splitIndex = (int)form; 2176 splitIndex = (int)form;
2131 continue; 2177 continue;
@@ -2234,7 +2280,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2234 2280
2235 // bool needScan = false; 2281 // bool needScan = false;
2236 2282
2237 if (!PhySizeDefined) 2283 if (!PhySize_Defined)
2238 { 2284 {
2239 // it's for Z format 2285 // it's for Z format
2240 pi.LenIsUnknown = true; 2286 pi.LenIsUnknown = true;
@@ -2726,14 +2772,14 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2726 } 2772 }
2727 continue; 2773 continue;
2728 } 2774 }
2729 if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0) 2775 if (!ErrorInfo.IsArc_After_NonOpen() || !PhySize_Defined || PhySize == 0)
2730 continue; 2776 continue;
2731 } 2777 }
2732 else 2778 else
2733 { 2779 {
2734 if (PhySizeDefined && PhySize == 0) 2780 if (PhySize_Defined && PhySize == 0)
2735 { 2781 {
2736 PRF(printf(" phySizeDefined && PhySize == 0 ")); 2782 PRF(printf(" phySize_Defined && PhySize == 0 "));
2737 // we skip that epmty archive case with unusual unexpected (PhySize == 0) from Code function. 2783 // we skip that epmty archive case with unusual unexpected (PhySize == 0) from Code function.
2738 continue; 2784 continue;
2739 } 2785 }
@@ -2754,10 +2800,10 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2754 else if (Offset != 0) 2800 else if (Offset != 0)
2755 return E_FAIL; 2801 return E_FAIL;
2756 2802
2757 UInt64 arcRem = FileSize - pi.Offset; 2803 const UInt64 arcRem = FileSize - pi.Offset;
2758 UInt64 phySize = arcRem; 2804 UInt64 phySize = arcRem;
2759 bool phySizeDefined = PhySizeDefined; 2805 const bool phySize_Defined = PhySize_Defined;
2760 if (phySizeDefined) 2806 if (phySize_Defined)
2761 { 2807 {
2762 if (pi.Offset + PhySize > FileSize) 2808 if (pi.Offset + PhySize > FileSize)
2763 { 2809 {
@@ -2783,7 +2829,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2783 bool needScan = false; 2829 bool needScan = false;
2784 2830
2785 2831
2786 if (isOpen && !phySizeDefined) 2832 if (isOpen && !phySize_Defined)
2787 { 2833 {
2788 // it's for Z format, or bzip2,gz,xz with phySize that was not detected 2834 // it's for Z format, or bzip2,gz,xz with phySize that was not detected
2789 pi.LenIsUnknown = true; 2835 pi.LenIsUnknown = true;
@@ -2802,7 +2848,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2802 2848
2803 /* 2849 /*
2804 if (needSkipFullArc) 2850 if (needSkipFullArc)
2805 if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize) 2851 if (pi.Offset == 0 && phySize_Defined && pi.Size >= fileSize)
2806 continue; 2852 continue;
2807 */ 2853 */
2808 if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) 2854 if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
@@ -2830,7 +2876,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2830 2876
2831 RINOK(ReadParseItemProps(archive, ai, pi)); 2877 RINOK(ReadParseItemProps(archive, ai, pi));
2832 2878
2833 if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */) 2879 if (pi.Offset < startArcPos && !mode.EachPos /* && phySize_Defined */)
2834 { 2880 {
2835 /* It's for DMG format. 2881 /* It's for DMG format.
2836 This code deletes all previous items that are included to current item */ 2882 This code deletes all previous items that are included to current item */
@@ -2849,7 +2895,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op)
2849 } 2895 }
2850 2896
2851 2897
2852 if (isOpen && mode.CanReturnArc && phySizeDefined) 2898 if (isOpen && mode.CanReturnArc && phySize_Defined)
2853 { 2899 {
2854 // if (pi.Offset + pi.Size >= fileSize) 2900 // if (pi.Offset + pi.Size >= fileSize)
2855 bool openCur = false; 2901 bool openCur = false;
@@ -2993,12 +3039,12 @@ HRESULT CArc::OpenStream(const COpenOptions &op)
2993 Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); 3039 Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps);
2994 Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); 3040 Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps);
2995 3041
2996 RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree)); 3042 RINOK(Archive_GetArcProp_Bool(Archive, kpidIsTree, IsTree));
2997 RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted)); 3043 RINOK(Archive_GetArcProp_Bool(Archive, kpidIsDeleted, Ask_Deleted));
2998 RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream)); 3044 RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAltStream, Ask_AltStream));
2999 RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux)); 3045 RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAux, Ask_Aux));
3000 RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode)); 3046 RINOK(Archive_GetArcProp_Bool(Archive, kpidINode, Ask_INode));
3001 RINOK(Archive_GetArcBoolProp(Archive, kpidReadOnly, IsReadOnly)); 3047 RINOK(Archive_GetArcProp_Bool(Archive, kpidReadOnly, IsReadOnly));
3002 3048
3003 const UString fileName = ExtractFileNameFromPath(Path); 3049 const UString fileName = ExtractFileNameFromPath(Path);
3004 UString extension; 3050 UString extension;
@@ -3092,7 +3138,7 @@ HRESULT CArc::OpenStreamOrFile(COpenOptions &op)
3092 FOR_VECTOR (i, op.codecs->Formats) 3138 FOR_VECTOR (i, op.codecs->Formats)
3093 { 3139 {
3094 const CArcInfoEx &ai = op.codecs->Formats[i]; 3140 const CArcInfoEx &ai = op.codecs->Formats[i];
3095 if (ai.IsSplit()) 3141 if (ai.Is_Split())
3096 continue; 3142 continue;
3097 UString path3 = path2; 3143 UString path3 = path2;
3098 path3 += '.'; 3144 path3 += '.';
@@ -3299,7 +3345,7 @@ HRESULT CArchiveLink::Open(COpenOptions &op)
3299 break; 3345 break;
3300 3346
3301 CArc arc2; 3347 CArc arc2;
3302 RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); 3348 RINOK(arc.GetItem_Path(mainSubfile, arc2.Path));
3303 3349
3304 bool zerosTailIsAllowed; 3350 bool zerosTailIsAllowed;
3305 RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)); 3351 RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed));
@@ -3343,7 +3389,7 @@ HRESULT CArchiveLink::Open(COpenOptions &op)
3343 break; 3389 break;
3344 } 3390 }
3345 RINOK(result); 3391 RINOK(result);
3346 RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); 3392 RINOK(arc.GetItem_MTime(mainSubfile, arc2.MTime));
3347 Arcs.Add(arc2); 3393 Arcs.Add(arc2);
3348 } 3394 }
3349 IsOpen = !Arcs.IsEmpty(); 3395 IsOpen = !Arcs.IsEmpty();
diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h
index 4e1192c..e3220b9 100644
--- a/CPP/7zip/UI/Common/OpenArchive.h
+++ b/CPP/7zip/UI/Common/OpenArchive.h
@@ -8,6 +8,7 @@
8#include "ArchiveOpenCallback.h" 8#include "ArchiveOpenCallback.h"
9#include "LoadCodecs.h" 9#include "LoadCodecs.h"
10#include "Property.h" 10#include "Property.h"
11#include "DirItem.h"
11 12
12#ifndef _SFX 13#ifndef _SFX
13 14
@@ -260,6 +261,9 @@ struct CReadArcItem
260 } 261 }
261}; 262};
262 263
264
265
266
263class CArc 267class CArc
264{ 268{
265 HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive); 269 HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
@@ -268,7 +272,7 @@ class CArc
268 272
269 #ifndef _SFX 273 #ifndef _SFX
270 // parts.Back() can contain alt stream name "nams:AltName" 274 // parts.Back() can contain alt stream name "nams:AltName"
271 HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; 275 HRESULT GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
272 #endif 276 #endif
273 277
274public: 278public:
@@ -289,19 +293,21 @@ public:
289 UString DefaultName; 293 UString DefaultName;
290 int FormatIndex; // -1 means Parser 294 int FormatIndex; // -1 means Parser
291 UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile 295 UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile
292 FILETIME MTime; 296
293 bool MTimeDefined; 297 // CFiTime MTime;
298 // bool MTime_Defined;
299 CArcTime MTime;
294 300
295 Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler 301 Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler
296 UInt64 PhySize; 302 UInt64 PhySize;
297 // UInt64 OkPhySize; 303 // UInt64 OkPhySize;
298 bool PhySizeDefined; 304 bool PhySize_Defined;
299 // bool OkPhySize_Defined; 305 // bool OkPhySize_Defined;
300 UInt64 FileSize; 306 UInt64 FileSize;
301 UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file 307 UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
302 // bool offsetDefined; 308 // bool offsetDefined;
303 309
304 UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; } 310 UInt64 GetEstmatedPhySize() const { return PhySize_Defined ? PhySize : FileSize; }
305 311
306 UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler 312 UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
307 Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive 313 Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive
@@ -323,7 +329,7 @@ public:
323 // void Set_ErrorFlagsText(); 329 // void Set_ErrorFlagsText();
324 330
325 CArc(): 331 CArc():
326 MTimeDefined(false), 332 // MTime_Defined(false),
327 IsTree(false), 333 IsTree(false),
328 IsReadOnly(false), 334 IsReadOnly(false),
329 Ask_Deleted(false), 335 Ask_Deleted(false),
@@ -343,17 +349,29 @@ public:
343 return Archive->Close(); 349 return Archive->Close();
344 } 350 }
345 351
346 HRESULT GetItemPath(UInt32 index, UString &result) const; 352 HRESULT GetItem_Path(UInt32 index, UString &result) const;
347 HRESULT GetDefaultItemPath(UInt32 index, UString &result) const; 353 HRESULT GetItem_DefaultPath(UInt32 index, UString &result) const;
348 354
349 // GetItemPath2 adds [DELETED] dir prefix for deleted items. 355 // GetItemPath2 adds [DELETED] dir prefix for deleted items.
350 HRESULT GetItemPath2(UInt32 index, UString &result) const; 356 HRESULT GetItem_Path2(UInt32 index, UString &result) const;
351 357
352 HRESULT GetItem(UInt32 index, CReadArcItem &item) const; 358 HRESULT GetItem(UInt32 index, CReadArcItem &item) const;
353 359
354 HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const; 360 HRESULT GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const;
355 HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; 361
356 HRESULT IsItemAnti(UInt32 index, bool &result) const 362 /* if (GetProperty() returns vt==VT_EMPTY), this function sets
363 timestamp from archive file timestamp (MTime).
364 So (at) will be set in most cases (at.Def == true)
365 if (at.Prec == 0)
366 {
367 it means that (Prec == 0) was returned for (kpidMTime),
368 and no value was returned for (kpidTimeType).
369 it can mean Windows precision or unknown precision.
370 }
371 */
372 HRESULT GetItem_MTime(UInt32 index, CArcTime &at) const;
373
374 HRESULT IsItem_Anti(UInt32 index, bool &result) const
357 { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } 375 { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); }
358 376
359 377
diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp
index 30efd53..72384b3 100644
--- a/CPP/7zip/UI/Common/PropIDUtils.cpp
+++ b/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -136,10 +136,37 @@ void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID p
136 if (prop.vt == VT_FILETIME) 136 if (prop.vt == VT_FILETIME)
137 { 137 {
138 const FILETIME &ft = prop.filetime; 138 const FILETIME &ft = prop.filetime;
139 if ((ft.dwHighDateTime == 0 && 139 unsigned ns100 = 0;
140 ft.dwLowDateTime == 0)) 140 int numDigits = kTimestampPrintLevel_NTFS;
141 const unsigned prec = prop.wReserved1;
142 const unsigned ns100_Temp = prop.wReserved2;
143 if (prec != 0
144 && prec <= k_PropVar_TimePrec_1ns
145 && ns100_Temp < 100
146 && prop.wReserved3 == 0)
147 {
148 ns100 = ns100_Temp;
149 if (prec == k_PropVar_TimePrec_Unix ||
150 prec == k_PropVar_TimePrec_DOS)
151 numDigits = 0;
152 else if (prec == k_PropVar_TimePrec_HighPrec)
153 numDigits = 9;
154 else
155 {
156 numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
157 if (
158 // numDigits < kTimestampPrintLevel_DAY // for debuf
159 numDigits < kTimestampPrintLevel_SEC
160 )
161
162 numDigits = kTimestampPrintLevel_NTFS;
163 }
164 }
165 if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0 && ns100 == 0)
141 return; 166 return;
142 ConvertUtcFileTimeToString(prop.filetime, dest, level); 167 if (level > numDigits)
168 level = numDigits;
169 ConvertUtcFileTimeToString2(ft, ns100, dest, level);
143 return; 170 return;
144 } 171 }
145 172
@@ -198,6 +225,24 @@ void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID p
198 ConvertUInt64ToHex(v, dest + 2); 225 ConvertUInt64ToHex(v, dest + 2);
199 return; 226 return;
200 } 227 }
228
229 /*
230 case kpidDevice:
231 {
232 UInt64 v = 0;
233 if (prop.vt == VT_UI4)
234 v = prop.ulVal;
235 else if (prop.vt == VT_UI8)
236 v = (UInt64)prop.uhVal.QuadPart;
237 else
238 break;
239 ConvertUInt32ToString(MY_dev_major(v), dest);
240 dest += strlen(dest);
241 *dest++ = ',';
242 ConvertUInt32ToString(MY_dev_minor(v), dest);
243 return;
244 }
245 */
201 } 246 }
202 247
203 ConvertPropVariantToShortString(prop, dest); 248 ConvertPropVariantToShortString(prop, dest);
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
index 032a876..042991d 100644
--- a/CPP/7zip/UI/Common/Update.cpp
+++ b/CPP/7zip/UI/Common/Update.cpp
@@ -2,6 +2,8 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5// #include <stdio.h>
6
5#include "Update.h" 7#include "Update.h"
6 8
7#include "../../../Common/StringConvert.h" 9#include "../../../Common/StringConvert.h"
@@ -101,7 +103,7 @@ public:
101 _length = 0; 103 _length = 0;
102 } 104 }
103 105
104 bool SetMTime(const FILETIME *mTime); 106 bool SetMTime(const CFiTime *mTime);
105 HRESULT Close(); 107 HRESULT Close();
106 108
107 UInt64 GetSize() const { return _length; } 109 UInt64 GetSize() const { return _length; }
@@ -131,7 +133,7 @@ HRESULT COutMultiVolStream::Close()
131 return res; 133 return res;
132} 134}
133 135
134bool COutMultiVolStream::SetMTime(const FILETIME *mTime) 136bool COutMultiVolStream::SetMTime(const CFiTime *mTime)
135{ 137{
136 bool res = true; 138 bool res = true;
137 FOR_VECTOR (i, Streams) 139 FOR_VECTOR (i, Streams)
@@ -545,11 +547,46 @@ static HRESULT Compress(
545 if (!outArchive) 547 if (!outArchive)
546 throw kUpdateIsNotSupoorted; 548 throw kUpdateIsNotSupoorted;
547 549
550 // we need to set properties to get fileTimeType.
551 RINOK(SetProperties(outArchive, options.MethodMode.Properties));
552
548 NFileTimeType::EEnum fileTimeType; 553 NFileTimeType::EEnum fileTimeType;
549 { 554 {
555 /*
556 how we compare file_in_archive::MTime with dirItem.MTime
557 for GetUpdatePairInfoList():
558
559 if (kpidMTime is not defined), external MTime of archive is used.
560
561 before 22.00:
562 if (kpidTimeType is defined)
563 {
564 kpidTimeType is used as precision.
565 (kpidTimeType > kDOS) is not allowed.
566 }
567 else GetFileTimeType() value is used as precision.
568
569 22.00:
570 if (kpidMTime is defined)
571 {
572 if (kpidMTime::precision != 0), then kpidMTime::precision is used as precision.
573 else
574 {
575 if (kpidTimeType is defined), kpidTimeType is used as precision.
576 else GetFileTimeType() value is used as precision.
577 }
578 }
579 else external MTime of archive is used as precision.
580 */
581
550 UInt32 value; 582 UInt32 value;
551 RINOK(outArchive->GetFileTimeType(&value)); 583 RINOK(outArchive->GetFileTimeType(&value));
584
585 // we support any future fileType here.
586 fileTimeType = (NFileTimeType::EEnum)value;
552 587
588 /*
589 old 21.07 code:
553 switch (value) 590 switch (value)
554 { 591 {
555 case NFileTimeType::kWindows: 592 case NFileTimeType::kWindows:
@@ -560,13 +597,26 @@ static HRESULT Compress(
560 default: 597 default:
561 return E_FAIL; 598 return E_FAIL;
562 } 599 }
600 */
563 } 601 }
564 602
603 // bool noTimestampExpected = false;
565 { 604 {
566 const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; 605 const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex];
606
607 // if (arcInfo.Flags_KeepName()) noTimestampExpected = true;
608 if (arcInfo.Is_Xz() ||
609 arcInfo.Is_BZip2())
610 {
611 /* 7-zip before 22.00 returns NFileTimeType::kUnix for xz and bzip2,
612 but we want to set timestamp without reduction to unix. */
613 // noTimestampExpected = true;
614 fileTimeType = NFileTimeType::kNotDefined; // it means not defined
615 }
616
567 if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) 617 if (options.AltStreams.Val && !arcInfo.Flags_AltStreams())
568 return E_NOTIMPL; 618 return E_NOTIMPL;
569 if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) 619 if (options.NtSecurity.Val && !arcInfo.Flags_NtSecurity())
570 return E_NOTIMPL; 620 return E_NOTIMPL;
571 if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler()) 621 if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler())
572 return E_NOTIMPL; 622 return E_NOTIMPL;
@@ -626,7 +676,7 @@ static HRESULT Compress(
626 if (needRename) 676 if (needRename)
627 { 677 {
628 up2.NewProps = true; 678 up2.NewProps = true;
629 RINOK(arc->IsItemAnti(i, up2.IsAnti)); 679 RINOK(arc->IsItem_Anti(i, up2.IsAnti));
630 up2.NewNameIndex = (int)newNames.Add(dest); 680 up2.NewNameIndex = (int)newNames.Add(dest);
631 } 681 }
632 updatePairs2.Add(up2); 682 updatePairs2.Add(up2);
@@ -661,6 +711,7 @@ static HRESULT Compress(
661 else 711 else
662 stat.NumDirs++; 712 stat.NumDirs++;
663 } 713 }
714 #ifdef _WIN32
664 else if (di.IsAltStream) 715 else if (di.IsAltStream)
665 { 716 {
666 if (up.IsAnti) 717 if (up.IsAnti)
@@ -671,6 +722,7 @@ static HRESULT Compress(
671 stat.AltStreamsSize += di.Size; 722 stat.AltStreamsSize += di.Size;
672 } 723 }
673 } 724 }
725 #endif
674 else 726 else
675 { 727 {
676 if (up.IsAnti) 728 if (up.IsAnti)
@@ -740,6 +792,8 @@ static HRESULT Compress(
740 updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; 792 updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val;
741 updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; 793 updateCallbackSpec->StoreHardLinks = options.HardLinks.Val;
742 updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; 794 updateCallbackSpec->StoreSymLinks = options.SymLinks.Val;
795 updateCallbackSpec->StoreOwnerName = options.StoreOwnerName.Val;
796 updateCallbackSpec->StoreOwnerId = options.StoreOwnerId.Val;
743 797
744 updateCallbackSpec->Arc = arc; 798 updateCallbackSpec->Arc = arc;
745 updateCallbackSpec->ArcItems = &arcItems; 799 updateCallbackSpec->ArcItems = &arcItems;
@@ -755,6 +809,12 @@ static HRESULT Compress(
755 if (options.RenamePairs.Size() != 0) 809 if (options.RenamePairs.Size() != 0)
756 updateCallbackSpec->NewNames = &newNames; 810 updateCallbackSpec->NewNames = &newNames;
757 811
812 if (options.SetArcMTime)
813 {
814 // updateCallbackSpec->Need_ArcMTime_Report = true;
815 updateCallbackSpec->Need_LatestMTime = true;
816 }
817
758 CMyComPtr<IOutStream> outSeekStream; 818 CMyComPtr<IOutStream> outSeekStream;
759 CMyComPtr<ISequentialOutStream> outStream; 819 CMyComPtr<ISequentialOutStream> outStream;
760 820
@@ -838,8 +898,6 @@ static HRESULT Compress(
838 */ 898 */
839 } 899 }
840 900
841 RINOK(SetProperties(outArchive, options.MethodMode.Properties));
842
843 if (options.SfxMode) 901 if (options.SfxMode)
844 { 902 {
845 CInFileStream *sfxStreamSpec = new CInFileStream; 903 CInFileStream *sfxStreamSpec = new CInFileStream;
@@ -909,24 +967,71 @@ static HRESULT Compress(
909 967
910 if (options.SetArcMTime) 968 if (options.SetArcMTime)
911 { 969 {
912 FILETIME ft; 970 CFiTime ft;
913 ft.dwLowDateTime = 0; 971 FiTime_Clear(ft);
914 ft.dwHighDateTime = 0; 972 bool isDefined = false;
915 FOR_VECTOR (i, updatePairs2) 973
974 // bool needNormalizeAfterStream;
975 // needParse;
976 /*
977 if (updateCallbackSpec->ArcMTime_WasReported)
916 { 978 {
917 const CUpdatePair2 &pair2 = updatePairs2[i]; 979 isDefined = updateCallbackSpec->Reported_ArcMTime.Def;
918 const FILETIME *ft2 = NULL; 980 if (isDefined)
919 if (pair2.NewProps && pair2.DirIndex >= 0) 981 updateCallbackSpec->Reported_ArcMTime.Write_To_FiTime(ft);
920 ft2 = &dirItems.Items[(unsigned)pair2.DirIndex].MTime; 982 else
921 else if (pair2.UseArcProps && pair2.ArcIndex >= 0) 983 fileTimeType = NFileTimeType::kNotDefined;
922 ft2 = &arcItems[(unsigned)pair2.ArcIndex].MTime; 984 }
923 if (ft2) 985 if (!isDefined)
986 */
987 {
988 if (updateCallbackSpec->LatestMTime_Defined)
924 { 989 {
925 if (::CompareFileTime(&ft, ft2) < 0) 990 // CArcTime at = StreamCallback_ArcMTime;
926 ft = *ft2; 991 // updateCallbackSpec->StreamCallback_ArcMTime.Write_To_FiTime(ft);
992 // we must normalize with precision from archive;
993 ft = updateCallbackSpec->LatestMTime;
994 isDefined = true;
927 } 995 }
996
997 FOR_VECTOR (i, updatePairs2)
998 {
999 const CUpdatePair2 &pair2 = updatePairs2[i];
1000 CFiTime ft2;
1001 bool ft2_Defined = false;
1002 /* we use full precision of dirItem, if dirItem is defined
1003 and (dirItem will be used or dirItem is sameTime in dir and arc */
1004 if (pair2.DirIndex >= 0 &&
1005 (pair2.NewProps || pair2.IsSameTime))
1006 {
1007 ft2 = dirItems.Items[(unsigned)pair2.DirIndex].MTime;
1008 ft2_Defined = true;
1009 }
1010 else if (pair2.UseArcProps && pair2.ArcIndex >= 0)
1011 {
1012 const CArcItem &arcItem = arcItems[(unsigned)pair2.ArcIndex];
1013 if (arcItem.MTime.Def)
1014 {
1015 arcItem.MTime.Write_To_FiTime(ft2);
1016 ft2_Defined = true;
1017 }
1018 }
1019 if (ft2_Defined)
1020 {
1021 if (Compare_FiTime(&ft, &ft2) < 0)
1022 {
1023 ft = ft2;
1024 isDefined = true;
1025 }
1026 }
1027 }
1028 /*
1029 if (fileTimeType != NFileTimeType::kNotDefined)
1030 FiTime_Normalize_With_Prec(ft, fileTimeType);
1031 */
928 } 1032 }
929 if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) 1033 // if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0)
1034 if (isDefined)
930 { 1035 {
931 if (outStreamSpec) 1036 if (outStreamSpec)
932 outStreamSpec->SetMTime(&ft); 1037 outStreamSpec->SetMTime(&ft);
@@ -1046,26 +1151,9 @@ static HRESULT EnumerateInArchiveItems(
1046 else 1151 else
1047 ai.Censored = Censor_CheckPath(censor, item); 1152 ai.Censored = Censor_CheckPath(censor, item);
1048 1153
1049 RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); 1154 // ai.MTime will be set to archive MTime, if not present in archive item
1050 RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); 1155 RINOK(arc.GetItem_MTime(i, ai.MTime));
1051 1156 RINOK(arc.GetItem_Size(i, ai.Size, ai.Size_Defined));
1052 {
1053 CPropVariant prop;
1054 RINOK(archive->GetProperty(i, kpidTimeType, &prop));
1055 if (prop.vt == VT_UI4)
1056 {
1057 ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;
1058 switch (ai.TimeType)
1059 {
1060 case NFileTimeType::kWindows:
1061 case NFileTimeType::kUnix:
1062 case NFileTimeType::kDOS:
1063 break;
1064 default:
1065 return E_FAIL;
1066 }
1067 }
1068 }
1069 1157
1070 ai.IndexInServer = i; 1158 ai.IndexInServer = i;
1071 arcItems.AddInReserved(ai); 1159 arcItems.AddInReserved(ai);
@@ -1198,8 +1286,10 @@ HRESULT UpdateArchive(
1198 EISDIR 1286 EISDIR
1199 #endif 1287 #endif
1200 ); 1288 );
1289 #ifdef _WIN32
1201 if (fi.IsDevice) 1290 if (fi.IsDevice)
1202 return E_NOTIMPL; 1291 return E_NOTIMPL;
1292 #endif
1203 1293
1204 if (!options.StdOutMode && options.UpdateArchiveItself) 1294 if (!options.StdOutMode && options.UpdateArchiveItself)
1205 if (fi.IsReadOnly()) 1295 if (fi.IsReadOnly())
@@ -1262,8 +1352,14 @@ HRESULT UpdateArchive(
1262 } 1352 }
1263 1353
1264 CArc &arc = arcLink.Arcs.Back(); 1354 CArc &arc = arcLink.Arcs.Back();
1265 arc.MTimeDefined = !fi.IsDevice; 1355 arc.MTime.Def =
1266 arc.MTime = fi.MTime; 1356 #ifdef _WIN32
1357 !fi.IsDevice;
1358 #else
1359 true;
1360 #endif
1361 if (arc.MTime.Def)
1362 arc.MTime.Set_From_FiTime(fi.MTime);
1267 1363
1268 if (arc.ErrorInfo.ThereIsTail) 1364 if (arc.ErrorInfo.ThereIsTail)
1269 { 1365 {
@@ -1307,10 +1403,11 @@ HRESULT UpdateArchive(
1307 if (options.StdInMode) 1403 if (options.StdInMode)
1308 { 1404 {
1309 CDirItem di; 1405 CDirItem di;
1406 di.ClearBase();
1310 di.Name = options.StdInFileName; 1407 di.Name = options.StdInFileName;
1311 di.Size = (UInt64)(Int64)-1; 1408 di.Size = (UInt64)(Int64)-1;
1312 di.Attrib = 0; 1409 di.SetAsFile();
1313 NTime::GetCurUtcFileTime(di.MTime); 1410 NTime::GetCurUtc_FiTime(di.MTime);
1314 di.CTime = di.ATime = di.MTime; 1411 di.CTime = di.ATime = di.MTime;
1315 dirItems.Items.Add(di); 1412 dirItems.Items.Add(di);
1316 } 1413 }
@@ -1336,8 +1433,14 @@ HRESULT UpdateArchive(
1336 dirItems.ScanAltStreams = options.AltStreams.Val; 1433 dirItems.ScanAltStreams = options.AltStreams.Val;
1337 dirItems.ExcludeDirItems = censor.ExcludeDirItems; 1434 dirItems.ExcludeDirItems = censor.ExcludeDirItems;
1338 dirItems.ExcludeFileItems = censor.ExcludeFileItems; 1435 dirItems.ExcludeFileItems = censor.ExcludeFileItems;
1436
1437 dirItems.ShareForWrite = options.OpenShareForWrite;
1438
1439 #ifndef _WIN32
1440 dirItems.StoreOwnerName = options.StoreOwnerName.Val;
1441 #endif
1339 1442
1340 HRESULT res = EnumerateItems(censor, 1443 const HRESULT res = EnumerateItems(censor,
1341 options.PathMode, 1444 options.PathMode,
1342 UString(), // options.AddPathPrefix, 1445 UString(), // options.AddPathPrefix,
1343 dirItems); 1446 dirItems);
@@ -1351,6 +1454,8 @@ HRESULT UpdateArchive(
1351 1454
1352 RINOK(callback->FinishScanning(dirItems.Stat)); 1455 RINOK(callback->FinishScanning(dirItems.Stat));
1353 1456
1457 // 22.00: we don't need parent folder, if absolute path mode
1458 if (options.PathMode != NWildcard::k_AbsPath)
1354 if (censor.Pairs.Size() == 1) 1459 if (censor.Pairs.Size() == 1)
1355 { 1460 {
1356 NFind::CFileInfo fi; 1461 NFind::CFileInfo fi;
@@ -1366,11 +1471,7 @@ HRESULT UpdateArchive(
1366 if (fi.Find(prefix)) 1471 if (fi.Find(prefix))
1367 if (fi.IsDir()) 1472 if (fi.IsDir())
1368 { 1473 {
1369 parentDirItem.Size = fi.Size; 1474 parentDirItem.Copy_From_FileInfoBase(fi);
1370 parentDirItem.CTime = fi.CTime;
1371 parentDirItem.ATime = fi.ATime;
1372 parentDirItem.MTime = fi.MTime;
1373 parentDirItem.Attrib = fi.Attrib;
1374 parentDirItem_Ptr = &parentDirItem; 1475 parentDirItem_Ptr = &parentDirItem;
1375 1476
1376 int secureIndex = -1; 1477 int secureIndex = -1;
@@ -1723,8 +1824,8 @@ HRESULT UpdateArchive(
1723 is_SameSize = (fileInfo.Size == dirItem.Size); 1824 is_SameSize = (fileInfo.Size == dirItem.Size);
1724 1825
1725 if (is_SameSize 1826 if (is_SameSize
1726 && CompareFileTime(&fileInfo.MTime, &dirItem.MTime) == 0 1827 && Compare_FiTime(&fileInfo.MTime, &dirItem.MTime) == 0
1727 && CompareFileTime(&fileInfo.CTime, &dirItem.CTime) == 0) 1828 && Compare_FiTime(&fileInfo.CTime, &dirItem.CTime) == 0)
1728 { 1829 {
1729 RINOK(callback->DeletingAfterArchiving(phyPath, false)); 1830 RINOK(callback->DeletingAfterArchiving(phyPath, false));
1730 DeleteFileAlways(phyPath); 1831 DeleteFileAlways(phyPath);
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h
index 06d1387..01fc43e 100644
--- a/CPP/7zip/UI/Common/Update.h
+++ b/CPP/7zip/UI/Common/Update.h
@@ -112,6 +112,9 @@ struct CUpdateOptions
112 CBoolPair HardLinks; 112 CBoolPair HardLinks;
113 CBoolPair SymLinks; 113 CBoolPair SymLinks;
114 114
115 CBoolPair StoreOwnerId;
116 CBoolPair StoreOwnerName;
117
115 bool DeleteAfterCompressing; 118 bool DeleteAfterCompressing;
116 119
117 bool SetArcMTime; 120 bool SetArcMTime;
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
index 7b705ba..926a275 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -4,6 +4,15 @@
4 4
5// #include <stdio.h> 5// #include <stdio.h>
6 6
7#ifndef _WIN32
8// #include <grp.h>
9// #include <pwd.h>
10
11// for major minor:
12// BSD: <sys/types.h>
13#include <sys/sysmacros.h>
14#endif
15
7#ifndef _7ZIP_ST 16#ifndef _7ZIP_ST
8#include "../../../Windows/Synchronization.h" 17#include "../../../Windows/Synchronization.h"
9#endif 18#endif
@@ -66,6 +75,18 @@ CArchiveUpdateCallback::CArchiveUpdateCallback():
66 StoreNtSecurity(false), 75 StoreNtSecurity(false),
67 StoreHardLinks(false), 76 StoreHardLinks(false),
68 StoreSymLinks(false), 77 StoreSymLinks(false),
78
79 #ifndef _WIN32
80 StoreOwnerId(false),
81 StoreOwnerName(false),
82 #endif
83
84 /*
85 , Need_ArcMTime_Report(false),
86 , ArcMTime_WasReported(false),
87 */
88 Need_LatestMTime(false),
89 LatestMTime_Defined(false),
69 90
70 ProcessedItemsStatuses(NULL) 91 ProcessedItemsStatuses(NULL)
71{ 92{
@@ -134,16 +155,17 @@ STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
134 COM_TRY_END 155 COM_TRY_END
135} 156}
136 157
158
137STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value) 159STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)
138{ 160{
139 NCOM::CPropVariant prop; 161 NCOM::CPropVariant prop;
140 switch (propID) 162 switch (propID)
141 { 163 {
142 case kpidIsDir: prop = true; break; 164 case kpidIsDir: prop = true; break;
143 case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break; 165 case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break;
144 case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; 166 case kpidCTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break;
145 case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; 167 case kpidATime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break;
146 case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; 168 case kpidMTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break;
147 case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break; 169 case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break;
148 } 170 }
149 prop.Detach(value); 171 prop.Detach(value);
@@ -446,25 +468,46 @@ STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
446 { 468 {
447 case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break; 469 case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break;
448 case kpidIsDir: prop = di.IsDir(); break; 470 case kpidIsDir: prop = di.IsDir(); break;
449 case kpidSize: prop = di.IsDir() ? (UInt64)0 : di.Size; break; 471 case kpidSize: prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break;
450 case kpidAttrib: prop = di.Attrib; break; 472 case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
451 case kpidCTime: prop = di.CTime; break; 473 case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
452 case kpidATime: prop = di.ATime; break; 474 case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
453 case kpidMTime: prop = di.MTime; break; 475 case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
476 case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
477
478 #if defined(_WIN32)
454 case kpidIsAltStream: prop = di.IsAltStream; break; 479 case kpidIsAltStream: prop = di.IsAltStream; break;
455 #if defined(_WIN32) && !defined(UNDER_CE)
456 // case kpidShortName: prop = di.ShortName; break; 480 // case kpidShortName: prop = di.ShortName; break;
457 #endif 481 #else
458 case kpidPosixAttrib: 482
459 { 483 case kpidDeviceMajor:
460 #ifdef _WIN32 484 /*
461 prop = di.GetPosixAttrib(); 485 printf("\ndi.mode = %o\n", di.mode);
462 #else 486 printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev));
463 if (di.Attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) 487 printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev));
464 prop = (UInt32)(di.Attrib >> 16); 488 */
465 #endif 489 if (S_ISCHR(di.mode) || S_ISBLK(di.mode))
490 prop = (UInt32)major(di.rdev);
466 break; 491 break;
467 } 492
493 case kpidDeviceMinor:
494 if (S_ISCHR(di.mode) || S_ISBLK(di.mode))
495 prop = (UInt32)minor(di.rdev);
496 break;
497
498 // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break;
499
500 case kpidUserId: if (StoreOwnerId) prop = (UInt32)di.uid; break;
501 case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break;
502 case kpidUser:
503 if (di.OwnerNameIndex >= 0)
504 prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex];
505 break;
506 case kpidGroup:
507 if (di.OwnerGroupIndex >= 0)
508 prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex];
509 break;
510 #endif
468 } 511 }
469 } 512 }
470 prop.Detach(value); 513 prop.Detach(value);
@@ -565,12 +608,41 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStrea
565 CInFileStream *inStreamSpec = new CInFileStream; 608 CInFileStream *inStreamSpec = new CInFileStream;
566 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); 609 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
567 610
611 /*
612 // for debug:
613 #ifdef _WIN32
614 inStreamSpec->StoreOwnerName = true;
615 inStreamSpec->OwnerName = "user_name";
616 inStreamSpec->OwnerName += di.Name;
617 inStreamSpec->OwnerName += "11111111112222222222222333333333333";
618 inStreamSpec->OwnerGroup = "gname_";
619 inStreamSpec->OwnerGroup += inStreamSpec->OwnerName;
620 #endif
621 */
622
623 #ifndef _WIN32
624 inStreamSpec->StoreOwnerId = StoreOwnerId;
625 inStreamSpec->StoreOwnerName = StoreOwnerName;
626
627 // if (StoreOwner)
628 {
629 inStreamSpec->_uid = di.uid;
630 inStreamSpec->_gid = di.gid;
631 if (di.OwnerNameIndex >= 0)
632 inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex];
633 if (di.OwnerGroupIndex >= 0)
634 inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex];
635 }
636 #endif
637
568 inStreamSpec->SupportHardLinks = StoreHardLinks; 638 inStreamSpec->SupportHardLinks = StoreHardLinks;
569 inStreamSpec->File.PreserveATime = PreserveATime; 639 inStreamSpec->Set_PreserveATime(PreserveATime
640 || mode == NUpdateNotifyOp::kAnalyze); // 22.00 : we don't change access time in Analyze pass.
570 641
571 const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex); 642 const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex);
572 _openFiles_Indexes.Add(index); 643 _openFiles_Indexes.Add(index);
573 _openFiles_Paths.Add(path); 644 _openFiles_Paths.Add(path);
645 // _openFiles_Streams.Add(inStreamSpec);
574 646
575 /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding 647 /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding
576 for correct working if exception was raised in GetPhyPath */ 648 for correct working if exception was raised in GetPhyPath */
@@ -579,14 +651,30 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStrea
579 651
580 if (!inStreamSpec->OpenShared(path, ShareForWrite)) 652 if (!inStreamSpec->OpenShared(path, ShareForWrite))
581 { 653 {
582 DWORD error = ::GetLastError(); 654 const DWORD error = ::GetLastError();
583 HRESULT hres = Callback->OpenFileError(path, error); 655 const HRESULT hres = Callback->OpenFileError(path, error);
584 if (StopAfterOpenError) 656 if (StopAfterOpenError)
585 if (hres == S_OK || hres == S_FALSE) 657 if (hres == S_OK || hres == S_FALSE)
586 return HRESULT_FROM_WIN32(error); 658 return HRESULT_FROM_WIN32(error);
587 return hres; 659 return hres;
588 } 660 }
589 661
662 /*
663 {
664 // for debug:
665 Byte b = 0;
666 UInt32 processedSize = 0;
667 if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK ||
668 processedSize != 1)
669 return E_FAIL;
670 }
671 */
672
673 if (Need_LatestMTime)
674 {
675 inStreamSpec->ReloadProps();
676 }
677
590 // #if defined(USE_WIN_FILE) || !defined(_WIN32) 678 // #if defined(USE_WIN_FILE) || !defined(_WIN32)
591 if (StoreHardLinks) 679 if (StoreHardLinks)
592 { 680 {
@@ -643,6 +731,8 @@ STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 in
643{ 731{
644 COM_TRY_BEGIN 732 COM_TRY_BEGIN
645 733
734 // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index);
735
646 bool isDir = false; 736 bool isDir = false;
647 737
648 if (indexType == NArchive::NEventIndexType::kOutArcIndex) 738 if (indexType == NArchive::NEventIndexType::kOutArcIndex)
@@ -676,7 +766,7 @@ STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 in
676 } 766 }
677 else if (Arc) 767 else if (Arc)
678 { 768 {
679 RINOK(Arc->GetItemPath(index, s2)); 769 RINOK(Arc->GetItem_Path(index, s2));
680 s = s2; 770 s = s2;
681 RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir)); 771 RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir));
682 } 772 }
@@ -731,7 +821,7 @@ STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt3
731 s = (*ArcItems)[index].Name; 821 s = (*ArcItems)[index].Name;
732 else if (Arc) 822 else if (Arc)
733 { 823 {
734 RINOK(Arc->GetItemPath(index, s2)); 824 RINOK(Arc->GetItem_Path(index, s2));
735 s = s2; 825 s = s2;
736 } 826 }
737 if (Archive) 827 if (Archive)
@@ -752,6 +842,51 @@ STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt3
752 COM_TRY_END 842 COM_TRY_END
753} 843}
754 844
845
846/*
847STDMETHODIMP CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer)
848{
849 *answer = 0;
850 if (Need_ArcMTime_Report && propID == kpidComboMTime)
851 *answer = 1;
852 return S_OK;
853}
854
855STDMETHODIMP CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)
856{
857 if (indexType == NArchive::NEventIndexType::kArcProp)
858 {
859 if (propID == kpidComboMTime)
860 {
861 ArcMTime_WasReported = true;
862 if (value->vt == VT_FILETIME)
863 {
864 Reported_ArcMTime.Set_From_Prop(*value);
865 Reported_ArcMTime.Def = true;
866 }
867 else
868 {
869 Reported_ArcMTime.Clear();
870 if (value->vt != VT_EMPTY)
871 return E_FAIL; // for debug
872 }
873 }
874 }
875 return Callback->ReportProp(indexType, index, propID, value);
876}
877
878STDMETHODIMP CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index,
879 PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)
880{
881 return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType);
882}
883
884STDMETHODIMP CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)
885{
886 return Callback->ReportFinished(indexType, index, opRes);
887}
888*/
889
755STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) 890STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
756{ 891{
757 if (VolumesSizes.Size() == 0) 892 if (VolumesSizes.Size() == 0)
@@ -805,7 +940,7 @@ HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
805 #endif 940 #endif
806 { 941 {
807 MT_LOCK 942 MT_LOCK
808 UInt32 index = (UInt32)val; 943 const UInt32 index = (UInt32)val;
809 FOR_VECTOR(i, _openFiles_Indexes) 944 FOR_VECTOR(i, _openFiles_Indexes)
810 { 945 {
811 if (_openFiles_Indexes[i] == index) 946 if (_openFiles_Indexes[i] == index)
@@ -818,21 +953,31 @@ HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
818 return HRESULT_FROM_WIN32(error); 953 return HRESULT_FROM_WIN32(error);
819} 954}
820 955
821void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val) 956void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val)
822{ 957{
823 {
824 MT_LOCK 958 MT_LOCK
825 UInt32 index = (UInt32)val; 959 if (Need_LatestMTime)
960 {
961 if (stream->_info_WasLoaded)
962 {
963 const CFiTime &ft = ST_MTIME(stream->_info);
964 if (!LatestMTime_Defined
965 || Compare_FiTime(&LatestMTime, &ft) < 0)
966 LatestMTime = ft;
967 LatestMTime_Defined = true;
968 }
969 }
970 const UInt32 index = (UInt32)val;
826 FOR_VECTOR(i, _openFiles_Indexes) 971 FOR_VECTOR(i, _openFiles_Indexes)
827 { 972 {
828 if (_openFiles_Indexes[i] == index) 973 if (_openFiles_Indexes[i] == index)
829 { 974 {
830 _openFiles_Indexes.Delete(i); 975 _openFiles_Indexes.Delete(i);
831 _openFiles_Paths.Delete(i); 976 _openFiles_Paths.Delete(i);
977 // _openFiles_Streams.Delete(i);
832 return; 978 return;
833 } 979 }
834 } 980 }
835 }
836 /* 21.02 : this function can be called in destructor. 981 /* 21.02 : this function can be called in destructor.
837 And destructor can be called after some exception. 982 And destructor can be called after some exception.
838 If we don't want to throw exception in desctructors or after another exceptions, 983 If we don't want to throw exception in desctructors or after another exceptions,
diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h
index d27776e..3719c1e 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.h
+++ b/CPP/7zip/UI/Common/UpdateCallback.h
@@ -45,6 +45,13 @@ struct CArcToDoStat
45 virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \ 45 virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
46 virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \ 46 virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \
47 virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x; \ 47 virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x; \
48
49 /*
50 virtual HRESULT ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x; \
51 virtual HRESULT ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x; \
52 virtual HRESULT ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) x; \
53 */
54
48 /* virtual HRESULT CloseProgress() { return S_OK; } */ 55 /* virtual HRESULT CloseProgress() { return S_OK; } */
49 56
50struct IUpdateCallbackUI 57struct IUpdateCallbackUI
@@ -70,6 +77,7 @@ struct CKeyKeyValPair
70class CArchiveUpdateCallback: 77class CArchiveUpdateCallback:
71 public IArchiveUpdateCallback2, 78 public IArchiveUpdateCallback2,
72 public IArchiveUpdateCallbackFile, 79 public IArchiveUpdateCallbackFile,
80 // public IArchiveUpdateCallbackArcProp,
73 public IArchiveExtractCallbackMessage, 81 public IArchiveExtractCallbackMessage,
74 public IArchiveGetRawProps, 82 public IArchiveGetRawProps,
75 public IArchiveGetRootProps, 83 public IArchiveGetRootProps,
@@ -92,6 +100,7 @@ class CArchiveUpdateCallback:
92public: 100public:
93 MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2) 101 MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2)
94 MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile) 102 MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile)
103 // MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackArcProp)
95 MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage) 104 MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage)
96 MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) 105 MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
97 MY_QUERYINTERFACE_ENTRY(IArchiveGetRootProps) 106 MY_QUERYINTERFACE_ENTRY(IArchiveGetRootProps)
@@ -106,6 +115,7 @@ public:
106 115
107 INTERFACE_IArchiveUpdateCallback2(;) 116 INTERFACE_IArchiveUpdateCallback2(;)
108 INTERFACE_IArchiveUpdateCallbackFile(;) 117 INTERFACE_IArchiveUpdateCallbackFile(;)
118 // INTERFACE_IArchiveUpdateCallbackArcProp(;)
109 INTERFACE_IArchiveExtractCallbackMessage(;) 119 INTERFACE_IArchiveExtractCallbackMessage(;)
110 INTERFACE_IArchiveGetRawProps(;) 120 INTERFACE_IArchiveGetRawProps(;)
111 INTERFACE_IArchiveGetRootProps(;) 121 INTERFACE_IArchiveGetRootProps(;)
@@ -115,10 +125,11 @@ public:
115 125
116 CRecordVector<UInt32> _openFiles_Indexes; 126 CRecordVector<UInt32> _openFiles_Indexes;
117 FStringVector _openFiles_Paths; 127 FStringVector _openFiles_Paths;
128 // CRecordVector< CInFileStream* > _openFiles_Streams;
118 129
119 bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); } 130 bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); }
120 virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error); 131 virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error);
121 virtual void InFileStream_On_Destroy(UINT_PTR val); 132 virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val);
122 133
123 CRecordVector<UInt64> VolumesSizes; 134 CRecordVector<UInt64> VolumesSizes;
124 FString VolName; 135 FString VolName;
@@ -148,8 +159,22 @@ public:
148 bool StoreHardLinks; 159 bool StoreHardLinks;
149 bool StoreSymLinks; 160 bool StoreSymLinks;
150 161
162 bool StoreOwnerId;
163 bool StoreOwnerName;
164
165 /*
166 bool Need_ArcMTime_Report;
167 bool ArcMTime_WasReported;
168 CArcTime Reported_ArcMTime;
169 */
170 bool Need_LatestMTime;
171 bool LatestMTime_Defined;
172 CFiTime LatestMTime;
173
151 Byte *ProcessedItemsStatuses; 174 Byte *ProcessedItemsStatuses;
152 175
176
177
153 CArchiveUpdateCallback(); 178 CArchiveUpdateCallback();
154 179
155 bool IsDir(const CUpdatePair2 &up) const 180 bool IsDir(const CUpdatePair2 &up) const
diff --git a/CPP/7zip/UI/Common/UpdatePair.cpp b/CPP/7zip/UI/Common/UpdatePair.cpp
index 31d73f9..e9a1644 100644
--- a/CPP/7zip/UI/Common/UpdatePair.cpp
+++ b/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -3,6 +3,7 @@
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#include <time.h> 5#include <time.h>
6// #include <stdio.h>
6 7
7#include "../../../Common/Wildcard.h" 8#include "../../../Common/Wildcard.h"
8 9
@@ -14,30 +15,90 @@
14using namespace NWindows; 15using namespace NWindows;
15using namespace NTime; 16using namespace NTime;
16 17
17static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2) 18
19/*
20 a2.Prec =
21 {
22 0 (k_PropVar_TimePrec_0):
23 if GetProperty(kpidMTime) returned 0 and
24 GetProperty(kpidTimeType) did not returned VT_UI4.
25 7z, wim, tar in 7-Zip before v21)
26 in that case we use
27 (prec) that is set by IOutArchive::GetFileTimeType()
28 }
29*/
30
31static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2)
18{ 32{
19 switch (fileTimeType) 33 // except of precision, we also have limitation, when timestamp is out of range
34
35 /* if (Prec) in archive item is defined, then use global (prec) */
36 if (a2.Prec != k_PropVar_TimePrec_0)
37 prec = a2.Prec;
38
39 CArcTime a1;
40 a1.Set_From_FiTime(f1);
41 /* Set_From_FiTime() must set full form precision:
42 k_PropVar_TimePrec_Base + numDigits
43 windows: 7 digits, non-windows: 9 digits */
44
45 if (prec == k_PropVar_TimePrec_DOS)
20 { 46 {
21 case NFileTimeType::kWindows: 47 const UInt32 dosTime1 = a1.Get_DosTime();
22 return ::CompareFileTime(&time1, &time2); 48 const UInt32 dosTime2 = a2.Get_DosTime();
23 case NFileTimeType::kUnix: 49 return MyCompare(dosTime1, dosTime2);
24 {
25 UInt32 unixTime1, unixTime2;
26 FileTimeToUnixTime(time1, unixTime1);
27 FileTimeToUnixTime(time2, unixTime2);
28 return MyCompare(unixTime1, unixTime2);
29 }
30 case NFileTimeType::kDOS:
31 {
32 UInt32 dosTime1, dosTime2;
33 FileTimeToDosTime(time1, dosTime1);
34 FileTimeToDosTime(time2, dosTime2);
35 return MyCompare(dosTime1, dosTime2);
36 }
37 } 50 }
38 throw 4191618; 51
52 if (prec == k_PropVar_TimePrec_Unix)
53 {
54 const Int64 u2 = FileTime_To_UnixTime64(a2.FT);
55 if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF)
56 {
57 // timestamp probably was saturated in archive to 32-bit
58 // so we use saturated 32-bit value for disk file too.
59 UInt32 u1;
60 FileTime_To_UnixTime(a1.FT, u1);
61 const UInt32 u2_32 = (UInt32)u2;
62 return MyCompare(u1, u2_32);
63 }
64
65 const Int64 u1 = FileTime_To_UnixTime64(a1.FT);
66 return MyCompare(u1, u2);
67 // prec = k_PropVar_TimePrec_Base; // for debug
68 }
69
70 if (prec == k_PropVar_TimePrec_0)
71 prec = k_PropVar_TimePrec_Base + 7;
72 else if (prec == k_PropVar_TimePrec_HighPrec)
73 prec = k_PropVar_TimePrec_Base + 9;
74 else if (prec < k_PropVar_TimePrec_Base)
75 prec = k_PropVar_TimePrec_Base;
76 else if (prec > k_PropVar_TimePrec_Base + 9)
77 prec = k_PropVar_TimePrec_Base + 7;
78
79 // prec now is full form: k_PropVar_TimePrec_Base + numDigits;
80 if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base)
81 prec = a1.Prec;
82
83 const unsigned numDigits = prec - k_PropVar_TimePrec_Base;
84 if (numDigits >= 7)
85 {
86 const int comp = CompareFileTime(&a1.FT, &a2.FT);
87 if (comp != 0 || numDigits == 7)
88 return comp;
89 return MyCompare(a1.Ns100, a2.Ns100);
90 }
91 UInt32 d = 1;
92 for (unsigned k = numDigits; k < 7; k++)
93 d *= 10;
94 const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d;
95 const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d;
96 // printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits);
97 return MyCompare(v1, v2);
39} 98}
40 99
100
101
41static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:"; 102static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:";
42static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:"; 103static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:";
43static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; 104static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
@@ -64,8 +125,8 @@ static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
64 125
65static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) 126static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
66{ 127{
67 unsigned i1 = *p1; 128 const unsigned i1 = *p1;
68 unsigned i2 = *p2; 129 const unsigned i2 = *p2;
69 const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param; 130 const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
70 int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); 131 int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
71 if (res != 0) 132 if (res != 0)
@@ -81,8 +142,8 @@ void GetUpdatePairInfoList(
81{ 142{
82 CUIntVector dirIndices, arcIndices; 143 CUIntVector dirIndices, arcIndices;
83 144
84 unsigned numDirItems = dirItems.Items.Size(); 145 const unsigned numDirItems = dirItems.Items.Size();
85 unsigned numArcItems = arcItems.Size(); 146 const unsigned numArcItems = arcItems.Size();
86 147
87 CIntArr duplicatedArcItem(numArcItems); 148 CIntArr duplicatedArcItem(numArcItems);
88 { 149 {
@@ -184,7 +245,7 @@ void GetUpdatePairInfoList(
184 } 245 }
185 else 246 else
186 { 247 {
187 int dupl = duplicatedArcItem[arcIndex]; 248 const int dupl = duplicatedArcItem[arcIndex];
188 if (dupl != 0) 249 if (dupl != 0)
189 ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name); 250 ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name);
190 251
@@ -195,14 +256,17 @@ void GetUpdatePairInfoList(
195 pair.DirIndex = dirIndex2; 256 pair.DirIndex = dirIndex2;
196 pair.ArcIndex = arcIndex2; 257 pair.ArcIndex = arcIndex2;
197 258
198 switch (ai->MTimeDefined ? MyCompareTime( 259 int compResult = 0;
199 ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType, 260 if (ai->MTime.Def)
200 di->MTime, ai->MTime): 0) 261 {
262 compResult = MyCompareTime(fileTimeType, di->MTime, ai->MTime);
263 }
264 switch (compResult)
201 { 265 {
202 case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; 266 case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
203 case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; 267 case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
204 default: 268 default:
205 pair.State = (ai->SizeDefined && di->Size == ai->Size) ? 269 pair.State = (ai->Size_Defined && di->Size == ai->Size) ?
206 NUpdateArchive::NPairState::kSameFiles : 270 NUpdateArchive::NPairState::kSameFiles :
207 NUpdateArchive::NPairState::kUnknowNewerFiles; 271 NUpdateArchive::NPairState::kUnknowNewerFiles;
208 } 272 }
@@ -211,7 +275,10 @@ void GetUpdatePairInfoList(
211 arcIndex++; 275 arcIndex++;
212 } 276 }
213 277
214 if ((di && di->IsAltStream) || 278 if (
279 #ifdef _WIN32
280 (di && di->IsAltStream) ||
281 #endif
215 (ai && ai->IsAltStream)) 282 (ai && ai->IsAltStream))
216 { 283 {
217 if (prevHostName) 284 if (prevHostName)
diff --git a/CPP/7zip/UI/Common/UpdateProduce.cpp b/CPP/7zip/UI/Common/UpdateProduce.cpp
index fa4bd69..e921dc3 100644
--- a/CPP/7zip/UI/Common/UpdateProduce.cpp
+++ b/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -63,6 +63,8 @@ void UpdateProduce(
63 break; 63 break;
64 } 64 }
65 65
66 up2.IsSameTime = ((unsigned)pair.State == NUpdateArchive::NPairState::kSameFiles);
67
66 operationChain.Add(up2); 68 operationChain.Add(up2);
67 } 69 }
68 70
diff --git a/CPP/7zip/UI/Common/UpdateProduce.h b/CPP/7zip/UI/Common/UpdateProduce.h
index 595370f..24bb32e 100644
--- a/CPP/7zip/UI/Common/UpdateProduce.h
+++ b/CPP/7zip/UI/Common/UpdateProduce.h
@@ -17,6 +17,7 @@ struct CUpdatePair2
17 int NewNameIndex; 17 int NewNameIndex;
18 18
19 bool IsMainRenameItem; 19 bool IsMainRenameItem;
20 bool IsSameTime;
20 21
21 void SetAs_NoChangeArcItem(unsigned arcIndex) // int 22 void SetAs_NoChangeArcItem(unsigned arcIndex) // int
22 { 23 {
@@ -37,7 +38,8 @@ struct CUpdatePair2
37 DirIndex(-1), 38 DirIndex(-1),
38 ArcIndex(-1), 39 ArcIndex(-1),
39 NewNameIndex(-1), 40 NewNameIndex(-1),
40 IsMainRenameItem(false) 41 IsMainRenameItem(false),
42 IsSameTime(false)
41 {} 43 {}
42}; 44};
43 45
diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp
index ab4871f..a67a99b 100644
--- a/CPP/7zip/UI/Common/ZipRegistry.cpp
+++ b/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -33,12 +33,45 @@ static LONG CreateMainKey(CKey &key, LPCTSTR keyName)
33 return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName)); 33 return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName));
34} 34}
35 35
36static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value)
37{
38 if (value == (UInt32)(Int32)-1)
39 key.DeleteValue(name);
40 else
41 key.SetValue(name, value);
42}
43
44
45static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value)
46{
47 if (key.QueryValue(name, value) != ERROR_SUCCESS)
48 value = (UInt32)(Int32)-1;
49}
50
51
36static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b) 52static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b)
37{ 53{
38 if (b.Def) 54 if (b.Def)
39 key.SetValue(name, b.Val); 55 key.SetValue(name, b.Val);
40} 56}
41 57
58static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val)
59{
60 bool oldVal = false;
61 if (key.GetValue_IfOk(name, oldVal) == ERROR_SUCCESS)
62 if (val == oldVal)
63 return;
64 key.SetValue(name, val);
65}
66
67static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoolPair &b)
68{
69 if (b.Def)
70 Key_Set_bool_if_Changed(key, name, b.Val);
71 else
72 key.DeleteValue(name);
73}
74
42static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b) 75static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b)
43{ 76{
44 b.Val = false; 77 b.Val = false;
@@ -169,6 +202,13 @@ static LPCTSTR const kNtSecur = TEXT("Security");
169static LPCTSTR const kAltStreams = TEXT("AltStreams"); 202static LPCTSTR const kAltStreams = TEXT("AltStreams");
170static LPCTSTR const kHardLinks = TEXT("HardLinks"); 203static LPCTSTR const kHardLinks = TEXT("HardLinks");
171static LPCTSTR const kSymLinks = TEXT("SymLinks"); 204static LPCTSTR const kSymLinks = TEXT("SymLinks");
205static LPCTSTR const kPreserveATime = TEXT("PreserveATime");
206
207static LPCTSTR const kTimePrec = TEXT("TimePrec");
208static LPCTSTR const kMTime = TEXT("MTime");
209static LPCTSTR const kATime = TEXT("ATime");
210static LPCTSTR const kCTime = TEXT("CTime");
211static LPCTSTR const kSetArcMTime = TEXT("SetArcMTime");
172 212
173static void SetRegString(CKey &key, LPCWSTR name, const UString &value) 213static void SetRegString(CKey &key, LPCWSTR name, const UString &value)
174{ 214{
@@ -178,26 +218,12 @@ static void SetRegString(CKey &key, LPCWSTR name, const UString &value)
178 key.SetValue(name, value); 218 key.SetValue(name, value);
179} 219}
180 220
181static void SetRegUInt32(CKey &key, LPCTSTR name, UInt32 value)
182{
183 if (value == (UInt32)(Int32)-1)
184 key.DeleteValue(name);
185 else
186 key.SetValue(name, value);
187}
188
189static void GetRegString(CKey &key, LPCWSTR name, UString &value) 221static void GetRegString(CKey &key, LPCWSTR name, UString &value)
190{ 222{
191 if (key.QueryValue(name, value) != ERROR_SUCCESS) 223 if (key.QueryValue(name, value) != ERROR_SUCCESS)
192 value.Empty(); 224 value.Empty();
193} 225}
194 226
195static void GetRegUInt32(CKey &key, LPCTSTR name, UInt32 &value)
196{
197 if (key.QueryValue(name, value) != ERROR_SUCCESS)
198 value = (UInt32)(Int32)-1;
199}
200
201static LPCWSTR const kMemUse = L"MemUse" 227static LPCWSTR const kMemUse = L"MemUse"
202 #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) 228 #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
203 L"32"; 229 L"32";
@@ -212,10 +238,11 @@ void CInfo::Save() const
212 CKey key; 238 CKey key;
213 CreateMainKey(key, kKeyName); 239 CreateMainKey(key, kKeyName);
214 240
215 Key_Set_BoolPair(key, kNtSecur, NtSecurity); 241 Key_Set_BoolPair_Delete_IfNotDef (key, kNtSecur, NtSecurity);
216 Key_Set_BoolPair(key, kAltStreams, AltStreams); 242 Key_Set_BoolPair_Delete_IfNotDef (key, kAltStreams, AltStreams);
217 Key_Set_BoolPair(key, kHardLinks, HardLinks); 243 Key_Set_BoolPair_Delete_IfNotDef (key, kHardLinks, HardLinks);
218 Key_Set_BoolPair(key, kSymLinks, SymLinks); 244 Key_Set_BoolPair_Delete_IfNotDef (key, kSymLinks, SymLinks);
245 Key_Set_BoolPair_Delete_IfNotDef (key, kPreserveATime, PreserveATime);
219 246
220 key.SetValue(kShowPassword, ShowPassword); 247 key.SetValue(kShowPassword, ShowPassword);
221 key.SetValue(kLevel, (UInt32)Level); 248 key.SetValue(kLevel, (UInt32)Level);
@@ -235,16 +262,22 @@ void CInfo::Save() const
235 CKey fk; 262 CKey fk;
236 fk.Create(optionsKey, fo.FormatID); 263 fk.Create(optionsKey, fo.FormatID);
237 264
238 SetRegUInt32(fk, kLevel, fo.Level);
239 SetRegUInt32(fk, kDictionary, fo.Dictionary);
240 SetRegUInt32(fk, kOrder, fo.Order);
241 SetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
242 SetRegUInt32(fk, kNumThreads, fo.NumThreads);
243
244 SetRegString(fk, kMethod, fo.Method); 265 SetRegString(fk, kMethod, fo.Method);
245 SetRegString(fk, kOptions, fo.Options); 266 SetRegString(fk, kOptions, fo.Options);
246 SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); 267 SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
247 SetRegString(fk, kMemUse, fo.MemUse); 268 SetRegString(fk, kMemUse, fo.MemUse);
269
270 Key_Set_UInt32(fk, kLevel, fo.Level);
271 Key_Set_UInt32(fk, kDictionary, fo.Dictionary);
272 Key_Set_UInt32(fk, kOrder, fo.Order);
273 Key_Set_UInt32(fk, kBlockSize, fo.BlockLogSize);
274 Key_Set_UInt32(fk, kNumThreads, fo.NumThreads);
275
276 Key_Set_UInt32(fk, kTimePrec, fo.TimePrec);
277 Key_Set_BoolPair_Delete_IfNotDef (fk, kMTime, fo.MTime);
278 Key_Set_BoolPair_Delete_IfNotDef (fk, kATime, fo.ATime);
279 Key_Set_BoolPair_Delete_IfNotDef (fk, kCTime, fo.CTime);
280 Key_Set_BoolPair_Delete_IfNotDef (fk, kSetArcMTime, fo.SetArcMTime);
248 } 281 }
249 } 282 }
250} 283}
@@ -269,6 +302,7 @@ void CInfo::Load()
269 Key_Get_BoolPair(key, kAltStreams, AltStreams); 302 Key_Get_BoolPair(key, kAltStreams, AltStreams);
270 Key_Get_BoolPair(key, kHardLinks, HardLinks); 303 Key_Get_BoolPair(key, kHardLinks, HardLinks);
271 Key_Get_BoolPair(key, kSymLinks, SymLinks); 304 Key_Get_BoolPair(key, kSymLinks, SymLinks);
305 Key_Get_BoolPair(key, kPreserveATime, PreserveATime);
272 306
273 key.GetValue_Strings(kArcHistory, ArcPaths); 307 key.GetValue_Strings(kArcHistory, ArcPaths);
274 308
@@ -290,11 +324,17 @@ void CInfo::Load()
290 GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); 324 GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
291 GetRegString(fk, kMemUse, fo.MemUse); 325 GetRegString(fk, kMemUse, fo.MemUse);
292 326
293 GetRegUInt32(fk, kLevel, fo.Level); 327 Key_Get_UInt32(fk, kLevel, fo.Level);
294 GetRegUInt32(fk, kDictionary, fo.Dictionary); 328 Key_Get_UInt32(fk, kDictionary, fo.Dictionary);
295 GetRegUInt32(fk, kOrder, fo.Order); 329 Key_Get_UInt32(fk, kOrder, fo.Order);
296 GetRegUInt32(fk, kBlockSize, fo.BlockLogSize); 330 Key_Get_UInt32(fk, kBlockSize, fo.BlockLogSize);
297 GetRegUInt32(fk, kNumThreads, fo.NumThreads); 331 Key_Get_UInt32(fk, kNumThreads, fo.NumThreads);
332
333 Key_Get_UInt32(fk, kTimePrec, fo.TimePrec);
334 Key_Get_BoolPair(fk, kMTime, fo.MTime);
335 Key_Get_BoolPair(fk, kATime, fo.ATime);
336 Key_Get_BoolPair(fk, kCTime, fo.CTime);
337 Key_Get_BoolPair(fk, kSetArcMTime, fo.SetArcMTime);
298 338
299 Formats.Add(fo); 339 Formats.Add(fo);
300 } 340 }
@@ -478,6 +518,7 @@ static LPCTSTR const kCascadedMenu = TEXT("CascadedMenu");
478static LPCTSTR const kContextMenu = TEXT("ContextMenu"); 518static LPCTSTR const kContextMenu = TEXT("ContextMenu");
479static LPCTSTR const kMenuIcons = TEXT("MenuIcons"); 519static LPCTSTR const kMenuIcons = TEXT("MenuIcons");
480static LPCTSTR const kElimDup = TEXT("ElimDupExtract"); 520static LPCTSTR const kElimDup = TEXT("ElimDupExtract");
521static LPCTSTR const kWriteZoneId = TEXT("WriteZoneIdExtract");
481 522
482void CContextMenuInfo::Save() const 523void CContextMenuInfo::Save() const
483{ 524{
@@ -488,6 +529,8 @@ void CContextMenuInfo::Save() const
488 Key_Set_BoolPair(key, kCascadedMenu, Cascaded); 529 Key_Set_BoolPair(key, kCascadedMenu, Cascaded);
489 Key_Set_BoolPair(key, kMenuIcons, MenuIcons); 530 Key_Set_BoolPair(key, kMenuIcons, MenuIcons);
490 Key_Set_BoolPair(key, kElimDup, ElimDup); 531 Key_Set_BoolPair(key, kElimDup, ElimDup);
532
533 Key_Set_UInt32(key, kWriteZoneId, WriteZone);
491 534
492 if (Flags_Def) 535 if (Flags_Def)
493 key.SetValue(kContextMenu, Flags); 536 key.SetValue(kContextMenu, Flags);
@@ -504,6 +547,8 @@ void CContextMenuInfo::Load()
504 ElimDup.Val = true; 547 ElimDup.Val = true;
505 ElimDup.Def = false; 548 ElimDup.Def = false;
506 549
550 WriteZone = (UInt32)(Int32)-1;
551
507 Flags = (UInt32)(Int32)-1; 552 Flags = (UInt32)(Int32)-1;
508 Flags_Def = false; 553 Flags_Def = false;
509 554
@@ -517,5 +562,7 @@ void CContextMenuInfo::Load()
517 Key_Get_BoolPair_true(key, kElimDup, ElimDup); 562 Key_Get_BoolPair_true(key, kElimDup, ElimDup);
518 Key_Get_BoolPair(key, kMenuIcons, MenuIcons); 563 Key_Get_BoolPair(key, kMenuIcons, MenuIcons);
519 564
565 Key_Get_UInt32(key, kWriteZoneId, WriteZone);
566
520 Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); 567 Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS);
521} 568}
diff --git a/CPP/7zip/UI/Common/ZipRegistry.h b/CPP/7zip/UI/Common/ZipRegistry.h
index 3d2e4b9..b7075e6 100644
--- a/CPP/7zip/UI/Common/ZipRegistry.h
+++ b/CPP/7zip/UI/Common/ZipRegistry.h
@@ -10,6 +10,16 @@
10 10
11#include "ExtractMode.h" 11#include "ExtractMode.h"
12 12
13/*
14CBoolPair::Def in writing functions means:
15 if ( CBoolPair::Def ), we write CBoolPair::Val
16 if ( !CBoolPair::Def )
17 {
18 in NCompression functions we delete registry value
19 in another functions we do nothing
20 }
21*/
22
13namespace NExtract 23namespace NExtract
14{ 24{
15 struct CInfo 25 struct CInfo
@@ -75,12 +85,29 @@ namespace NCompression
75 UInt32 BlockLogSize; 85 UInt32 BlockLogSize;
76 UInt32 NumThreads; 86 UInt32 NumThreads;
77 87
88 UInt32 TimePrec;
89 CBoolPair MTime;
90 CBoolPair ATime;
91 CBoolPair CTime;
92 CBoolPair SetArcMTime;
93
78 CSysString FormatID; 94 CSysString FormatID;
79 UString Method; 95 UString Method;
80 UString Options; 96 UString Options;
81 UString EncryptionMethod; 97 UString EncryptionMethod;
82 UString MemUse; 98 UString MemUse;
83 99
100 void Reset_TimePrec()
101 {
102 TimePrec = (UInt32)(Int32)-1;
103 }
104
105 bool IsSet_TimePrec() const
106 {
107 return TimePrec != (UInt32)(Int32)-1;
108 }
109
110
84 void Reset_BlockLogSize() 111 void Reset_BlockLogSize()
85 { 112 {
86 BlockLogSize = (UInt32)(Int32)-1; 113 BlockLogSize = (UInt32)(Int32)-1;
@@ -93,7 +120,12 @@ namespace NCompression
93 // Options.Empty(); 120 // Options.Empty();
94 // EncryptionMethod.Empty(); 121 // EncryptionMethod.Empty();
95 } 122 }
96 CFormatOptions() { ResetForLevelChange(); } 123 CFormatOptions()
124 {
125 // TimePrec = 0;
126 Reset_TimePrec();
127 ResetForLevelChange();
128 }
97 }; 129 };
98 130
99 struct CInfo 131 struct CInfo
@@ -111,6 +143,8 @@ namespace NCompression
111 CBoolPair HardLinks; 143 CBoolPair HardLinks;
112 CBoolPair SymLinks; 144 CBoolPair SymLinks;
113 145
146 CBoolPair PreserveATime;
147
114 void Save() const; 148 void Save() const;
115 void Load(); 149 void Load();
116 }; 150 };
@@ -152,9 +186,18 @@ struct CContextMenuInfo
152 CBoolPair Cascaded; 186 CBoolPair Cascaded;
153 CBoolPair MenuIcons; 187 CBoolPair MenuIcons;
154 CBoolPair ElimDup; 188 CBoolPair ElimDup;
155 189
156 bool Flags_Def; 190 bool Flags_Def;
157 UInt32 Flags; 191 UInt32 Flags;
192 UInt32 WriteZone;
193
194 /*
195 CContextMenuInfo():
196 Flags_Def(0),
197 WriteZone((UInt32)(Int32)-1),
198 Flags((UInt32)(Int32)-1)
199 {}
200 */
158 201
159 void Save() const; 202 void Save() const;
160 void Load(); 203 void Load();
diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
index 24c21e8..7f791b0 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -56,6 +56,9 @@ HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString
56 56
57HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError) 57HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError)
58{ 58{
59 // 22.00:
60 // ScanErrors.AddError(path, systemError);
61
59 ClosePercentsAndFlush(); 62 ClosePercentsAndFlush();
60 63
61 if (_se) 64 if (_se)
@@ -66,6 +69,10 @@ HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError)
66 _se->Flush(); 69 _se->Flush();
67 } 70 }
68 return HRESULT_FROM_WIN32(systemError); 71 return HRESULT_FROM_WIN32(systemError);
72
73 // 22.00: commented
74 // CommonError(path, systemError, true);
75 // return S_OK;
69} 76}
70 77
71 78
diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/CPP/7zip/UI/Console/ExtractCallbackConsole.h
index 5ac1d0b..7964813 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.h
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.h
@@ -15,12 +15,33 @@
15 15
16#include "OpenCallbackConsole.h" 16#include "OpenCallbackConsole.h"
17 17
18/*
19struct CErrorPathCodes2
20{
21 FStringVector Paths;
22 CRecordVector<DWORD> Codes;
23
24 void AddError(const FString &path, DWORD systemError)
25 {
26 Paths.Add(path);
27 Codes.Add(systemError);
28 }
29 void Clear()
30 {
31 Paths.Clear();
32 Codes.Clear();
33 }
34};
35*/
36
18class CExtractScanConsole: public IDirItemsCallback 37class CExtractScanConsole: public IDirItemsCallback
19{ 38{
20 CStdOutStream *_so; 39 CStdOutStream *_so;
21 CStdOutStream *_se; 40 CStdOutStream *_se;
22 CPercentPrinter _percent; 41 CPercentPrinter _percent;
23 42
43 // CErrorPathCodes2 ScanErrors;
44
24 bool NeedPercents() const { return _percent._so != NULL; } 45 bool NeedPercents() const { return _percent._so != NULL; }
25 46
26 void ClosePercentsAndFlush() 47 void ClosePercentsAndFlush()
diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp
index 9000e57..f764f07 100644
--- a/CPP/7zip/UI/Console/List.cpp
+++ b/CPP/7zip/UI/Console/List.cpp
@@ -124,6 +124,13 @@ static const char * const kPropIdToName[] =
124 , "Read-only" 124 , "Read-only"
125 , "Out Name" 125 , "Out Name"
126 , "Copy Link" 126 , "Copy Link"
127 , "ArcFileName"
128 , "IsHash"
129 , "Metadata Changed"
130 , "User ID"
131 , "Group ID"
132 , "Device Major"
133 , "Device Minor"
127}; 134};
128 135
129static const char kEmptyAttribChar = '.'; 136static const char kEmptyAttribChar = '.';
@@ -303,22 +310,18 @@ struct CListUInt64Def
303 void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } 310 void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); }
304}; 311};
305 312
306struct CListFileTimeDef
307{
308 FILETIME Val;
309 bool Def;
310 313
311 CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; } 314struct CListFileTimeDef: public CArcTime
315{
312 void Update(const CListFileTimeDef &t) 316 void Update(const CListFileTimeDef &t)
313 { 317 {
314 if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0)) 318 if (t.Def && (!Def || CompareWith(t) < 0))
315 { 319 (*this) = t;
316 Val = t.Val;
317 Def = true;
318 }
319 } 320 }
320}; 321};
321 322
323
324
322struct CListStat 325struct CListStat
323{ 326{
324 CListUInt64Def Size; 327 CListUInt64Def Size;
@@ -493,12 +496,24 @@ void CFieldPrinter::PrintTitleLines()
493 g_StdOut << LinesString; 496 g_StdOut << LinesString;
494} 497}
495 498
496static void PrintTime(char *dest, const FILETIME *ft) 499static void PrintTime(char *dest, const CListFileTimeDef &t, bool showNS)
497{ 500{
498 *dest = 0; 501 *dest = 0;
499 if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0) 502 if (t.IsZero())
500 return; 503 return;
501 ConvertUtcFileTimeToString(*ft, dest, kTimestampPrintLevel_SEC); 504 int prec = kTimestampPrintLevel_SEC;
505 if (showNS)
506 {
507 prec = kTimestampPrintLevel_NTFS;
508 if (t.Prec != 0)
509 {
510 prec = t.GetNumDigits();
511 if (prec < kTimestampPrintLevel_DAY)
512 prec = kTimestampPrintLevel_NTFS;
513 }
514 }
515
516 ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec);
502} 517}
503 518
504#ifndef _SFX 519#ifndef _SFX
@@ -631,7 +646,13 @@ HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
631 { 646 {
632 case kpidSize: if (st.Size.Def) prop = st.Size.Val; break; 647 case kpidSize: if (st.Size.Def) prop = st.Size.Val; break;
633 case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break; 648 case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break;
634 case kpidMTime: if (st.MTime.Def) prop = st.MTime.Val; break; 649 case kpidMTime:
650 {
651 const CListFileTimeDef &mtime = st.MTime;
652 if (mtime.Def)
653 prop.SetAsTimeFrom_FT_Prec_Ns100(mtime.FT, mtime.Prec, mtime.Ns100);
654 break;
655 }
635 default: 656 default:
636 RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)); 657 RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop));
637 } 658 }
@@ -653,7 +674,9 @@ HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
653 } 674 }
654 else if (prop.vt == VT_FILETIME) 675 else if (prop.vt == VT_FILETIME)
655 { 676 {
656 PrintTime(temp + tempPos, &prop.filetime); 677 CListFileTimeDef t;
678 t.Set_From_Prop(prop);
679 PrintTime(temp + tempPos, t, techMode);
657 if (techMode) 680 if (techMode)
658 g_StdOut << temp + tempPos; 681 g_StdOut << temp + tempPos;
659 else 682 else
@@ -726,7 +749,7 @@ void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *st
726 char s[64]; 749 char s[64];
727 s[0] = 0; 750 s[0] = 0;
728 if (st.MTime.Def) 751 if (st.MTime.Def)
729 PrintTime(s, &st.MTime.Val); 752 PrintTime(s, st.MTime, false); // showNS
730 PrintString(f.TextAdjustment, f.Width, s); 753 PrintString(f.TextAdjustment, f.Width, s);
731 } 754 }
732 else if (f.PropID == kpidPath) 755 else if (f.PropID == kpidPath)
@@ -770,16 +793,14 @@ static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID,
770 793
771static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) 794static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t)
772{ 795{
773 t.Val.dwLowDateTime = 0; 796 /* maybe we could call CArc::GetItemMTime(UInt32 index, CArcTime &ft, bool &defined) here
774 t.Val.dwHighDateTime = 0; 797 that can set default timestamp, if not defined */
775 t.Def = false; 798 t.Clear();
799 // t.Def = false;
776 CPropVariant prop; 800 CPropVariant prop;
777 RINOK(archive->GetProperty(index, kpidMTime, &prop)); 801 RINOK(archive->GetProperty(index, kpidMTime, &prop));
778 if (prop.vt == VT_FILETIME) 802 if (prop.vt == VT_FILETIME)
779 { 803 t.Set_From_Prop(prop);
780 t.Val = prop.filetime;
781 t.Def = true;
782 }
783 else if (prop.vt != VT_EMPTY) 804 else if (prop.vt != VT_EMPTY)
784 return E_FAIL; 805 return E_FAIL;
785 return S_OK; 806 return S_OK;
@@ -879,7 +900,8 @@ static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *va
879static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop) 900static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)
880{ 901{
881 UString s; 902 UString s;
882 ConvertPropertyToString2(s, prop, propID); 903 const int levelTopLimit = 9; // 1ns level
904 ConvertPropertyToString2(s, prop, propID, levelTopLimit);
883 if (!s.IsEmpty()) 905 if (!s.IsEmpty())
884 { 906 {
885 AString nameA; 907 AString nameA;
@@ -1249,7 +1271,7 @@ HRESULT ListArchives(
1249 if (NConsoleClose::TestBreakSignal()) 1271 if (NConsoleClose::TestBreakSignal())
1250 return E_ABORT; 1272 return E_ABORT;
1251 1273
1252 HRESULT res = arc.GetItemPath2(i, fp.FilePath); 1274 HRESULT res = arc.GetItem_Path2(i, fp.FilePath);
1253 1275
1254 if (stdInMode && res == E_INVALIDARG) 1276 if (stdInMode && res == E_INVALIDARG)
1255 break; 1277 break;
diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp
index 0455ed5..d01aa4d 100644
--- a/CPP/7zip/UI/Console/Main.cpp
+++ b/CPP/7zip/UI/Console/Main.cpp
@@ -75,6 +75,8 @@ extern const CHasherInfo *g_Hashers[];
75const CExternalCodecs *g_ExternalCodecs_Ptr; 75const CExternalCodecs *g_ExternalCodecs_Ptr;
76#endif 76#endif
77 77
78DECLARE_AND_SET_CLIENT_VERSION_VAR
79
78#if defined(PROG_VARIANT_Z) 80#if defined(PROG_VARIANT_Z)
79 #define PROG_POSTFIX "z" 81 #define PROG_POSTFIX "z"
80 #define PROG_POSTFIX_2 " (z)" 82 #define PROG_POSTFIX_2 " (z)"
@@ -510,7 +512,7 @@ static void PrintStat()
510 , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT)) 512 , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT))
511 return; 513 return;
512 FILETIME curTimeFT; 514 FILETIME curTimeFT;
513 NTime::GetCurUtcFileTime(curTimeFT); 515 NTime::GetCurUtc_FiTime(curTimeFT);
514 516
515 #ifndef UNDER_CE 517 #ifndef UNDER_CE
516 518
@@ -845,7 +847,7 @@ int Main2(
845 #if !defined(UNDER_CE) 847 #if !defined(UNDER_CE)
846 CONSOLE_SCREEN_BUFFER_INFO consoleInfo; 848 CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
847 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo)) 849 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
848 consoleWidth = (unsigned)consoleInfo.dwSize.X; 850 consoleWidth = (unsigned)(unsigned short)consoleInfo.dwSize.X;
849 #endif 851 #endif
850 852
851 #else 853 #else
@@ -859,7 +861,7 @@ int Main2(
859 861
860 CREATE_CODECS_OBJECT 862 CREATE_CODECS_OBJECT
861 863
862 codecs->CaseSensitiveChange = options.CaseSensitiveChange; 864 codecs->CaseSensitive_Change = options.CaseSensitive_Change;
863 codecs->CaseSensitive = options.CaseSensitive; 865 codecs->CaseSensitive = options.CaseSensitive;
864 ThrowException_if_Error(codecs->Load()); 866 ThrowException_if_Error(codecs->Load());
865 Codecs_AddHashArcHandler(codecs); 867 Codecs_AddHashArcHandler(codecs);
@@ -952,9 +954,11 @@ int Main2(
952 954
953 so << endl << "Formats:" << endl; 955 so << endl << "Formats:" << endl;
954 956
955 const char * const kArcFlags = "KSNFMGOPBELHXC"; 957 const char * const kArcFlags = "KSNFMGOPBELHXCc+a+m+r+";
958 const char * const kArcTimeFlags = "wudn";
956 const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); 959 const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);
957 960 const unsigned kNumArcTimeFlags = (unsigned)strlen(kArcTimeFlags);
961
958 for (i = 0; i < codecs->Formats.Size(); i++) 962 for (i = 0; i < codecs->Formats.Size(); i++)
959 { 963 {
960 const CArcInfoEx &arc = codecs->Formats[i]; 964 const CArcInfoEx &arc = codecs->Formats[i];
@@ -967,12 +971,22 @@ int Main2(
967 971
968 so << (char)(arc.UpdateEnabled ? 'C' : ' '); 972 so << (char)(arc.UpdateEnabled ? 'C' : ' ');
969 973
970 for (unsigned b = 0; b < kNumArcFlags; b++)
971 { 974 {
972 so << (char) 975 unsigned b;
973 ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' '); 976 for (b = 0; b < kNumArcFlags; b++)
977 so << (char)((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : '.');
978 so << ' ';
974 } 979 }
975 980
981 if (arc.TimeFlags != 0)
982 {
983 unsigned b;
984 for (b = 0; b < kNumArcTimeFlags; b++)
985 so << (char)((arc.TimeFlags & ((UInt32)1 << b)) != 0 ? kArcTimeFlags[b] : '.');
986 so << arc.Get_DefaultTimePrec();
987 so << ' ';
988 }
989
976 so << ' '; 990 so << ' ';
977 PrintString(so, arc.Name, 8); 991 PrintString(so, arc.Name, 8);
978 so << ' '; 992 so << ' ';
diff --git a/CPP/7zip/UI/Console/PercentPrinter.cpp b/CPP/7zip/UI/Console/PercentPrinter.cpp
index 4341fd9..49d0393 100644
--- a/CPP/7zip/UI/Console/PercentPrinter.cpp
+++ b/CPP/7zip/UI/Console/PercentPrinter.cpp
@@ -63,7 +63,8 @@ void CPercentPrinter::GetPercents()
63 { 63 {
64 char c = '%'; 64 char c = '%';
65 UInt64 val = 0; 65 UInt64 val = 0;
66 if (Total == (UInt64)(Int64)-1) 66 if (Total == (UInt64)(Int64)-1 ||
67 (Total == 0 && Completed != 0))
67 { 68 {
68 val = Completed >> 20; 69 val = Completed >> 20;
69 c = 'M'; 70 c = 'M';
diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
index 0a25c22..1a6b820 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -11,6 +11,8 @@
11#include "../../../Windows/Synchronization.h" 11#include "../../../Windows/Synchronization.h"
12#endif 12#endif
13 13
14// #include "../Common/PropIDUtils.h"
15
14#include "ConsoleClose.h" 16#include "ConsoleClose.h"
15#include "UserInputUtils.h" 17#include "UserInputUtils.h"
16#include "UpdateCallbackConsole.h" 18#include "UpdateCallbackConsole.h"
@@ -195,6 +197,22 @@ void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, b
195 } 197 }
196} 198}
197 199
200/*
201void CCallbackConsoleBase::CommonError(const char *message)
202{
203 ClosePercents2();
204
205 if (_se)
206 {
207 if (_so)
208 _so->Flush();
209
210 *_se << endl << kError << message << endl;
211 _se->Flush();
212 }
213}
214*/
215
198 216
199HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError) 217HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError)
200{ 218{
@@ -519,6 +537,28 @@ HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, con
519 return CheckBreak2(); 537 return CheckBreak2();
520} 538}
521 539
540
541/*
542void CCallbackConsoleBase::PrintInfoLine(const UString &s)
543{
544 if (LogLevel < 1000)
545 return;
546
547 MT_LOCK
548
549 const bool show2 = (_so != NULL);
550
551 if (show2)
552 {
553 ClosePercents_for_so();
554 _so->PrintUString(s, _tempA);
555 *_so << endl;
556 if (NeedFlush)
557 _so->Flush();
558 }
559}
560*/
561
522HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) 562HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode)
523{ 563{
524 if (StdOutMode) 564 if (StdOutMode)
@@ -562,10 +602,19 @@ HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD syst
562 return ReadingFileError_Base(path, systemError); 602 return ReadingFileError_Base(path, systemError);
563} 603}
564 604
565HRESULT CUpdateCallbackConsole::SetOperationResult(Int32) 605HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */)
566{ 606{
567 MT_LOCK 607 MT_LOCK
568 _percent.Files++; 608 _percent.Files++;
609 /*
610 if (opRes != NArchive::NUpdate::NOperationResult::kOK)
611 {
612 if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged)
613 {
614 CommonError("Input file changed");
615 }
616 }
617 */
569 return S_OK; 618 return S_OK;
570} 619}
571 620
@@ -616,6 +665,8 @@ HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *
616 case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break; 665 case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break;
617 case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break; 666 case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break;
618 case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break; 667 case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break;
668 case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break;
669 // case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break;
619 default: 670 default:
620 { 671 {
621 temp[0] = 'o'; 672 temp[0] = 'o';
@@ -710,3 +761,119 @@ HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir)
710 } 761 }
711 return S_OK; 762 return S_OK;
712} 763}
764
765/*
766void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU);
767
768static void GetPropName(PROPID propID, UString &nameU)
769{
770 AString nameA;
771 GetPropName(propID, NULL, nameA, nameU);
772 // if (!nameA.IsEmpty())
773 nameU = nameA;
774}
775
776
777static void AddPropNamePrefix(UString &s, PROPID propID)
778{
779 UString name;
780 GetPropName(propID, name);
781 s += name;
782 s += " = ";
783}
784
785void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value)
786{
787 AddPropNamePrefix(s, propID);
788 {
789 UString dest;
790 const int level = 9; // we show up to ns precision level
791 ConvertPropertyToString2(dest, *value, propID, level);
792 s += dest;
793 }
794 PrintInfoLine(s);
795}
796
797static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index)
798{
799 if (indexType == NArchive::NEventIndexType::kArcProp)
800 {
801 }
802 else
803 {
804 if (indexType == NArchive::NEventIndexType::kBlockIndex)
805 {
806 s += "#";
807 }
808 else if (indexType == NArchive::NEventIndexType::kOutArcIndex)
809 {
810 }
811 else
812 {
813 s += "indexType_";
814 s.Add_UInt32(indexType);
815 s.Add_Space();
816 }
817 s.Add_UInt32(index);
818 }
819 s += ": ";
820}
821
822HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)
823{
824 UString s;
825 Add_IndexType_Index(s, indexType, index);
826 PrintPropInfo(s, propID, value);
827 return S_OK;
828}
829
830static inline char GetHex(Byte value)
831{
832 return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10)));
833}
834
835static void AddHexToString(UString &dest, const Byte *data, UInt32 size)
836{
837 for (UInt32 i = 0; i < size; i++)
838 {
839 Byte b = data[i];
840 dest += GetHex((Byte)((b >> 4) & 0xF));
841 dest += GetHex((Byte)(b & 0xF));
842 }
843}
844
845void HashHexToString(char *dest, const Byte *data, UInt32 size);
846
847HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index,
848 PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)
849{
850 UString s;
851 propType = propType;
852 Add_IndexType_Index(s, indexType, index);
853 AddPropNamePrefix(s, propID);
854 if (propID == kpidChecksum)
855 {
856 char temp[k_HashCalc_DigestSize_Max + 8];
857 HashHexToString(temp, (const Byte *)data, dataSize);
858 s += temp;
859 }
860 else
861 AddHexToString(s, (const Byte *)data, dataSize);
862 PrintInfoLine(s);
863 return S_OK;
864}
865
866HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)
867{
868 UString s;
869 Add_IndexType_Index(s, indexType, index);
870 s += "finished";
871 if (opRes != NArchive::NUpdate::NOperationResult::kOK)
872 {
873 s += ": ";
874 s.Add_UInt32(opRes);
875 }
876 PrintInfoLine(s);
877 return S_OK;
878}
879*/
diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
index 700d511..b7ffef0 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -35,7 +35,8 @@ protected:
35 CStdOutStream *_se; 35 CStdOutStream *_se;
36 36
37 void CommonError(const FString &path, DWORD systemError, bool isWarning); 37 void CommonError(const FString &path, DWORD systemError, bool isWarning);
38 38 // void CommonError(const char *message);
39
39 HRESULT ScanError_Base(const FString &path, DWORD systemError); 40 HRESULT ScanError_Base(const FString &path, DWORD systemError);
40 HRESULT OpenFileError_Base(const FString &name, DWORD systemError); 41 HRESULT OpenFileError_Base(const FString &name, DWORD systemError);
41 HRESULT ReadingFileError_Base(const FString &name, DWORD systemError); 42 HRESULT ReadingFileError_Base(const FString &name, DWORD systemError);
@@ -89,6 +90,8 @@ public:
89 90
90 HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog); 91 HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog);
91 92
93 // void PrintInfoLine(const UString &s);
94 // void PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value);
92}; 95};
93 96
94class CUpdateCallbackConsole: public IUpdateCallbackUI2, public CCallbackConsoleBase 97class CUpdateCallbackConsole: public IUpdateCallbackUI2, public CCallbackConsoleBase
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp
index 6907021..7dbb504 100644
--- a/CPP/7zip/UI/Explorer/ContextMenu.cpp
+++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp
@@ -102,6 +102,7 @@ CZipContextMenu::CZipContextMenu():
102 _isMenuForFM(false), 102 _isMenuForFM(false),
103 _dropMode(false), 103 _dropMode(false),
104 _bitmap(NULL), 104 _bitmap(NULL),
105 _writeZone((UInt32)(Int32)-1),
105 IsSeparator(false), 106 IsSeparator(false),
106 IsRoot(true), 107 IsRoot(true),
107 CurrentSubCommand(0) 108 CurrentSubCommand(0)
@@ -560,6 +561,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu,
560 ci.Load(); 561 ci.Load();
561 562
562 _elimDup = ci.ElimDup; 563 _elimDup = ci.ElimDup;
564 _writeZone = ci.WriteZone;
563 565
564 HBITMAP bitmap = NULL; 566 HBITMAP bitmap = NULL;
565 if (ci.MenuIcons.Val) 567 if (ci.MenuIcons.Val)
@@ -1167,7 +1169,8 @@ HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi)
1167 { 1169 {
1168 ExtractArchives(_fileNames, cmi.Folder, 1170 ExtractArchives(_fileNames, cmi.Folder,
1169 (cmdID == kExtract), // showDialog 1171 (cmdID == kExtract), // showDialog
1170 (cmdID == kExtractTo) && _elimDup.Val // elimDup 1172 (cmdID == kExtractTo) && _elimDup.Val, // elimDup
1173 _writeZone
1171 ); 1174 );
1172 break; 1175 break;
1173 } 1176 }
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.h b/CPP/7zip/UI/Explorer/ContextMenu.h
index 285044e..5b56d63 100644
--- a/CPP/7zip/UI/Explorer/ContextMenu.h
+++ b/CPP/7zip/UI/Explorer/ContextMenu.h
@@ -129,6 +129,7 @@ private:
129 129
130 HBITMAP _bitmap; 130 HBITMAP _bitmap;
131 CBoolPair _elimDup; 131 CBoolPair _elimDup;
132 UInt32 _writeZone;
132 133
133 bool IsSeparator; 134 bool IsSeparator;
134 bool IsRoot; 135 bool IsRoot;
diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp
index f3e04b3..72cb0ce 100644
--- a/CPP/7zip/UI/FileManager/FSFolder.cpp
+++ b/CPP/7zip/UI/FileManager/FSFolder.cpp
@@ -2,11 +2,19 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#if defined(_MSC_VER)
6#include <winternl.h>
7#else
8// mingw
9#include <ddk/winddk.h>
10#endif
11
5#include "../../../Common/ComTry.h" 12#include "../../../Common/ComTry.h"
6#include "../../../Common/Defs.h" 13#include "../../../Common/Defs.h"
7#include "../../../Common/StringConvert.h" 14#include "../../../Common/StringConvert.h"
8#include "../../../Common/UTFConvert.h" 15#include "../../../Common/UTFConvert.h"
9 16
17#include "../../../Windows/DLL.h"
10#include "../../../Windows/FileDir.h" 18#include "../../../Windows/FileDir.h"
11#include "../../../Windows/FileIO.h" 19#include "../../../Windows/FileIO.h"
12#include "../../../Windows/FileName.h" 20#include "../../../Windows/FileName.h"
@@ -56,12 +64,15 @@ static const Byte kProps[] =
56 kpidMTime, 64 kpidMTime,
57 kpidCTime, 65 kpidCTime,
58 kpidATime, 66 kpidATime,
67 #ifdef FS_SHOW_LINKS_INFO
68 kpidChangeTime,
69 #endif
59 kpidAttrib, 70 kpidAttrib,
60 kpidPackSize, 71 kpidPackSize,
61 #ifdef FS_SHOW_LINKS_INFO 72 #ifdef FS_SHOW_LINKS_INFO
62 kpidINode, 73 kpidINode,
63 kpidLinks, 74 kpidLinks,
64 #endif 75 #endif
65 kpidComment, 76 kpidComment,
66 kpidNumSubDirs, 77 kpidNumSubDirs,
67 kpidNumSubFiles, 78 kpidNumSubFiles,
@@ -199,19 +210,23 @@ HRESULT CFSFolder::LoadSubItems(int dirItem, const FString &relPrefix)
199 */ 210 */
200 } 211 }
201 212
202 #ifndef UNDER_CE 213 #ifndef UNDER_CE
203 214
204 fi.Reparse.Free(); 215 fi.Reparse.Free();
205 fi.PackSize_Defined = false; 216 fi.PackSize_Defined = false;
206 217
207 #ifdef FS_SHOW_LINKS_INFO 218 #ifdef FS_SHOW_LINKS_INFO
208 fi.FileInfo_Defined = false; 219 fi.FileInfo_Defined = false;
209 fi.FileInfo_WasRequested = false; 220 fi.FileInfo_WasRequested = false;
210 fi.FileIndex = 0; 221 fi.FileIndex = 0;
211 fi.NumLinks = 0; 222 fi.NumLinks = 0;
212 #endif 223 fi.ChangeTime_Defined = false;
224 fi.ChangeTime_WasRequested = false;
225 #endif
213 226
214 fi.PackSize = fi.Size; 227 fi.PackSize = fi.Size;
228
229 #ifdef FS_SHOW_LINKS_INFO
215 if (fi.HasReparsePoint()) 230 if (fi.HasReparsePoint())
216 { 231 {
217 fi.FileInfo_WasRequested = true; 232 fi.FileInfo_WasRequested = true;
@@ -221,8 +236,9 @@ HRESULT CFSFolder::LoadSubItems(int dirItem, const FString &relPrefix)
221 fi.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; 236 fi.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
222 fi.FileInfo_Defined = true; 237 fi.FileInfo_Defined = true;
223 } 238 }
239 #endif
224 240
225 #endif 241 #endif // UNDER_CE
226 242
227 /* unsigned fileIndex = */ Files.Add(fi); 243 /* unsigned fileIndex = */ Files.Add(fi);
228 244
@@ -396,7 +412,9 @@ STDMETHODIMP_(UInt64) CFSFolder::GetItemSize(UInt32 index)
396 412
397#endif 413#endif
398 414
415
399#ifdef FS_SHOW_LINKS_INFO 416#ifdef FS_SHOW_LINKS_INFO
417
400bool CFSFolder::ReadFileInfo(CDirItem &di) 418bool CFSFolder::ReadFileInfo(CDirItem &di)
401{ 419{
402 di.FileInfo_WasRequested = true; 420 di.FileInfo_WasRequested = true;
@@ -409,7 +427,71 @@ bool CFSFolder::ReadFileInfo(CDirItem &di)
409 di.FileInfo_Defined = true; 427 di.FileInfo_Defined = true;
410 return true; 428 return true;
411} 429}
412#endif 430
431
432typedef struct
433{
434 LARGE_INTEGER CreationTime;
435 LARGE_INTEGER LastAccessTime;
436 LARGE_INTEGER LastWriteTime;
437 LARGE_INTEGER ChangeTime;
438 ULONG FileAttributes;
439 UInt32 Reserved; // it's expected for alignment
440}
441MY__FILE_BASIC_INFORMATION;
442
443
444typedef enum
445{
446 MY__FileDirectoryInformation = 1,
447 MY__FileFullDirectoryInformation,
448 MY__FileBothDirectoryInformation,
449 MY__FileBasicInformation
450}
451MY__FILE_INFORMATION_CLASS;
452
453
454typedef NTSTATUS (WINAPI * Func_NtQueryInformationFile)(
455 HANDLE handle, IO_STATUS_BLOCK *io,
456 void *ptr, LONG len, MY__FILE_INFORMATION_CLASS cls);
457
458#define MY__STATUS_SUCCESS 0
459
460static Func_NtQueryInformationFile f_NtQueryInformationFile;
461static bool g_NtQueryInformationFile_WasRequested = false;
462
463void CFSFolder::ReadChangeTime(CDirItem &di)
464{
465 di.ChangeTime_WasRequested = true;
466
467 if (!g_NtQueryInformationFile_WasRequested)
468 {
469 g_NtQueryInformationFile_WasRequested = true;
470 f_NtQueryInformationFile = (Func_NtQueryInformationFile)
471 My_GetProcAddress(::GetModuleHandleW(L"ntdll.dll"),
472 "NtQueryInformationFile");
473 }
474 if (!f_NtQueryInformationFile)
475 return;
476
477 NIO::CInFile file;
478 if (!file.Open_for_ReadAttributes(_path + GetRelPath(di)))
479 return;
480 MY__FILE_BASIC_INFORMATION fbi;
481 IO_STATUS_BLOCK IoStatusBlock;
482 const NTSTATUS status = f_NtQueryInformationFile(file.GetHandle(), &IoStatusBlock,
483 &fbi, sizeof(fbi), MY__FileBasicInformation);
484 if (status != MY__STATUS_SUCCESS)
485 return;
486 if (IoStatusBlock.Information != sizeof(fbi))
487 return;
488 di.ChangeTime.dwLowDateTime = fbi.ChangeTime.u.LowPart;
489 di.ChangeTime.dwHighDateTime = fbi.ChangeTime.u.HighPart;
490 di.ChangeTime_Defined = true;
491}
492
493#endif // FS_SHOW_LINKS_INFO
494
413 495
414STDMETHODIMP CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 496STDMETHODIMP CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
415{ 497{
@@ -492,7 +574,14 @@ STDMETHODIMP CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
492 prop = fi.FileIndex; 574 prop = fi.FileIndex;
493 #endif 575 #endif
494 break; 576 break;
495 577
578 case kpidChangeTime:
579 if (!fi.ChangeTime_WasRequested)
580 ReadChangeTime(fi);
581 if (fi.ChangeTime_Defined)
582 prop = fi.ChangeTime;
583 break;
584
496 #endif 585 #endif
497 586
498 case kpidAttrib: prop = (UInt32)fi.Attrib; break; 587 case kpidAttrib: prop = (UInt32)fi.Attrib; break;
diff --git a/CPP/7zip/UI/FileManager/FSFolder.h b/CPP/7zip/UI/FileManager/FSFolder.h
index fac1ef9..4f8c344 100644
--- a/CPP/7zip/UI/FileManager/FSFolder.h
+++ b/CPP/7zip/UI/FileManager/FSFolder.h
@@ -18,6 +18,7 @@ namespace NFsFolder {
18class CFSFolder; 18class CFSFolder;
19 19
20#define FS_SHOW_LINKS_INFO 20#define FS_SHOW_LINKS_INFO
21// #define FS_SHOW_CHANGE_TIME
21 22
22struct CDirItem: public NWindows::NFile::NFind::CFileInfo 23struct CDirItem: public NWindows::NFile::NFind::CFileInfo
23{ 24{
@@ -26,10 +27,13 @@ struct CDirItem: public NWindows::NFile::NFind::CFileInfo
26 #endif 27 #endif
27 28
28 #ifdef FS_SHOW_LINKS_INFO 29 #ifdef FS_SHOW_LINKS_INFO
30 FILETIME ChangeTime;
29 UInt64 FileIndex; 31 UInt64 FileIndex;
30 UInt32 NumLinks; 32 UInt32 NumLinks;
31 bool FileInfo_Defined; 33 bool FileInfo_Defined;
32 bool FileInfo_WasRequested; 34 bool FileInfo_WasRequested;
35 bool ChangeTime_Defined;
36 bool ChangeTime_WasRequested;
33 #endif 37 #endif
34 38
35 #ifndef UNDER_CE 39 #ifndef UNDER_CE
@@ -158,6 +162,7 @@ private:
158 162
159 #ifdef FS_SHOW_LINKS_INFO 163 #ifdef FS_SHOW_LINKS_INFO
160 bool ReadFileInfo(CDirItem &di); 164 bool ReadFileInfo(CDirItem &di);
165 void ReadChangeTime(CDirItem &di);
161 #endif 166 #endif
162 167
163public: 168public:
diff --git a/CPP/7zip/UI/FileManager/HelpUtils.cpp b/CPP/7zip/UI/FileManager/HelpUtils.cpp
index 2db9501..5cb78fc 100644
--- a/CPP/7zip/UI/FileManager/HelpUtils.cpp
+++ b/CPP/7zip/UI/FileManager/HelpUtils.cpp
@@ -12,7 +12,20 @@ void ShowHelpWindow(LPCSTR)
12 12
13#else 13#else
14 14
15// #define USE_EXTERNAL_HELP
16
17#if defined(_MSC_VER)
18#endif
19
20#ifdef USE_EXTERNAL_HELP
21
22#include "../../../Windows/ProcessUtils.h"
23#include "../../../Windows/FileDir.h"
24#include "../../../Windows/FileName.h"
25
26#else
15#include <HtmlHelp.h> 27#include <HtmlHelp.h>
28#endif
16 29
17#include "../../../Common/StringConvert.h" 30#include "../../../Common/StringConvert.h"
18 31
@@ -25,8 +38,37 @@ void ShowHelpWindow(LPCSTR topicFile)
25 FString path = NWindows::NDLL::GetModuleDirPrefix(); 38 FString path = NWindows::NDLL::GetModuleDirPrefix();
26 path += kHelpFileName; 39 path += kHelpFileName;
27 path += topicFile; 40 path += topicFile;
41 #ifdef USE_EXTERNAL_HELP
42 FString prog;
43
44 #ifdef UNDER_CE
45 prog = "\\Windows\\";
46 #else
47 if (!NWindows::NFile::NDir::GetWindowsDir(prog))
48 return;
49 NWindows::NFile::NName::NormalizeDirPathPrefix(prog);
50 #endif
51 prog += "hh.exe";
52
53 UString params;
54 params += '"';
55 params += fs2us(path);
56 params += '"';
57
58 NWindows::CProcess process;
59 const WRes wres = process.Create(fs2us(prog), params, NULL); // curDir);
60 if (wres != 0)
61 {
62 /*
63 HRESULT hres = HRESULT_FROM_WIN32(wres);
64 ErrorMessageHRESULT(hres, imageName);
65 return hres;
66 */
67 }
68 #else
28 // HWND hwnd = NULL; 69 // HWND hwnd = NULL;
29 HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0); 70 HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0);
71 #endif
30} 72}
31 73
32#endif 74#endif
diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp
index 05f24d7..32dabae 100644
--- a/CPP/7zip/UI/FileManager/MenuPage.cpp
+++ b/CPP/7zip/UI/FileManager/MenuPage.cpp
@@ -32,6 +32,7 @@ static const UInt32 kLangIDs[] =
32 IDX_SYSTEM_CASCADED_MENU, 32 IDX_SYSTEM_CASCADED_MENU,
33 IDX_SYSTEM_ICON_IN_MENU, 33 IDX_SYSTEM_ICON_IN_MENU,
34 IDX_EXTRACT_ELIM_DUP, 34 IDX_EXTRACT_ELIM_DUP,
35 IDT_SYSTEM_ZONE,
35 IDT_SYSTEM_CONTEXT_MENU_ITEMS 36 IDT_SYSTEM_CONTEXT_MENU_ITEMS
36}; 37};
37 38
@@ -80,6 +81,16 @@ extern bool g_Is_Wow64;
80 #define KEY_WOW64_32KEY (0x0200) 81 #define KEY_WOW64_32KEY (0x0200)
81#endif 82#endif
82 83
84
85static void LoadLang_Spec(UString &s, UInt32 id, const char *eng)
86{
87 LangString(id, s);
88 if (s.IsEmpty())
89 s = eng;
90 s.RemoveChar(L'&');
91}
92
93
83bool CMenuPage::OnInit() 94bool CMenuPage::OnInit()
84{ 95{
85 _initMode = true; 96 _initMode = true;
@@ -176,6 +187,44 @@ bool CMenuPage::OnInit()
176 CheckButton(IDX_EXTRACT_ELIM_DUP, ci.ElimDup.Val); 187 CheckButton(IDX_EXTRACT_ELIM_DUP, ci.ElimDup.Val);
177 188
178 _listView.Attach(GetItem(IDL_SYSTEM_OPTIONS)); 189 _listView.Attach(GetItem(IDL_SYSTEM_OPTIONS));
190 _zoneCombo.Attach(GetItem(IDC_SYSTEM_ZONE));
191
192 {
193 unsigned wz = ci.WriteZone;
194 if (wz == (UInt32)(Int32)-1)
195 wz = 0;
196 for (unsigned i = 0; i <= 3; i++)
197 {
198 unsigned val = i;
199 UString s;
200 if (i == 3)
201 {
202 if (wz < 3)
203 break;
204 val = wz;
205 }
206 else
207 {
208 #define MY_IDYES 406
209 #define MY_IDNO 407
210 if (i == 0)
211 LoadLang_Spec(s, MY_IDNO, "No");
212 else if (i == 1)
213 LoadLang_Spec(s, MY_IDYES, "Yes");
214 else
215 LangString(IDT_ZONE_FOR_OFFICE, s);
216 }
217 if (s.IsEmpty())
218 s.Add_UInt32(val);
219 if (i == 0)
220 s.Insert(0, L"* ");
221 const int index = (int)_zoneCombo.AddString(s);
222 _zoneCombo.SetItemData(index, val);
223 if (val == wz)
224 _zoneCombo.SetCurSel(index);
225 }
226 }
227
179 228
180 const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT; 229 const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT;
181 _listView.SetExtendedListViewStyle(newFlags, newFlags); 230 _listView.SetExtendedListViewStyle(newFlags, newFlags);
@@ -266,7 +315,11 @@ LONG CMenuPage::OnApply()
266 315
267 #endif 316 #endif
268 317
269 if (_cascaded_Changed || _menuIcons_Changed || _elimDup_Changed || _flags_Changed) 318 if (_cascaded_Changed
319 || _menuIcons_Changed
320 || _elimDup_Changed
321 || _writeZone_Changed
322 || _flags_Changed)
270 { 323 {
271 CContextMenuInfo ci; 324 CContextMenuInfo ci;
272 ci.Cascaded.Val = IsButtonCheckedBool(IDX_SYSTEM_CASCADED_MENU); 325 ci.Cascaded.Val = IsButtonCheckedBool(IDX_SYSTEM_CASCADED_MENU);
@@ -278,6 +331,13 @@ LONG CMenuPage::OnApply()
278 ci.ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP); 331 ci.ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP);
279 ci.ElimDup.Def = _elimDup_Changed; 332 ci.ElimDup.Def = _elimDup_Changed;
280 333
334 {
335 int zoneIndex = (int)_zoneCombo.GetItemData_of_CurSel();
336 if (zoneIndex <= 0)
337 zoneIndex = -1;
338 ci.WriteZone = (UInt32)(Int32)zoneIndex;
339 }
340
281 ci.Flags = 0; 341 ci.Flags = 0;
282 342
283 for (unsigned i = 0; i < ARRAY_SIZE(kMenuItems); i++) 343 for (unsigned i = 0; i < ARRAY_SIZE(kMenuItems); i++)
@@ -321,6 +381,7 @@ bool CMenuPage::OnButtonClicked(int buttonID, HWND buttonHWND)
321 case IDX_SYSTEM_CASCADED_MENU: _cascaded_Changed = true; break; 381 case IDX_SYSTEM_CASCADED_MENU: _cascaded_Changed = true; break;
322 case IDX_SYSTEM_ICON_IN_MENU: _menuIcons_Changed = true; break; 382 case IDX_SYSTEM_ICON_IN_MENU: _menuIcons_Changed = true; break;
323 case IDX_EXTRACT_ELIM_DUP: _elimDup_Changed = true; break; 383 case IDX_EXTRACT_ELIM_DUP: _elimDup_Changed = true; break;
384 // case IDX_EXTRACT_WRITE_ZONE: _writeZone_Changed = true; break;
324 385
325 default: 386 default:
326 return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); 387 return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
@@ -330,6 +391,19 @@ bool CMenuPage::OnButtonClicked(int buttonID, HWND buttonHWND)
330 return true; 391 return true;
331} 392}
332 393
394
395bool CMenuPage::OnCommand(int code, int itemID, LPARAM param)
396{
397 if (code == CBN_SELCHANGE && itemID == IDC_SYSTEM_ZONE)
398 {
399 _writeZone_Changed = true;
400 Changed();
401 return true;
402 }
403 return CPropertyPage::OnCommand(code, itemID, param);
404}
405
406
333bool CMenuPage::OnNotify(UINT controlID, LPNMHDR lParam) 407bool CMenuPage::OnNotify(UINT controlID, LPNMHDR lParam)
334{ 408{
335 if (lParam->hwndFrom == HWND(_listView)) 409 if (lParam->hwndFrom == HWND(_listView))
diff --git a/CPP/7zip/UI/FileManager/MenuPage.h b/CPP/7zip/UI/FileManager/MenuPage.h
index 3807d9d..02aee6d 100644
--- a/CPP/7zip/UI/FileManager/MenuPage.h
+++ b/CPP/7zip/UI/FileManager/MenuPage.h
@@ -4,6 +4,7 @@
4#define __MENU_PAGE_H 4#define __MENU_PAGE_H
5 5
6#include "../../../Windows/Control/PropertyPage.h" 6#include "../../../Windows/Control/PropertyPage.h"
7#include "../../../Windows/Control/ComboBox.h"
7#include "../../../Windows/Control/ListView.h" 8#include "../../../Windows/Control/ListView.h"
8 9
9struct CShellDll 10struct CShellDll
@@ -24,6 +25,7 @@ class CMenuPage: public NWindows::NControl::CPropertyPage
24 bool _cascaded_Changed; 25 bool _cascaded_Changed;
25 bool _menuIcons_Changed; 26 bool _menuIcons_Changed;
26 bool _elimDup_Changed; 27 bool _elimDup_Changed;
28 bool _writeZone_Changed;
27 bool _flags_Changed; 29 bool _flags_Changed;
28 30
29 void Clear_MenuChanged() 31 void Clear_MenuChanged()
@@ -31,6 +33,7 @@ class CMenuPage: public NWindows::NControl::CPropertyPage
31 _cascaded_Changed = false; 33 _cascaded_Changed = false;
32 _menuIcons_Changed = false; 34 _menuIcons_Changed = false;
33 _elimDup_Changed = false; 35 _elimDup_Changed = false;
36 _writeZone_Changed = false;
34 _flags_Changed = false; 37 _flags_Changed = false;
35 } 38 }
36 39
@@ -39,6 +42,7 @@ class CMenuPage: public NWindows::NControl::CPropertyPage
39 #endif 42 #endif
40 43
41 NWindows::NControl::CListView _listView; 44 NWindows::NControl::CListView _listView;
45 NWindows::NControl::CComboBox _zoneCombo;
42 46
43 virtual bool OnInit(); 47 virtual bool OnInit();
44 virtual void OnNotifyHelp(); 48 virtual void OnNotifyHelp();
@@ -46,6 +50,7 @@ class CMenuPage: public NWindows::NControl::CPropertyPage
46 virtual bool OnItemChanged(const NMLISTVIEW *info); 50 virtual bool OnItemChanged(const NMLISTVIEW *info);
47 virtual LONG OnApply(); 51 virtual LONG OnApply();
48 virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); 52 virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
53 virtual bool OnCommand(int code, int itemID, LPARAM param);
49public: 54public:
50}; 55};
51 56
diff --git a/CPP/7zip/UI/FileManager/MenuPage2.rc b/CPP/7zip/UI/FileManager/MenuPage2.rc
index af86226..4d1ba21 100644
--- a/CPP/7zip/UI/FileManager/MenuPage2.rc
+++ b/CPP/7zip/UI/FileManager/MenuPage2.rc
@@ -1,6 +1,8 @@
1#include "../GUI/ExtractDialogRes.h" 1#include "../GUI/ExtractDialogRes.h"
2 2
3#define y 82 3#define y 96
4
5#define zoneX 90
4 6
5CAPTION "7-Zip" 7CAPTION "7-Zip"
6BEGIN 8BEGIN
@@ -10,8 +12,17 @@ BEGIN
10 CONTROL "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, MY_CHECKBOX, m, m + 42, xc, 10 12 CONTROL "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, MY_CHECKBOX, m, m + 42, xc, 10
11 CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, m, m + 56, xc, 10 13 CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, m, m + 56, xc, 10
12 14
13 LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 70, xc, 8 15 LTEXT "Propagate Zone.Id stream:", IDT_SYSTEM_ZONE, m, m + 70, xc - zoneX, 8
16 COMBOBOX IDC_SYSTEM_ZONE, m + xc - zoneX, m + 70 - 2, zoneX, 50, MY_COMBO
17
18 LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 84, xc, 8
14 CONTROL "List", IDL_SYSTEM_OPTIONS, "SysListView32", 19 CONTROL "List", IDL_SYSTEM_OPTIONS, "SysListView32",
15 LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP, 20 LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,
16 m, m + y, xc, yc - y 21 m, m + y, xc, yc - y
17END 22END
23
24
25STRINGTABLE
26BEGIN
27 IDT_ZONE_FOR_OFFICE "For Office files"
28END
diff --git a/CPP/7zip/UI/FileManager/MenuPageRes.h b/CPP/7zip/UI/FileManager/MenuPageRes.h
index ae0bf66..e2cf798 100644
--- a/CPP/7zip/UI/FileManager/MenuPageRes.h
+++ b/CPP/7zip/UI/FileManager/MenuPageRes.h
@@ -8,4 +8,8 @@
8 8
9#define IDX_SYSTEM_INTEGRATE_TO_MENU_2 2310 9#define IDX_SYSTEM_INTEGRATE_TO_MENU_2 2310
10 10
11#define IDT_SYSTEM_ZONE 3440
12#define IDT_ZONE_FOR_OFFICE 3441
13
11#define IDL_SYSTEM_OPTIONS 100 14#define IDL_SYSTEM_OPTIONS 100
15#define IDC_SYSTEM_ZONE 101
diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
index d87dfe3..3973bb2 100644
--- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
+++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
@@ -380,7 +380,8 @@ void OnMenuActivating(HWND /* hWnd */, HMENU hMenu, int position)
380 kTimestampPrintLevel_MIN, 380 kTimestampPrintLevel_MIN,
381 kTimestampPrintLevel_SEC, 381 kTimestampPrintLevel_SEC,
382 // 1,2,3,4,5,6, 382 // 1,2,3,4,5,6,
383 kTimestampPrintLevel_NTFS 383 kTimestampPrintLevel_NTFS,
384 kTimestampPrintLevel_NS
384 }; 385 };
385 386
386 unsigned last = kMenuID_Time; 387 unsigned last = kMenuID_Time;
diff --git a/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp
index e8c0b94..f7cdb5b 100644
--- a/CPP/7zip/UI/FileManager/Panel.cpp
+++ b/CPP/7zip/UI/FileManager/Panel.cpp
@@ -20,6 +20,7 @@
20 20
21#include "../Common/ArchiveName.h" 21#include "../Common/ArchiveName.h"
22#include "../Common/CompressCall.h" 22#include "../Common/CompressCall.h"
23#include "../Common/ZipRegistry.h"
23 24
24#include "../Agent/IFolderArchive.h" 25#include "../Agent/IFolderArchive.h"
25 26
@@ -971,9 +972,13 @@ void CPanel::ExtractArchives()
971 outFolder += '*'; 972 outFolder += '*';
972 outFolder.Add_PathSepar(); 973 outFolder.Add_PathSepar();
973 974
975 CContextMenuInfo ci;
976 ci.Load();
977
974 ::ExtractArchives(paths, outFolder 978 ::ExtractArchives(paths, outFolder
975 , true // showDialog 979 , true // showDialog
976 , false // elimDup 980 , false // elimDup
981 , ci.WriteZone
977 ); 982 );
978} 983}
979 984
diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h
index d1e4d24..4755678 100644
--- a/CPP/7zip/UI/FileManager/Panel.h
+++ b/CPP/7zip/UI/FileManager/Panel.h
@@ -244,6 +244,9 @@ struct CCopyToOptions
244 bool replaceAltStreamChars; 244 bool replaceAltStreamChars;
245 bool showErrorMessages; 245 bool showErrorMessages;
246 246
247 bool NeedRegistryZone;
248 NExtract::NZoneIdMode::EEnum ZoneIdMode;
249
247 UString folder; 250 UString folder;
248 251
249 UStringVector hashMethods; 252 UStringVector hashMethods;
@@ -258,6 +261,8 @@ struct CCopyToOptions
258 includeAltStreams(true), 261 includeAltStreams(true),
259 replaceAltStreamChars(false), 262 replaceAltStreamChars(false),
260 showErrorMessages(false), 263 showErrorMessages(false),
264 NeedRegistryZone(true),
265 ZoneIdMode(NExtract::NZoneIdMode::kNone),
261 VirtFileSystemSpec(NULL), 266 VirtFileSystemSpec(NULL),
262 VirtFileSystem(NULL) 267 VirtFileSystem(NULL)
263 {} 268 {}
diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp
index 7e1937c..2ea3e3b 100644
--- a/CPP/7zip/UI/FileManager/PanelCopy.cpp
+++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp
@@ -4,6 +4,8 @@
4 4
5#include "../../../Common/MyException.h" 5#include "../../../Common/MyException.h"
6 6
7#include "../Common/ZipRegistry.h"
8
7#include "../GUI/HashGUI.h" 9#include "../GUI/HashGUI.h"
8 10
9#include "ExtractCallback.h" 11#include "ExtractCallback.h"
@@ -70,6 +72,15 @@ HRESULT CPanelCopyThread::ProcessVirt()
70 72
71 HRESULT result2; 73 HRESULT result2;
72 74
75 {
76 CMyComPtr<IFolderSetZoneIdMode> setZoneMode;
77 FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode);
78 if (setZoneMode)
79 {
80 RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode));
81 }
82 }
83
73 if (options->testMode) 84 if (options->testMode)
74 { 85 {
75 CMyComPtr<IArchiveFolder> archiveFolder; 86 CMyComPtr<IArchiveFolder> archiveFolder;
@@ -126,6 +137,14 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector<UInt32> &ind
126 UStringVector *messages, 137 UStringVector *messages,
127 bool &usePassword, UString &password) 138 bool &usePassword, UString &password)
128{ 139{
140 if (options.NeedRegistryZone && !options.testMode)
141 {
142 CContextMenuInfo ci;
143 ci.Load();
144 if (ci.WriteZone != (UInt32)(Int32)-1)
145 options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone;
146 }
147
129 if (IsHashFolder()) 148 if (IsHashFolder())
130 { 149 {
131 if (!options.testMode) 150 if (!options.testMode)
@@ -221,7 +240,7 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector<UInt32> &ind
221 title = LangString(titleID); 240 title = LangString(titleID);
222 } 241 }
223 242
224 UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); 243 const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
225 244
226 extracter.MainWindow = GetParent(); 245 extracter.MainWindow = GetParent();
227 extracter.MainTitle = progressWindowTitle; 246 extracter.MainTitle = progressWindowTitle;
diff --git a/CPP/7zip/UI/FileManager/PanelCrc.cpp b/CPP/7zip/UI/FileManager/PanelCrc.cpp
index 1d483ca..32948d8 100644
--- a/CPP/7zip/UI/FileManager/PanelCrc.cpp
+++ b/CPP/7zip/UI/FileManager/PanelCrc.cpp
@@ -351,6 +351,7 @@ HRESULT CApp::CalculateCrc2(const UString &methodName)
351 options.streamMode = true; 351 options.streamMode = true;
352 options.showErrorMessages = true; 352 options.showErrorMessages = true;
353 options.hashMethods.Add(methodName); 353 options.hashMethods.Add(methodName);
354 options.NeedRegistryZone = false;
354 355
355 UStringVector messages; 356 UStringVector messages;
356 return srcPanel.CopyTo(options, indices, &messages); 357 return srcPanel.CopyTo(options, indices, &messages);
diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
index ba54491..17301b5 100644
--- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
@@ -1403,7 +1403,7 @@ static THREAD_FUNC_DECL MyThreadFunction(void *param)
1403} 1403}
1404 1404
1405 1405
1406 1406/*
1407#if defined(_WIN32) && !defined(UNDER_CE) 1407#if defined(_WIN32) && !defined(UNDER_CE)
1408static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); 1408static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier");
1409#endif 1409#endif
@@ -1441,6 +1441,7 @@ static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
1441} 1441}
1442 1442
1443#endif 1443#endif
1444*/
1444 1445
1445/* 1446/*
1446class CBufSeqOutStream_WithFile: 1447class CBufSeqOutStream_WithFile:
@@ -1654,6 +1655,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
1654 password = fl.Password; 1655 password = fl.Password;
1655 } 1656 }
1656 1657
1658 /*
1657 #if defined(_WIN32) && !defined(UNDER_CE) 1659 #if defined(_WIN32) && !defined(UNDER_CE)
1658 CByteBuffer zoneBuf; 1660 CByteBuffer zoneBuf;
1659 #ifndef _UNICODE 1661 #ifndef _UNICODE
@@ -1666,16 +1668,25 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
1666 ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf); 1668 ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf);
1667 } 1669 }
1668 #endif 1670 #endif
1671 */
1669 1672
1670 1673
1671 CVirtFileSystem *virtFileSystemSpec = NULL; 1674 CVirtFileSystem *virtFileSystemSpec = NULL;
1672 CMyComPtr<ISequentialOutStream> virtFileSystem; 1675 CMyComPtr<ISequentialOutStream> virtFileSystem;
1673 1676
1674 bool isAltStream = IsItem_AltStream(index); 1677 const bool isAltStream = IsItem_AltStream(index);
1675 1678
1676 CCopyToOptions options; 1679 CCopyToOptions options;
1677 options.includeAltStreams = true; 1680 options.includeAltStreams = true;
1678 options.replaceAltStreamChars = isAltStream; 1681 options.replaceAltStreamChars = isAltStream;
1682 {
1683 // CContextMenuInfo ci;
1684 // ci.Load();
1685 // if (ci.WriteZone != (UInt32)(Int32)-1)
1686 // we use kAll when we unpack just one file.
1687 options.ZoneIdMode = NExtract::NZoneIdMode::kAll;
1688 options.NeedRegistryZone = false;
1689 }
1679 1690
1680 if (tryAsArchive) 1691 if (tryAsArchive)
1681 { 1692 {
@@ -1706,7 +1717,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
1706 options.folder = fs2us(tempDirNorm); 1717 options.folder = fs2us(tempDirNorm);
1707 options.showErrorMessages = true; 1718 options.showErrorMessages = true;
1708 1719
1709 HRESULT result = CopyTo(options, indices, &messages, usePassword, password); 1720 const HRESULT result = CopyTo(options, indices, &messages, usePassword, password);
1710 1721
1711 if (_parentFolders.Size() > 0) 1722 if (_parentFolders.Size() > 0)
1712 { 1723 {
@@ -1759,6 +1770,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
1759 } 1770 }
1760 1771
1761 1772
1773 /*
1762 #if defined(_WIN32) && !defined(UNDER_CE) 1774 #if defined(_WIN32) && !defined(UNDER_CE)
1763 if (zoneBuf.Size() != 0) 1775 if (zoneBuf.Size() != 0)
1764 { 1776 {
@@ -1768,6 +1780,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo
1768 } 1780 }
1769 } 1781 }
1770 #endif 1782 #endif
1783 */
1771 1784
1772 1785
1773 if (tryAsArchive) 1786 if (tryAsArchive)
diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp
index 33e4458..3cccf27 100644
--- a/CPP/7zip/UI/FileManager/PanelItems.cpp
+++ b/CPP/7zip/UI/FileManager/PanelItems.cpp
@@ -29,6 +29,7 @@ static bool GetColumnVisible(PROPID propID, bool isFsFolder)
29 switch (propID) 29 switch (propID)
30 { 30 {
31 case kpidATime: 31 case kpidATime:
32 case kpidChangeTime:
32 case kpidAttrib: 33 case kpidAttrib:
33 case kpidPackSize: 34 case kpidPackSize:
34 case kpidINode: 35 case kpidINode:
@@ -56,6 +57,7 @@ static int GetColumnAlign(PROPID propID, VARTYPE varType)
56 case kpidCTime: 57 case kpidCTime:
57 case kpidATime: 58 case kpidATime:
58 case kpidMTime: 59 case kpidMTime:
60 case kpidChangeTime:
59 return LVCFMT_LEFT; 61 return LVCFMT_LEFT;
60 } 62 }
61 63
@@ -201,7 +203,7 @@ HRESULT CPanel::InitColumns()
201 for (i = 0; i < _listViewInfo.Columns.Size(); i++) 203 for (i = 0; i < _listViewInfo.Columns.Size(); i++)
202 { 204 {
203 const CColumnInfo &columnInfo = _listViewInfo.Columns[i]; 205 const CColumnInfo &columnInfo = _listViewInfo.Columns[i];
204 int index = _columns.FindItem_for_PropID(columnInfo.PropID); 206 const int index = _columns.FindItem_for_PropID(columnInfo.PropID);
205 if (index >= 0) 207 if (index >= 0)
206 { 208 {
207 CPropColumn &item = _columns[index]; 209 CPropColumn &item = _columns[index];
@@ -650,7 +652,7 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
650 relPath += name; 652 relPath += name;
651 if (relPath == state.FocusedName) 653 if (relPath == state.FocusedName)
652 cursorIndex = listViewItemCount; 654 cursorIndex = listViewItemCount;
653 if (state.SelectedNames.FindInSorted(relPath) >= 0) 655 if (state.SelectedNames.FindInSorted(relPath) != -1)
654 selected = true; 656 selected = true;
655 } 657 }
656 658
diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp
index 1a09a8f..9e86951 100644
--- a/CPP/7zip/UI/FileManager/PanelMenu.cpp
+++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp
@@ -111,7 +111,7 @@ static void AddPropertyString(PROPID propID, const wchar_t *nameBSTR,
111 val = ConvertSizeToString(v); 111 val = ConvertSizeToString(v);
112 } 112 }
113 else 113 else
114 ConvertPropertyToString2(val, prop, propID); 114 ConvertPropertyToString2(val, prop, propID, 9); // we send 9 - is ns precision
115 } 115 }
116 116
117 if (!val.IsEmpty()) 117 if (!val.IsEmpty())
diff --git a/CPP/7zip/UI/FileManager/PropertyName.rc b/CPP/7zip/UI/FileManager/PropertyName.rc
index 5de5aee..e16c526 100644
--- a/CPP/7zip/UI/FileManager/PropertyName.rc
+++ b/CPP/7zip/UI/FileManager/PropertyName.rc
@@ -97,4 +97,11 @@ BEGIN
97 IDS_PROP_READ_ONLY "Read-only" 97 IDS_PROP_READ_ONLY "Read-only"
98 IDS_PROP_OUT_NAME "Out Name" 98 IDS_PROP_OUT_NAME "Out Name"
99 IDS_PROP_COPY_LINK "Copy Link" 99 IDS_PROP_COPY_LINK "Copy Link"
100 IDS_PROP_ARC_FILE_NAME "ArcFileName"
101 IDS_PROP_IS_HASH "IsHash"
102 IDS_PROP_CHANGE_TIME "Metadata Changed"
103 IDS_PROP_USER_ID "User ID"
104 IDS_PROP_GROUP_ID "Group ID"
105 IDS_PROP_DEVICE_MAJOR "Device Major"
106 IDS_PROP_DEVICE_MINOR "Device Minor"
100END 107END
diff --git a/CPP/7zip/UI/FileManager/PropertyNameRes.h b/CPP/7zip/UI/FileManager/PropertyNameRes.h
index 67f3390..e3d08db 100644
--- a/CPP/7zip/UI/FileManager/PropertyNameRes.h
+++ b/CPP/7zip/UI/FileManager/PropertyNameRes.h
@@ -93,3 +93,10 @@
93#define IDS_PROP_READ_ONLY 1093 93#define IDS_PROP_READ_ONLY 1093
94#define IDS_PROP_OUT_NAME 1094 94#define IDS_PROP_OUT_NAME 1094
95#define IDS_PROP_COPY_LINK 1095 95#define IDS_PROP_COPY_LINK 1095
96#define IDS_PROP_ARC_FILE_NAME 1096
97#define IDS_PROP_IS_HASH 1097
98#define IDS_PROP_CHANGE_TIME 1098
99#define IDS_PROP_USER_ID 1099
100#define IDS_PROP_GROUP_ID 1100
101#define IDS_PROP_DEVICE_MAJOR 1101
102#define IDS_PROP_DEVICE_MINOR 1102
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp
index 16a3585..25b9219 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.cpp
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -16,6 +16,7 @@
16#include "../FileManager/BrowseDialog.h" 16#include "../FileManager/BrowseDialog.h"
17#include "../FileManager/FormatUtils.h" 17#include "../FileManager/FormatUtils.h"
18#include "../FileManager/HelpUtils.h" 18#include "../FileManager/HelpUtils.h"
19#include "../FileManager/PropertyName.h"
19#include "../FileManager/SplitUtils.h" 20#include "../FileManager/SplitUtils.h"
20 21
21#include "../Explorer/MyMessages.h" 22#include "../Explorer/MyMessages.h"
@@ -36,6 +37,9 @@ extern bool g_IsNT;
36#include "ExtractRes.h" 37#include "ExtractRes.h"
37 38
38#ifdef LANG 39#ifdef LANG
40
41// #define IDS_OPTIONS 2100
42
39static const UInt32 kLangIDs[] = 43static const UInt32 kLangIDs[] =
40{ 44{
41 IDT_COMPRESS_ARCHIVE, 45 IDT_COMPRESS_ARCHIVE,
@@ -49,6 +53,8 @@ static const UInt32 kLangIDs[] =
49 IDT_COMPRESS_THREADS, 53 IDT_COMPRESS_THREADS,
50 IDT_COMPRESS_PARAMETERS, 54 IDT_COMPRESS_PARAMETERS,
51 55
56 IDB_COMPRESS_OPTIONS, // IDS_OPTIONS
57
52 IDG_COMPRESS_OPTIONS, 58 IDG_COMPRESS_OPTIONS,
53 IDX_COMPRESS_SFX, 59 IDX_COMPRESS_SFX,
54 IDX_COMPRESS_SHARED, 60 IDX_COMPRESS_SHARED,
@@ -57,11 +63,6 @@ static const UInt32 kLangIDs[] =
57 IDT_COMPRESS_MEMORY, 63 IDT_COMPRESS_MEMORY,
58 IDT_COMPRESS_MEMORY_DE, 64 IDT_COMPRESS_MEMORY_DE,
59 65
60 IDX_COMPRESS_NT_SYM_LINKS,
61 IDX_COMPRESS_NT_HARD_LINKS,
62 IDX_COMPRESS_NT_ALT_STREAMS,
63 IDX_COMPRESS_NT_SECUR,
64
65 IDG_COMPRESS_ENCRYPTION, 66 IDG_COMPRESS_ENCRYPTION,
66 IDT_COMPRESS_ENCRYPTION_METHOD, 67 IDT_COMPRESS_ENCRYPTION_METHOD,
67 IDX_COMPRESS_ENCRYPT_FILE_NAMES, 68 IDX_COMPRESS_ENCRYPT_FILE_NAMES,
@@ -71,7 +72,7 @@ static const UInt32 kLangIDs[] =
71 IDX_PASSWORD_SHOW, 72 IDX_PASSWORD_SHOW,
72 73
73 IDT_SPLIT_TO_VOLUMES, 74 IDT_SPLIT_TO_VOLUMES,
74 IDT_COMPRESS_PATH_MODE 75 IDT_COMPRESS_PATH_MODE,
75}; 76};
76#endif 77#endif
77 78
@@ -89,8 +90,6 @@ static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28;
89 90
90static LPCSTR const kExeExt = ".exe"; 91static LPCSTR const kExeExt = ".exe";
91 92
92#define k7zFormat "7z"
93
94static const UInt32 g_Levels[] = 93static const UInt32 g_Levels[] =
95{ 94{
96 IDS_METHOD_STORE, 95 IDS_METHOD_STORE,
@@ -119,6 +118,8 @@ enum EMethodID
119 kSha1, 118 kSha1,
120 kCrc32, 119 kCrc32,
121 kCrc64, 120 kCrc64,
121 kGnu,
122 kPosix
122}; 123};
123 124
124static LPCSTR const kMethodsNames[] = 125static LPCSTR const kMethodsNames[] =
@@ -135,6 +136,8 @@ static LPCSTR const kMethodsNames[] =
135 , "SHA1" 136 , "SHA1"
136 , "CRC32" 137 , "CRC32"
137 , "CRC64" 138 , "CRC64"
139 , "GNU"
140 , "POSIX"
138}; 141};
139 142
140static const EMethodID g_7zMethods[] = 143static const EMethodID g_7zMethods[] =
@@ -186,6 +189,12 @@ static const EMethodID g_SwfcMethods[] =
186 // kLZMA 189 // kLZMA
187}; 190};
188 191
192static const EMethodID g_TarMethods[] =
193{
194 kGnu,
195 kPosix
196};
197
189static const EMethodID g_HashMethods[] = 198static const EMethodID g_HashMethods[] =
190{ 199{
191 kSha256 200 kSha256
@@ -202,6 +211,13 @@ static const UInt32 kFF_EncryptFileNames = 1 << 4;
202static const UInt32 kFF_MemUse = 1 << 5; 211static const UInt32 kFF_MemUse = 1 << 5;
203static const UInt32 kFF_SFX = 1 << 6; 212static const UInt32 kFF_SFX = 1 << 6;
204 213
214/*
215static const UInt32 kFF_Time_Win = 1 << 10;
216static const UInt32 kFF_Time_Unix = 1 << 11;
217static const UInt32 kFF_Time_DOS = 1 << 12;
218static const UInt32 kFF_Time_1ns = 1 << 13;
219*/
220
205struct CFormatInfo 221struct CFormatInfo
206{ 222{
207 LPCSTR Name; 223 LPCSTR Name;
@@ -233,23 +249,26 @@ static const CFormatInfo g_Formats[] =
233 kFF_MultiThread | kFF_MemUse 249 kFF_MultiThread | kFF_MemUse
234 }, 250 },
235 { 251 {
236 k7zFormat, 252 "7z",
237 (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), 253 (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
238 METHODS_PAIR(g_7zMethods), 254 METHODS_PAIR(g_7zMethods),
239 kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt | 255 kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt |
240 kFF_EncryptFileNames | kFF_MemUse | kFF_SFX 256 kFF_EncryptFileNames | kFF_MemUse | kFF_SFX
257 // | kFF_Time_Win
241 }, 258 },
242 { 259 {
243 "Zip", 260 "Zip",
244 (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), 261 (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
245 METHODS_PAIR(g_ZipMethods), 262 METHODS_PAIR(g_ZipMethods),
246 kFF_MultiThread | kFF_Encrypt | kFF_MemUse 263 kFF_MultiThread | kFF_Encrypt | kFF_MemUse
264 // | kFF_Time_Win | kFF_Time_Unix | kFF_Time_DOS
247 }, 265 },
248 { 266 {
249 "GZip", 267 "GZip",
250 (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), 268 (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9),
251 METHODS_PAIR(g_GZipMethods), 269 METHODS_PAIR(g_GZipMethods),
252 kFF_MemUse 270 kFF_MemUse
271 // | kFF_Time_Unix
253 }, 272 },
254 { 273 {
255 "BZip2", 274 "BZip2",
@@ -272,14 +291,15 @@ static const CFormatInfo g_Formats[] =
272 { 291 {
273 "Tar", 292 "Tar",
274 (1 << 0), 293 (1 << 0),
275 0, NULL, 294 METHODS_PAIR(g_TarMethods),
276 0 295 // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns
277 }, 296 },
278 { 297 {
279 "wim", 298 "wim",
280 (1 << 0), 299 (1 << 0),
281 0, NULL, 300 0, NULL,
282 0 301 0
302 // | kFF_Time_Win
283 }, 303 },
284 { 304 {
285 "Hash", 305 "Hash",
@@ -335,22 +355,6 @@ static const UInt32 k_PathMode_IDs[] =
335}; 355};
336 356
337void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal); 357void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal);
338bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2);
339
340void CCompressDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2)
341{
342 CheckButton(id, GetBoolsVal(b1, b2));
343}
344
345void CCompressDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2)
346{
347 bool val = IsButtonCheckedBool(id);
348 bool oldVal = GetBoolsVal(b1, b2);
349 if (val != oldVal)
350 b1.Def = b2.Def = true;
351 b1.Val = b2.Val = val;
352}
353
354 358
355void CCompressDialog::SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs) 359void CCompressDialog::SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs)
356{ 360{
@@ -375,12 +379,13 @@ void CCompressDialog::SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs
375 } 379 }
376} 380}
377 381
378 382
379bool CCompressDialog::OnInit() 383bool CCompressDialog::OnInit()
380{ 384{
381 #ifdef LANG 385 #ifdef LANG
382 LangSetWindowText(*this, IDD_COMPRESS); 386 LangSetWindowText(*this, IDD_COMPRESS);
383 LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); 387 LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
388 // LangSetDlgItemText(*this, IDB_COMPRESS_OPTIONS, IDS_OPTIONS); // IDG_COMPRESS_OPTIONS
384 #endif 389 #endif
385 390
386 { 391 {
@@ -435,11 +440,6 @@ bool CCompressDialog::OnInit()
435 CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword); 440 CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword);
436 CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders); 441 CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders);
437 442
438 CheckButton_TwoBools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks);
439 CheckButton_TwoBools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks);
440 CheckButton_TwoBools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams);
441 CheckButton_TwoBools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity);
442
443 UpdatePasswordControl(); 443 UpdatePasswordControl();
444 444
445 { 445 {
@@ -490,7 +490,7 @@ bool CCompressDialog::OnInit()
490 CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite); 490 CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite);
491 CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing); 491 CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing);
492 492
493 FormatChanged(); 493 FormatChanged(false); // isChanged
494 494
495 // OnButtonSFX(); 495 // OnButtonSFX();
496 496
@@ -552,6 +552,13 @@ bool CCompressDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
552 UpdatePasswordControl(); 552 UpdatePasswordControl();
553 return true; 553 return true;
554 } 554 }
555 case IDB_COMPRESS_OPTIONS:
556 {
557 COptionsDialog dialog(this);
558 if (dialog.Create(*this) == IDOK)
559 ShowOptionsString();
560 return true;
561 }
555 } 562 }
556 return CModalDialog::OnButtonClicked(buttonID, buttonHWND); 563 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
557} 564}
@@ -588,8 +595,44 @@ void CCompressDialog::EnableMultiCombo(unsigned id)
588 EnableItem(id, enable); 595 EnableItem(id, enable);
589} 596}
590 597
598static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s);
599static void FormatOptions_To_String(const NCompression::CFormatOptions &fo, AString &s);
591 600
592void CCompressDialog::FormatChanged() 601static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res)
602{
603 if (!b1.Def && b2.Def)
604 res.Val = b2.Val;
605 else
606 res.Val = b1.Val;
607}
608
609#define SET_GUI_BOOL(name) \
610 Combine_Two_BoolPairs(Info. ## name, m_RegistryInfo. ## name, name)
611
612
613static void Set_Final_BoolPairs(
614 const CBool1 &gui,
615 CBoolPair &cmd,
616 CBoolPair &reg)
617{
618 if (!cmd.Def)
619 {
620 reg.Val = gui.Val;
621 reg.Def = gui.Val;
622 }
623 if (gui.Supported)
624 {
625 cmd.Val = gui.Val;
626 cmd.Def = gui.Val;
627 }
628 else
629 cmd.Init();
630}
631
632#define SET_FINAL_BOOL_PAIRS(name) \
633 Set_Final_BoolPairs(name, Info. ## name, m_RegistryInfo. ## name)
634
635void CCompressDialog::FormatChanged(bool isChanged)
593{ 636{
594 SetLevel(); 637 SetLevel();
595 SetSolidBlockSize(); 638 SetSolidBlockSize();
@@ -615,18 +658,26 @@ void CCompressDialog::FormatChanged()
615 CheckSFXControlsEnable(); 658 CheckSFXControlsEnable();
616 659
617 { 660 {
618 const CArcInfoEx &ai = Get_ArcInfoEx(); 661 if (!isChanged)
619 662 {
620 ShowItem_Bool(IDX_COMPRESS_NT_SYM_LINKS, ai.Flags_SymLinks()); 663 SET_GUI_BOOL (SymLinks);
621 ShowItem_Bool(IDX_COMPRESS_NT_HARD_LINKS, ai.Flags_HardLinks()); 664 SET_GUI_BOOL (HardLinks);
622 ShowItem_Bool(IDX_COMPRESS_NT_ALT_STREAMS, ai.Flags_AltStreams()); 665 SET_GUI_BOOL (AltStreams);
623 ShowItem_Bool(IDX_COMPRESS_NT_SECUR, ai.Flags_NtSecure()); 666 SET_GUI_BOOL (NtSecurity);
667 SET_GUI_BOOL (PreserveATime);
668 }
624 669
625 ShowItem_Bool(IDG_COMPRESS_NTFS, 670 PreserveATime.Supported = true;
626 ai.Flags_SymLinks() 671
627 || ai.Flags_HardLinks() 672 {
628 || ai.Flags_AltStreams() 673 const CArcInfoEx &ai = Get_ArcInfoEx();
629 || ai.Flags_NtSecure()); 674 SymLinks.Supported = ai.Flags_SymLinks();
675 HardLinks.Supported = ai.Flags_HardLinks();
676 AltStreams.Supported = ai.Flags_AltStreams();
677 NtSecurity.Supported = ai.Flags_NtSecurity();
678 }
679
680 ShowOptionsString();
630 } 681 }
631 // CheckVolumeEnable(); 682 // CheckVolumeEnable();
632 683
@@ -821,7 +872,7 @@ void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64
821 872
822 s.Add_LF(); 873 s.Add_LF();
823 s.Add_LF(); 874 s.Add_LF();
824 s += LangString(IDS_MEM_ERROR); 875 AddLangString(s, IDS_MEM_ERROR);
825} 876}
826 877
827 878
@@ -933,17 +984,32 @@ void CCompressDialog::OnOK()
933 Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES); 984 Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES);
934 985
935 986
936 GetButton_Bools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); 987 /* (Info) is for saving to registry:
937 GetButton_Bools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); 988 (CBoolPair::Val) will be set as (false), if it was (false)
938 GetButton_Bools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); 989 in registry at dialog creation, and user didn't click checkbox.
939 GetButton_Bools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); 990 in another case (CBoolPair::Val) will be set as (true) */
940 991
941 { 992 {
942 const CArcInfoEx &ai = Get_ArcInfoEx(); 993 /* Info properties could be for another archive types.
943 if (!ai.Flags_SymLinks()) Info.SymLinks.Val = false; 994 so we disable unsupported properties in Info */
944 if (!ai.Flags_HardLinks()) Info.HardLinks.Val = false; 995 // const CArcInfoEx &ai = Get_ArcInfoEx();
945 if (!ai.Flags_AltStreams()) Info.AltStreams.Val = false; 996
946 if (!ai.Flags_NtSecure()) Info.NtSecurity.Val = false; 997 SET_FINAL_BOOL_PAIRS (SymLinks);
998 SET_FINAL_BOOL_PAIRS (HardLinks);
999 SET_FINAL_BOOL_PAIRS (AltStreams);
1000 SET_FINAL_BOOL_PAIRS (NtSecurity);
1001
1002 SET_FINAL_BOOL_PAIRS (PreserveATime);
1003 }
1004
1005 {
1006 const NCompression::CFormatOptions &fo = Get_FormatOptions();
1007
1008 Info.TimePrec = fo.TimePrec;
1009 Info.MTime = fo.MTime;
1010 Info.CTime = fo.CTime;
1011 Info.ATime = fo.ATime;
1012 Info.SetArcMTime = fo.SetArcMTime;
947 } 1013 }
948 1014
949 m_Params.GetText(Info.Options); 1015 m_Params.GetText(Info.Options);
@@ -1031,7 +1097,7 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam)
1031 { 1097 {
1032 const bool isSFX = IsSFX(); 1098 const bool isSFX = IsSFX();
1033 SaveOptionsInMem(); 1099 SaveOptionsInMem();
1034 FormatChanged(); 1100 FormatChanged(true); // isChanged
1035 SetArchiveName2(isSFX); 1101 SetArchiveName2(isSFX);
1036 return true; 1102 return true;
1037 } 1103 }
@@ -1057,6 +1123,7 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam)
1057 SetMemoryUsage(); 1123 SetMemoryUsage();
1058 if (Get_ArcInfoEx().Flags_HashHandler()) 1124 if (Get_ArcInfoEx().Flags_HashHandler())
1059 SetArchiveName2(false); 1125 SetArchiveName2(false);
1126
1060 return true; 1127 return true;
1061 } 1128 }
1062 1129
@@ -1188,6 +1255,7 @@ void CCompressDialog::SetArchiveName(const UString &name)
1188 m_ArchivePath.SetText(fileName); 1255 m_ArchivePath.SetText(fileName);
1189} 1256}
1190 1257
1258
1191int CCompressDialog::FindRegistryFormat(const UString &name) 1259int CCompressDialog::FindRegistryFormat(const UString &name)
1192{ 1260{
1193 FOR_VECTOR (i, m_RegistryInfo.Formats) 1261 FOR_VECTOR (i, m_RegistryInfo.Formats)
@@ -1199,7 +1267,8 @@ int CCompressDialog::FindRegistryFormat(const UString &name)
1199 return -1; 1267 return -1;
1200} 1268}
1201 1269
1202int CCompressDialog::FindRegistryFormatAlways(const UString &name) 1270
1271unsigned CCompressDialog::FindRegistryFormat_Always(const UString &name)
1203{ 1272{
1204 int index = FindRegistryFormat(name); 1273 int index = FindRegistryFormat(name);
1205 if (index < 0) 1274 if (index < 0)
@@ -1211,6 +1280,14 @@ int CCompressDialog::FindRegistryFormatAlways(const UString &name)
1211 return index; 1280 return index;
1212} 1281}
1213 1282
1283
1284NCompression::CFormatOptions &CCompressDialog::Get_FormatOptions()
1285{
1286 const CArcInfoEx &ai = Get_ArcInfoEx();
1287 return m_RegistryInfo.Formats[FindRegistryFormat_Always(ai.Name)];
1288}
1289
1290
1214int CCompressDialog::GetStaticFormatIndex() 1291int CCompressDialog::GetStaticFormatIndex()
1215{ 1292{
1216 const CArcInfoEx &ai = Get_ArcInfoEx(); 1293 const CArcInfoEx &ai = Get_ArcInfoEx();
@@ -1293,8 +1370,11 @@ void CCompressDialog::SetMethod2(int keepMethodId)
1293 const CArcInfoEx &ai = Get_ArcInfoEx(); 1370 const CArcInfoEx &ai = Get_ArcInfoEx();
1294 if (GetLevel() == 0 && !ai.Flags_HashHandler()) 1371 if (GetLevel() == 0 && !ai.Flags_HashHandler())
1295 { 1372 {
1296 MethodChanged(); 1373 if (!ai.Is_Tar())
1297 return; 1374 {
1375 MethodChanged();
1376 return;
1377 }
1298 } 1378 }
1299 UString defaultMethod; 1379 UString defaultMethod;
1300 { 1380 {
@@ -1308,7 +1388,7 @@ void CCompressDialog::SetMethod2(int keepMethodId)
1308 const bool isSfx = IsSFX(); 1388 const bool isSfx = IsSFX();
1309 bool weUseSameMethod = false; 1389 bool weUseSameMethod = false;
1310 1390
1311 const bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); 1391 const bool is7z = ai.Is_7z();
1312 1392
1313 for (unsigned m = 0;; m++) 1393 for (unsigned m = 0;; m++)
1314 { 1394 {
@@ -1367,12 +1447,12 @@ void CCompressDialog::SetMethod2(int keepMethodId)
1367 1447
1368bool CCompressDialog::IsZipFormat() 1448bool CCompressDialog::IsZipFormat()
1369{ 1449{
1370 return Get_ArcInfoEx().Name.IsEqualTo_Ascii_NoCase("zip"); 1450 return Get_ArcInfoEx().Is_Zip();
1371} 1451}
1372 1452
1373bool CCompressDialog::IsXzFormat() 1453bool CCompressDialog::IsXzFormat()
1374{ 1454{
1375 return Get_ArcInfoEx().Name.IsEqualTo_Ascii_NoCase("xz"); 1455 return Get_ArcInfoEx().Is_Xz();
1376} 1456}
1377 1457
1378void CCompressDialog::SetEncryptionMethod() 1458void CCompressDialog::SetEncryptionMethod()
@@ -1380,13 +1460,13 @@ void CCompressDialog::SetEncryptionMethod()
1380 _encryptionMethod.ResetContent(); 1460 _encryptionMethod.ResetContent();
1381 _default_encryptionMethod_Index = -1; 1461 _default_encryptionMethod_Index = -1;
1382 const CArcInfoEx &ai = Get_ArcInfoEx(); 1462 const CArcInfoEx &ai = Get_ArcInfoEx();
1383 if (ai.Name.IsEqualTo_Ascii_NoCase("7z")) 1463 if (ai.Is_7z())
1384 { 1464 {
1385 ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); 1465 ComboBox_AddStringAscii(_encryptionMethod, "AES-256");
1386 _encryptionMethod.SetCurSel(0); 1466 _encryptionMethod.SetCurSel(0);
1387 _default_encryptionMethod_Index = 0; 1467 _default_encryptionMethod_Index = 0;
1388 } 1468 }
1389 else if (ai.Name.IsEqualTo_Ascii_NoCase("zip")) 1469 else if (ai.Is_Zip())
1390 { 1470 {
1391 int index = FindRegistryFormat(ai.Name); 1471 int index = FindRegistryFormat(ai.Name);
1392 UString encryptionMethod; 1472 UString encryptionMethod;
@@ -1929,7 +2009,7 @@ void CCompressDialog::SetSolidBlockSize2()
1929 } 2009 }
1930 } 2010 }
1931 2011
1932 const bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); 2012 const bool is7z = ai.Is_7z();
1933 2013
1934 const UInt64 cs = Get_Lzma2_ChunkSize(dict); 2014 const UInt64 cs = Get_Lzma2_ChunkSize(dict);
1935 2015
@@ -2549,11 +2629,16 @@ void CCompressDialog::SetParams()
2549 2629
2550void CCompressDialog::SaveOptionsInMem() 2630void CCompressDialog::SaveOptionsInMem()
2551{ 2631{
2632 /* these options are for (Info.FormatIndex).
2633 If it's called just after format changing,
2634 then it's format that was selected before format changing
2635 So we store previous format properties */
2636
2552 m_Params.GetText(Info.Options); 2637 m_Params.GetText(Info.Options);
2553 Info.Options.Trim(); 2638 Info.Options.Trim();
2554 2639
2555 const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; 2640 const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
2556 const int index = FindRegistryFormatAlways(ai.Name); 2641 const unsigned index = FindRegistryFormat_Always(ai.Name);
2557 NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; 2642 NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
2558 fo.Options = Info.Options; 2643 fo.Options = Info.Options;
2559 fo.Level = GetLevelSpec(); 2644 fo.Level = GetLevelSpec();
@@ -2587,7 +2672,512 @@ void CCompressDialog::SaveOptionsInMem()
2587 fo.MemUse = Get_MemUse_Spec(); 2672 fo.MemUse = Get_MemUse_Spec();
2588} 2673}
2589 2674
2675
2590unsigned CCompressDialog::GetFormatIndex() 2676unsigned CCompressDialog::GetFormatIndex()
2591{ 2677{
2592 return (unsigned)m_Format.GetItemData_of_CurSel(); 2678 return (unsigned)m_Format.GetItemData_of_CurSel();
2593} 2679}
2680
2681
2682
2683static void AddText_from_BoolPair(AString &s, const char *name, const CBoolPair &bp)
2684{
2685 if (bp.Def)
2686 {
2687 s.Add_OptSpaced(name);
2688 if (!bp.Val)
2689 s += "-";
2690 }
2691 /*
2692 else if (bp.Val)
2693 {
2694 s.Add_OptSpaced("[");
2695 s += name;
2696 s += "]";
2697 }
2698 */
2699}
2700
2701
2702static void AddText_from_Bool1(AString &s, const char *name, const CBool1 &b)
2703{
2704 if (b.Supported && b.Val)
2705 s.Add_OptSpaced(name);
2706}
2707
2708
2709void CCompressDialog::ShowOptionsString()
2710{
2711 NCompression::CFormatOptions &fo = Get_FormatOptions();
2712
2713 AString s;
2714 if (fo.TimePrec != -1)
2715 {
2716 s.Add_OptSpaced("tp");
2717 s.Add_UInt32(fo.TimePrec);
2718 }
2719 AddText_from_BoolPair(s, "tm", fo.MTime);
2720 AddText_from_BoolPair(s, "tc", fo.CTime);
2721 AddText_from_BoolPair(s, "ta", fo.ATime);
2722 AddText_from_BoolPair(s, "-stl", fo.SetArcMTime);
2723
2724 // const CArcInfoEx &ai = Get_ArcInfoEx();
2725 AddText_from_Bool1(s, "SL", SymLinks);
2726 AddText_from_Bool1(s, "HL", HardLinks);
2727 AddText_from_Bool1(s, "AS", AltStreams);
2728 AddText_from_Bool1(s, "Sec", NtSecurity);
2729
2730 // AddText_from_Bool1(s, "Preserve", PreserveATime);
2731
2732 SetItemText(IDT_COMPRESS_OPTIONS, GetUnicodeString(s));
2733}
2734
2735
2736
2737
2738
2739// ---------- OPTIONS ----------
2740
2741
2742void COptionsDialog::CheckButton_Bool1(UINT id, const CBool1 &b1)
2743{
2744 CheckButton(id, b1.Val);
2745}
2746
2747void COptionsDialog::GetButton_Bool1(UINT id, CBool1 &b1)
2748{
2749 b1.Val = IsButtonCheckedBool(id);
2750}
2751
2752
2753void COptionsDialog::CheckButton_BoolBox(
2754 bool supported, const CBoolPair &b2, CBoolBox &bb)
2755{
2756 const bool isSet = b2.Def;
2757 const bool val = isSet ? b2.Val : bb.DefaultVal;
2758
2759 bb.IsSupported = supported;
2760
2761 CheckButton (bb.Set_Id, isSet);
2762 ShowItem_Bool (bb.Set_Id, supported);
2763 CheckButton (bb.Id, val);
2764 EnableItem (bb.Id, isSet);
2765 ShowItem_Bool (bb.Id, supported);
2766}
2767
2768void COptionsDialog::GetButton_BoolBox(CBoolBox &bb)
2769{
2770 // we save value for invisible buttons too
2771 bb.BoolPair.Val = IsButtonCheckedBool (bb.Id);
2772 bb.BoolPair.Def = IsButtonCheckedBool (bb.Set_Id);
2773}
2774
2775
2776void COptionsDialog::Store_TimeBoxes()
2777{
2778 TimePrec = GetPrecSpec();
2779 GetButton_BoolBox (MTime);
2780 GetButton_BoolBox (CTime);
2781 GetButton_BoolBox (ATime);
2782 GetButton_BoolBox (ZTime);
2783}
2784
2785
2786UInt32 COptionsDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax)
2787{
2788 if (c.GetCount() <= defMax)
2789 return (UInt32)(Int32)-1;
2790 return (UInt32)c.GetItemData_of_CurSel();
2791}
2792
2793static const unsigned kTimePrec_Win = 0;
2794static const unsigned kTimePrec_Unix = 1;
2795static const unsigned kTimePrec_DOS = 2;
2796static const unsigned kTimePrec_1ns = 3;
2797
2798static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL)
2799{
2800 // s += " : ";
2801 {
2802 AString s2;
2803 s2.Add_UInt32(val);
2804 s += s2;
2805 }
2806 s.Add_Space();
2807 s += unit;
2808 if (sys)
2809 {
2810 s += " : ";
2811 s += sys;
2812 }
2813}
2814
2815int COptionsDialog::AddPrec(unsigned prec, bool isDefault)
2816{
2817 UString s;
2818 UInt32 writePrec = prec;
2819 if (isDefault)
2820 {
2821 // s += "* ";
2822 // writePrec = (UInt32)(Int32)-1;
2823 }
2824 if (prec == kTimePrec_Win) AddTimeOption(s, 100, NsString, "Windows");
2825 else if (prec == kTimePrec_Unix) AddTimeOption(s, 1, SecString, "Unix");
2826 else if (prec == kTimePrec_DOS) AddTimeOption(s, 2, SecString, "DOS");
2827 else if (prec == kTimePrec_1ns) AddTimeOption(s, 1, NsString, "Linux");
2828 else if (prec == k_PropVar_TimePrec_Base) AddTimeOption(s, 1, SecString);
2829 else if (prec >= k_PropVar_TimePrec_Base)
2830 {
2831 UInt32 d = 1;
2832 for (unsigned i = prec; i < k_PropVar_TimePrec_Base + 9; i++)
2833 d *= 10;
2834 AddTimeOption(s, d, NsString);
2835 }
2836 else
2837 s.Add_UInt32(prec);
2838 const int index = (int)m_Prec.AddString(s);
2839 m_Prec.SetItemData(index, writePrec);
2840 return index;
2841}
2842
2843
2844void COptionsDialog::SetPrec()
2845{
2846 // const CFormatInfo &fi = g_Formats[cd->GetStaticFormatIndex()];
2847 const CArcInfoEx &ai = cd->Get_ArcInfoEx();
2848
2849 // UInt32 flags = fi.Flags;
2850
2851 UInt32 flags = ai.Get_TimePrecFlags();
2852 UInt32 defaultPrec = ai.Get_DefaultTimePrec();
2853 if (defaultPrec != 0)
2854 flags |= ((UInt32)1 << defaultPrec);
2855
2856 // const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
2857
2858 // unsigned defaultPrec = kTimePrec_Win;
2859
2860 if (ai.Is_GZip())
2861 defaultPrec = kTimePrec_Unix;
2862
2863 {
2864 UString s;
2865 s += GetNameOfProperty(kpidType, L"type");
2866 s += ": ";
2867 s += ai.Name;
2868 if (ai.Is_Tar())
2869 {
2870 const int methodID = cd->GetMethodID();
2871
2872 // for debug
2873 // defaultPrec = kTimePrec_Unix;
2874 // flags = (UInt32)1 << kTimePrec_Unix;
2875
2876 s += ":";
2877 if (methodID >= 0 && (unsigned)methodID < ARRAY_SIZE(kMethodsNames))
2878 s += kMethodsNames[methodID];
2879 if (methodID == kPosix)
2880 {
2881 // for debug
2882 // flags |= (UInt32)1 << kTimePrec_Win;
2883 // flags |= (UInt32)1 << kTimePrec_1ns;
2884 }
2885 }
2886 else
2887 {
2888 // if (is_for_MethodChanging) return;
2889 }
2890
2891 SetItemText(IDT_COMPRESS_TIME_INFO, s);
2892 }
2893
2894 m_Prec.ResetContent();
2895 _auto_Prec = defaultPrec;
2896
2897 unsigned selectedPrec = defaultPrec;
2898 {
2899 // if (TimePrec >= kTimePrec_Win && TimePrec <= kTimePrec_DOS)
2900 if ((Int32)TimePrec >= 0)
2901 selectedPrec = TimePrec;
2902 }
2903
2904 int curSel = -1;
2905 int defaultPrecIndex = -1;
2906 for (unsigned prec = 0;
2907 // prec <= k_PropVar_TimePrec_HighPrec;
2908 prec <= k_PropVar_TimePrec_1ns;
2909 prec++)
2910 {
2911 if (((flags >> prec) & 1) == 0)
2912 continue;
2913 const bool isDefault = (defaultPrec == prec);
2914 const int index = AddPrec(prec, isDefault);
2915 if (isDefault)
2916 defaultPrecIndex = index;
2917 if (selectedPrec == prec)
2918 curSel = index;
2919 }
2920
2921 if (curSel < 0 && selectedPrec > kTimePrec_DOS)
2922 curSel = AddPrec(selectedPrec, false); // isDefault
2923 if (curSel < 0)
2924 curSel = defaultPrecIndex;
2925 if (curSel >= 0)
2926 m_Prec.SetCurSel(curSel);
2927
2928 {
2929 const bool isSet = IsSet_TimePrec();
2930 const int count = m_Prec.GetCount();
2931 const bool showPrec = (count != 0);
2932 ShowItem_Bool(IDC_COMPRESS_TIME_PREC, showPrec);
2933 ShowItem_Bool(IDT_COMPRESS_TIME_PREC, showPrec);
2934 EnableItem(IDC_COMPRESS_TIME_PREC, isSet && (count > 1));
2935
2936 CheckButton(IDX_COMPRESS_PREC_SET, isSet);
2937 const bool setIsSupported = isSet || (count > 1);
2938 EnableItem(IDX_COMPRESS_PREC_SET, setIsSupported);
2939 ShowItem_Bool(IDX_COMPRESS_PREC_SET, setIsSupported);
2940 }
2941
2942 SetTimeMAC();
2943}
2944
2945
2946void COptionsDialog::SetTimeMAC()
2947{
2948 const CArcInfoEx &ai = cd->Get_ArcInfoEx();
2949
2950 const
2951 bool m_allow = ai.Flags_MTime();
2952 bool c_allow = ai.Flags_CTime();
2953 bool a_allow = ai.Flags_ATime();
2954
2955 if (ai.Is_Tar())
2956 {
2957 const int methodID = cd->GetMethodID();
2958 c_allow = false;
2959 a_allow = false;
2960 if (methodID == kPosix)
2961 {
2962 // c_allow = true; // do we need it as change time ?
2963 a_allow = true;
2964 }
2965 }
2966
2967 if (ai.Is_Zip())
2968 {
2969 // const int methodID = GetMethodID();
2970 UInt32 prec = GetPrec();
2971 if (prec == (UInt32)(Int32)-1)
2972 prec = _auto_Prec;
2973 if (prec != kTimePrec_Win)
2974 {
2975 c_allow = false;
2976 a_allow = false;
2977 }
2978 }
2979
2980
2981 /*
2982 MTime.DefaultVal = true;
2983 CTime.DefaultVal = false;
2984 ATime.DefaultVal = false;
2985 */
2986
2987 MTime.DefaultVal = ai.Flags_MTime_Default();
2988 CTime.DefaultVal = ai.Flags_CTime_Default();
2989 ATime.DefaultVal = ai.Flags_ATime_Default();
2990
2991 ZTime.DefaultVal = false;
2992
2993 const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
2994
2995 CheckButton_BoolBox (m_allow, fo.MTime, MTime );
2996 CheckButton_BoolBox (c_allow, fo.CTime, CTime );
2997 CheckButton_BoolBox (a_allow, fo.ATime, ATime );
2998 CheckButton_BoolBox (true, fo.SetArcMTime, ZTime);
2999
3000 if (m_allow && !fo.MTime.Def)
3001 {
3002 const bool isSingleFile = ai.Flags_KeepName();
3003 if (!isSingleFile)
3004 {
3005 // we can hide changing checkboxes for MTime here:
3006 ShowItem_Bool (MTime.Set_Id, false);
3007 EnableItem (MTime.Id, false);
3008 }
3009 }
3010 // On_CheckBoxSet_Prec_Clicked();
3011 // const bool isSingleFile = ai.Flags_KeepName();
3012 // mtime for Gz can be
3013}
3014
3015
3016
3017void COptionsDialog::On_CheckBoxSet_Prec_Clicked()
3018{
3019 const bool isSet = IsButtonCheckedBool(IDX_COMPRESS_PREC_SET);
3020 if (!isSet)
3021 {
3022 // We save current MAC boxes to memory before SetPrec()
3023 Store_TimeBoxes();
3024 Reset_TimePrec();
3025 SetPrec();
3026 }
3027 EnableItem(IDC_COMPRESS_TIME_PREC, isSet);
3028}
3029
3030void COptionsDialog::On_CheckBoxSet_Clicked(const CBoolBox &bb)
3031{
3032 const bool isSet = IsButtonCheckedBool(bb.Set_Id);
3033 if (!isSet)
3034 CheckButton(bb.Id, bb.DefaultVal);
3035 EnableItem(bb.Id, isSet);
3036}
3037
3038
3039
3040
3041#ifdef LANG
3042static const UInt32 kLangIDs_Options[] =
3043{
3044 IDX_COMPRESS_NT_SYM_LINKS,
3045 IDX_COMPRESS_NT_HARD_LINKS,
3046 IDX_COMPRESS_NT_ALT_STREAMS,
3047 IDX_COMPRESS_NT_SECUR,
3048
3049 IDG_COMPRESS_TIME,
3050 IDT_COMPRESS_TIME_PREC,
3051 IDX_COMPRESS_MTIME,
3052 IDX_COMPRESS_CTIME,
3053 IDX_COMPRESS_ATIME,
3054 IDX_COMPRESS_ZTIME,
3055 IDX_COMPRESS_PRESERVE_ATIME
3056};
3057#endif
3058
3059
3060bool COptionsDialog::OnInit()
3061{
3062 #ifdef LANG
3063 LangSetWindowText(*this, IDB_COMPRESS_OPTIONS); // IDS_OPTIONS
3064 LangSetDlgItems(*this, kLangIDs_Options, ARRAY_SIZE(kLangIDs_Options));
3065 // LangSetDlgItemText(*this, IDB_COMPRESS_TIME_DEFAULT, IDB_COMPRESS_TIME_DEFAULT);
3066 // LangSetDlgItemText(*this, IDX_COMPRESS_TIME_DEFAULT, IDX_COMPRESS_TIME_DEFAULT);
3067 #endif
3068
3069 LangString(IDS_COMPRESS_SEC, SecString);
3070 if (SecString.IsEmpty())
3071 SecString = "sec";
3072 LangString(IDS_COMPRESS_NS, NsString);
3073 if (NsString.IsEmpty())
3074 NsString = "ns";
3075
3076 {
3077 // const CArcInfoEx &ai = cd->Get_ArcInfoEx();
3078
3079 ShowItem_Bool ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks.Supported);
3080 ShowItem_Bool ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks.Supported);
3081 ShowItem_Bool ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams.Supported);
3082 ShowItem_Bool ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity.Supported);
3083
3084 ShowItem_Bool ( IDG_COMPRESS_NTFS,
3085 cd->SymLinks.Supported
3086 || cd->HardLinks.Supported
3087 || cd->AltStreams.Supported
3088 || cd->NtSecurity.Supported);
3089 }
3090
3091 /* we read property from two sources:
3092 1) command line : (Info)
3093 2) registry : (m_RegistryInfo)
3094 (Info) has priority, if both are no defined */
3095
3096 CheckButton_Bool1 ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks);
3097 CheckButton_Bool1 ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks);
3098 CheckButton_Bool1 ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams);
3099 CheckButton_Bool1 ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity);
3100
3101 CheckButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime);
3102
3103 m_Prec.Attach (GetItem(IDC_COMPRESS_TIME_PREC));
3104
3105 MTime.SetIDs ( IDX_COMPRESS_MTIME, IDX_COMPRESS_MTIME_SET);
3106 CTime.SetIDs ( IDX_COMPRESS_CTIME, IDX_COMPRESS_CTIME_SET);
3107 ATime.SetIDs ( IDX_COMPRESS_ATIME, IDX_COMPRESS_ATIME_SET);
3108 ZTime.SetIDs ( IDX_COMPRESS_ZTIME, IDX_COMPRESS_ZTIME_SET);
3109
3110 {
3111 const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
3112 TimePrec = fo.TimePrec;
3113 MTime.BoolPair = fo.MTime;
3114 CTime.BoolPair = fo.CTime;
3115 ATime.BoolPair = fo.ATime;
3116 ZTime.BoolPair = fo.SetArcMTime;
3117 }
3118
3119 SetPrec();
3120
3121 NormalizePosition();
3122
3123 return CModalDialog::OnInit();
3124}
3125
3126
3127bool COptionsDialog::OnCommand(int code, int itemID, LPARAM lParam)
3128{
3129 if (code == CBN_SELCHANGE)
3130 {
3131 switch (itemID)
3132 {
3133 case IDC_COMPRESS_TIME_PREC:
3134 {
3135 Store_TimeBoxes();
3136 SetTimeMAC(); // for zip/tar
3137 return true;
3138 }
3139 }
3140 }
3141 return CModalDialog::OnCommand(code, itemID, lParam);
3142}
3143
3144
3145bool COptionsDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
3146{
3147 switch (buttonID)
3148 {
3149 case IDX_COMPRESS_PREC_SET: { On_CheckBoxSet_Prec_Clicked(); return true; }
3150 case IDX_COMPRESS_MTIME_SET: { On_CheckBoxSet_Clicked (MTime); return true; }
3151 case IDX_COMPRESS_CTIME_SET: { On_CheckBoxSet_Clicked (CTime); return true; }
3152 case IDX_COMPRESS_ATIME_SET: { On_CheckBoxSet_Clicked (ATime); return true; }
3153 case IDX_COMPRESS_ZTIME_SET: { On_CheckBoxSet_Clicked (ZTime); return true; }
3154 }
3155 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
3156}
3157
3158
3159void COptionsDialog::OnOK()
3160{
3161 GetButton_Bool1 (IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks);
3162 GetButton_Bool1 (IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks);
3163 GetButton_Bool1 (IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams);
3164 GetButton_Bool1 (IDX_COMPRESS_NT_SECUR, cd->NtSecurity);
3165 GetButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime);
3166
3167 Store_TimeBoxes();
3168 {
3169 NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
3170 fo.TimePrec = TimePrec;
3171 fo.MTime = MTime.BoolPair;
3172 fo.CTime = CTime.BoolPair;
3173 fo.ATime = ATime.BoolPair;
3174 fo.SetArcMTime = ZTime.BoolPair;
3175 }
3176
3177 CModalDialog::OnOK();
3178}
3179
3180void COptionsDialog::OnHelp()
3181{
3182 ShowHelpWindow(kHelpTopic);
3183}
diff --git a/CPP/7zip/UI/GUI/CompressDialog.h b/CPP/7zip/UI/GUI/CompressDialog.h
index 171d118..d4590c9 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.h
+++ b/CPP/7zip/UI/GUI/CompressDialog.h
@@ -59,6 +59,14 @@ namespace NCompressDialog
59 CBoolPair HardLinks; 59 CBoolPair HardLinks;
60 CBoolPair AltStreams; 60 CBoolPair AltStreams;
61 CBoolPair NtSecurity; 61 CBoolPair NtSecurity;
62
63 CBoolPair PreserveATime;
64
65 UInt32 TimePrec;
66 CBoolPair MTime;
67 CBoolPair CTime;
68 CBoolPair ATime;
69 CBoolPair SetArcMTime;
62 70
63 UString ArcPath; // in: Relative or abs ; out: Relative or abs 71 UString ArcPath; // in: Relative or abs ; out: Relative or abs
64 72
@@ -89,11 +97,46 @@ namespace NCompressDialog
89 Method.Empty(); 97 Method.Empty();
90 Options.Empty(); 98 Options.Empty();
91 EncryptionMethod.Empty(); 99 EncryptionMethod.Empty();
100 TimePrec = (UInt32)(Int32)(-1);
92 } 101 }
93 }; 102 };
94} 103}
95 104
96 105
106struct CBool1
107{
108 bool Val;
109 bool Supported;
110
111 CBool1(): Val(false), Supported(false) {}
112
113 void Init()
114 {
115 Val = false;
116 Supported = false;
117 }
118
119 void SetTrueTrue()
120 {
121 Val = true;
122 Supported = true;
123 }
124
125 void SetVal_as_Supported(bool val)
126 {
127 Val = val;
128 Supported = true;
129 }
130
131 /*
132 bool IsVal_True_and_Defined() const
133 {
134 return Def && Val;
135 }
136 */
137};
138
139
97class CCompressDialog: public NWindows::NControl::CModalDialog 140class CCompressDialog: public NWindows::NControl::CModalDialog
98{ 141{
99 NWindows::NControl::CComboBox m_ArchivePath; 142 NWindows::NControl::CComboBox m_ArchivePath;
@@ -126,8 +169,6 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
126 169
127 int _default_encryptionMethod_Index; 170 int _default_encryptionMethod_Index;
128 171
129 NCompression::CInfo m_RegistryInfo;
130
131 int m_PrevFormat; 172 int m_PrevFormat;
132 UString DirPrefix; 173 UString DirPrefix;
133 UString StartDirPrefix; 174 UString StartDirPrefix;
@@ -137,23 +178,25 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
137 UInt64 _ramSize_Reduced; // full for 64-bit and reduced for 32-bit 178 UInt64 _ramSize_Reduced; // full for 64-bit and reduced for 32-bit
138 UInt64 _ramUsage_Auto; 179 UInt64 _ramUsage_Auto;
139 180
140 void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); 181public:
141 void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); 182 NCompression::CInfo m_RegistryInfo;
183
184 CBool1 SymLinks;
185 CBool1 HardLinks;
186 CBool1 AltStreams;
187 CBool1 NtSecurity;
188 CBool1 PreserveATime;
142 189
143 void SetArchiveName(const UString &name); 190 void SetArchiveName(const UString &name);
144 int FindRegistryFormat(const UString &name); 191 int FindRegistryFormat(const UString &name);
145 int FindRegistryFormatAlways(const UString &name); 192 unsigned FindRegistryFormat_Always(const UString &name);
146 193
147 const CArcInfoEx &Get_ArcInfoEx() 194 const CArcInfoEx &Get_ArcInfoEx()
148 { 195 {
149 return (*ArcFormats)[GetFormatIndex()]; 196 return (*ArcFormats)[GetFormatIndex()];
150 } 197 }
151 198
152 NCompression::CFormatOptions &Get_FormatOptions() 199 NCompression::CFormatOptions &Get_FormatOptions();
153 {
154 const CArcInfoEx &ai = Get_ArcInfoEx();
155 return m_RegistryInfo.Formats[ FindRegistryFormatAlways(ai.Name) ];
156 }
157 200
158 void CheckSFXNameChange(); 201 void CheckSFXNameChange();
159 void SetArchiveName2(bool prevWasSFX); 202 void SetArchiveName2(bool prevWasSFX);
@@ -237,6 +280,12 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
237 280
238 UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } 281 UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); }
239 282
283 /*
284 UInt32 GetPrecSpec() { return GetComboValue(m_Prec, 1); }
285 UInt32 GetPrec() { return GetComboValue(m_Prec, 0); }
286 */
287
288
240 int AddOrder(UInt32 size); 289 int AddOrder(UInt32 size);
241 int AddOrder_Auto(); 290 int AddOrder_Auto();
242 291
@@ -271,6 +320,7 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
271 void PrintMemUsage(UINT res, UInt64 value); 320 void PrintMemUsage(UINT res, UInt64 value);
272 void SetMemoryUsage(); 321 void SetMemoryUsage();
273 void SetParams(); 322 void SetParams();
323
274 void SaveOptionsInMem(); 324 void SaveOptionsInMem();
275 325
276 void UpdatePasswordControl(); 326 void UpdatePasswordControl();
@@ -283,7 +333,7 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
283 void CheckSFXControlsEnable(); 333 void CheckSFXControlsEnable();
284 // void CheckVolumeEnable(); 334 // void CheckVolumeEnable();
285 void EnableMultiCombo(unsigned id); 335 void EnableMultiCombo(unsigned id);
286 void FormatChanged(); 336 void FormatChanged(bool isChanged);
287 337
288 void OnButtonSetArchive(); 338 void OnButtonSetArchive();
289 bool IsSFX(); 339 bool IsSFX();
@@ -300,6 +350,8 @@ class CCompressDialog: public NWindows::NControl::CModalDialog
300 MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); 350 MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR);
301 } 351 }
302 352
353 void ShowOptionsString();
354
303public: 355public:
304 const CObjectVector<CArcInfoEx> *ArcFormats; 356 const CObjectVector<CArcInfoEx> *ArcFormats;
305 CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 357 CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0
@@ -313,11 +365,103 @@ public:
313 365
314 INT_PTR Create(HWND wndParent = 0) 366 INT_PTR Create(HWND wndParent = 0)
315 { 367 {
316 BIG_DIALOG_SIZE(400, 304); 368 BIG_DIALOG_SIZE(400, 320);
317 return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent); 369 return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent);
318 } 370 }
319 371
320 CCompressDialog(): CurrentDirWasChanged(false) {}; 372 CCompressDialog(): CurrentDirWasChanged(false) {};
321}; 373};
322 374
375
376
377
378class COptionsDialog: public NWindows::NControl::CModalDialog
379{
380 struct CBoolBox
381 {
382 bool IsSupported;
383 bool DefaultVal;
384 CBoolPair BoolPair;
385
386 int Id;
387 int Set_Id;
388
389 void SetIDs(int id, int set_Id)
390 {
391 Id = id;
392 Set_Id = set_Id;
393 }
394
395 CBoolBox():
396 IsSupported(false),
397 DefaultVal(false)
398 {}
399 };
400
401 CCompressDialog *cd;
402
403 NWindows::NControl::CComboBox m_Prec;
404
405 UInt32 _auto_Prec;
406 UInt32 TimePrec;
407
408 void Reset_TimePrec() { TimePrec = (UInt32)(Int32)-1; }
409 bool IsSet_TimePrec() const { return TimePrec != (UInt32)(Int32)-1; }
410
411 CBoolBox MTime;
412 CBoolBox CTime;
413 CBoolBox ATime;
414 CBoolBox ZTime;
415
416 UString SecString;
417 UString NsString;
418
419
420 void CheckButton_Bool1(UINT id, const CBool1 &b1);
421 void GetButton_Bool1(UINT id, CBool1 &b1);
422 void CheckButton_BoolBox(bool supported, const CBoolPair &b2, CBoolBox &bb);
423 void GetButton_BoolBox(CBoolBox &bb);
424
425 void Store_TimeBoxes();
426
427 UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0);
428 UInt32 GetPrecSpec()
429 {
430 UInt32 prec = GetComboValue(m_Prec, 1);
431 if (prec == _auto_Prec)
432 prec = (UInt32)(Int32)-1;
433 return prec;
434 }
435 UInt32 GetPrec() { return GetComboValue(m_Prec, 0); }
436
437 // void OnButton_TimeDefault();
438 int AddPrec(unsigned prec, bool isDefault);
439 void SetPrec();
440 void SetTimeMAC();
441
442 void On_CheckBoxSet_Prec_Clicked();
443 void On_CheckBoxSet_Clicked(const CBoolBox &bb);
444
445 virtual bool OnInit();
446 virtual bool OnCommand(int code, int itemID, LPARAM lParam);
447 virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
448 virtual void OnOK();
449 virtual void OnHelp();
450
451public:
452
453 INT_PTR Create(HWND wndParent = 0)
454 {
455 BIG_DIALOG_SIZE(240, 232);
456 return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS_OPTIONS), wndParent);
457 }
458
459 COptionsDialog(CCompressDialog *cdLoc):
460 cd(cdLoc)
461 // , TimePrec(0)
462 {
463 Reset_TimePrec();
464 };
465};
466
323#endif 467#endif
diff --git a/CPP/7zip/UI/GUI/CompressDialog.rc b/CPP/7zip/UI/GUI/CompressDialog.rc
index 52c9546..d47a3ed 100644
--- a/CPP/7zip/UI/GUI/CompressDialog.rc
+++ b/CPP/7zip/UI/GUI/CompressDialog.rc
@@ -2,7 +2,7 @@
2#include "../../GuiCommon.rc" 2#include "../../GuiCommon.rc"
3 3
4#define xc 400 4#define xc 400
5#define yc 354 5#define yc 320
6 6
7#undef gSize 7#undef gSize
8#undef gSpace 8#undef gSpace
@@ -20,10 +20,6 @@
20#define gSize 192 20#define gSize 192
21#define gSpace 24 21#define gSpace 24
22 22
23#define ntSize2 168
24#define ntSizeX (ntSize2 - m - m)
25#define ntPosX m + m
26#define ntPosY 292
27 23
28#define g1xs 88 24#define g1xs 88
29#define g0xs (gSize - g1xs) 25#define g0xs (gSize - g1xs)
@@ -99,18 +95,9 @@ BEGIN
99 LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m, 256, gSize, 8 95 LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m, 256, gSize, 8
100 EDITTEXT IDE_COMPRESS_PARAMETERS, m, 268, gSize, 14, ES_AUTOHSCROLL 96 EDITTEXT IDE_COMPRESS_PARAMETERS, m, 268, gSize, 14, ES_AUTOHSCROLL
101 97
102 98 PUSHBUTTON "Options", IDB_COMPRESS_OPTIONS, m, 292, bxs, bys
103 GROUPBOX "NTFS", IDG_COMPRESS_NTFS, m, ntPosY, ntSize2, 68 99 LTEXT "", IDT_COMPRESS_OPTIONS, m + bxs + m, 294, gSize - bxs - m, 16, SS_NOPREFIX
104 100
105 CONTROL "Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, MY_CHECKBOX,
106 ntPosX, ntPosY + 12, ntSizeX, 10
107 CONTROL "Store hard links", IDX_COMPRESS_NT_HARD_LINKS, MY_CHECKBOX,
108 ntPosX, ntPosY + 26, ntSizeX, 10
109 CONTROL "Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, MY_CHECKBOX,
110 ntPosX, ntPosY + 40, ntSizeX, 10
111 CONTROL "Store file security", IDX_COMPRESS_NT_SECUR, MY_CHECKBOX,
112 ntPosX, ntPosY + 54, ntSizeX, 10
113
114 101
115 LTEXT "&Update mode:", IDT_COMPRESS_UPDATE_MODE, g4x, 41, 80, 8 102 LTEXT "&Update mode:", IDT_COMPRESS_UPDATE_MODE, g4x, 41, 80, 8
116 COMBOBOX IDC_COMPRESS_UPDATE_MODE, g4x + 84, 39, g4xs - 84, 80, MY_COMBO 103 COMBOBOX IDC_COMPRESS_UPDATE_MODE, g4x + 84, 39, g4xs - 84, 80, MY_COMBO
@@ -225,4 +212,10 @@ BEGIN
225 IDS_COMPRESS_SOLID "Solid" 212 IDS_COMPRESS_SOLID "Solid"
226 213
227 IDS_SPLIT_CONFIRM "Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?" 214 IDS_SPLIT_CONFIRM "Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?"
215
216 IDS_COMPRESS_SEC "sec"
217 IDS_COMPRESS_NS "ns"
228END 218END
219
220
221#include "CompressOptionsDialog.rc"
diff --git a/CPP/7zip/UI/GUI/CompressDialogRes.h b/CPP/7zip/UI/GUI/CompressDialogRes.h
index 341b753..80b39be 100644
--- a/CPP/7zip/UI/GUI/CompressDialogRes.h
+++ b/CPP/7zip/UI/GUI/CompressDialogRes.h
@@ -1,5 +1,6 @@
1#define IDD_COMPRESS 4000 1#define IDD_COMPRESS 4000
2#define IDD_COMPRESS_2 14000 2#define IDD_COMPRESS_2 14000
3#define IDD_COMPRESS_OPTIONS 14001
3 4
4#define IDC_COMPRESS_ARCHIVE 100 5#define IDC_COMPRESS_ARCHIVE 100
5#define IDB_COMPRESS_SET_ARCHIVE 101 6#define IDB_COMPRESS_SET_ARCHIVE 101
@@ -28,6 +29,10 @@
28 29
29#define IDT_COMPRESS_ARCHIVE_FOLDER 130 30#define IDT_COMPRESS_ARCHIVE_FOLDER 130
30 31
32// #define IDB_COMPRESS_OPTIONS 140
33#define IDB_COMPRESS_OPTIONS 2100
34#define IDT_COMPRESS_OPTIONS 141
35
31#define IDT_COMPRESS_PATH_MODE 3410 36#define IDT_COMPRESS_PATH_MODE 3410
32 37
33#define IDT_PASSWORD_ENTER 3801 38#define IDT_PASSWORD_ENTER 3801
@@ -86,3 +91,31 @@
86#define IDT_SPLIT_TO_VOLUMES 7302 91#define IDT_SPLIT_TO_VOLUMES 7302
87#define IDS_INCORRECT_VOLUME_SIZE 7307 92#define IDS_INCORRECT_VOLUME_SIZE 7307
88#define IDS_SPLIT_CONFIRM 7308 93#define IDS_SPLIT_CONFIRM 7308
94
95
96// Options Dialog
97
98#define IDG_COMPRESS_TIME 4080
99#define IDT_COMPRESS_TIME_PREC 4081
100#define IDX_COMPRESS_MTIME 4082
101#define IDX_COMPRESS_CTIME 4083
102#define IDX_COMPRESS_ATIME 4084
103#define IDX_COMPRESS_ZTIME 4085
104#define IDX_COMPRESS_PRESERVE_ATIME 4086
105
106#define IDS_COMPRESS_SEC 4090
107#define IDS_COMPRESS_NS 4091
108
109#define IDC_COMPRESS_TIME_PREC 190
110#define IDT_COMPRESS_TIME_INFO 191
111
112#define IDX_COMPRESS_PREC_SET 201
113#define IDX_COMPRESS_MTIME_SET 202
114#define IDX_COMPRESS_CTIME_SET 203
115#define IDX_COMPRESS_ATIME_SET 204
116#define IDX_COMPRESS_ZTIME_SET 205
117
118// #define IDX_COMPRESS_NT_SYM_LINKS_SET 210
119// #define IDX_COMPRESS_NT_HARD_LINKS_SET 211
120// #define IDX_COMPRESS_NT_ALT_STREAMS_SET 212
121// #define IDX_COMPRESS_NT_SECUR_SET 213
diff --git a/CPP/7zip/UI/GUI/CompressOptionsDialog.rc b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc
new file mode 100644
index 0000000..0578227
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc
@@ -0,0 +1,76 @@
1#include "CompressDialogRes.h"
2#include "../../GuiCommon.rc"
3
4#define xc 240
5#define yc 232
6
7#define g5x m
8#define g5x2 (g5x + m)
9#define g5xs (xc)
10#define g5xs2 (g5xs - m - m)
11
12#define ntPosX g5x2
13#define ntPosY m
14#define ntSizeX g5xs2
15#define precSizeX 76
16
17#define ntSizeY 72
18#define timePosY (ntPosY + ntSizeY + 20)
19
20#define ceSize 18
21#define ceString ":"
22
23
24IDD_COMPRESS_OPTIONS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
25CAPTION "Options"
26BEGIN
27 GROUPBOX "NTFS", IDG_COMPRESS_NTFS, g5x, ntPosY, g5xs, ntSizeY
28
29 CONTROL "Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, MY_CHECKBOX,
30 ntPosX, ntPosY + 12, ntSizeX, 10
31 CONTROL "Store hard links", IDX_COMPRESS_NT_HARD_LINKS, MY_CHECKBOX,
32 ntPosX, ntPosY + 26, ntSizeX, 10
33 CONTROL "Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, MY_CHECKBOX,
34 ntPosX, ntPosY + 40, ntSizeX, 10
35 CONTROL "Store file security", IDX_COMPRESS_NT_SECUR, MY_CHECKBOX,
36 ntPosX, ntPosY + 54, ntSizeX, 10
37
38 LTEXT "", IDT_COMPRESS_TIME_INFO, g5x, timePosY - 14, g5xs, 8
39
40
41 GROUPBOX "Time", IDG_COMPRESS_TIME, g5x, timePosY, g5xs, 112
42
43// CONTROL "Default", IDX_COMPRESS_TIME_DEFAULT, MY_CHECKBOX,
44// ntPosX, timePosY + 10, ntSizeX, 16
45
46 CONTROL ceString, IDX_COMPRESS_PREC_SET, MY_CHECKBOX, ntPosX, timePosY + 14, ceSize, 10
47 LTEXT "Timestamp precision:", IDT_COMPRESS_TIME_PREC,
48 ntPosX + ceSize, timePosY + 14, ntSizeX - precSizeX - ceSize, 8
49 COMBOBOX IDC_COMPRESS_TIME_PREC, ntPosX + ntSizeX - precSizeX, timePosY + 12, precSizeX, 70, MY_COMBO
50
51 // PUSHBUTTON "Default", IDB_COMPRESS_TIME_DEFAULT, ntPosX + ntSizeX - bxs, timePosY + 22, bxs, bys, WS_GROUP
52
53 CONTROL ceString, IDX_COMPRESS_MTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 28, ceSize, 10
54 CONTROL "Store modification time", IDX_COMPRESS_MTIME, MY_CHECKBOX,
55 ntPosX + ceSize, timePosY + 28, ntSizeX - ceSize, 10
56
57 CONTROL ceString, IDX_COMPRESS_CTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 42, ceSize, 10
58 CONTROL "Store creation time", IDX_COMPRESS_CTIME, MY_CHECKBOX,
59 ntPosX + ceSize, timePosY + 42, ntSizeX - ceSize, 10
60
61 CONTROL ceString, IDX_COMPRESS_ATIME_SET, MY_CHECKBOX, ntPosX, timePosY + 56, ceSize, 10
62 CONTROL "Store last access time", IDX_COMPRESS_ATIME, MY_CHECKBOX,
63 ntPosX + ceSize, timePosY + 56, ntSizeX - ceSize, 10
64
65 CONTROL ceString, IDX_COMPRESS_ZTIME_SET, MY_CHECKBOX | BS_MULTILINE, ntPosX, timePosY + 72, ceSize, 16
66 CONTROL "Set archive time to latest file time", IDX_COMPRESS_ZTIME, MY_CHECKBOX | BS_MULTILINE,
67 ntPosX + ceSize, timePosY + 72, ntSizeX - ceSize, 16
68
69 CONTROL "Do not change source files last access time", IDX_COMPRESS_PRESERVE_ATIME, MY_CHECKBOX | BS_MULTILINE,
70 ntPosX, timePosY + 92, ntSizeX, 16
71
72
73 DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP
74 PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys
75 PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys
76END
diff --git a/CPP/7zip/UI/GUI/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp
index 32a48e7..c977516 100644
--- a/CPP/7zip/UI/GUI/GUI.cpp
+++ b/CPP/7zip/UI/GUI/GUI.cpp
@@ -75,6 +75,8 @@ extern
75bool g_LVN_ITEMACTIVATE_Support; 75bool g_LVN_ITEMACTIVATE_Support;
76bool g_LVN_ITEMACTIVATE_Support = true; 76bool g_LVN_ITEMACTIVATE_Support = true;
77 77
78DECLARE_AND_SET_CLIENT_VERSION_VAR
79
78static void ErrorMessage(LPCWSTR message) 80static void ErrorMessage(LPCWSTR message)
79{ 81{
80 MessageBoxW(NULL, message, L"7-Zip", MB_ICONERROR | MB_OK); 82 MessageBoxW(NULL, message, L"7-Zip", MB_ICONERROR | MB_OK);
@@ -135,7 +137,7 @@ static int Main2()
135 137
136 CREATE_CODECS_OBJECT 138 CREATE_CODECS_OBJECT
137 139
138 codecs->CaseSensitiveChange = options.CaseSensitiveChange; 140 codecs->CaseSensitive_Change = options.CaseSensitive_Change;
139 codecs->CaseSensitive = options.CaseSensitive; 141 codecs->CaseSensitive = options.CaseSensitive;
140 ThrowException_if_Error(codecs->Load()); 142 ThrowException_if_Error(codecs->Load());
141 Codecs_AddHashArcHandler(codecs); 143 Codecs_AddHashArcHandler(codecs);
diff --git a/CPP/7zip/UI/GUI/GUI.dsp b/CPP/7zip/UI/GUI/GUI.dsp
index 53a2c92..b55a115 100644
--- a/CPP/7zip/UI/GUI/GUI.dsp
+++ b/CPP/7zip/UI/GUI/GUI.dsp
@@ -773,6 +773,10 @@ SOURCE=..\..\..\..\C\7zCrcOpt.c
773# End Source File 773# End Source File
774# Begin Source File 774# Begin Source File
775 775
776SOURCE=..\..\..\..\C\7zTypes.h
777# End Source File
778# Begin Source File
779
776SOURCE=..\..\..\..\C\Alloc.c 780SOURCE=..\..\..\..\C\Alloc.c
777# SUBTRACT CPP /YX /Yc /Yu 781# SUBTRACT CPP /YX /Yc /Yu
778# End Source File 782# End Source File
@@ -1211,5 +1215,17 @@ SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
1211SOURCE=..\..\Archive\Common\OutStreamWithCRC.h 1215SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
1212# End Source File 1216# End Source File
1213# End Group 1217# End Group
1218# Begin Group "7-Zip"
1219
1220# PROP Default_Filter ""
1221# Begin Source File
1222
1223SOURCE=..\..\Archive\IArchive.h
1224# End Source File
1225# Begin Source File
1226
1227SOURCE=..\..\ICoder.h
1228# End Source File
1229# End Group
1214# End Target 1230# End Target
1215# End Project 1231# End Project
diff --git a/CPP/7zip/UI/GUI/UpdateGUI.cpp b/CPP/7zip/UI/GUI/UpdateGUI.cpp
index a3a1d88..2d04143 100644
--- a/CPP/7zip/UI/GUI/UpdateGUI.cpp
+++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp
@@ -61,6 +61,53 @@ HRESULT CThreadUpdating::ProcessVirt()
61 return HRESULT_FROM_WIN32(ei.SystemError); 61 return HRESULT_FROM_WIN32(ei.SystemError);
62} 62}
63 63
64
65// parse command line properties
66
67static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp)
68{
69 if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name))
70 return false;
71 const UString rem = prop.Name.Ptr((unsigned)strlen(name));
72 UString val = prop.Value;
73 if (!rem.IsEmpty())
74 {
75 if (!val.IsEmpty())
76 return true;
77 val = rem;
78 }
79 bool res;
80 if (StringToBool(val, res))
81 {
82 bp.Val = res;
83 bp.Def = true;
84 }
85 return true;
86}
87
88static void ParseProp(
89 const CProperty &prop,
90 NCompressDialog::CInfo &di)
91{
92 if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return;
93 if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return;
94 if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return;
95}
96
97static void ParseProperties(
98 const CObjectVector<CProperty> &properties,
99 NCompressDialog::CInfo &di)
100{
101 FOR_VECTOR (i, properties)
102 {
103 ParseProp(properties[i], di);
104 }
105}
106
107
108
109
110
64static void AddProp_UString(CObjectVector<CProperty> &properties, const char *name, const UString &value) 111static void AddProp_UString(CObjectVector<CProperty> &properties, const char *name, const UString &value)
65{ 112{
66 CProperty prop; 113 CProperty prop;
@@ -81,10 +128,31 @@ static void AddProp_bool(CObjectVector<CProperty> &properties, const char *name,
81 AddProp_UString(properties, name, UString(value ? "on": "off")); 128 AddProp_UString(properties, name, UString(value ? "on": "off"));
82} 129}
83 130
84static bool IsThereMethodOverride(bool is7z, const UString &propertiesString) 131
132static void AddProp_BoolPair(CObjectVector<CProperty> &properties,
133 const char *name, const CBoolPair &bp)
134{
135 if (bp.Def)
136 AddProp_bool(properties, name, bp.Val);
137}
138
139
140
141static void SplitOptionsToStrings(const UString &src, UStringVector &strings)
142{
143 SplitString(src, strings);
144 FOR_VECTOR (i, strings)
145 {
146 UString &s = strings[i];
147 if (s.Len() > 2
148 && s[0] == '-'
149 && MyCharLower_Ascii(s[1]) == 'm')
150 s.DeleteFrontal(2);
151 }
152}
153
154static bool IsThereMethodOverride(bool is7z, const UStringVector &strings)
85{ 155{
86 UStringVector strings;
87 SplitString(propertiesString, strings);
88 FOR_VECTOR (i, strings) 156 FOR_VECTOR (i, strings)
89 { 157 {
90 const UString &s = strings[i]; 158 const UString &s = strings[i];
@@ -106,17 +174,11 @@ static bool IsThereMethodOverride(bool is7z, const UString &propertiesString)
106} 174}
107 175
108static void ParseAndAddPropertires(CObjectVector<CProperty> &properties, 176static void ParseAndAddPropertires(CObjectVector<CProperty> &properties,
109 const UString &propertiesString) 177 const UStringVector &strings)
110{ 178{
111 UStringVector strings;
112 SplitString(propertiesString, strings);
113 FOR_VECTOR (i, strings) 179 FOR_VECTOR (i, strings)
114 { 180 {
115 UString s = strings[i]; 181 const UString &s = strings[i];
116 if (s.Len() > 2
117 && s[0] == '-'
118 && MyCharLower_Ascii(s[1]) == 'm')
119 s.DeleteFrontal(2);
120 CProperty property; 182 CProperty property;
121 const int index = s.Find(L'='); 183 const int index = s.Find(L'=');
122 if (index < 0) 184 if (index < 0)
@@ -142,58 +204,49 @@ static void AddProp_Size(CObjectVector<CProperty> &properties, const char *name,
142 204
143static void SetOutProperties( 205static void SetOutProperties(
144 CObjectVector<CProperty> &properties, 206 CObjectVector<CProperty> &properties,
207 const NCompressDialog::CInfo &di,
145 bool is7z, 208 bool is7z,
146 UInt32 level, 209 bool setMethod)
147 bool setMethod,
148 const UString &method,
149 UInt64 dict64,
150 bool orderMode,
151 UInt32 order,
152 bool solidIsSpecified, UInt64 solidBlockSize,
153 // bool multiThreadIsAllowed,
154 UInt32 numThreads,
155 const UString &encryptionMethod,
156 bool encryptHeadersIsAllowed, bool encryptHeaders,
157 const NCompression::CMemUse &memUse,
158 bool /* sfxMode */)
159{ 210{
160 if (level != (UInt32)(Int32)-1) 211 if (di.Level != (UInt32)(Int32)-1)
161 AddProp_UInt32(properties, "x", (UInt32)level); 212 AddProp_UInt32(properties, "x", (UInt32)di.Level);
162 if (setMethod) 213 if (setMethod)
163 { 214 {
164 if (!method.IsEmpty()) 215 if (!di.Method.IsEmpty())
165 AddProp_UString(properties, is7z ? "0": "m", method); 216 AddProp_UString(properties, is7z ? "0": "m", di.Method);
166 if (dict64 != (UInt64)(Int64)-1) 217 if (di.Dict64 != (UInt64)(Int64)-1)
167 { 218 {
168 AString name; 219 AString name;
169 if (is7z) 220 if (is7z)
170 name = "0"; 221 name = "0";
171 name += (orderMode ? "mem" : "d"); 222 name += (di.OrderMode ? "mem" : "d");
172 AddProp_Size(properties, name, dict64); 223 AddProp_Size(properties, name, di.Dict64);
173 } 224 }
174 if (order != (UInt32)(Int32)-1) 225 if (di.Order != (UInt32)(Int32)-1)
175 { 226 {
176 AString name; 227 AString name;
177 if (is7z) 228 if (is7z)
178 name = "0"; 229 name = "0";
179 name += (orderMode ? "o" : "fb"); 230 name += (di.OrderMode ? "o" : "fb");
180 AddProp_UInt32(properties, name, (UInt32)order); 231 AddProp_UInt32(properties, name, (UInt32)di.Order);
181 } 232 }
182 } 233 }
183 234
184 if (!encryptionMethod.IsEmpty()) 235 if (!di.EncryptionMethod.IsEmpty())
185 AddProp_UString(properties, "em", encryptionMethod); 236 AddProp_UString(properties, "em", di.EncryptionMethod);
186 237
187 if (encryptHeadersIsAllowed) 238 if (di.EncryptHeadersIsAllowed)
188 AddProp_bool(properties, "he", encryptHeaders); 239 AddProp_bool(properties, "he", di.EncryptHeaders);
189 if (solidIsSpecified) 240
190 AddProp_Size(properties, "s", solidBlockSize); 241 if (di.SolidIsSpecified)
242 AddProp_Size(properties, "s", di.SolidBlockSize);
191 243
192 if ( 244 if (
193 // multiThreadIsAllowed && 245 // di.MultiThreadIsAllowed &&
194 numThreads != (UInt32)(Int32)-1) 246 di.NumThreads != (UInt32)(Int32)-1)
195 AddProp_UInt32(properties, "mt", numThreads); 247 AddProp_UInt32(properties, "mt", di.NumThreads);
196 248
249 const NCompression::CMemUse &memUse = di.MemUsage;
197 if (memUse.IsDefined) 250 if (memUse.IsDefined)
198 { 251 {
199 const char *kMemUse = "memuse"; 252 const char *kMemUse = "memuse";
@@ -208,8 +261,16 @@ static void SetOutProperties(
208 else 261 else
209 AddProp_Size(properties, kMemUse, memUse.Val); 262 AddProp_Size(properties, kMemUse, memUse.Val);
210 } 263 }
264
265 AddProp_BoolPair(properties, "tm", di.MTime);
266 AddProp_BoolPair(properties, "tc", di.CTime);
267 AddProp_BoolPair(properties, "ta", di.ATime);
268
269 if (di.TimePrec != (UInt32)(Int32)-1)
270 AddProp_UInt32(properties, "tp", di.TimePrec);
211} 271}
212 272
273
213struct C_UpdateMode_ToAction_Pair 274struct C_UpdateMode_ToAction_Pair
214{ 275{
215 NCompressDialog::NUpdateMode::EEnum UpdateMode; 276 NCompressDialog::NUpdateMode::EEnum UpdateMode;
@@ -358,6 +419,10 @@ static HRESULT ShowDialog(
358 di.HardLinks = options.HardLinks; 419 di.HardLinks = options.HardLinks;
359 di.AltStreams = options.AltStreams; 420 di.AltStreams = options.AltStreams;
360 di.NtSecurity = options.NtSecurity; 421 di.NtSecurity = options.NtSecurity;
422 if (options.SetArcMTime)
423 di.SetArcMTime.SetTrueTrue();
424 if (options.PreserveATime)
425 di.PreserveATime.SetTrueTrue();
361 426
362 if (callback->PasswordIsDefined) 427 if (callback->PasswordIsDefined)
363 di.Password = callback->Password; 428 di.Password = callback->Password;
@@ -373,6 +438,8 @@ static HRESULT ShowDialog(
373 di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode; 438 di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode;
374 } 439 }
375 440
441 ParseProperties(options.MethodMode.Properties, di);
442
376 if (dialog.Create(hwndParent) != IDOK) 443 if (dialog.Create(hwndParent) != IDOK)
377 return E_ABORT; 444 return E_ABORT;
378 445
@@ -382,6 +449,9 @@ static HRESULT ShowDialog(
382 options.HardLinks = di.HardLinks; 449 options.HardLinks = di.HardLinks;
383 options.AltStreams = di.AltStreams; 450 options.AltStreams = di.AltStreams;
384 options.NtSecurity = di.NtSecurity; 451 options.NtSecurity = di.NtSecurity;
452 options.SetArcMTime = di.SetArcMTime.Val;
453 if (di.PreserveATime.Def)
454 options.PreserveATime = di.PreserveATime.Val;
385 455
386 #if defined(_WIN32) && !defined(UNDER_CE) 456 #if defined(_WIN32) && !defined(UNDER_CE)
387 curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged; 457 curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged;
@@ -411,29 +481,21 @@ static HRESULT ShowDialog(
411 if (callback->PasswordIsDefined) 481 if (callback->PasswordIsDefined)
412 callback->Password = di.Password; 482 callback->Password = di.Password;
413 483
484 // we clear command line options, and fill options form Dialog
414 options.MethodMode.Properties.Clear(); 485 options.MethodMode.Properties.Clear();
415 486
416 bool is7z = archiverInfo.Name.IsEqualTo_Ascii_NoCase("7z"); 487 const bool is7z = archiverInfo.Is_7z();
417 bool methodOverride = IsThereMethodOverride(is7z, di.Options); 488
489 UStringVector optionStrings;
490 SplitOptionsToStrings(di.Options, optionStrings);
491 const bool methodOverride = IsThereMethodOverride(is7z, optionStrings);
418 492
419 SetOutProperties( 493 SetOutProperties(options.MethodMode.Properties, di,
420 options.MethodMode.Properties,
421 is7z, 494 is7z,
422 di.Level, 495 !methodOverride); // setMethod
423 !methodOverride,
424 di.Method,
425 di.Dict64,
426 di.OrderMode, di.Order,
427 di.SolidIsSpecified, di.SolidBlockSize,
428 // di.MultiThreadIsAllowed,
429 di.NumThreads,
430 di.EncryptionMethod,
431 di.EncryptHeadersIsAllowed, di.EncryptHeaders,
432 di.MemUsage,
433 di.SFXMode);
434 496
435 options.OpenShareForWrite = di.OpenShareForWrite; 497 options.OpenShareForWrite = di.OpenShareForWrite;
436 ParseAndAddPropertires(options.MethodMode.Properties, di.Options); 498 ParseAndAddPropertires(options.MethodMode.Properties, optionStrings);
437 499
438 if (di.SFXMode) 500 if (di.SFXMode)
439 options.SfxMode = true; 501 options.SfxMode = true;
diff --git a/CPP/Common/Common.h b/CPP/Common/Common.h
index 8dac613..72db7a8 100644
--- a/CPP/Common/Common.h
+++ b/CPP/Common/Common.h
@@ -35,7 +35,7 @@ you can change this h file or h files included in this file.
35 So we can use MY_ARRAY_NEW macro instead of new[] operator. */ 35 So we can use MY_ARRAY_NEW macro instead of new[] operator. */
36 36
37#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64) 37#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64)
38 #define MY_ARRAY_NEW(p, T, size) p = new T[(size > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : size]; 38 #define MY_ARRAY_NEW(p, T, size) p = new T[((size) > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : (size)];
39#else 39#else
40 #define MY_ARRAY_NEW(p, T, size) p = new T[size]; 40 #define MY_ARRAY_NEW(p, T, size) p = new T[size];
41#endif 41#endif
diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h
index ce2f0dd..ff54278 100644
--- a/CPP/Common/MyCom.h
+++ b/CPP/Common/MyCom.h
@@ -67,6 +67,7 @@ public:
67 template <class Q> 67 template <class Q>
68 HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() 68 HRESULT QueryInterface(REFGUID iid, Q** pp) const throw()
69 { 69 {
70 // if (*pp) throw 20220216; // for debug
70 return _p->QueryInterface(iid, (void**)pp); 71 return _p->QueryInterface(iid, (void**)pp);
71 } 72 }
72}; 73};
diff --git a/CPP/Common/MyLinux.h b/CPP/Common/MyLinux.h
index 1a91899..98b453c 100644
--- a/CPP/Common/MyLinux.h
+++ b/CPP/Common/MyLinux.h
@@ -3,6 +3,18 @@
3#ifndef __MY_LIN_LINUX_H 3#ifndef __MY_LIN_LINUX_H
4#define __MY_LIN_LINUX_H 4#define __MY_LIN_LINUX_H
5 5
6// #include "../../C/7zTypes.h"
7
8#define MY_LIN_DT_UNKNOWN 0
9#define MY_LIN_DT_FIFO 1
10#define MY_LIN_DT_CHR 2
11#define MY_LIN_DT_DIR 4
12#define MY_LIN_DT_BLK 6
13#define MY_LIN_DT_REG 8
14#define MY_LIN_DT_LNK 10
15#define MY_LIN_DT_SOCK 12
16#define MY_LIN_DT_WHT 14
17
6#define MY_LIN_S_IFMT 00170000 18#define MY_LIN_S_IFMT 00170000
7#define MY_LIN_S_IFSOCK 0140000 19#define MY_LIN_S_IFSOCK 0140000
8#define MY_LIN_S_IFLNK 0120000 20#define MY_LIN_S_IFLNK 0120000
@@ -39,4 +51,25 @@
39#define MY_LIN_S_IWOTH 00002 51#define MY_LIN_S_IWOTH 00002
40#define MY_LIN_S_IXOTH 00001 52#define MY_LIN_S_IXOTH 00001
41 53
54/*
55// major/minor encoding for makedev(): MMMMMmmmmmmMMMmm:
56
57inline UInt32 MY_dev_major(UInt64 dev)
58{
59 return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff);
60}
61
62inline UInt32 MY_dev_minor(UInt64 dev)
63{
64 return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~0xff);
65}
66
67inline UInt64 MY_dev_makedev(UInt32 __major, UInt32 __minor)
68{
69 return (__minor & 0xff) | ((__major & 0xfff) << 8)
70 | ((UInt64) (__minor & ~0xff) << 12)
71 | ((UInt64) (__major & ~0xfff) << 32);
72}
73*/
74
42#endif 75#endif
diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp
index db202f4..bf1638e 100644
--- a/CPP/Common/MyString.cpp
+++ b/CPP/Common/MyString.cpp
@@ -30,8 +30,8 @@ inline const char* MyStringGetNextCharPointer(const char *p) throw()
30} 30}
31*/ 31*/
32 32
33#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, _size_) 33#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, (_size_))
34#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, _size_) 34#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, (_size_))
35 35
36 36
37int FindCharPosInString(const char *s, char c) throw() 37int FindCharPosInString(const char *s, char c) throw()
@@ -190,8 +190,8 @@ bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
190{ 190{
191 for (;;) 191 for (;;)
192 { 192 {
193 unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true; 193 const unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
194 unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false; 194 const unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
195 } 195 }
196} 196}
197 197
@@ -199,8 +199,8 @@ bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
199{ 199{
200 for (;;) 200 for (;;)
201 { 201 {
202 wchar_t c1 = *s1++; 202 const wchar_t c1 = *s1++;
203 wchar_t c2 = *s2++; 203 const wchar_t c2 = *s2++;
204 if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; 204 if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
205 if (c1 == 0) return true; 205 if (c1 == 0) return true;
206 } 206 }
@@ -213,10 +213,10 @@ bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
213 const char *s1 = _chars; 213 const char *s1 = _chars;
214 for (;;) 214 for (;;)
215 { 215 {
216 char c2 = *s++; 216 const char c2 = *s++;
217 if (c2 == 0) 217 if (c2 == 0)
218 return true; 218 return true;
219 char c1 = *s1++; 219 const char c1 = *s1++;
220 if (MyCharLower_Ascii(c1) != 220 if (MyCharLower_Ascii(c1) !=
221 MyCharLower_Ascii(c2)) 221 MyCharLower_Ascii(c2))
222 return false; 222 return false;
@@ -228,10 +228,10 @@ bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
228 const wchar_t *s1 = _chars; 228 const wchar_t *s1 = _chars;
229 for (;;) 229 for (;;)
230 { 230 {
231 char c2 = *s++; 231 const char c2 = *s++;
232 if (c2 == 0) 232 if (c2 == 0)
233 return true; 233 return true;
234 wchar_t c1 = *s1++; 234 const wchar_t c1 = *s1++;
235 if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) 235 if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
236 return false; 236 return false;
237 } 237 }
@@ -241,7 +241,7 @@ bool StringsAreEqual_Ascii(const char *u, const char *a) throw()
241{ 241{
242 for (;;) 242 for (;;)
243 { 243 {
244 char c = *a; 244 const char c = *a;
245 if (c != *u) 245 if (c != *u)
246 return false; 246 return false;
247 if (c == 0) 247 if (c == 0)
@@ -255,7 +255,7 @@ bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
255{ 255{
256 for (;;) 256 for (;;)
257 { 257 {
258 unsigned char c = (unsigned char)*a; 258 const unsigned char c = (unsigned char)*a;
259 if (c != *u) 259 if (c != *u)
260 return false; 260 return false;
261 if (c == 0) 261 if (c == 0)
@@ -269,8 +269,8 @@ bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
269{ 269{
270 for (;;) 270 for (;;)
271 { 271 {
272 char c1 = *s1++; 272 const char c1 = *s1++;
273 char c2 = *s2++; 273 const char c2 = *s2++;
274 if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) 274 if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
275 return false; 275 return false;
276 if (c1 == 0) 276 if (c1 == 0)
@@ -282,8 +282,8 @@ bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
282{ 282{
283 for (;;) 283 for (;;)
284 { 284 {
285 wchar_t c1 = *s1++; 285 const wchar_t c1 = *s1++;
286 wchar_t c2 = *s2++; 286 const wchar_t c2 = *s2++;
287 if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) 287 if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
288 return false; 288 return false;
289 if (c1 == 0) 289 if (c1 == 0)
@@ -295,8 +295,8 @@ bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
295{ 295{
296 for (;;) 296 for (;;)
297 { 297 {
298 wchar_t c1 = *s1++; 298 const wchar_t c1 = *s1++;
299 char c2 = *s2++; 299 const char c2 = *s2++;
300 if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) 300 if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
301 return false; 301 return false;
302 if (c1 == 0) 302 if (c1 == 0)
@@ -308,8 +308,8 @@ bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
308{ 308{
309 for (;;) 309 for (;;)
310 { 310 {
311 wchar_t c2 = *s2++; if (c2 == 0) return true; 311 const wchar_t c2 = *s2++; if (c2 == 0) return true;
312 wchar_t c1 = *s1++; if (c1 != c2) return false; 312 const wchar_t c1 = *s1++; if (c1 != c2) return false;
313 } 313 }
314} 314}
315 315
@@ -317,8 +317,8 @@ bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw()
317{ 317{
318 for (;;) 318 for (;;)
319 { 319 {
320 unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true; 320 const unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true;
321 wchar_t c1 = *s1++; if (c1 != c2) return false; 321 const wchar_t c1 = *s1++; if (c1 != c2) return false;
322 } 322 }
323} 323}
324 324
@@ -326,8 +326,8 @@ bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) thr
326{ 326{
327 for (;;) 327 for (;;)
328 { 328 {
329 char c2 = *s2++; if (c2 == 0) return true; 329 const char c2 = *s2++; if (c2 == 0) return true;
330 char c1 = *s1++; 330 const char c1 = *s1++;
331 if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) 331 if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
332 return false; 332 return false;
333 } 333 }
@@ -337,8 +337,8 @@ bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2)
337{ 337{
338 for (;;) 338 for (;;)
339 { 339 {
340 char c2 = *s2++; if (c2 == 0) return true; 340 const char c2 = *s2++; if (c2 == 0) return true;
341 wchar_t c1 = *s1++; 341 const wchar_t c1 = *s1++;
342 if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) 342 if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
343 return false; 343 return false;
344 } 344 }
@@ -348,8 +348,8 @@ bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) thr
348{ 348{
349 for (;;) 349 for (;;)
350 { 350 {
351 wchar_t c2 = *s2++; if (c2 == 0) return true; 351 const wchar_t c2 = *s2++; if (c2 == 0) return true;
352 wchar_t c1 = *s1++; 352 const wchar_t c1 = *s1++;
353 if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) 353 if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2))
354 return false; 354 return false;
355 } 355 }
@@ -360,12 +360,12 @@ int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
360{ 360{
361 for (;;) 361 for (;;)
362 { 362 {
363 wchar_t c1 = *s1++; 363 const wchar_t c1 = *s1++;
364 wchar_t c2 = *s2++; 364 const wchar_t c2 = *s2++;
365 if (c1 != c2) 365 if (c1 != c2)
366 { 366 {
367 wchar_t u1 = MyCharUpper(c1); 367 const wchar_t u1 = MyCharUpper(c1);
368 wchar_t u2 = MyCharUpper(c2); 368 const wchar_t u2 = MyCharUpper(c2);
369 if (u1 < u2) return -1; 369 if (u1 < u2) return -1;
370 if (u1 > u2) return 1; 370 if (u1 > u2) return 1;
371 } 371 }
@@ -401,14 +401,13 @@ void AString::InsertSpace(unsigned &index, unsigned size)
401 MoveItems(index + size, index); 401 MoveItems(index + size, index);
402} 402}
403 403
404#define k_Alloc_Len_Limit 0x40000000 404#define k_Alloc_Len_Limit (0x40000000 - 2)
405 405
406void AString::ReAlloc(unsigned newLimit) 406void AString::ReAlloc(unsigned newLimit)
407{ 407{
408 if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220; 408 // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, (size_t)_len + 1);
409 // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1); 409 char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1);
410 char *newBuf = MY_STRING_NEW_char(newLimit + 1); 410 memcpy(newBuf, _chars, (size_t)_len + 1);
411 memcpy(newBuf, _chars, (size_t)(_len + 1));
412 MY_STRING_DELETE(_chars); 411 MY_STRING_DELETE(_chars);
413 _chars = newBuf; 412 _chars = newBuf;
414 _limit = newLimit; 413 _limit = newLimit;
@@ -416,9 +415,9 @@ void AString::ReAlloc(unsigned newLimit)
416 415
417void AString::ReAlloc2(unsigned newLimit) 416void AString::ReAlloc2(unsigned newLimit)
418{ 417{
419 if (newLimit >= k_Alloc_Len_Limit) throw 20130220; 418 if (newLimit > k_Alloc_Len_Limit) throw 20130220;
420 // MY_STRING_REALLOC(_chars, char, newLimit + 1, 0); 419 // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, 0);
421 char *newBuf = MY_STRING_NEW_char(newLimit + 1); 420 char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1);
422 newBuf[0] = 0; 421 newBuf[0] = 0;
423 MY_STRING_DELETE(_chars); 422 MY_STRING_DELETE(_chars);
424 _chars = newBuf; 423 _chars = newBuf;
@@ -427,8 +426,8 @@ void AString::ReAlloc2(unsigned newLimit)
427 426
428void AString::SetStartLen(unsigned len) 427void AString::SetStartLen(unsigned len)
429{ 428{
430 _chars = 0; 429 _chars = NULL;
431 _chars = MY_STRING_NEW_char(len + 1); 430 _chars = MY_STRING_NEW_char((size_t)len + 1);
432 _len = len; 431 _len = len;
433 _limit = len; 432 _limit = len;
434} 433}
@@ -439,20 +438,30 @@ void AString::Grow_1()
439 next += next / 2; 438 next += next / 2;
440 next += 16; 439 next += 16;
441 next &= ~(unsigned)15; 440 next &= ~(unsigned)15;
442 ReAlloc(next - 1); 441 next--;
442 if (next < _len || next > k_Alloc_Len_Limit)
443 next = k_Alloc_Len_Limit;
444 if (next <= _len)
445 throw 20130220;
446 ReAlloc(next);
447 // Grow(1);
443} 448}
444 449
445void AString::Grow(unsigned n) 450void AString::Grow(unsigned n)
446{ 451{
447 unsigned freeSize = _limit - _len; 452 const unsigned freeSize = _limit - _len;
448 if (n <= freeSize) 453 if (n <= freeSize)
449 return; 454 return;
450
451 unsigned next = _len + n; 455 unsigned next = _len + n;
452 next += next / 2; 456 next += next / 2;
453 next += 16; 457 next += 16;
454 next &= ~(unsigned)15; 458 next &= ~(unsigned)15;
455 ReAlloc(next - 1); 459 next--;
460 if (next < _len || next > k_Alloc_Len_Limit)
461 next = k_Alloc_Len_Limit;
462 if (next <= _len || next - _len < n)
463 throw 20130220;
464 ReAlloc(next);
456} 465}
457 466
458AString::AString(unsigned num, const char *s) 467AString::AString(unsigned num, const char *s)
@@ -500,7 +509,7 @@ static const unsigned kStartStringCapacity = 4;
500 509
501AString::AString() 510AString::AString()
502{ 511{
503 _chars = 0; 512 _chars = NULL;
504 _chars = MY_STRING_NEW_char(kStartStringCapacity); 513 _chars = MY_STRING_NEW_char(kStartStringCapacity);
505 _len = 0; 514 _len = 0;
506 _limit = kStartStringCapacity - 1; 515 _limit = kStartStringCapacity - 1;
@@ -548,7 +557,7 @@ AString &AString::operator=(const char *s)
548 unsigned len = MyStringLen(s); 557 unsigned len = MyStringLen(s);
549 if (len > _limit) 558 if (len > _limit)
550 { 559 {
551 char *newBuf = MY_STRING_NEW_char(len + 1); 560 char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
552 MY_STRING_DELETE(_chars); 561 MY_STRING_DELETE(_chars);
553 _chars = newBuf; 562 _chars = newBuf;
554 _limit = len; 563 _limit = len;
@@ -565,7 +574,7 @@ AString &AString::operator=(const AString &s)
565 unsigned len = s._len; 574 unsigned len = s._len;
566 if (len > _limit) 575 if (len > _limit)
567 { 576 {
568 char *newBuf = MY_STRING_NEW_char(len + 1); 577 char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
569 MY_STRING_DELETE(_chars); 578 MY_STRING_DELETE(_chars);
570 _chars = newBuf; 579 _chars = newBuf;
571 _limit = len; 580 _limit = len;
@@ -590,7 +599,7 @@ void AString::SetFromWStr_if_Ascii(const wchar_t *s)
590 } 599 }
591 if (len > _limit) 600 if (len > _limit)
592 { 601 {
593 char *newBuf = MY_STRING_NEW_char(len + 1); 602 char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
594 MY_STRING_DELETE(_chars); 603 MY_STRING_DELETE(_chars);
595 _chars = newBuf; 604 _chars = newBuf;
596 _limit = len; 605 _limit = len;
@@ -614,7 +623,7 @@ void AString::SetFromBstr_if_Ascii(BSTR s)
614 } 623 }
615 if (len > _limit) 624 if (len > _limit)
616 { 625 {
617 char *newBuf = MY_STRING_NEW_char(len + 1); 626 char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
618 MY_STRING_DELETE(_chars); 627 MY_STRING_DELETE(_chars);
619 _chars = newBuf; 628 _chars = newBuf;
620 _limit = len; 629 _limit = len;
@@ -631,6 +640,7 @@ void AString::SetFromBstr_if_Ascii(BSTR s)
631void AString::Add_Space() { operator+=(' '); } 640void AString::Add_Space() { operator+=(' '); }
632void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } 641void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
633void AString::Add_LF() { operator+=('\n'); } 642void AString::Add_LF() { operator+=('\n'); }
643void AString::Add_Slash() { operator+=('/'); }
634 644
635AString &AString::operator+=(const char *s) 645AString &AString::operator+=(const char *s)
636{ 646{
@@ -667,11 +677,23 @@ void UString::Add_UInt64(UInt64 v)
667 _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); 677 _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars);
668} 678}
669 679
680void AString::AddFrom(const char *s, unsigned len) // no check
681{
682 if (len != 0)
683 {
684 Grow(len);
685 memcpy(_chars + _len, s, len);
686 len += _len;
687 _chars[len] = 0;
688 _len = len;
689 }
690}
691
670void AString::SetFrom(const char *s, unsigned len) // no check 692void AString::SetFrom(const char *s, unsigned len) // no check
671{ 693{
672 if (len > _limit) 694 if (len > _limit)
673 { 695 {
674 char *newBuf = MY_STRING_NEW_char(len + 1); 696 char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
675 MY_STRING_DELETE(_chars); 697 MY_STRING_DELETE(_chars);
676 _chars = newBuf; 698 _chars = newBuf;
677 _limit = len; 699 _limit = len;
@@ -976,9 +998,8 @@ void UString::InsertSpace(unsigned index, unsigned size)
976 998
977void UString::ReAlloc(unsigned newLimit) 999void UString::ReAlloc(unsigned newLimit)
978{ 1000{
979 if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221; 1001 // MY_STRING_REALLOC(_chars, wchar_t, (size_t)newLimit + 1, (size_t)_len + 1);
980 // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1); 1002 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1);
981 wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1);
982 wmemcpy(newBuf, _chars, _len + 1); 1003 wmemcpy(newBuf, _chars, _len + 1);
983 MY_STRING_DELETE(_chars); 1004 MY_STRING_DELETE(_chars);
984 _chars = newBuf; 1005 _chars = newBuf;
@@ -987,9 +1008,9 @@ void UString::ReAlloc(unsigned newLimit)
987 1008
988void UString::ReAlloc2(unsigned newLimit) 1009void UString::ReAlloc2(unsigned newLimit)
989{ 1010{
990 if (newLimit >= k_Alloc_Len_Limit) throw 20130221; 1011 if (newLimit > k_Alloc_Len_Limit) throw 20130221;
991 // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); 1012 // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
992 wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1); 1013 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1);
993 newBuf[0] = 0; 1014 newBuf[0] = 0;
994 MY_STRING_DELETE(_chars); 1015 MY_STRING_DELETE(_chars);
995 _chars = newBuf; 1016 _chars = newBuf;
@@ -999,7 +1020,7 @@ void UString::ReAlloc2(unsigned newLimit)
999void UString::SetStartLen(unsigned len) 1020void UString::SetStartLen(unsigned len)
1000{ 1021{
1001 _chars = 0; 1022 _chars = 0;
1002 _chars = MY_STRING_NEW_wchar_t(len + 1); 1023 _chars = MY_STRING_NEW_wchar_t((size_t)len + 1);
1003 _len = len; 1024 _len = len;
1004 _limit = len; 1025 _limit = len;
1005} 1026}
@@ -1010,19 +1031,28 @@ void UString::Grow_1()
1010 next += next / 2; 1031 next += next / 2;
1011 next += 16; 1032 next += 16;
1012 next &= ~(unsigned)15; 1033 next &= ~(unsigned)15;
1013 ReAlloc(next - 1); 1034 next--;
1035 if (next < _len || next > k_Alloc_Len_Limit)
1036 next = k_Alloc_Len_Limit;
1037 if (next <= _len)
1038 throw 20130220;
1039 ReAlloc(next);
1014} 1040}
1015 1041
1016void UString::Grow(unsigned n) 1042void UString::Grow(unsigned n)
1017{ 1043{
1018 unsigned freeSize = _limit - _len; 1044 const unsigned freeSize = _limit - _len;
1019 if (n <= freeSize) 1045 if (n <= freeSize)
1020 return; 1046 return;
1021
1022 unsigned next = _len + n; 1047 unsigned next = _len + n;
1023 next += next / 2; 1048 next += next / 2;
1024 next += 16; 1049 next += 16;
1025 next &= ~(unsigned)15; 1050 next &= ~(unsigned)15;
1051 next--;
1052 if (next < _len || next > k_Alloc_Len_Limit)
1053 next = k_Alloc_Len_Limit;
1054 if (next <= _len || next - _len < n)
1055 throw 20130220;
1026 ReAlloc(next - 1); 1056 ReAlloc(next - 1);
1027} 1057}
1028 1058
@@ -1149,7 +1179,7 @@ UString &UString::operator=(const wchar_t *s)
1149 unsigned len = MyStringLen(s); 1179 unsigned len = MyStringLen(s);
1150 if (len > _limit) 1180 if (len > _limit)
1151 { 1181 {
1152 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1182 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1153 MY_STRING_DELETE(_chars); 1183 MY_STRING_DELETE(_chars);
1154 _chars = newBuf; 1184 _chars = newBuf;
1155 _limit = len; 1185 _limit = len;
@@ -1166,7 +1196,7 @@ UString &UString::operator=(const UString &s)
1166 unsigned len = s._len; 1196 unsigned len = s._len;
1167 if (len > _limit) 1197 if (len > _limit)
1168 { 1198 {
1169 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1199 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1170 MY_STRING_DELETE(_chars); 1200 MY_STRING_DELETE(_chars);
1171 _chars = newBuf; 1201 _chars = newBuf;
1172 _limit = len; 1202 _limit = len;
@@ -1180,7 +1210,7 @@ void UString::SetFrom(const wchar_t *s, unsigned len) // no check
1180{ 1210{
1181 if (len > _limit) 1211 if (len > _limit)
1182 { 1212 {
1183 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1213 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1184 MY_STRING_DELETE(_chars); 1214 MY_STRING_DELETE(_chars);
1185 _chars = newBuf; 1215 _chars = newBuf;
1186 _limit = len; 1216 _limit = len;
@@ -1218,7 +1248,7 @@ void UString::SetFromBstr(LPCOLESTR s)
1218 1248
1219 if (len > _limit) 1249 if (len > _limit)
1220 { 1250 {
1221 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1251 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1222 MY_STRING_DELETE(_chars); 1252 MY_STRING_DELETE(_chars);
1223 _chars = newBuf; 1253 _chars = newBuf;
1224 _limit = len; 1254 _limit = len;
@@ -1258,7 +1288,7 @@ UString &UString::operator=(const char *s)
1258 unsigned len = MyStringLen(s); 1288 unsigned len = MyStringLen(s);
1259 if (len > _limit) 1289 if (len > _limit)
1260 { 1290 {
1261 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1291 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1262 MY_STRING_DELETE(_chars); 1292 MY_STRING_DELETE(_chars);
1263 _chars = newBuf; 1293 _chars = newBuf;
1264 _limit = len; 1294 _limit = len;
@@ -1566,15 +1596,24 @@ void UString::DeleteFrontal(unsigned num) throw()
1566 1596
1567void UString2::ReAlloc2(unsigned newLimit) 1597void UString2::ReAlloc2(unsigned newLimit)
1568{ 1598{
1569 if (newLimit >= k_Alloc_Len_Limit) throw 20130221; 1599 // wrong (_len) is allowed after this function
1600 if (newLimit > k_Alloc_Len_Limit) throw 20130221;
1570 // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); 1601 // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
1571 _chars = MY_STRING_NEW_wchar_t(newLimit + 1); 1602 if (_chars)
1603 {
1604 MY_STRING_DELETE(_chars);
1605 _chars = NULL;
1606 // _len = 0;
1607 }
1608 _chars = MY_STRING_NEW_wchar_t((size_t)newLimit + 1);
1609 _chars[0] = 0;
1610 // _len = newLimit;
1572} 1611}
1573 1612
1574void UString2::SetStartLen(unsigned len) 1613void UString2::SetStartLen(unsigned len)
1575{ 1614{
1576 _chars = 0; 1615 _chars = NULL;
1577 _chars = MY_STRING_NEW_wchar_t(len + 1); 1616 _chars = MY_STRING_NEW_wchar_t((size_t)len + 1);
1578 _len = len; 1617 _len = len;
1579} 1618}
1580 1619
@@ -1591,7 +1630,7 @@ UString2::UString2(wchar_t c)
1591 1630
1592UString2::UString2(const wchar_t *s) 1631UString2::UString2(const wchar_t *s)
1593{ 1632{
1594 unsigned len = MyStringLen(s); 1633 const unsigned len = MyStringLen(s);
1595 SetStartLen(len); 1634 SetStartLen(len);
1596 wmemcpy(_chars, s, len + 1); 1635 wmemcpy(_chars, s, len + 1);
1597} 1636}
@@ -1628,7 +1667,7 @@ UString2 &UString2::operator=(const wchar_t *s)
1628 unsigned len = MyStringLen(s); 1667 unsigned len = MyStringLen(s);
1629 if (len > _len) 1668 if (len > _len)
1630 { 1669 {
1631 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1670 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1632 if (_chars) 1671 if (_chars)
1633 MY_STRING_DELETE(_chars); 1672 MY_STRING_DELETE(_chars);
1634 _chars = newBuf; 1673 _chars = newBuf;
@@ -1643,7 +1682,7 @@ void UString2::SetFromAscii(const char *s)
1643 unsigned len = MyStringLen(s); 1682 unsigned len = MyStringLen(s);
1644 if (len > _len) 1683 if (len > _len)
1645 { 1684 {
1646 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1685 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1647 if (_chars) 1686 if (_chars)
1648 MY_STRING_DELETE(_chars); 1687 MY_STRING_DELETE(_chars);
1649 _chars = newBuf; 1688 _chars = newBuf;
@@ -1662,7 +1701,7 @@ UString2 &UString2::operator=(const UString2 &s)
1662 unsigned len = s._len; 1701 unsigned len = s._len;
1663 if (len > _len) 1702 if (len > _len)
1664 { 1703 {
1665 wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); 1704 wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
1666 if (_chars) 1705 if (_chars)
1667 MY_STRING_DELETE(_chars); 1706 MY_STRING_DELETE(_chars);
1668 _chars = newBuf; 1707 _chars = newBuf;
diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h
index aa3c301..c777c8c 100644
--- a/CPP/Common/MyString.h
+++ b/CPP/Common/MyString.h
@@ -378,6 +378,7 @@ public:
378 void Add_Space_if_NotEmpty(); 378 void Add_Space_if_NotEmpty();
379 void Add_OptSpaced(const char *s); 379 void Add_OptSpaced(const char *s);
380 void Add_LF(); 380 void Add_LF();
381 void Add_Slash();
381 void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); } 382 void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); }
382 383
383 AString &operator+=(const char *s); 384 AString &operator+=(const char *s);
@@ -386,12 +387,12 @@ public:
386 void Add_UInt32(UInt32 v); 387 void Add_UInt32(UInt32 v);
387 void Add_UInt64(UInt64 v); 388 void Add_UInt64(UInt64 v);
388 389
390 void AddFrom(const char *s, unsigned len); // no check
389 void SetFrom(const char *s, unsigned len); // no check 391 void SetFrom(const char *s, unsigned len); // no check
390 void SetFrom_CalcLen(const char *s, unsigned len); 392 void SetFrom_CalcLen(const char *s, unsigned len);
391 393
392 AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } 394 AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); }
393 AString Left(unsigned count) const { return AString(count, *this); } 395 AString Left(unsigned count) const { return AString(count, *this); }
394
395 // void MakeUpper() { MyStringUpper(_chars); } 396 // void MakeUpper() { MyStringUpper(_chars); }
396 // void MakeLower() { MyStringLower(_chars); } 397 // void MakeLower() { MyStringLower(_chars); }
397 void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } 398 void MakeLower_Ascii() { MyStringLower_Ascii(_chars); }
diff --git a/CPP/Common/MyVector.h b/CPP/Common/MyVector.h
index c851234..3417a17 100644
--- a/CPP/Common/MyVector.h
+++ b/CPP/Common/MyVector.h
@@ -5,6 +5,8 @@
5 5
6#include <string.h> 6#include <string.h>
7 7
8const unsigned k_VectorSizeMax = ((unsigned)1 << 31) - 1;
9
8template <class T> 10template <class T>
9class CRecordVector 11class CRecordVector
10{ 12{
@@ -17,31 +19,41 @@ class CRecordVector
17 memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T)); 19 memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T));
18 } 20 }
19 21
20 void ReserveOnePosition() 22 void ReAllocForNewCapacity(const unsigned newCapacity)
21 { 23 {
22 if (_size == _capacity) 24 T *p;
23 { 25 MY_ARRAY_NEW(p, T, newCapacity);
24 unsigned newCapacity = _capacity + (_capacity >> 2) + 1; 26 // p = new T[newCapacity];
25 T *p; 27 if (_size != 0)
26 MY_ARRAY_NEW(p, T, newCapacity); 28 memcpy(p, _items, (size_t)_size * sizeof(T));
27 // p = new T[newCapacity]; 29 delete []_items;
28 if (_size != 0) 30 _items = p;
29 memcpy(p, _items, (size_t)_size * sizeof(T)); 31 _capacity = newCapacity;
30 delete []_items;
31 _items = p;
32 _capacity = newCapacity;
33 }
34 } 32 }
35 33
36public: 34public:
37 35
36 void ReserveOnePosition()
37 {
38 if (_size != _capacity)
39 return;
40 if (_capacity >= k_VectorSizeMax)
41 throw 2021;
42 const unsigned rem = k_VectorSizeMax - _capacity;
43 unsigned add = (_capacity >> 2) + 1;
44 if (add > rem)
45 add = rem;
46 ReAllocForNewCapacity(_capacity + add);
47 }
48
38 CRecordVector(): _items(NULL), _size(0), _capacity(0) {} 49 CRecordVector(): _items(NULL), _size(0), _capacity(0) {}
39 50
40 CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0) 51 CRecordVector(const CRecordVector &v): _items(NULL), _size(0), _capacity(0)
41 { 52 {
42 unsigned size = v.Size(); 53 const unsigned size = v.Size();
43 if (size != 0) 54 if (size != 0)
44 { 55 {
56 // MY_ARRAY_NEW(_items, T, size)
45 _items = new T[size]; 57 _items = new T[size];
46 _size = size; 58 _size = size;
47 _capacity = size; 59 _capacity = size;
@@ -66,22 +78,25 @@ public:
66 { 78 {
67 if (newCapacity > _capacity) 79 if (newCapacity > _capacity)
68 { 80 {
69 T *p; 81 if (newCapacity > k_VectorSizeMax)
70 MY_ARRAY_NEW(p, T, newCapacity); 82 throw 2021;
71 // p = new T[newCapacity]; 83 ReAllocForNewCapacity(newCapacity);
72 if (_size != 0)
73 memcpy(p, _items, (size_t)_size * sizeof(T));
74 delete []_items;
75 _items = p;
76 _capacity = newCapacity;
77 } 84 }
78 } 85 }
79 86
87 void ChangeSize_KeepData(unsigned newSize)
88 {
89 Reserve(newSize);
90 _size = newSize;
91 }
92
80 void ClearAndReserve(unsigned newCapacity) 93 void ClearAndReserve(unsigned newCapacity)
81 { 94 {
82 Clear(); 95 Clear();
83 if (newCapacity > _capacity) 96 if (newCapacity > _capacity)
84 { 97 {
98 if (newCapacity > k_VectorSizeMax)
99 throw 2021;
85 delete []_items; 100 delete []_items;
86 _items = NULL; 101 _items = NULL;
87 _capacity = 0; 102 _capacity = 0;
@@ -97,22 +112,6 @@ public:
97 _size = newSize; 112 _size = newSize;
98 } 113 }
99 114
100 void ChangeSize_KeepData(unsigned newSize)
101 {
102 if (newSize > _capacity)
103 {
104 T *p;
105 MY_ARRAY_NEW(p, T, newSize)
106 // p = new T[newSize];
107 if (_size != 0)
108 memcpy(p, _items, (size_t)_size * sizeof(T));
109 delete []_items;
110 _items = p;
111 _capacity = newSize;
112 }
113 _size = newSize;
114 }
115
116 void ReserveDown() 115 void ReserveDown()
117 { 116 {
118 if (_size == _capacity) 117 if (_size == _capacity)
@@ -120,6 +119,7 @@ public:
120 T *p = NULL; 119 T *p = NULL;
121 if (_size != 0) 120 if (_size != 0)
122 { 121 {
122 // MY_ARRAY_NEW(p, T, _size)
123 p = new T[_size]; 123 p = new T[_size];
124 memcpy(p, _items, (size_t)_size * sizeof(T)); 124 memcpy(p, _items, (size_t)_size * sizeof(T));
125 } 125 }
@@ -178,7 +178,7 @@ public:
178 { 178 {
179 if (&v == this) 179 if (&v == this)
180 return *this; 180 return *this;
181 unsigned size = v.Size(); 181 const unsigned size = v.Size();
182 if (size > _capacity) 182 if (size > _capacity)
183 { 183 {
184 delete []_items; 184 delete []_items;
@@ -196,24 +196,45 @@ public:
196 196
197 CRecordVector& operator+=(const CRecordVector &v) 197 CRecordVector& operator+=(const CRecordVector &v)
198 { 198 {
199 unsigned size = v.Size(); 199 const unsigned size = v.Size();
200 Reserve(_size + size);
201 if (size != 0) 200 if (size != 0)
201 {
202 if (_size >= k_VectorSizeMax || size > k_VectorSizeMax - _size)
203 throw 2021;
204 const unsigned newSize = _size + size;
205 Reserve(newSize);
202 memcpy(_items + _size, v._items, (size_t)size * sizeof(T)); 206 memcpy(_items + _size, v._items, (size_t)size * sizeof(T));
203 _size += size; 207 _size = newSize;
208 }
204 return *this; 209 return *this;
205 } 210 }
206 211
207 unsigned Add(const T item) 212 unsigned Add(const T item)
208 { 213 {
209 ReserveOnePosition(); 214 ReserveOnePosition();
210 _items[_size] = item; 215 const unsigned size = _size;
211 return _size++; 216 _size = size + 1;
217 _items[size] = item;
218 return size;
219 }
220
221 /*
222 unsigned Add2(const T &item)
223 {
224 ReserveOnePosition();
225 const unsigned size = _size;
226 _size = size + 1;
227 _items[size] = item;
228 return size;
212 } 229 }
230 */
213 231
214 void AddInReserved(const T item) 232 unsigned AddInReserved(const T item)
215 { 233 {
216 _items[_size++] = item; 234 const unsigned size = _size;
235 _size = size + 1;
236 _items[size] = item;
237 return size;
217 } 238 }
218 239
219 void Insert(unsigned index, const T item) 240 void Insert(unsigned index, const T item)
@@ -224,6 +245,13 @@ public:
224 _size++; 245 _size++;
225 } 246 }
226 247
248 void InsertInReserved(unsigned index, const T item)
249 {
250 MoveItems(index + 1, index);
251 _items[index] = item;
252 _size++;
253 }
254
227 void MoveToFront(unsigned index) 255 void MoveToFront(unsigned index)
228 { 256 {
229 if (index != 0) 257 if (index != 0)
@@ -254,7 +282,8 @@ public:
254 { 282 {
255 while (left != right) 283 while (left != right)
256 { 284 {
257 unsigned mid = (left + right) / 2; 285 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
286 const unsigned mid = (left + right) / 2;
258 const T midVal = (*this)[mid]; 287 const T midVal = (*this)[mid];
259 if (item == midVal) 288 if (item == midVal)
260 return (int)mid; 289 return (int)mid;
@@ -270,9 +299,10 @@ public:
270 { 299 {
271 while (left != right) 300 while (left != right)
272 { 301 {
273 unsigned mid = (left + right) / 2; 302 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
303 const unsigned mid = (left + right) / 2;
274 const T& midVal = (*this)[mid]; 304 const T& midVal = (*this)[mid];
275 int comp = item.Compare(midVal); 305 const int comp = item.Compare(midVal);
276 if (comp == 0) 306 if (comp == 0)
277 return (int)mid; 307 return (int)mid;
278 if (comp < 0) 308 if (comp < 0)
@@ -298,7 +328,8 @@ public:
298 unsigned left = 0, right = _size; 328 unsigned left = 0, right = _size;
299 while (left != right) 329 while (left != right)
300 { 330 {
301 unsigned mid = (left + right) / 2; 331 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
332 const unsigned mid = (left + right) / 2;
302 const T midVal = (*this)[mid]; 333 const T midVal = (*this)[mid];
303 if (item == midVal) 334 if (item == midVal)
304 return mid; 335 return mid;
@@ -316,9 +347,10 @@ public:
316 unsigned left = 0, right = _size; 347 unsigned left = 0, right = _size;
317 while (left != right) 348 while (left != right)
318 { 349 {
319 unsigned mid = (left + right) / 2; 350 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
351 const unsigned mid = (left + right) / 2;
320 const T& midVal = (*this)[mid]; 352 const T& midVal = (*this)[mid];
321 int comp = item.Compare(midVal); 353 const int comp = item.Compare(midVal);
322 if (comp == 0) 354 if (comp == 0)
323 return mid; 355 return mid;
324 if (comp < 0) 356 if (comp < 0)
@@ -431,29 +463,35 @@ public:
431 CObjectVector() {} 463 CObjectVector() {}
432 CObjectVector(const CObjectVector &v) 464 CObjectVector(const CObjectVector &v)
433 { 465 {
434 unsigned size = v.Size(); 466 const unsigned size = v.Size();
435 _v.ConstructReserve(size); 467 _v.ConstructReserve(size);
436 for (unsigned i = 0; i < size; i++) 468 for (unsigned i = 0; i < size; i++)
437 _v.AddInReserved(new T(v[i])); 469 AddInReserved(v[i]);
438 } 470 }
439 CObjectVector& operator=(const CObjectVector &v) 471 CObjectVector& operator=(const CObjectVector &v)
440 { 472 {
441 if (&v == this) 473 if (&v == this)
442 return *this; 474 return *this;
443 Clear(); 475 Clear();
444 unsigned size = v.Size(); 476 const unsigned size = v.Size();
445 _v.Reserve(size); 477 _v.Reserve(size);
446 for (unsigned i = 0; i < size; i++) 478 for (unsigned i = 0; i < size; i++)
447 _v.AddInReserved(new T(v[i])); 479 AddInReserved(v[i]);
448 return *this; 480 return *this;
449 } 481 }
450 482
451 CObjectVector& operator+=(const CObjectVector &v) 483 CObjectVector& operator+=(const CObjectVector &v)
452 { 484 {
453 unsigned size = v.Size(); 485 const unsigned addSize = v.Size();
454 _v.Reserve(Size() + size); 486 if (addSize != 0)
455 for (unsigned i = 0; i < size; i++) 487 {
456 _v.AddInReserved(new T(v[i])); 488 const unsigned size = Size();
489 if (size >= k_VectorSizeMax || addSize > k_VectorSizeMax - size)
490 throw 2021;
491 _v.Reserve(size + addSize);
492 for (unsigned i = 0; i < addSize; i++)
493 AddInReserved(v[i]);
494 }
457 return *this; 495 return *this;
458 } 496 }
459 497
@@ -466,14 +504,37 @@ public:
466 504
467 void MoveToFront(unsigned index) { _v.MoveToFront(index); } 505 void MoveToFront(unsigned index) { _v.MoveToFront(index); }
468 506
469 unsigned Add(const T& item) { return _v.Add(new T(item)); } 507 unsigned Add(const T& item)
508 {
509 _v.ReserveOnePosition();
510 return AddInReserved(item);
511 }
512
513 unsigned AddInReserved(const T& item)
514 {
515 return _v.AddInReserved(new T(item));
516 }
517
518 void ReserveOnePosition()
519 {
520 _v.ReserveOnePosition();
521 }
522
523 unsigned AddInReserved_Ptr_of_new(T *ptr)
524 {
525 return _v.AddInReserved(ptr);
526 }
527
528 #define VECTOR_ADD_NEW_OBJECT(v, a) \
529 (v).ReserveOnePosition(); \
530 (v).AddInReserved_Ptr_of_new(new a);
470 531
471 void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); }
472 532
473 T& AddNew() 533 T& AddNew()
474 { 534 {
535 _v.ReserveOnePosition();
475 T *p = new T; 536 T *p = new T;
476 _v.Add(p); 537 _v.AddInReserved(p);
477 return *p; 538 return *p;
478 } 539 }
479 540
@@ -484,12 +545,17 @@ public:
484 return *p; 545 return *p;
485 } 546 }
486 547
487 void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); } 548 void Insert(unsigned index, const T& item)
549 {
550 _v.ReserveOnePosition();
551 _v.InsertInReserved(index, new T(item));
552 }
488 553
489 T& InsertNew(unsigned index) 554 T& InsertNew(unsigned index)
490 { 555 {
556 _v.ReserveOnePosition();
491 T *p = new T; 557 T *p = new T;
492 _v.Insert(index, p); 558 _v.InsertInReserved(index, p);
493 return *p; 559 return *p;
494 } 560 }
495 561
@@ -514,7 +580,7 @@ public:
514 580
515 void DeleteFrom(unsigned index) 581 void DeleteFrom(unsigned index)
516 { 582 {
517 unsigned size = _v.Size(); 583 const unsigned size = _v.Size();
518 for (unsigned i = index; i < size; i++) 584 for (unsigned i = index; i < size; i++)
519 delete (T *)_v[i]; 585 delete (T *)_v[i];
520 _v.DeleteFrom(index); 586 _v.DeleteFrom(index);
@@ -564,9 +630,10 @@ public:
564 unsigned left = 0, right = Size(); 630 unsigned left = 0, right = Size();
565 while (left != right) 631 while (left != right)
566 { 632 {
567 unsigned mid = (left + right) / 2; 633 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
634 const unsigned mid = (left + right) / 2;
568 const T& midVal = (*this)[mid]; 635 const T& midVal = (*this)[mid];
569 int comp = item.Compare(midVal); 636 const int comp = item.Compare(midVal);
570 if (comp == 0) 637 if (comp == 0)
571 return (int)mid; 638 return (int)mid;
572 if (comp < 0) 639 if (comp < 0)
@@ -582,9 +649,10 @@ public:
582 unsigned left = 0, right = Size(); 649 unsigned left = 0, right = Size();
583 while (left != right) 650 while (left != right)
584 { 651 {
585 unsigned mid = (left + right) / 2; 652 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
653 const unsigned mid = (left + right) / 2;
586 const T& midVal = (*this)[mid]; 654 const T& midVal = (*this)[mid];
587 int comp = item.Compare(midVal); 655 const int comp = item.Compare(midVal);
588 if (comp == 0) 656 if (comp == 0)
589 return mid; 657 return mid;
590 if (comp < 0) 658 if (comp < 0)
@@ -602,9 +670,10 @@ public:
602 unsigned left = 0, right = Size(); 670 unsigned left = 0, right = Size();
603 while (left != right) 671 while (left != right)
604 { 672 {
605 unsigned mid = (left + right) / 2; 673 // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
674 const unsigned mid = (left + right) / 2;
606 const T& midVal = (*this)[mid]; 675 const T& midVal = (*this)[mid];
607 int comp = item.Compare(midVal); 676 const int comp = item.Compare(midVal);
608 if (comp == 0) 677 if (comp == 0)
609 { 678 {
610 right = mid + 1; 679 right = mid + 1;
diff --git a/CPP/Common/MyWindows.h b/CPP/Common/MyWindows.h
index 0664a5e..15db524 100644
--- a/CPP/Common/MyWindows.h
+++ b/CPP/Common/MyWindows.h
@@ -76,7 +76,6 @@ typedef struct _FILETIME
76 DWORD dwHighDateTime; 76 DWORD dwHighDateTime;
77} FILETIME; 77} FILETIME;
78 78
79#define HRESULT LONG
80#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) 79#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
81#define FAILED(hr) ((HRESULT)(hr) < 0) 80#define FAILED(hr) ((HRESULT)(hr) < 0)
82typedef ULONG PROPID; 81typedef ULONG PROPID;
@@ -150,6 +149,7 @@ enum VARENUM
150 VT_VARIANT = 12, 149 VT_VARIANT = 12,
151 VT_UNKNOWN = 13, 150 VT_UNKNOWN = 13,
152 VT_DECIMAL = 14, 151 VT_DECIMAL = 14,
152
153 VT_I1 = 16, 153 VT_I1 = 16,
154 VT_UI1 = 17, 154 VT_UI1 = 17,
155 VT_UI2 = 18, 155 VT_UI2 = 18,
diff --git a/CPP/Common/NewHandler.cpp b/CPP/Common/NewHandler.cpp
index 7e5b1d4..65ef41d 100644
--- a/CPP/Common/NewHandler.cpp
+++ b/CPP/Common/NewHandler.cpp
@@ -97,19 +97,33 @@ const int kDebugSize = 1000000;
97static void *a[kDebugSize]; 97static void *a[kDebugSize];
98static int index = 0; 98static int index = 0;
99 99
100static bool wasInit = false;
101static CRITICAL_SECTION cs;
102
100static int numAllocs = 0; 103static int numAllocs = 0;
101void * __cdecl operator new(size_t size) 104void * __cdecl operator new(size_t size)
102{ 105{
106 if (!wasInit)
107 {
108 InitializeCriticalSection(&cs);
109 wasInit = true;
110 }
111 EnterCriticalSection(&cs);
112
103 numAllocs++; 113 numAllocs++;
114 int loc = numAllocs;
104 void *p = HeapAlloc(GetProcessHeap(), 0, size); 115 void *p = HeapAlloc(GetProcessHeap(), 0, size);
116 /*
105 if (index < kDebugSize) 117 if (index < kDebugSize)
106 { 118 {
107 a[index] = p; 119 a[index] = p;
108 index++; 120 index++;
109 } 121 }
122 */
123 printf("Alloc %6d, size = %8u\n", loc, (unsigned)size);
124 LeaveCriticalSection(&cs);
110 if (p == 0) 125 if (p == 0)
111 throw CNewException(); 126 throw CNewException();
112 printf("Alloc %6d, size = %8u\n", numAllocs, (unsigned)size);
113 return p; 127 return p;
114} 128}
115 129
@@ -123,6 +137,7 @@ public:
123 } 137 }
124 ~CC() 138 ~CC()
125 { 139 {
140 printf("\nDestructor: %d\n", numAllocs);
126 for (int i = 0; i < kDebugSize; i++) 141 for (int i = 0; i < kDebugSize; i++)
127 if (a[i] != 0) 142 if (a[i] != 0)
128 return; 143 return;
@@ -134,6 +149,7 @@ void __cdecl operator delete(void *p)
134{ 149{
135 if (p == 0) 150 if (p == 0)
136 return; 151 return;
152 EnterCriticalSection(&cs);
137 /* 153 /*
138 for (int i = 0; i < index; i++) 154 for (int i = 0; i < index; i++)
139 if (a[i] == p) 155 if (a[i] == p)
@@ -142,6 +158,7 @@ void __cdecl operator delete(void *p)
142 HeapFree(GetProcessHeap(), 0, p); 158 HeapFree(GetProcessHeap(), 0, p);
143 numAllocs--; 159 numAllocs--;
144 printf("Free %d\n", numAllocs); 160 printf("Free %d\n", numAllocs);
161 LeaveCriticalSection(&cs);
145} 162}
146 163
147#endif 164#endif
diff --git a/CPP/Common/StringToInt.cpp b/CPP/Common/StringToInt.cpp
index 839867a..bc4926e 100644
--- a/CPP/Common/StringToInt.cpp
+++ b/CPP/Common/StringToInt.cpp
@@ -26,6 +26,33 @@ CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t)
26CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte) 26CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte)
27CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t) 27CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t)
28 28
29/*
30Int32 ConvertStringToInt32(const char *s, const char **end) throw()
31{
32 if (end)
33 *end = s;
34 const char *s2 = s;
35 if (*s == '-')
36 s2++;
37 if (*s2 == 0)
38 return 0;
39 const char *end2;
40 UInt32 res = ConvertStringToUInt32(s2, &end2);
41 if (*s == '-')
42 {
43 if (res > ((UInt32)1 << (32 - 1)))
44 return 0;
45 }
46 else if ((res & ((UInt32)1 << (32 - 1))) != 0)
47 return 0;
48 if (end)
49 *end = end2;
50 if (*s == '-')
51 return -(Int32)res;
52 return (Int32)res;
53}
54*/
55
29Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() 56Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw()
30{ 57{
31 if (end) 58 if (end)
diff --git a/CPP/Common/StringToInt.h b/CPP/Common/StringToInt.h
index 5c5d7d7..4057e49 100644
--- a/CPP/Common/StringToInt.h
+++ b/CPP/Common/StringToInt.h
@@ -10,6 +10,7 @@ UInt64 ConvertStringToUInt64(const char *s, const char **end) throw();
10UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); 10UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw();
11UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); 11UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw();
12 12
13// Int32 ConvertStringToInt32(const char *s, const char **end) throw();
13Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); 14Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw();
14 15
15UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); 16UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw();
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
index 8a33fc8..cce2638 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -17,7 +17,6 @@
17 17
18#include "../Common/StringConvert.h" 18#include "../Common/StringConvert.h"
19#include "../Common/C_FileIO.h" 19#include "../Common/C_FileIO.h"
20#include "TimeUtils.h"
21#endif 20#endif
22 21
23#include "FileDir.h" 22#include "FileDir.h"
@@ -32,6 +31,30 @@ using namespace NWindows;
32using namespace NFile; 31using namespace NFile;
33using namespace NName; 32using namespace NName;
34 33
34#ifndef _WIN32
35
36static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts)
37{
38 if (ft)
39 {
40 ts = *ft;
41 return true;
42 }
43 // else
44 {
45 ts.tv_sec = 0;
46 ts.tv_nsec =
47 #ifdef UTIME_OMIT
48 UTIME_OMIT; // -2 keep old timesptamp
49 #else
50 // UTIME_NOW; -1 // set to the current time
51 0;
52 #endif
53 return false;
54 }
55}
56#endif
57
35namespace NWindows { 58namespace NWindows {
36namespace NFile { 59namespace NFile {
37namespace NDir { 60namespace NDir {
@@ -86,7 +109,7 @@ bool GetSystemDir(FString &path)
86#endif // UNDER_CE 109#endif // UNDER_CE
87 110
88 111
89bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) 112bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
90{ 113{
91 #ifndef _UNICODE 114 #ifndef _UNICODE
92 if (!g_IsNT) 115 if (!g_IsNT)
@@ -920,39 +943,11 @@ bool GetCurrentDir(FString &path)
920 // #define UTIME_OMIT -2 943 // #define UTIME_OMIT -2
921#endif 944#endif
922 945
923static bool FILETME_To_timespec(const FILETIME *ft, timespec &ts)
924{
925 if (ft)
926 {
927 const Int64 sec = NTime::FileTimeToUnixTime64(*ft);
928 // time_t is long
929 const time_t sec2 = (time_t)sec;
930 if (sec2 == sec)
931 {
932 ts.tv_sec = sec2;
933 const UInt64 winTime = (((UInt64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
934 ts.tv_nsec = (long)((winTime % 10000000) * 100);
935 return true;
936 }
937 }
938 // else
939 {
940 ts.tv_sec = 0;
941 ts.tv_nsec =
942 #ifdef UTIME_OMIT
943 UTIME_OMIT; // keep old timesptamp
944 #else
945 // UTIME_NOW; // set to the current time
946 0;
947 #endif
948 return false;
949 }
950}
951 946
952 947
953 948
954 949
955bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) 950bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
956{ 951{
957 // need testing 952 // need testing
958 /* 953 /*
@@ -998,12 +993,18 @@ bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const
998 UNUSED_VAR(cTime) 993 UNUSED_VAR(cTime)
999 994
1000 bool needChange; 995 bool needChange;
1001 needChange = FILETME_To_timespec(aTime, times[0]); 996 needChange = FiTime_To_timespec(aTime, times[0]);
1002 needChange |= FILETME_To_timespec(mTime, times[1]); 997 needChange |= FiTime_To_timespec(mTime, times[1]);
998
999 /*
1000 if (mTime)
1001 {
1002 printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec);
1003 }
1004 */
1003 1005
1004 if (!needChange) 1006 if (!needChange)
1005 return true; 1007 return true;
1006
1007 const int flags = 0; // follow link 1008 const int flags = 0; // follow link
1008 // = AT_SYMLINK_NOFOLLOW; // don't follow link 1009 // = AT_SYMLINK_NOFOLLOW; // don't follow link
1009 return utimensat(AT_FDCWD, path, times, flags) == 0; 1010 return utimensat(AT_FDCWD, path, times, flags) == 0;
@@ -1039,6 +1040,10 @@ static C_umask g_umask;
1039#define TRACE_chmod(s, mode) \ 1040#define TRACE_chmod(s, mode) \
1040 PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode))); 1041 PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode)));
1041 1042
1043int my_chown(CFSTR path, uid_t owner, gid_t group)
1044{
1045 return chown(path, owner, group);
1046}
1042 1047
1043bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) 1048bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
1044{ 1049{
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 6d6ddea..08281aa 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -14,7 +14,12 @@ namespace NDir {
14bool GetWindowsDir(FString &path); 14bool GetWindowsDir(FString &path);
15bool GetSystemDir(FString &path); 15bool GetSystemDir(FString &path);
16 16
17bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); 17/*
18WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file
19but linux : allows unix time = 0 in filesystem
20*/
21
22bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
18 23
19 24
20#ifdef _WIN32 25#ifdef _WIN32
@@ -27,6 +32,9 @@ bool SetFileAttrib(CFSTR path, DWORD attrib);
27 SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute 32 SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute
28 bits that are related to current system only. 33 bits that are related to current system only.
29*/ 34*/
35#else
36
37int my_chown(CFSTR path, uid_t owner, gid_t group);
30 38
31#endif 39#endif
32 40
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp
index 591f8df..c655759 100644
--- a/CPP/Windows/FileFind.cpp
+++ b/CPP/Windows/FileFind.cpp
@@ -7,6 +7,8 @@
7#ifndef _WIN32 7#ifndef _WIN32
8#include <fcntl.h> /* Definition of AT_* constants */ 8#include <fcntl.h> /* Definition of AT_* constants */
9#include "TimeUtils.h" 9#include "TimeUtils.h"
10// for major
11// #include <sys/sysmacros.h>
10#endif 12#endif
11 13
12#include "FileFind.h" 14#include "FileFind.h"
@@ -62,24 +64,35 @@ bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize,
62 64
63namespace NFind { 65namespace NFind {
64 66
67/*
68#ifdef _WIN32
65#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; 69#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0;
70#else
71#define MY_CLEAR_FILETIME(ft) ft.tv_sec = 0; ft.tv_nsec = 0;
72#endif
73*/
66 74
67void CFileInfoBase::ClearBase() throw() 75void CFileInfoBase::ClearBase() throw()
68{ 76{
69 Size = 0; 77 Size = 0;
70 MY_CLEAR_FILETIME(CTime); 78 FiTime_Clear(CTime);
71 MY_CLEAR_FILETIME(ATime); 79 FiTime_Clear(ATime);
72 MY_CLEAR_FILETIME(MTime); 80 FiTime_Clear(MTime);
81
82 #ifdef _WIN32
73 Attrib = 0; 83 Attrib = 0;
74 // ReparseTag = 0; 84 // ReparseTag = 0;
75 IsAltStream = false; 85 IsAltStream = false;
76 IsDevice = false; 86 IsDevice = false;
77 87 #else
78 #ifndef _WIN32 88 dev = 0;
79 ino = 0; 89 ino = 0;
80 nlink = 0;
81 mode = 0; 90 mode = 0;
82 #endif 91 nlink = 0;
92 uid = 0;
93 gid = 0;
94 rdev = 0;
95 #endif
83} 96}
84 97
85bool CFileInfo::IsDots() const throw() 98bool CFileInfo::IsDots() const throw()
@@ -439,6 +452,20 @@ also we support paths that are not supported by FindFirstFile:
439bool CFileInfo::Find(CFSTR path, bool followLink) 452bool CFileInfo::Find(CFSTR path, bool followLink)
440{ 453{
441 #ifdef SUPPORT_DEVICE_FILE 454 #ifdef SUPPORT_DEVICE_FILE
455
456 if (IS_PATH_SEPAR(path[0]) &&
457 IS_PATH_SEPAR(path[1]) &&
458 path[2] == '.' &&
459 path[3] == 0)
460 {
461 // 22.00 : it's virtual directory for devices
462 // IsDevice = true;
463 ClearBase();
464 Name = path + 2;
465 Attrib = FILE_ATTRIBUTE_DIRECTORY;
466 return true;
467 }
468
442 if (IsDevicePath(path)) 469 if (IsDevicePath(path))
443 { 470 {
444 ClearBase(); 471 ClearBase();
@@ -469,7 +496,7 @@ bool CFileInfo::Find(CFSTR path, bool followLink)
469 496
470 #if defined(_WIN32) && !defined(UNDER_CE) 497 #if defined(_WIN32) && !defined(UNDER_CE)
471 498
472 int colonPos = FindAltStreamColon(path); 499 const int colonPos = FindAltStreamColon(path);
473 if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) 500 if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0)
474 { 501 {
475 UString streamName = fs2us(path + (unsigned)colonPos); 502 UString streamName = fs2us(path + (unsigned)colonPos);
@@ -635,7 +662,7 @@ bool CFileInfo::Find(CFSTR path, bool followLink)
635 return Fill_From_ByHandleFileInfo(path); 662 return Fill_From_ByHandleFileInfo(path);
636} 663}
637 664
638bool CFileInfo::Fill_From_ByHandleFileInfo(CFSTR path) 665bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path)
639{ 666{
640 BY_HANDLE_FILE_INFORMATION info; 667 BY_HANDLE_FILE_INFORMATION info;
641 if (!NIO::CFileBase::GetFileInformation(path, &info)) 668 if (!NIO::CFileBase::GetFileInformation(path, &info))
@@ -950,13 +977,6 @@ static const char *Get_Name_from_Path(CFSTR path) throw()
950} 977}
951 978
952 979
953void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft)
954{
955 UInt64 v = NTime::UnixTime64ToFileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
956 ft.dwLowDateTime = (DWORD)v;
957 ft.dwHighDateTime = (DWORD)(v >> 32);
958}
959
960UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) 980UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode)
961{ 981{
962 UInt32 attrib = S_ISDIR(mode) ? 982 UInt32 attrib = S_ISDIR(mode) ?
@@ -984,7 +1004,7 @@ UInt32 Get_WinAttrib_From_stat(const struct stat &st)
984 1004
985void CFileInfo::SetFrom_stat(const struct stat &st) 1005void CFileInfo::SetFrom_stat(const struct stat &st)
986{ 1006{
987 IsDevice = false; 1007 // IsDevice = false;
988 1008
989 if (S_ISDIR(st.st_mode)) 1009 if (S_ISDIR(st.st_mode))
990 { 1010 {
@@ -995,7 +1015,7 @@ void CFileInfo::SetFrom_stat(const struct stat &st)
995 Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename 1015 Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename
996 } 1016 }
997 1017
998 Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); 1018 // Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode);
999 1019
1000 // NTime::UnixTimeToFileTime(st.st_ctime, CTime); 1020 // NTime::UnixTimeToFileTime(st.st_ctime, CTime);
1001 // NTime::UnixTimeToFileTime(st.st_mtime, MTime); 1021 // NTime::UnixTimeToFileTime(st.st_mtime, MTime);
@@ -1010,27 +1030,89 @@ void CFileInfo::SetFrom_stat(const struct stat &st)
1010 */ 1030 */
1011 // timespec_To_FILETIME(st.st_birthtimespec, CTime); 1031 // timespec_To_FILETIME(st.st_birthtimespec, CTime);
1012 // #else 1032 // #else
1013 timespec_To_FILETIME(st.st_ctimespec, CTime); 1033 // timespec_To_FILETIME(st.st_ctimespec, CTime);
1014 // #endif 1034 // #endif
1015 timespec_To_FILETIME(st.st_mtimespec, MTime); 1035 // timespec_To_FILETIME(st.st_mtimespec, MTime);
1016 timespec_To_FILETIME(st.st_atimespec, ATime); 1036 // timespec_To_FILETIME(st.st_atimespec, ATime);
1037 CTime = st.st_ctimespec;
1038 MTime = st.st_mtimespec;
1039 ATime = st.st_atimespec;
1040
1017 #else 1041 #else
1018 timespec_To_FILETIME(st.st_ctim, CTime); 1042 // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100);
1019 timespec_To_FILETIME(st.st_mtim, MTime); 1043 // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100);
1020 timespec_To_FILETIME(st.st_atim, ATime); 1044 // timespec_To_FILETIME(st.st_atim, ATime, &ATime_ns100);
1045 CTime = st.st_ctim;
1046 MTime = st.st_mtim;
1047 ATime = st.st_atim;
1048
1021 #endif 1049 #endif
1022 1050
1023 dev = st.st_dev; 1051 dev = st.st_dev;
1024 ino = st.st_ino; 1052 ino = st.st_ino;
1025 nlink = st.st_nlink;
1026 mode = st.st_mode; 1053 mode = st.st_mode;
1054 nlink = st.st_nlink;
1055 uid = st.st_uid;
1056 gid = st.st_gid;
1057 rdev = st.st_rdev;
1058
1059 /*
1060 printf("\n sizeof timespec = %d", (int)sizeof(timespec));
1061 printf("\n sizeof st_rdev = %d", (int)sizeof(rdev));
1062 printf("\n sizeof st_ino = %d", (int)sizeof(ino));
1063 printf("\n sizeof mode_t = %d", (int)sizeof(mode_t));
1064 printf("\n sizeof nlink_t = %d", (int)sizeof(nlink_t));
1065 printf("\n sizeof uid_t = %d", (int)sizeof(uid_t));
1066 printf("\n");
1067 */
1068 /*
1069 printf("\n st_rdev = %llx", (long long)rdev);
1070 printf("\n st_dev = %llx", (long long)dev);
1071 printf("\n dev : major = %5x minor = %5x", (unsigned)major(dev), (unsigned)minor(dev));
1072 printf("\n st_ino = %lld", (long long)(ino));
1073 printf("\n rdev : major = %5x minor = %5x", (unsigned)major(rdev), (unsigned)minor(rdev));
1074 printf("\n size = %lld \n", (long long)(Size));
1075 printf("\n");
1076 */
1077}
1078
1079/*
1080int Uid_To_Uname(uid_t uid, AString &name)
1081{
1082 name.Empty();
1083 struct passwd *passwd;
1084
1085 if (uid != 0 && uid == cached_no_such_uid)
1086 {
1087 *uname = xstrdup ("");
1088 return;
1089 }
1090
1091 if (!cached_uname || uid != cached_uid)
1092 {
1093 passwd = getpwuid (uid);
1094 if (passwd)
1095 {
1096 cached_uid = uid;
1097 assign_string (&cached_uname, passwd->pw_name);
1098 }
1099 else
1100 {
1101 cached_no_such_uid = uid;
1102 *uname = xstrdup ("");
1103 return;
1104 }
1105 }
1106 *uname = xstrdup (cached_uname);
1027} 1107}
1108*/
1028 1109
1029bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) 1110bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink)
1030{ 1111{
1031 struct stat st; 1112 struct stat st;
1032 if (MY__lstat(path, &st, followLink) != 0) 1113 if (MY__lstat(path, &st, followLink) != 0)
1033 return false; 1114 return false;
1115 // printf("\nFind_DontFill_Name : name=%s\n", path);
1034 SetFrom_stat(st); 1116 SetFrom_stat(st);
1035 return true; 1117 return true;
1036} 1118}
@@ -1232,6 +1314,7 @@ bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool f
1232 1314
1233 if (res != 0) 1315 if (res != 0)
1234 return false; 1316 return false;
1317 // printf("\nname=%s\n", de.Name.Ptr());
1235 fileInfo.SetFrom_stat(st); 1318 fileInfo.SetFrom_stat(st);
1236 fileInfo.Name = de.Name; 1319 fileInfo.Name = de.Name;
1237 return true; 1320 return true;
diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h
index 8f28ee3..fcfe02c 100644
--- a/CPP/Windows/FileFind.h
+++ b/CPP/Windows/FileFind.h
@@ -9,10 +9,14 @@
9#include <dirent.h> 9#include <dirent.h>
10#endif 10#endif
11 11
12#include "../Common/MyLinux.h"
12#include "../Common/MyString.h" 13#include "../Common/MyString.h"
13#include "../Common/MyWindows.h" 14#include "../Common/MyWindows.h"
15
14#include "Defs.h" 16#include "Defs.h"
15 17
18#include "FileIO.h"
19
16namespace NWindows { 20namespace NWindows {
17namespace NFile { 21namespace NFile {
18namespace NFind { 22namespace NFind {
@@ -32,6 +36,7 @@ bool DoesFileOrDirExist(CFSTR name);
32 36
33DWORD GetFileAttrib(CFSTR path); 37DWORD GetFileAttrib(CFSTR path);
34 38
39#ifdef _WIN32
35 40
36namespace NAttributes 41namespace NAttributes
37{ 42{
@@ -42,21 +47,38 @@ namespace NAttributes
42 inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } 47 inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
43 inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } 48 inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
44 inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } 49 inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
50
51 inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib)
52 {
53 UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG;
54 /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY).
55 So extracting at Linux will be allowed to write files inside (0777) directories. */
56 v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777);
57 return v;
58 }
45} 59}
46 60
61#else
62
63UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode);
64
65#endif
66
47class CFileInfoBase 67class CFileInfoBase
48{ 68{
69 #ifdef _WIN32
49 bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } 70 bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
71 #endif
50public: 72public:
51 UInt64 Size; 73 UInt64 Size;
52 FILETIME CTime; 74 CFiTime CTime;
53 FILETIME ATime; 75 CFiTime ATime;
54 FILETIME MTime; 76 CFiTime MTime;
77 #ifdef _WIN32
55 DWORD Attrib; 78 DWORD Attrib;
56 bool IsAltStream; 79 bool IsAltStream;
57 bool IsDevice; 80 bool IsDevice;
58 81
59 #ifdef _WIN32
60 /* 82 /*
61 #ifdef UNDER_CE 83 #ifdef UNDER_CE
62 DWORD ObjectID; 84 DWORD ObjectID;
@@ -64,24 +86,25 @@ public:
64 UINT32 ReparseTag; 86 UINT32 ReparseTag;
65 #endif 87 #endif
66 */ 88 */
67 #else 89 #else
68 dev_t dev; 90 dev_t dev; /* ID of device containing file */
69 ino_t ino; 91 ino_t ino;
70 nlink_t nlink;
71 mode_t mode; 92 mode_t mode;
93 nlink_t nlink;
94 uid_t uid; /* user ID of owner */
95 gid_t gid; /* group ID of owner */
96 dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */
72 // bool Use_lstat; 97 // bool Use_lstat;
73 #endif 98 #endif
74 99
75 CFileInfoBase() { ClearBase(); } 100 CFileInfoBase() { ClearBase(); }
76 void ClearBase() throw(); 101 void ClearBase() throw();
77 102
78 void SetAsDir() 103 #ifdef _WIN32
79 { 104
80 Attrib = FILE_ATTRIBUTE_DIRECTORY; 105 bool Fill_From_ByHandleFileInfo(CFSTR path);
81 #ifndef _WIN32 106 void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16));
82 Attrib |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); 107 void SetAsFile() { Attrib = 0; }
83 #endif
84 }
85 108
86 bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } 109 bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
87 bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } 110 bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
@@ -96,13 +119,33 @@ public:
96 bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } 119 bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
97 bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } 120 bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
98 121
99 #ifndef _WIN32 122 UInt32 GetWinAttrib() const { return Attrib; }
100 bool IsPosixLink() const 123 UInt32 GetPosixAttrib() const
101 { 124 {
102 const UInt32 mod = Attrib >> 16; 125 return NAttributes::Get_PosixMode_From_WinAttrib(Attrib);
103 return S_ISLNK(mod);
104 } 126 }
105 #endif 127 bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; }
128
129 #else
130
131 UInt32 GetPosixAttrib() const { return mode; }
132 UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); }
133
134 bool IsDir() const { return S_ISDIR(mode); }
135 void SetAsDir() { mode = S_IFDIR; }
136 void SetAsFile() { mode = S_IFREG; }
137
138 bool IsReadOnly() const
139 {
140 // does linux support writing to ReadOnly files?
141 if ((mode & 0222) == 0) // S_IWUSR in p7zip
142 return true;
143 return false;
144 }
145
146 bool IsPosixLink() const { return S_ISLNK(mode); }
147
148 #endif
106 149
107 bool IsOsSymLink() const 150 bool IsOsSymLink() const
108 { 151 {
@@ -126,7 +169,7 @@ struct CFileInfo: public CFileInfoBase
126 bool Find_FollowLink(CFSTR path) { return Find(path, true); } 169 bool Find_FollowLink(CFSTR path) { return Find(path, true); }
127 170
128 #ifdef _WIN32 171 #ifdef _WIN32
129 bool Fill_From_ByHandleFileInfo(CFSTR path); 172 // bool Fill_From_ByHandleFileInfo(CFSTR path);
130 // bool FollowReparse(CFSTR path, bool isDir); 173 // bool FollowReparse(CFSTR path, bool isDir);
131 #else 174 #else
132 bool Find_DontFill_Name(CFSTR path, bool followLink = false); 175 bool Find_DontFill_Name(CFSTR path, bool followLink = false);
@@ -287,16 +330,8 @@ inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode)
287} 330}
288*/ 331*/
289 332
290UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode);
291
292// UInt32 Get_WinAttrib_From_stat(const struct stat &st); 333// UInt32 Get_WinAttrib_From_stat(const struct stat &st);
293#if defined(_AIX)
294 #define MY_ST_TIMESPEC st_timespec
295#else
296 #define MY_ST_TIMESPEC timespec
297#endif
298 334
299void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft);
300 335
301#endif // WIN32 336#endif // WIN32
302 337
diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp
index 2974b1b..e51b0eb 100644
--- a/CPP/Windows/FileIO.cpp
+++ b/CPP/Windows/FileIO.cpp
@@ -8,6 +8,14 @@
8 8
9// #include <stdio.h> 9// #include <stdio.h>
10 10
11/*
12#ifndef _WIN32
13// for ioctl BLKGETSIZE64
14#include <sys/ioctl.h>
15#include <linux/fs.h>
16#endif
17*/
18
11#include "FileIO.h" 19#include "FileIO.h"
12#include "FileName.h" 20#include "FileName.h"
13 21
@@ -615,7 +623,7 @@ namespace NWindows {
615namespace NFile { 623namespace NFile {
616 624
617namespace NDir { 625namespace NDir {
618bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); 626bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
619} 627}
620 628
621namespace NIO { 629namespace NIO {
@@ -629,6 +637,19 @@ bool CFileBase::OpenBinary(const char *name, int flags)
629 Close(); 637 Close();
630 _handle = ::open(name, flags, 0666); 638 _handle = ::open(name, flags, 0666);
631 return _handle != -1; 639 return _handle != -1;
640
641 /*
642 if (_handle == -1)
643 return false;
644 if (IsString1PrefixedByString2(name, "/dev/"))
645 {
646 // /dev/sda
647 // IsDeviceFile = true; // for debug
648 // SizeDefined = false;
649 // SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
650 }
651 return true;
652 */
632} 653}
633 654
634bool CFileBase::Close() 655bool CFileBase::Close()
@@ -638,6 +659,10 @@ bool CFileBase::Close()
638 if (close(_handle) != 0) 659 if (close(_handle) != 0)
639 return false; 660 return false;
640 _handle = -1; 661 _handle = -1;
662 /*
663 IsDeviceFile = false;
664 SizeDefined = false;
665 */
641 return true; 666 return true;
642} 667}
643 668
@@ -651,15 +676,35 @@ bool CFileBase::GetLength(UInt64 &length) const
651 const off_t lengthTemp = seek(0, SEEK_END); 676 const off_t lengthTemp = seek(0, SEEK_END);
652 seek(curPos, SEEK_SET); 677 seek(curPos, SEEK_SET);
653 length = (UInt64)lengthTemp; 678 length = (UInt64)lengthTemp;
679
680 /*
681 // 22.00:
682 if (lengthTemp == 1)
683 if (IsDeviceFile && SizeDefined)
684 {
685 length = Size;
686 return true;
687 }
688 */
689
654 return (lengthTemp != -1); 690 return (lengthTemp != -1);
655} 691}
656 692
657off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const 693off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
658{ 694{
695 /*
696 if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
697 {
698 printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
699 distanceToMove += Size;
700 moveMethod = SEEK_SET;
701 }
702 */
703
659 // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove); 704 // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
660 // off_t res = ::lseek(_handle, distanceToMove, moveMethod); 705 // off_t res = ::lseek(_handle, distanceToMove, moveMethod);
706 // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
661 return ::lseek(_handle, distanceToMove, moveMethod); 707 return ::lseek(_handle, distanceToMove, moveMethod);
662 // printf(" res = %lld", (long long)res);
663 // return res; 708 // return res;
664} 709}
665 710
@@ -694,6 +739,28 @@ bool CInFile::OpenShared(const char *name, bool)
694 return Open(name); 739 return Open(name);
695} 740}
696 741
742
743/*
744int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
745{
746 // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
747 // #include <linux/fs.h>
748 return ioctl(_handle, BLKGETSIZE64, numBlocks);
749 // in block size
750}
751
752int CFileBase::GetDeviceSize_InBytes(UInt64 &size)
753{
754 size = 0;
755 unsigned long long numBlocks;
756 int res = my_ioctl_BLKGETSIZE64(&numBlocks);
757 if (res == 0)
758 size = numBlocks; // another blockSize s possible?
759 printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
760 return res;
761}
762*/
763
697/* 764/*
698On Linux (32-bit and 64-bit): 765On Linux (32-bit and 64-bit):
699read(), write() (and similar system calls) will transfer at most 766read(), write() (and similar system calls) will transfer at most
@@ -802,7 +869,7 @@ bool COutFile::Close()
802 return res; 869 return res;
803} 870}
804 871
805bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() 872bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
806{ 873{
807 // On some OS (cygwin, MacOSX ...), you must close the file before updating times 874 // On some OS (cygwin, MacOSX ...), you must close the file before updating times
808 // return true; 875 // return true;
@@ -811,9 +878,22 @@ bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILET
811 if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false; 878 if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
812 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; 879 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
813 return true; 880 return true;
881
882 /*
883 struct timespec times[2];
884 UNUSED_VAR(cTime)
885 if (!aTime && !mTime)
886 return true;
887 bool needChange;
888 needChange = FiTime_To_timespec(aTime, times[0]);
889 needChange |= FiTime_To_timespec(mTime, times[1]);
890 if (!needChange)
891 return true;
892 return futimens(_handle, times) == 0;
893 */
814} 894}
815 895
816bool COutFile::SetMTime(const FILETIME *mTime) throw() 896bool COutFile::SetMTime(const CFiTime *mTime) throw()
817{ 897{
818 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; 898 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
819 return true; 899 return true;
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h
index 22998eb..8050965 100644
--- a/CPP/Windows/FileIO.h
+++ b/CPP/Windows/FileIO.h
@@ -30,6 +30,8 @@
30#include "../Common/MyString.h" 30#include "../Common/MyString.h"
31#include "../Common/MyBuffer.h" 31#include "../Common/MyBuffer.h"
32 32
33#include "../Windows/TimeUtils.h"
34
33#include "Defs.h" 35#include "Defs.h"
34 36
35HRESULT GetLastError_noZero_HRESULT(); 37HRESULT GetLastError_noZero_HRESULT();
@@ -94,6 +96,12 @@ struct CReparseAttr
94 UString GetPath() const; 96 UString GetPath() const;
95}; 97};
96 98
99#ifdef _WIN32
100#define CFiInfo BY_HANDLE_FILE_INFORMATION
101#define ST_MTIME(st) (st).ftLastWriteTime
102#else
103#define CFiInfo stat
104#endif
97 105
98#ifdef _WIN32 106#ifdef _WIN32
99 107
@@ -142,6 +150,8 @@ public:
142 CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {}; 150 CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {};
143 ~CFileBase() { Close(); } 151 ~CFileBase() { Close(); }
144 152
153 HANDLE GetHandle() const { return _handle; }
154
145 bool Close() throw(); 155 bool Close() throw();
146 156
147 bool GetPosition(UInt64 &position) const throw(); 157 bool GetPosition(UInt64 &position) const throw();
@@ -213,6 +223,15 @@ public:
213 223
214 #ifndef UNDER_CE 224 #ifndef UNDER_CE
215 225
226 bool Open_for_ReadAttributes(CFSTR fileName)
227 {
228 return Create(fileName, FILE_READ_ATTRIBUTES,
229 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
230 OPEN_EXISTING,
231 FILE_FLAG_BACKUP_SEMANTICS);
232 // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory.
233 }
234
216 bool OpenReparse(CFSTR fileName) 235 bool OpenReparse(CFSTR fileName)
217 { 236 {
218 // 17.02 fix: to support Windows XP compatibility junctions: 237 // 17.02 fix: to support Windows XP compatibility junctions:
@@ -240,8 +259,8 @@ public:
240 bool Create(CFSTR fileName, bool createAlways); 259 bool Create(CFSTR fileName, bool createAlways);
241 bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes); 260 bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes);
242 261
243 bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); 262 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
244 bool SetMTime(const FILETIME *mTime) throw(); 263 bool SetMTime(const CFiTime *mTime) throw();
245 bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); 264 bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();
246 bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); 265 bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw();
247 bool WriteFull(const void *data, size_t size) throw(); 266 bool WriteFull(const void *data, size_t size) throw();
@@ -270,6 +289,12 @@ class CFileBase
270protected: 289protected:
271 int _handle; 290 int _handle;
272 291
292 /*
293 bool IsDeviceFile;
294 bool SizeDefined;
295 UInt64 Size; // it can be larger than real available size
296 */
297
273 bool OpenBinary(const char *name, int flags); 298 bool OpenBinary(const char *name, int flags);
274public: 299public:
275 bool PreserveATime; 300 bool PreserveATime;
@@ -283,6 +308,11 @@ public:
283 off_t seekToCur() const throw(); 308 off_t seekToCur() const throw();
284 // bool SeekToBegin() throw(); 309 // bool SeekToBegin() throw();
285 int my_fstat(struct stat *st) const { return fstat(_handle, st); } 310 int my_fstat(struct stat *st) const { return fstat(_handle, st); }
311 /*
312 int my_ioctl_BLKGETSIZE64(unsigned long long *val);
313 int GetDeviceSize_InBytes(UInt64 &size);
314 void CalcDeviceSize(CFSTR s);
315 */
286}; 316};
287 317
288class CInFile: public CFileBase 318class CInFile: public CFileBase
@@ -301,9 +331,9 @@ class COutFile: public CFileBase
301 bool ATime_defined; 331 bool ATime_defined;
302 bool MTime_defined; 332 bool MTime_defined;
303 333
304 FILETIME CTime; 334 CFiTime CTime;
305 FILETIME ATime; 335 CFiTime ATime;
306 FILETIME MTime; 336 CFiTime MTime;
307 337
308 AString Path; 338 AString Path;
309 ssize_t write_part(const void *data, size_t size) throw(); 339 ssize_t write_part(const void *data, size_t size) throw();
@@ -333,8 +363,8 @@ public:
333 { 363 {
334 return SetLength(length); 364 return SetLength(length);
335 } 365 }
336 bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); 366 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
337 bool SetMTime(const FILETIME *mTime) throw(); 367 bool SetMTime(const CFiTime *mTime) throw();
338}; 368};
339 369
340} 370}
diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp
index 6e43c7b..2b17950 100644
--- a/CPP/Windows/PropVariant.cpp
+++ b/CPP/Windows/PropVariant.cpp
@@ -193,7 +193,7 @@ BSTR CPropVariant::AllocBstr(unsigned numChars)
193} 193}
194 194
195#define SET_PROP_id_dest(id, dest) \ 195#define SET_PROP_id_dest(id, dest) \
196 if (vt != id) { InternalClear(); vt = id; } dest = value; 196 if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0;
197 197
198void CPropVariant::Set_Int32(Int32 value) throw() 198void CPropVariant::Set_Int32(Int32 value) throw()
199{ 199{
@@ -217,67 +217,83 @@ SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
217// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) 217// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
218SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) 218SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
219 219
220#define CASE_SIMPLE_VT_VALUES \
221 case VT_EMPTY: \
222 case VT_BOOL: \
223 case VT_FILETIME: \
224 case VT_UI8: \
225 case VT_UI4: \
226 case VT_UI2: \
227 case VT_UI1: \
228 case VT_I8: \
229 case VT_I4: \
230 case VT_I2: \
231 case VT_I1: \
232 case VT_UINT: \
233 case VT_INT: \
234 case VT_NULL: \
235 case VT_ERROR: \
236 case VT_R4: \
237 case VT_R8: \
238 case VT_CY: \
239 case VT_DATE: \
240
241
242/*
243 ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME)
244 So we handle VT_FILETIME and another simple types directly
245 we call system functions for VT_BSTR and for unknown typed
246*/
247
248CPropVariant::~CPropVariant()
249{
250 switch ((unsigned)vt)
251 {
252 CASE_SIMPLE_VT_VALUES
253 // vt = VT_EMPTY; // it's optional
254 return;
255 }
256 ::VariantClear((tagVARIANT *)this);
257}
258
220HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() 259HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
221{ 260{
222 switch (prop->vt) 261 switch ((unsigned)prop->vt)
223 { 262 {
224 case VT_EMPTY: 263 CASE_SIMPLE_VT_VALUES
225 case VT_UI1:
226 case VT_I1:
227 case VT_I2:
228 case VT_UI2:
229 case VT_BOOL:
230 case VT_I4:
231 case VT_UI4:
232 case VT_R4:
233 case VT_INT:
234 case VT_UINT:
235 case VT_ERROR:
236 case VT_FILETIME:
237 case VT_UI8:
238 case VT_R8:
239 case VT_CY:
240 case VT_DATE:
241 prop->vt = VT_EMPTY; 264 prop->vt = VT_EMPTY;
242 prop->wReserved1 = 0; 265 break;
243 prop->wReserved2 = 0; 266 default:
244 prop->wReserved3 = 0; 267 {
245 prop->uhVal.QuadPart = 0; 268 const HRESULT res = ::VariantClear((VARIANTARG *)prop);
246 return S_OK; 269 if (res != S_OK || prop->vt != VT_EMPTY)
270 return res;
271 break;
272 }
247 } 273 }
248 return ::VariantClear((VARIANTARG *)prop); 274 prop->wReserved1 = 0;
249 // return ::PropVariantClear(prop); 275 prop->wReserved2 = 0;
250 // PropVariantClear can clear VT_BLOB. 276 prop->wReserved3 = 0;
277 prop->uhVal.QuadPart = 0;
278 return S_OK;
251} 279}
252 280
253HRESULT CPropVariant::Clear() throw() 281HRESULT CPropVariant::Clear() throw()
254{ 282{
255 if (vt == VT_EMPTY) 283 if (vt == VT_EMPTY)
284 {
285 wReserved1 = 0;
256 return S_OK; 286 return S_OK;
287 }
257 return PropVariant_Clear(this); 288 return PropVariant_Clear(this);
258} 289}
259 290
260HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() 291HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
261{ 292{
262 ::VariantClear((tagVARIANT *)this); 293 Clear();
263 switch (pSrc->vt) 294 switch ((unsigned)pSrc->vt)
264 { 295 {
265 case VT_UI1: 296 CASE_SIMPLE_VT_VALUES
266 case VT_I1:
267 case VT_I2:
268 case VT_UI2:
269 case VT_BOOL:
270 case VT_I4:
271 case VT_UI4:
272 case VT_R4:
273 case VT_INT:
274 case VT_UINT:
275 case VT_ERROR:
276 case VT_FILETIME:
277 case VT_UI8:
278 case VT_R8:
279 case VT_CY:
280 case VT_DATE:
281 memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); 297 memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
282 return S_OK; 298 return S_OK;
283 } 299 }
@@ -287,12 +303,13 @@ HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
287 303
288HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() 304HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
289{ 305{
290 HRESULT hr = Clear(); 306 const HRESULT hr = Clear();
291 if (FAILED(hr)) 307 if (FAILED(hr))
292 return hr; 308 return hr;
293 // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); 309 // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT));
294 *(PROPVARIANT *)this = *pSrc; 310 *(PROPVARIANT *)this = *pSrc;
295 pSrc->vt = VT_EMPTY; 311 pSrc->vt = VT_EMPTY;
312 pSrc->wReserved1 = 0;
296 return S_OK; 313 return S_OK;
297} 314}
298 315
@@ -300,21 +317,25 @@ HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
300{ 317{
301 if (pDest->vt != VT_EMPTY) 318 if (pDest->vt != VT_EMPTY)
302 { 319 {
303 HRESULT hr = PropVariant_Clear(pDest); 320 const HRESULT hr = PropVariant_Clear(pDest);
304 if (FAILED(hr)) 321 if (FAILED(hr))
305 return hr; 322 return hr;
306 } 323 }
307 // memcpy(pDest, this, sizeof(PROPVARIANT)); 324 // memcpy(pDest, this, sizeof(PROPVARIANT));
308 *pDest = *(PROPVARIANT *)this; 325 *pDest = *(PROPVARIANT *)this;
309 vt = VT_EMPTY; 326 vt = VT_EMPTY;
327 wReserved1 = 0;
310 return S_OK; 328 return S_OK;
311} 329}
312 330
313HRESULT CPropVariant::InternalClear() throw() 331HRESULT CPropVariant::InternalClear() throw()
314{ 332{
315 if (vt == VT_EMPTY) 333 if (vt == VT_EMPTY)
334 {
335 wReserved1 = 0;
316 return S_OK; 336 return S_OK;
317 HRESULT hr = Clear(); 337 }
338 const HRESULT hr = Clear();
318 if (FAILED(hr)) 339 if (FAILED(hr))
319 { 340 {
320 vt = VT_ERROR; 341 vt = VT_ERROR;
@@ -325,7 +346,7 @@ HRESULT CPropVariant::InternalClear() throw()
325 346
326void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) 347void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
327{ 348{
328 HRESULT hr = Copy(pSrc); 349 const HRESULT hr = Copy(pSrc);
329 if (FAILED(hr)) 350 if (FAILED(hr))
330 { 351 {
331 if (hr == E_OUTOFMEMORY) 352 if (hr == E_OUTOFMEMORY)
@@ -335,11 +356,12 @@ void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
335 } 356 }
336} 357}
337 358
359
338int CPropVariant::Compare(const CPropVariant &a) throw() 360int CPropVariant::Compare(const CPropVariant &a) throw()
339{ 361{
340 if (vt != a.vt) 362 if (vt != a.vt)
341 return MyCompare(vt, a.vt); 363 return MyCompare(vt, a.vt);
342 switch (vt) 364 switch ((unsigned)vt)
343 { 365 {
344 case VT_EMPTY: return 0; 366 case VT_EMPTY: return 0;
345 // case VT_I1: return MyCompare(cVal, a.cVal); 367 // case VT_I1: return MyCompare(cVal, a.cVal);
@@ -352,7 +374,15 @@ int CPropVariant::Compare(const CPropVariant &a) throw()
352 case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); 374 case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
353 case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); 375 case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
354 case VT_BOOL: return -MyCompare(boolVal, a.boolVal); 376 case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
355 case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime); 377 case VT_FILETIME:
378 {
379 const int res = CompareFileTime(&filetime, &a.filetime);
380 if (res != 0)
381 return res;
382 const unsigned v1 = Get_Ns100();
383 const unsigned v2 = a.Get_Ns100();
384 return MyCompare(v1, v2);
385 }
356 case VT_BSTR: return 0; // Not implemented 386 case VT_BSTR: return 0; // Not implemented
357 default: return 0; 387 default: return 0;
358 } 388 }
diff --git a/CPP/Windows/PropVariant.h b/CPP/Windows/PropVariant.h
index 108bf6b..171402f 100644
--- a/CPP/Windows/PropVariant.h
+++ b/CPP/Windows/PropVariant.h
@@ -29,11 +29,14 @@ inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw()
29 p->uhVal.QuadPart = v; 29 p->uhVal.QuadPart = v;
30} 30}
31 31
32inline void PropVarEm_Set_FileTime64(PROPVARIANT *p, UInt64 v) throw() 32inline void PropVarEm_Set_FileTime64_Prec(PROPVARIANT *p, UInt64 v, unsigned prec) throw()
33{ 33{
34 p->vt = VT_FILETIME; 34 p->vt = VT_FILETIME;
35 p->filetime.dwLowDateTime = (DWORD)v; 35 p->filetime.dwLowDateTime = (DWORD)v;
36 p->filetime.dwHighDateTime = (DWORD)(v >> 32); 36 p->filetime.dwHighDateTime = (DWORD)(v >> 32);
37 p->wReserved1 = (WORD)prec;
38 p->wReserved2 = 0;
39 p->wReserved3 = 0;
37} 40}
38 41
39inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() 42inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw()
@@ -63,7 +66,51 @@ public:
63 // uhVal.QuadPart = 0; 66 // uhVal.QuadPart = 0;
64 bstrVal = 0; 67 bstrVal = 0;
65 } 68 }
66 ~CPropVariant() throw() { Clear(); } 69
70
71 void Set_FtPrec(unsigned prec)
72 {
73 wReserved1 = (WORD)prec;
74 wReserved2 = 0;
75 wReserved3 = 0;
76 }
77
78 void SetAsTimeFrom_FT_Prec(const FILETIME &ft, unsigned prec)
79 {
80 operator=(ft);
81 Set_FtPrec(prec);
82 }
83
84 void SetAsTimeFrom_Ft64_Prec(UInt64 v, unsigned prec)
85 {
86 FILETIME ft;
87 ft.dwLowDateTime = (DWORD)(UInt32)v;
88 ft.dwHighDateTime = (DWORD)(UInt32)(v >> 32);
89 operator=(ft);
90 Set_FtPrec(prec);
91 }
92
93 void SetAsTimeFrom_FT_Prec_Ns100(const FILETIME &ft, unsigned prec, unsigned ns100)
94 {
95 operator=(ft);
96 wReserved1 = (WORD)prec;
97 wReserved2 = (WORD)ns100;
98 wReserved3 = 0;
99 }
100
101 unsigned Get_Ns100() const
102 {
103 const unsigned prec = wReserved1;
104 const unsigned ns100 = wReserved2;
105 if (prec == 0
106 && prec <= k_PropVar_TimePrec_1ns
107 && ns100 < 100
108 && wReserved3 == 0)
109 return ns100;
110 return 0;
111 }
112
113 ~CPropVariant();
67 CPropVariant(const PROPVARIANT &varSrc); 114 CPropVariant(const PROPVARIANT &varSrc);
68 CPropVariant(const CPropVariant &varSrc); 115 CPropVariant(const CPropVariant &varSrc);
69 CPropVariant(BSTR bstrSrc); 116 CPropVariant(BSTR bstrSrc);
@@ -118,7 +165,6 @@ public:
118 165
119 HRESULT InternalClear() throw(); 166 HRESULT InternalClear() throw();
120 void InternalCopy(const PROPVARIANT *pSrc); 167 void InternalCopy(const PROPVARIANT *pSrc);
121
122 int Compare(const CPropVariant &a) throw(); 168 int Compare(const CPropVariant &a) throw();
123}; 169};
124 170
diff --git a/CPP/Windows/PropVariantConv.cpp b/CPP/Windows/PropVariantConv.cpp
index b58d37e..3c9bbd1 100644
--- a/CPP/Windows/PropVariantConv.cpp
+++ b/CPP/Windows/PropVariantConv.cpp
@@ -9,7 +9,7 @@
9 9
10#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } 10#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; }
11 11
12bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw() 12bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level) throw()
13{ 13{
14 *s = 0; 14 *s = 0;
15 FILETIME ft; 15 FILETIME ft;
@@ -18,7 +18,10 @@ bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
18 18
19 SYSTEMTIME st; 19 SYSTEMTIME st;
20 if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) 20 if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
21 {
22 // win10 : that function doesn't work, if bit 63 of 64-bit FILETIME is set.
21 return false; 23 return false;
24 }
22 25
23 { 26 {
24 unsigned val = st.wYear; 27 unsigned val = st.wYear;
@@ -71,6 +74,12 @@ bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
71 numDigits = (unsigned)level; 74 numDigits = (unsigned)level;
72 s += numDigits; 75 s += numDigits;
73 } 76 }
77 if (level >= kTimestampPrintLevel_NTFS + 1)
78 {
79 *s++ = (char)('0' + (ns100 / 10));
80 if (level >= kTimestampPrintLevel_NTFS + 2)
81 *s++ = (char)('0' + (ns100 % 10));
82 }
74 } 83 }
75 } 84 }
76 } 85 }
@@ -80,6 +89,25 @@ bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
80} 89}
81 90
82 91
92bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
93{
94 return ConvertUtcFileTimeToString2(utc, 0, s, level);
95}
96
97bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *dest, int level) throw()
98{
99 char s[32];
100 bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level);
101 for (unsigned i = 0;; i++)
102 {
103 Byte c = (Byte)s[i];
104 dest[i] = c;
105 if (c == 0)
106 break;
107 }
108 return res;
109}
110
83bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw() 111bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw()
84{ 112{
85 char s[32]; 113 char s[32];
@@ -106,7 +134,19 @@ void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw(
106 case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; 134 case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
107 case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; 135 case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
108 case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; 136 case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
109 case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return; 137 case VT_FILETIME:
138 {
139 // const unsigned prec = prop.wReserved1;
140 int level = 0;
141 /*
142 if (prec == 0)
143 level = 7;
144 else if (prec > 16 && prec <= 16 + 9)
145 level = prec - 16;
146 */
147 ConvertUtcFileTimeToString(prop.filetime, dest, level);
148 return;
149 }
110 // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; 150 // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
111 case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; 151 case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
112 case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; 152 case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
@@ -127,7 +167,19 @@ void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) thr
127 case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; 167 case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
128 case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; 168 case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
129 case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; 169 case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
130 case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return; 170 case VT_FILETIME:
171 {
172 // const unsigned prec = prop.wReserved1;
173 int level = 0;
174 /*
175 if (prec == 0)
176 level = 7;
177 else if (prec > 16 && prec <= 16 + 9)
178 level = prec - 16;
179 */
180 ConvertUtcFileTimeToString(prop.filetime, dest, level);
181 return;
182 }
131 // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; 183 // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
132 case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; 184 case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
133 case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; 185 case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
diff --git a/CPP/Windows/PropVariantConv.h b/CPP/Windows/PropVariantConv.h
index 390e0b8..6067784 100644
--- a/CPP/Windows/PropVariantConv.h
+++ b/CPP/Windows/PropVariantConv.h
@@ -10,11 +10,14 @@
10#define kTimestampPrintLevel_DAY -3 10#define kTimestampPrintLevel_DAY -3
11// #define kTimestampPrintLevel_HOUR -2 11// #define kTimestampPrintLevel_HOUR -2
12#define kTimestampPrintLevel_MIN -1 12#define kTimestampPrintLevel_MIN -1
13#define kTimestampPrintLevel_SEC 0 13#define kTimestampPrintLevel_SEC 0
14#define kTimestampPrintLevel_NTFS 7 14#define kTimestampPrintLevel_NTFS 7
15#define kTimestampPrintLevel_NS 9
15 16
16bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw(); 17bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw();
17bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); 18bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
19bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, char *s, int level = kTimestampPrintLevel_SEC) throw();
20bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
18 21
19// provide at least 32 bytes for buffer including zero-end 22// provide at least 32 bytes for buffer including zero-end
20// don't send VT_BSTR to these functions 23// don't send VT_BSTR to these functions
diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp
index 640c90d..8a7f45c 100644
--- a/CPP/Windows/SecurityUtils.cpp
+++ b/CPP/Windows/SecurityUtils.cpp
@@ -2,8 +2,6 @@
2 2
3#include "StdAfx.h" 3#include "StdAfx.h"
4 4
5#include "../Common/MyString.h"
6
7#include "SecurityUtils.h" 5#include "SecurityUtils.h"
8 6
9namespace NWindows { 7namespace NWindows {
diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp
index 1f1335f..77d2c51 100644
--- a/CPP/Windows/TimeUtils.cpp
+++ b/CPP/Windows/TimeUtils.cpp
@@ -22,7 +22,7 @@ static const UInt64 kUnixTimeOffset =
22 (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); 22 (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
23static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; 23static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond;
24 24
25bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw() 25bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw()
26{ 26{
27 #if defined(_WIN32) && !defined(UNDER_CE) 27 #if defined(_WIN32) && !defined(UNDER_CE)
28 return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); 28 return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft));
@@ -43,7 +43,7 @@ bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw()
43static const UInt32 kHighDosTime = 0xFF9FBF7D; 43static const UInt32 kHighDosTime = 0xFF9FBF7D;
44static const UInt32 kLowDosTime = 0x210000; 44static const UInt32 kLowDosTime = 0x210000;
45 45
46bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() 46bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw()
47{ 47{
48 #if defined(_WIN32) && !defined(UNDER_CE) 48 #if defined(_WIN32) && !defined(UNDER_CE)
49 49
@@ -121,49 +121,86 @@ bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw()
121 return true; 121 return true;
122} 122}
123 123
124UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw() 124
125bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw()
126{
127 FILETIME loc = { 0, 0 };
128 const UInt64 u1 = FILETIME_To_UInt64(utc);
129 const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec.
130 if (u1 >= kDelta)
131 {
132 if (!FileTimeToLocalFileTime(&utc, &loc))
133 loc = utc;
134 else
135 {
136 const UInt64 u2 = FILETIME_To_UInt64(loc);
137 const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2);
138 if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time
139 loc = utc;
140 }
141 }
142 return FileTime_To_DosTime(loc, dosTime);
143}
144
145UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw()
125{ 146{
126 return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; 147 return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;
127} 148}
128 149
129void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw() 150void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw()
130{ 151{
131 UInt64 v = UnixTimeToFileTime64(unixTime); 152 const UInt64 v = UnixTime_To_FileTime64(unixTime);
132 ft.dwLowDateTime = (DWORD)v; 153 ft.dwLowDateTime = (DWORD)v;
133 ft.dwHighDateTime = (DWORD)(v >> 32); 154 ft.dwHighDateTime = (DWORD)(v >> 32);
134} 155}
135 156
136UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw() 157UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw()
137{ 158{
138 return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; 159 return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond;
139} 160}
140 161
141bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw() 162
163bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw()
142{ 164{
143 if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset)) 165 if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset))
144 { 166 {
145 ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1; 167 fileTime = (UInt64)(Int64)-1;
146 return false; 168 return false;
147 } 169 }
148 Int64 v = (Int64)kUnixTimeOffset + unixTime; 170 if (unixTime < -(Int64)kUnixTimeOffset)
149 if (v < 0)
150 { 171 {
151 ft.dwLowDateTime = ft.dwHighDateTime = 0; 172 fileTime = 0;
152 return false; 173 return false;
153 } 174 }
154 UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond; 175 fileTime = UnixTime64_To_FileTime64(unixTime);
155 ft.dwLowDateTime = (DWORD)v2;
156 ft.dwHighDateTime = (DWORD)(v2 >> 32);
157 return true; 176 return true;
158} 177}
159 178
160Int64 FileTimeToUnixTime64(const FILETIME &ft) throw() 179
180bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw()
161{ 181{
162 UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 182 UInt64 v;
183 const bool res = UnixTime64_To_FileTime64(unixTime, v);
184 ft.dwLowDateTime = (DWORD)v;
185 ft.dwHighDateTime = (DWORD)(v >> 32);
186 return res;
187}
188
189
190Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw()
191{
192 const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
193 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
194}
195
196Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw()
197{
198 const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
199 quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond);
163 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; 200 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
164} 201}
165 202
166bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw() 203bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw()
167{ 204{
168 UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 205 UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
169 winTime /= kNumTimeQuantumsInSecond; 206 winTime /= kNumTimeQuantumsInSecond;
@@ -173,9 +210,9 @@ bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw()
173 return false; 210 return false;
174 } 211 }
175 winTime -= kUnixTimeOffset; 212 winTime -= kUnixTimeOffset;
176 if (winTime > 0xFFFFFFFF) 213 if (winTime > (UInt32)0xFFFFFFFF)
177 { 214 {
178 unixTime = 0xFFFFFFFF; 215 unixTime = (UInt32)0xFFFFFFFF;
179 return false; 216 return false;
180 } 217 }
181 unixTime = (UInt32)winTime; 218 unixTime = (UInt32)winTime;
@@ -202,12 +239,13 @@ bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
202 return true; 239 return true;
203} 240}
204 241
205void GetCurUtcFileTime(FILETIME &ft) throw() 242
243void GetCurUtc_FiTime(CFiTime &ft) throw()
206{ 244{
245 #ifdef _WIN32
246
207 // Both variants provide same low resolution on WinXP: about 15 ms. 247 // Both variants provide same low resolution on WinXP: about 15 ms.
208 // But GetSystemTimeAsFileTime is much faster. 248 // But GetSystemTimeAsFileTime is much faster.
209 #ifdef _WIN32
210
211 #ifdef UNDER_CE 249 #ifdef UNDER_CE
212 SYSTEMTIME st; 250 SYSTEMTIME st;
213 GetSystemTime(&st); 251 GetSystemTime(&st);
@@ -216,8 +254,22 @@ void GetCurUtcFileTime(FILETIME &ft) throw()
216 GetSystemTimeAsFileTime(&ft); 254 GetSystemTimeAsFileTime(&ft);
217 #endif 255 #endif
218 256
219 #else 257 #else
220 258
259 FiTime_Clear(ft);
260 struct timeval now;
261 if (gettimeofday(&now, 0 ) == 0)
262 {
263 ft.tv_sec = now.tv_sec;
264 ft.tv_nsec = now.tv_usec * 1000;
265 }
266
267 #endif
268}
269
270#ifndef _WIN32
271void GetCurUtcFileTime(FILETIME &ft) throw()
272{
221 UInt64 v = 0; 273 UInt64 v = 0;
222 struct timeval now; 274 struct timeval now;
223 if (gettimeofday(&now, 0 ) == 0) 275 if (gettimeofday(&now, 0 ) == 0)
@@ -227,8 +279,126 @@ void GetCurUtcFileTime(FILETIME &ft) throw()
227 } 279 }
228 ft.dwLowDateTime = (DWORD)v; 280 ft.dwLowDateTime = (DWORD)v;
229 ft.dwHighDateTime = (DWORD)(v >> 32); 281 ft.dwHighDateTime = (DWORD)(v >> 32);
230
231 #endif
232} 282}
283#endif
284
233 285
234}} 286}}
287
288
289#ifdef _WIN32
290
291/*
292void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
293{
294 if (prec == k_PropVar_TimePrec_0
295 || prec == k_PropVar_TimePrec_HighPrec
296 || prec >= k_PropVar_TimePrec_100ns)
297 return;
298 UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
299
300 int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
301 UInt32 d;
302 if (prec == k_PropVar_TimePrec_DOS)
303 {
304 // we round up as windows DosDateTimeToFileTime()
305 v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1;
306 d = NWindows::NTime::kNumTimeQuantumsInSecond * 2;
307 }
308 else
309 {
310 if (prec == k_PropVar_TimePrec_Unix)
311 numDigits = 0;
312 else if (numDigits < 0)
313 return;
314 d = 1;
315 for (unsigned k = numDigits; k < 7; k++)
316 d *= 10;
317 }
318 v /= d;
319 v *= d;
320 ft.dwLowDateTime = (DWORD)v;
321 ft.dwHighDateTime = (DWORD)(v >> 32);
322}
323*/
324
325#else
326
327/*
328void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
329{
330 if (prec >= k_PropVar_TimePrec_1ns
331 || prec == k_PropVar_TimePrec_HighPrec)
332 return;
333
334 int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
335 UInt32 d;
336 if (prec == k_PropVar_TimePrec_Unix ||
337 prec == (int)k_PropVar_TimePrec_Base)
338 {
339 ft.tv_nsec = 0;
340 return;
341 }
342 if (prec == k_PropVar_TimePrec_DOS)
343 {
344 // we round up as windows DosDateTimeToFileTime()
345 const unsigned sec1 = (ft.tv_sec & 1);
346 if (ft.tv_nsec == 0 && sec1 == 0)
347 return;
348 ft.tv_nsec = 0;
349 ft.tv_sec += 2 - sec1;
350 return;
351 }
352 {
353 if (prec == k_PropVar_TimePrec_0
354 || numDigits < 0)
355 numDigits = 7;
356 d = 1;
357 for (unsigned k = numDigits; k < 9; k++)
358 d *= 10;
359 ft.tv_nsec /= d;
360 ft.tv_nsec *= d;
361 }
362}
363*/
364
365int Compare_FiTime(const CFiTime *a1, const CFiTime *a2)
366{
367 if (a1->tv_sec < a2->tv_sec) return -1;
368 if (a1->tv_sec > a2->tv_sec) return 1;
369 if (a1->tv_nsec < a2->tv_nsec) return -1;
370 if (a1->tv_nsec > a2->tv_nsec) return 1;
371 return 0;
372}
373
374bool FILETIME_To_timespec(const FILETIME &ft, timespec &ts)
375{
376 UInt32 quantums;
377 const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums);
378 // time_t is long
379 const time_t sec2 = (time_t)sec;
380 if (sec2 == sec)
381 {
382 ts.tv_sec = sec2;
383 ts.tv_nsec = (long)(quantums * 100);
384 return true;
385 }
386 return false;
387}
388
389void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100)
390{
391 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
392 ns100 = (unsigned)((UInt64)ts.tv_nsec % 100);
393 ft.dwLowDateTime = (DWORD)v;
394 ft.dwHighDateTime = (DWORD)(v >> 32);
395}
396
397void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
398{
399 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
400 ft.dwLowDateTime = (DWORD)v;
401 ft.dwHighDateTime = (DWORD)(v >> 32);
402}
403
404#endif
diff --git a/CPP/Windows/TimeUtils.h b/CPP/Windows/TimeUtils.h
index d1d8c15..60ee739 100644
--- a/CPP/Windows/TimeUtils.h
+++ b/CPP/Windows/TimeUtils.h
@@ -5,28 +5,142 @@
5 5
6#include "../Common/MyTypes.h" 6#include "../Common/MyTypes.h"
7#include "../Common/MyWindows.h" 7#include "../Common/MyWindows.h"
8#include "PropVariant.h"
9
10inline UInt64 FILETIME_To_UInt64(const FILETIME &ft)
11{
12 return (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
13}
14
15inline void FILETIME_Clear(FILETIME &ft)
16{
17 ft.dwLowDateTime = 0;
18 ft.dwHighDateTime = 0;
19}
20
21inline bool FILETIME_IsZero(const FILETIME &ft)
22{
23 return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0);
24}
25
26
27#ifdef _WIN32
28 #define CFiTime FILETIME
29 #define Compare_FiTime ::CompareFileTime
30 inline void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
31 {
32 ft = ts;
33 }
34 /*
35 inline void FILETIME_To_FiTime(const FILETIME &ft, CFiTime &ts)
36 {
37 ts = ft;
38 }
39 */
40 inline void FiTime_Clear(CFiTime &ft)
41 {
42 ft.dwLowDateTime = 0;
43 ft.dwHighDateTime = 0;
44 }
45#else
46
47 #include <sys/stat.h>
48
49 #if defined(_AIX)
50 #define CFiTime st_timespec
51 #else
52 #define CFiTime timespec
53 #endif
54 int Compare_FiTime(const CFiTime *a1, const CFiTime *a2);
55 bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts);
56 void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft);
57 void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100);
58 inline void FiTime_Clear(CFiTime &ft)
59 {
60 ft.tv_sec = 0;
61 ft.tv_nsec = 0;
62 }
63
64 #ifdef __APPLE__
65 #define ST_MTIME(st) st.st_mtimespec
66 #define ST_ATIME(st) st.st_atimespec
67 #define ST_CTIME(st) st.st_ctimespec
68 #else
69 #define ST_MTIME(st) st.st_mtim
70 #define ST_ATIME(st) st.st_atim
71 #define ST_CTIME(st) st.st_ctim
72 #endif
73
74#endif
75
76// void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec);
8 77
9namespace NWindows { 78namespace NWindows {
10namespace NTime { 79namespace NTime {
11 80
12bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw(); 81bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &fileTime) throw();
13bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); 82bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw();
83bool FileTime_To_DosTime(const FILETIME &fileTime, UInt32 &dosTime) throw();
14 84
15// UInt32 Unix Time : for dates 1970-2106 85// UInt32 Unix Time : for dates 1970-2106
16UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw(); 86UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw();
17void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw(); 87void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &fileTime) throw();
18 88
19// Int64 Unix Time : negative values for dates before 1970 89// Int64 Unix Time : negative values for dates before 1970
20UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw(); 90UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw(); // no check
21bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw(); 91bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw();
92bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &fileTime) throw();
22 93
23bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); 94Int64 FileTime64_To_UnixTime64(UInt64 ft64) throw();
24Int64 FileTimeToUnixTime64(const FILETIME &ft) throw(); 95bool FileTime_To_UnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw();
96Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw();
97Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw();
25 98
26bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, 99bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
27 unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); 100 unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw();
101
102void GetCurUtc_FiTime(CFiTime &ft) throw();
103#ifdef _WIN32
104#define GetCurUtcFileTime GetCurUtc_FiTime
105#else
28void GetCurUtcFileTime(FILETIME &ft) throw(); 106void GetCurUtcFileTime(FILETIME &ft) throw();
107#endif
29 108
30}} 109}}
31 110
111inline void PropVariant_SetFrom_UnixTime(NWindows::NCOM::CPropVariant &prop, UInt32 unixTime)
112{
113 FILETIME ft;
114 NWindows::NTime::UnixTime_To_FileTime(unixTime, ft);
115 prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
116}
117
118inline void PropVariant_SetFrom_NtfsTime(NWindows::NCOM::CPropVariant &prop, const FILETIME &ft)
119{
120 prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_100ns);
121}
122
123inline void PropVariant_SetFrom_FiTime(NWindows::NCOM::CPropVariant &prop, const CFiTime &fts)
124{
125 #ifdef _WIN32
126 PropVariant_SetFrom_NtfsTime(prop, fts);
127 #else
128 unsigned ns100;
129 FILETIME ft;
130 FiTime_To_FILETIME_ns100(fts, ft, ns100);
131 prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
132 #endif
133}
134
135inline bool PropVariant_SetFrom_DosTime(NWindows::NCOM::CPropVariant &prop, UInt32 dosTime)
136{
137 FILETIME localFileTime, utc;
138 if (!NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
139 return false;
140 if (!LocalFileTimeToFileTime(&localFileTime, &utc))
141 return false;
142 prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_DOS);
143 return true;
144}
145
32#endif 146#endif
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs
index fdc63ce..c7a61b4 100644
--- a/DOC/7zip.wxs
+++ b/DOC/7zip.wxs
@@ -1,7 +1,7 @@
1<?xml version="1.0"?> 1<?xml version="1.0"?>
2 2
3<?define VerMajor = "21" ?> 3<?define VerMajor = "22" ?>
4<?define VerMinor = "07" ?> 4<?define VerMinor = "00" ?>
5<?define VerBuild = "00" ?> 5<?define VerBuild = "00" ?>
6<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> 6<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
7<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> 7<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>
diff --git a/DOC/src-history.txt b/DOC/src-history.txt
index 0b54fe3..f546c4e 100644
--- a/DOC/src-history.txt
+++ b/DOC/src-history.txt
@@ -1,6 +1,12 @@
1HISTORY of the 7-Zip source code 1HISTORY of the 7-Zip source code
2-------------------------------- 2--------------------------------
3 3
422.00 2022-06-16
5-------------------------
6- 7-Zip interfaces now support high precision (1 ns) timestamps with reserved
7 fields of tagPROPVARIANT (VT_FILETIME).
8
9
421.07 2021-12-26 1021.07 2021-12-26
5------------------------- 11-------------------------
6- The sorting order of files in archives was slightly changed to be more consistent 12- The sorting order of files in archives was slightly changed to be more consistent