1*f6dc9357SAndroid Build Coastguard Worker // TarOut.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../../C/7zCrc.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/IntToString.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
10*f6dc9357SAndroid Build Coastguard Worker
11*f6dc9357SAndroid Build Coastguard Worker #include "TarOut.h"
12*f6dc9357SAndroid Build Coastguard Worker
13*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
14*f6dc9357SAndroid Build Coastguard Worker namespace NTar {
15*f6dc9357SAndroid Build Coastguard Worker
16*f6dc9357SAndroid Build Coastguard Worker using namespace NFileHeader;
17*f6dc9357SAndroid Build Coastguard Worker
18*f6dc9357SAndroid Build Coastguard Worker // it's path prefix assigned by 7-Zip to show that file path was cut
19*f6dc9357SAndroid Build Coastguard Worker #define K_PREFIX_PATH_CUT "@PathCut"
20*f6dc9357SAndroid Build Coastguard Worker
21*f6dc9357SAndroid Build Coastguard Worker static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1;
22*f6dc9357SAndroid Build Coastguard Worker
WriteOctal_8(char * s,UInt32 val)23*f6dc9357SAndroid Build Coastguard Worker static void WriteOctal_8(char *s, UInt32 val)
24*f6dc9357SAndroid Build Coastguard Worker {
25*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumDigits = 8 - 1;
26*f6dc9357SAndroid Build Coastguard Worker if (val >= ((UInt32)1 << (kNumDigits * 3)))
27*f6dc9357SAndroid Build Coastguard Worker {
28*f6dc9357SAndroid Build Coastguard Worker val = 0;
29*f6dc9357SAndroid Build Coastguard Worker // return false;
30*f6dc9357SAndroid Build Coastguard Worker }
31*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNumDigits; i++)
32*f6dc9357SAndroid Build Coastguard Worker {
33*f6dc9357SAndroid Build Coastguard Worker s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
34*f6dc9357SAndroid Build Coastguard Worker val >>= 3;
35*f6dc9357SAndroid Build Coastguard Worker }
36*f6dc9357SAndroid Build Coastguard Worker // return true;
37*f6dc9357SAndroid Build Coastguard Worker }
38*f6dc9357SAndroid Build Coastguard Worker
WriteBin_64bit(char * s,UInt64 val)39*f6dc9357SAndroid Build Coastguard Worker static void WriteBin_64bit(char *s, UInt64 val)
40*f6dc9357SAndroid Build Coastguard Worker {
41*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 8; i++, val <<= 8)
42*f6dc9357SAndroid Build Coastguard Worker s[i] = (char)(val >> 56);
43*f6dc9357SAndroid Build Coastguard Worker }
44*f6dc9357SAndroid Build Coastguard Worker
WriteOctal_12(char * s,UInt64 val)45*f6dc9357SAndroid Build Coastguard Worker static void WriteOctal_12(char *s, UInt64 val)
46*f6dc9357SAndroid Build Coastguard Worker {
47*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumDigits = 12 - 1;
48*f6dc9357SAndroid Build Coastguard Worker if (val >= ((UInt64)1 << (kNumDigits * 3)))
49*f6dc9357SAndroid Build Coastguard Worker {
50*f6dc9357SAndroid Build Coastguard Worker // GNU extension;
51*f6dc9357SAndroid Build Coastguard Worker s[0] = (char)(Byte)0x80;
52*f6dc9357SAndroid Build Coastguard Worker s[1] = s[2] = s[3] = 0;
53*f6dc9357SAndroid Build Coastguard Worker WriteBin_64bit(s + 4, val);
54*f6dc9357SAndroid Build Coastguard Worker return;
55*f6dc9357SAndroid Build Coastguard Worker }
56*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNumDigits; i++)
57*f6dc9357SAndroid Build Coastguard Worker {
58*f6dc9357SAndroid Build Coastguard Worker s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
59*f6dc9357SAndroid Build Coastguard Worker val >>= 3;
60*f6dc9357SAndroid Build Coastguard Worker }
61*f6dc9357SAndroid Build Coastguard Worker }
62*f6dc9357SAndroid Build Coastguard Worker
WriteOctal_12_Signed(char * s,const Int64 val)63*f6dc9357SAndroid Build Coastguard Worker static void WriteOctal_12_Signed(char *s, const Int64 val)
64*f6dc9357SAndroid Build Coastguard Worker {
65*f6dc9357SAndroid Build Coastguard Worker if (val >= 0)
66*f6dc9357SAndroid Build Coastguard Worker {
67*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12(s, (UInt64)val);
68*f6dc9357SAndroid Build Coastguard Worker return;
69*f6dc9357SAndroid Build Coastguard Worker }
70*f6dc9357SAndroid Build Coastguard Worker s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
71*f6dc9357SAndroid Build Coastguard Worker WriteBin_64bit(s + 4, (UInt64)val);
72*f6dc9357SAndroid Build Coastguard Worker }
73*f6dc9357SAndroid Build Coastguard Worker
CopyString(char * dest,const AString & src,const unsigned maxSize)74*f6dc9357SAndroid Build Coastguard Worker static void CopyString(char *dest, const AString &src, const unsigned maxSize)
75*f6dc9357SAndroid Build Coastguard Worker {
76*f6dc9357SAndroid Build Coastguard Worker unsigned len = src.Len();
77*f6dc9357SAndroid Build Coastguard Worker if (len == 0)
78*f6dc9357SAndroid Build Coastguard Worker return;
79*f6dc9357SAndroid Build Coastguard Worker // 21.07: new gnu : we don't require additional 0 character at the end
80*f6dc9357SAndroid Build Coastguard Worker // if (len >= maxSize)
81*f6dc9357SAndroid Build Coastguard Worker if (len > maxSize)
82*f6dc9357SAndroid Build Coastguard Worker {
83*f6dc9357SAndroid Build Coastguard Worker len = maxSize;
84*f6dc9357SAndroid Build Coastguard Worker /*
85*f6dc9357SAndroid Build Coastguard Worker // oldgnu needs 0 character at the end
86*f6dc9357SAndroid Build Coastguard Worker len = maxSize - 1;
87*f6dc9357SAndroid Build Coastguard Worker dest[len] = 0;
88*f6dc9357SAndroid Build Coastguard Worker */
89*f6dc9357SAndroid Build Coastguard Worker }
90*f6dc9357SAndroid Build Coastguard Worker memcpy(dest, src.Ptr(), len);
91*f6dc9357SAndroid Build Coastguard Worker }
92*f6dc9357SAndroid Build Coastguard Worker
93*f6dc9357SAndroid Build Coastguard Worker // #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; }
94*f6dc9357SAndroid Build Coastguard Worker #define RETURN_IF_NOT_TRUE(x) { x; }
95*f6dc9357SAndroid Build Coastguard Worker
96*f6dc9357SAndroid Build Coastguard Worker #define COPY_STRING_CHECK(dest, src, size) \
97*f6dc9357SAndroid Build Coastguard Worker CopyString(dest, src, size); dest += (size);
98*f6dc9357SAndroid Build Coastguard Worker
99*f6dc9357SAndroid Build Coastguard Worker #define WRITE_OCTAL_8_CHECK(dest, src) \
100*f6dc9357SAndroid Build Coastguard Worker RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src))
101*f6dc9357SAndroid Build Coastguard Worker
102*f6dc9357SAndroid Build Coastguard Worker
WriteHeaderReal(const CItem & item,bool isPax)103*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax
104*f6dc9357SAndroid Build Coastguard Worker // , bool zero_PackSize
105*f6dc9357SAndroid Build Coastguard Worker // , bool zero_MTime
106*f6dc9357SAndroid Build Coastguard Worker )
107*f6dc9357SAndroid Build Coastguard Worker {
108*f6dc9357SAndroid Build Coastguard Worker /*
109*f6dc9357SAndroid Build Coastguard Worker if (isPax) { we don't use Glob_Name and Prefix }
110*f6dc9357SAndroid Build Coastguard Worker if (!isPax)
111*f6dc9357SAndroid Build Coastguard Worker {
112*f6dc9357SAndroid Build Coastguard Worker we use Glob_Name if it's not empty
113*f6dc9357SAndroid Build Coastguard Worker we use Prefix if it's not empty
114*f6dc9357SAndroid Build Coastguard Worker }
115*f6dc9357SAndroid Build Coastguard Worker */
116*f6dc9357SAndroid Build Coastguard Worker char record[kRecordSize];
117*f6dc9357SAndroid Build Coastguard Worker memset(record, 0, kRecordSize);
118*f6dc9357SAndroid Build Coastguard Worker char *cur = record;
119*f6dc9357SAndroid Build Coastguard Worker
120*f6dc9357SAndroid Build Coastguard Worker COPY_STRING_CHECK (cur,
121*f6dc9357SAndroid Build Coastguard Worker (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name,
122*f6dc9357SAndroid Build Coastguard Worker kNameSize)
123*f6dc9357SAndroid Build Coastguard Worker
124*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, item.Mode) cur += 8; // & k_7_oct_digits_Val_Max
125*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, item.UID) cur += 8;
126*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, item.GID) cur += 8;
127*f6dc9357SAndroid Build Coastguard Worker
128*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12;
129*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12;
130*f6dc9357SAndroid Build Coastguard Worker
131*f6dc9357SAndroid Build Coastguard Worker // we will use binary init for checksum instead of memset
132*f6dc9357SAndroid Build Coastguard Worker // checksum field:
133*f6dc9357SAndroid Build Coastguard Worker // memset(cur, ' ', 8);
134*f6dc9357SAndroid Build Coastguard Worker cur += 8;
135*f6dc9357SAndroid Build Coastguard Worker
136*f6dc9357SAndroid Build Coastguard Worker *cur++ = item.LinkFlag;
137*f6dc9357SAndroid Build Coastguard Worker
138*f6dc9357SAndroid Build Coastguard Worker COPY_STRING_CHECK (cur, item.LinkName, kNameSize)
139*f6dc9357SAndroid Build Coastguard Worker
140*f6dc9357SAndroid Build Coastguard Worker memcpy(cur, item.Magic, 8);
141*f6dc9357SAndroid Build Coastguard Worker cur += 8;
142*f6dc9357SAndroid Build Coastguard Worker
143*f6dc9357SAndroid Build Coastguard Worker COPY_STRING_CHECK (cur, item.User, kUserNameSize)
144*f6dc9357SAndroid Build Coastguard Worker COPY_STRING_CHECK (cur, item.Group, kGroupNameSize)
145*f6dc9357SAndroid Build Coastguard Worker
146*f6dc9357SAndroid Build Coastguard Worker const bool needDevice = (IsPosixMode && !isPax);
147*f6dc9357SAndroid Build Coastguard Worker
148*f6dc9357SAndroid Build Coastguard Worker if (item.DeviceMajor_Defined)
149*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor)
150*f6dc9357SAndroid Build Coastguard Worker else if (needDevice)
151*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, 0)
152*f6dc9357SAndroid Build Coastguard Worker cur += 8;
153*f6dc9357SAndroid Build Coastguard Worker
154*f6dc9357SAndroid Build Coastguard Worker if (item.DeviceMinor_Defined)
155*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
156*f6dc9357SAndroid Build Coastguard Worker else if (needDevice)
157*f6dc9357SAndroid Build Coastguard Worker WRITE_OCTAL_8_CHECK (cur, 0)
158*f6dc9357SAndroid Build Coastguard Worker cur += 8;
159*f6dc9357SAndroid Build Coastguard Worker
160*f6dc9357SAndroid Build Coastguard Worker if (!isPax && !Prefix.IsEmpty())
161*f6dc9357SAndroid Build Coastguard Worker {
162*f6dc9357SAndroid Build Coastguard Worker COPY_STRING_CHECK (cur, Prefix, kPrefixSize)
163*f6dc9357SAndroid Build Coastguard Worker }
164*f6dc9357SAndroid Build Coastguard Worker
165*f6dc9357SAndroid Build Coastguard Worker if (item.Is_Sparse())
166*f6dc9357SAndroid Build Coastguard Worker {
167*f6dc9357SAndroid Build Coastguard Worker record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
168*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12(record + 483, item.Size);
169*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++)
170*f6dc9357SAndroid Build Coastguard Worker {
171*f6dc9357SAndroid Build Coastguard Worker const CSparseBlock &sb = item.SparseBlocks[i];
172*f6dc9357SAndroid Build Coastguard Worker char *p = record + 386 + 24 * i;
173*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12(p, sb.Offset);
174*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12(p + 12, sb.Size);
175*f6dc9357SAndroid Build Coastguard Worker }
176*f6dc9357SAndroid Build Coastguard Worker }
177*f6dc9357SAndroid Build Coastguard Worker
178*f6dc9357SAndroid Build Coastguard Worker {
179*f6dc9357SAndroid Build Coastguard Worker UInt32 sum = (unsigned)(' ') * 8; // we use binary init
180*f6dc9357SAndroid Build Coastguard Worker {
181*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kRecordSize; i++)
182*f6dc9357SAndroid Build Coastguard Worker sum += (Byte)record[i];
183*f6dc9357SAndroid Build Coastguard Worker }
184*f6dc9357SAndroid Build Coastguard Worker /* checksum field is formatted differently from the
185*f6dc9357SAndroid Build Coastguard Worker other fields: it has [6] digits, a null, then a space. */
186*f6dc9357SAndroid Build Coastguard Worker // WRITE_OCTAL_8_CHECK(record + 148, sum);
187*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumDigits = 6;
188*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNumDigits; i++)
189*f6dc9357SAndroid Build Coastguard Worker {
190*f6dc9357SAndroid Build Coastguard Worker record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7));
191*f6dc9357SAndroid Build Coastguard Worker sum >>= 3;
192*f6dc9357SAndroid Build Coastguard Worker }
193*f6dc9357SAndroid Build Coastguard Worker // record[148 + 6] = 0; // we need it, if we use memset(' ') init
194*f6dc9357SAndroid Build Coastguard Worker record[148 + 7] = ' '; // we need it, if we use binary init
195*f6dc9357SAndroid Build Coastguard Worker }
196*f6dc9357SAndroid Build Coastguard Worker
197*f6dc9357SAndroid Build Coastguard Worker RINOK(Write_Data(record, kRecordSize))
198*f6dc9357SAndroid Build Coastguard Worker
199*f6dc9357SAndroid Build Coastguard Worker if (item.Is_Sparse())
200*f6dc9357SAndroid Build Coastguard Worker {
201*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 4; i < item.SparseBlocks.Size();)
202*f6dc9357SAndroid Build Coastguard Worker {
203*f6dc9357SAndroid Build Coastguard Worker memset(record, 0, kRecordSize);
204*f6dc9357SAndroid Build Coastguard Worker for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
205*f6dc9357SAndroid Build Coastguard Worker {
206*f6dc9357SAndroid Build Coastguard Worker const CSparseBlock &sb = item.SparseBlocks[i];
207*f6dc9357SAndroid Build Coastguard Worker char *p = record + 24 * t;
208*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12(p, sb.Offset);
209*f6dc9357SAndroid Build Coastguard Worker WriteOctal_12(p + 12, sb.Size);
210*f6dc9357SAndroid Build Coastguard Worker }
211*f6dc9357SAndroid Build Coastguard Worker record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
212*f6dc9357SAndroid Build Coastguard Worker RINOK(Write_Data(record, kRecordSize))
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker
216*f6dc9357SAndroid Build Coastguard Worker return S_OK;
217*f6dc9357SAndroid Build Coastguard Worker }
218*f6dc9357SAndroid Build Coastguard Worker
219*f6dc9357SAndroid Build Coastguard Worker
AddPaxLine(AString & s,const char * name,const AString & val)220*f6dc9357SAndroid Build Coastguard Worker static void AddPaxLine(AString &s, const char *name, const AString &val)
221*f6dc9357SAndroid Build Coastguard Worker {
222*f6dc9357SAndroid Build Coastguard Worker // s.Add_LF(); // for debug
223*f6dc9357SAndroid Build Coastguard Worker const unsigned len = 3 + (unsigned)strlen(name) + val.Len();
224*f6dc9357SAndroid Build Coastguard Worker AString n;
225*f6dc9357SAndroid Build Coastguard Worker for (unsigned numDigits = 1;; numDigits++)
226*f6dc9357SAndroid Build Coastguard Worker {
227*f6dc9357SAndroid Build Coastguard Worker n.Empty();
228*f6dc9357SAndroid Build Coastguard Worker n.Add_UInt32(numDigits + len);
229*f6dc9357SAndroid Build Coastguard Worker if (numDigits == n.Len())
230*f6dc9357SAndroid Build Coastguard Worker break;
231*f6dc9357SAndroid Build Coastguard Worker }
232*f6dc9357SAndroid Build Coastguard Worker s += n;
233*f6dc9357SAndroid Build Coastguard Worker s.Add_Space();
234*f6dc9357SAndroid Build Coastguard Worker s += name;
235*f6dc9357SAndroid Build Coastguard Worker s.Add_Char('=');
236*f6dc9357SAndroid Build Coastguard Worker s += val;
237*f6dc9357SAndroid Build Coastguard Worker s.Add_LF();
238*f6dc9357SAndroid Build Coastguard Worker }
239*f6dc9357SAndroid Build Coastguard Worker
240*f6dc9357SAndroid Build Coastguard Worker // pt is defined : (pt.NumDigits >= 0)
AddPaxTime(AString & s,const char * name,const CPaxTime & pt,const CTimeOptions & options)241*f6dc9357SAndroid Build Coastguard Worker static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt,
242*f6dc9357SAndroid Build Coastguard Worker const CTimeOptions &options)
243*f6dc9357SAndroid Build Coastguard Worker {
244*f6dc9357SAndroid Build Coastguard Worker unsigned numDigits = (unsigned)pt.NumDigits;
245*f6dc9357SAndroid Build Coastguard Worker if (numDigits > options.NumDigitsMax)
246*f6dc9357SAndroid Build Coastguard Worker numDigits = options.NumDigitsMax;
247*f6dc9357SAndroid Build Coastguard Worker
248*f6dc9357SAndroid Build Coastguard Worker bool needNs = false;
249*f6dc9357SAndroid Build Coastguard Worker UInt32 ns = 0;
250*f6dc9357SAndroid Build Coastguard Worker if (numDigits != 0)
251*f6dc9357SAndroid Build Coastguard Worker {
252*f6dc9357SAndroid Build Coastguard Worker ns = pt.Ns;
253*f6dc9357SAndroid Build Coastguard Worker // if (ns != 0) before reduction, we show all digits after digits reduction
254*f6dc9357SAndroid Build Coastguard Worker needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero);
255*f6dc9357SAndroid Build Coastguard Worker UInt32 d = 1;
256*f6dc9357SAndroid Build Coastguard Worker for (unsigned k = numDigits; k < 9; k++)
257*f6dc9357SAndroid Build Coastguard Worker d *= 10;
258*f6dc9357SAndroid Build Coastguard Worker ns /= d;
259*f6dc9357SAndroid Build Coastguard Worker ns *= d;
260*f6dc9357SAndroid Build Coastguard Worker }
261*f6dc9357SAndroid Build Coastguard Worker
262*f6dc9357SAndroid Build Coastguard Worker AString v;
263*f6dc9357SAndroid Build Coastguard Worker {
264*f6dc9357SAndroid Build Coastguard Worker Int64 sec = pt.Sec;
265*f6dc9357SAndroid Build Coastguard Worker if (pt.Sec < 0)
266*f6dc9357SAndroid Build Coastguard Worker {
267*f6dc9357SAndroid Build Coastguard Worker sec = -sec;
268*f6dc9357SAndroid Build Coastguard Worker v.Add_Minus();
269*f6dc9357SAndroid Build Coastguard Worker if (ns != 0)
270*f6dc9357SAndroid Build Coastguard Worker {
271*f6dc9357SAndroid Build Coastguard Worker ns = 1000*1000*1000 - ns;
272*f6dc9357SAndroid Build Coastguard Worker sec--;
273*f6dc9357SAndroid Build Coastguard Worker }
274*f6dc9357SAndroid Build Coastguard Worker }
275*f6dc9357SAndroid Build Coastguard Worker v.Add_UInt64((UInt64)sec);
276*f6dc9357SAndroid Build Coastguard Worker }
277*f6dc9357SAndroid Build Coastguard Worker
278*f6dc9357SAndroid Build Coastguard Worker if (needNs)
279*f6dc9357SAndroid Build Coastguard Worker {
280*f6dc9357SAndroid Build Coastguard Worker AString d;
281*f6dc9357SAndroid Build Coastguard Worker d.Add_UInt32(ns);
282*f6dc9357SAndroid Build Coastguard Worker while (d.Len() < 9)
283*f6dc9357SAndroid Build Coastguard Worker d.InsertAtFront('0');
284*f6dc9357SAndroid Build Coastguard Worker // here we have precision
285*f6dc9357SAndroid Build Coastguard Worker while (d.Len() > (unsigned)numDigits)
286*f6dc9357SAndroid Build Coastguard Worker d.DeleteBack();
287*f6dc9357SAndroid Build Coastguard Worker // GNU TAR reduces '0' digits.
288*f6dc9357SAndroid Build Coastguard Worker if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always)
289*f6dc9357SAndroid Build Coastguard Worker while (!d.IsEmpty() && d.Back() == '0')
290*f6dc9357SAndroid Build Coastguard Worker d.DeleteBack();
291*f6dc9357SAndroid Build Coastguard Worker
292*f6dc9357SAndroid Build Coastguard Worker if (!d.IsEmpty())
293*f6dc9357SAndroid Build Coastguard Worker {
294*f6dc9357SAndroid Build Coastguard Worker v.Add_Dot();
295*f6dc9357SAndroid Build Coastguard Worker v += d;
296*f6dc9357SAndroid Build Coastguard Worker // v += "1234567009999"; // for debug
297*f6dc9357SAndroid Build Coastguard Worker // for (int y = 0; y < 1000; y++) v += '8'; // for debug
298*f6dc9357SAndroid Build Coastguard Worker }
299*f6dc9357SAndroid Build Coastguard Worker }
300*f6dc9357SAndroid Build Coastguard Worker
301*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, name, v);
302*f6dc9357SAndroid Build Coastguard Worker }
303*f6dc9357SAndroid Build Coastguard Worker
304*f6dc9357SAndroid Build Coastguard Worker
AddPax_UInt32_ifBig(AString & s,const char * name,const UInt32 & v)305*f6dc9357SAndroid Build Coastguard Worker static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v)
306*f6dc9357SAndroid Build Coastguard Worker {
307*f6dc9357SAndroid Build Coastguard Worker if (v > k_7_oct_digits_Val_Max)
308*f6dc9357SAndroid Build Coastguard Worker {
309*f6dc9357SAndroid Build Coastguard Worker AString s2;
310*f6dc9357SAndroid Build Coastguard Worker s2.Add_UInt32(v);
311*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, name, s2);
312*f6dc9357SAndroid Build Coastguard Worker }
313*f6dc9357SAndroid Build Coastguard Worker }
314*f6dc9357SAndroid Build Coastguard Worker
315*f6dc9357SAndroid Build Coastguard Worker
316*f6dc9357SAndroid Build Coastguard Worker /* OLD_GNU_TAR: writes name with zero at the end
317*f6dc9357SAndroid Build Coastguard Worker NEW_GNU_TAR: can write name filled with all kNameSize characters */
318*f6dc9357SAndroid Build Coastguard Worker
319*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNameSize_Max =
320*f6dc9357SAndroid Build Coastguard Worker kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
321*f6dc9357SAndroid Build Coastguard Worker // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
322*f6dc9357SAndroid Build Coastguard Worker
323*f6dc9357SAndroid Build Coastguard Worker #define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max)
324*f6dc9357SAndroid Build Coastguard Worker
325*f6dc9357SAndroid Build Coastguard Worker
WriteHeader(const CItem & item)326*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::WriteHeader(const CItem &item)
327*f6dc9357SAndroid Build Coastguard Worker {
328*f6dc9357SAndroid Build Coastguard Worker Glob_Name.Empty();
329*f6dc9357SAndroid Build Coastguard Worker Prefix.Empty();
330*f6dc9357SAndroid Build Coastguard Worker
331*f6dc9357SAndroid Build Coastguard Worker unsigned namePos = 0;
332*f6dc9357SAndroid Build Coastguard Worker bool needPathCut = false;
333*f6dc9357SAndroid Build Coastguard Worker bool allowPrefix = false;
334*f6dc9357SAndroid Build Coastguard Worker
335*f6dc9357SAndroid Build Coastguard Worker if (!DOES_NAME_FIT_IN_FIELD(item.Name))
336*f6dc9357SAndroid Build Coastguard Worker {
337*f6dc9357SAndroid Build Coastguard Worker const char *s = item.Name;
338*f6dc9357SAndroid Build Coastguard Worker const char *p = s + item.Name.Len() - 1;
339*f6dc9357SAndroid Build Coastguard Worker for (; *p == '/' && p != s; p--)
340*f6dc9357SAndroid Build Coastguard Worker {}
341*f6dc9357SAndroid Build Coastguard Worker for (; p != s && p[-1] != '/'; p--)
342*f6dc9357SAndroid Build Coastguard Worker {}
343*f6dc9357SAndroid Build Coastguard Worker namePos = (unsigned)(p - s);
344*f6dc9357SAndroid Build Coastguard Worker needPathCut = true;
345*f6dc9357SAndroid Build Coastguard Worker }
346*f6dc9357SAndroid Build Coastguard Worker
347*f6dc9357SAndroid Build Coastguard Worker if (IsPosixMode)
348*f6dc9357SAndroid Build Coastguard Worker {
349*f6dc9357SAndroid Build Coastguard Worker AString s;
350*f6dc9357SAndroid Build Coastguard Worker
351*f6dc9357SAndroid Build Coastguard Worker if (needPathCut)
352*f6dc9357SAndroid Build Coastguard Worker {
353*f6dc9357SAndroid Build Coastguard Worker const unsigned nameLen = item.Name.Len() - namePos;
354*f6dc9357SAndroid Build Coastguard Worker if ( item.LinkFlag >= NLinkFlag::kNormal
355*f6dc9357SAndroid Build Coastguard Worker && item.LinkFlag <= NLinkFlag::kDirectory
356*f6dc9357SAndroid Build Coastguard Worker && namePos > 1
357*f6dc9357SAndroid Build Coastguard Worker && nameLen != 0
358*f6dc9357SAndroid Build Coastguard Worker // && IsPrefixAllowed
359*f6dc9357SAndroid Build Coastguard Worker && item.IsMagic_Posix_ustar_00())
360*f6dc9357SAndroid Build Coastguard Worker {
361*f6dc9357SAndroid Build Coastguard Worker /* GNU TAR decoder supports prefix field, only if (magic)
362*f6dc9357SAndroid Build Coastguard Worker signature matches 6-bytes "ustar\0".
363*f6dc9357SAndroid Build Coastguard Worker so here we use prefix field only in posix mode with posix signature */
364*f6dc9357SAndroid Build Coastguard Worker
365*f6dc9357SAndroid Build Coastguard Worker allowPrefix = true;
366*f6dc9357SAndroid Build Coastguard Worker // allowPrefix = false; // for debug
367*f6dc9357SAndroid Build Coastguard Worker if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max)
368*f6dc9357SAndroid Build Coastguard Worker {
369*f6dc9357SAndroid Build Coastguard Worker needPathCut = false;
370*f6dc9357SAndroid Build Coastguard Worker /* we will set Prefix and Glob_Name later, for such conditions:
371*f6dc9357SAndroid Build Coastguard Worker if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */
372*f6dc9357SAndroid Build Coastguard Worker }
373*f6dc9357SAndroid Build Coastguard Worker }
374*f6dc9357SAndroid Build Coastguard Worker
375*f6dc9357SAndroid Build Coastguard Worker if (needPathCut)
376*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, "path", item.Name);
377*f6dc9357SAndroid Build Coastguard Worker }
378*f6dc9357SAndroid Build Coastguard Worker
379*f6dc9357SAndroid Build Coastguard Worker // AddPaxLine(s, "testname", AString("testval")); // for debug
380*f6dc9357SAndroid Build Coastguard Worker
381*f6dc9357SAndroid Build Coastguard Worker if (item.LinkName.Len() > kNameSize_Max)
382*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, "linkpath", item.LinkName);
383*f6dc9357SAndroid Build Coastguard Worker
384*f6dc9357SAndroid Build Coastguard Worker const UInt64 kPaxSize_Limit = ((UInt64)1 << 33);
385*f6dc9357SAndroid Build Coastguard Worker // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug
386*f6dc9357SAndroid Build Coastguard Worker // bool zero_PackSize = false;
387*f6dc9357SAndroid Build Coastguard Worker if (item.PackSize >= kPaxSize_Limit)
388*f6dc9357SAndroid Build Coastguard Worker {
389*f6dc9357SAndroid Build Coastguard Worker /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB
390*f6dc9357SAndroid Build Coastguard Worker But old 7-Zip doesn't detect "size" property from pax header.
391*f6dc9357SAndroid Build Coastguard Worker So we write real size (>= 8 GiB) to main record in binary format,
392*f6dc9357SAndroid Build Coastguard Worker and old 7-Zip can decode size correctly */
393*f6dc9357SAndroid Build Coastguard Worker // zero_PackSize = true;
394*f6dc9357SAndroid Build Coastguard Worker AString v;
395*f6dc9357SAndroid Build Coastguard Worker v.Add_UInt64(item.PackSize);
396*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, "size", v);
397*f6dc9357SAndroid Build Coastguard Worker }
398*f6dc9357SAndroid Build Coastguard Worker
399*f6dc9357SAndroid Build Coastguard Worker /* GNU TAR encoder can set "devmajor" / "devminor" attributes,
400*f6dc9357SAndroid Build Coastguard Worker but GNU TAR decoder doesn't parse "devmajor" / "devminor" */
401*f6dc9357SAndroid Build Coastguard Worker if (item.DeviceMajor_Defined)
402*f6dc9357SAndroid Build Coastguard Worker AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor);
403*f6dc9357SAndroid Build Coastguard Worker if (item.DeviceMinor_Defined)
404*f6dc9357SAndroid Build Coastguard Worker AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor);
405*f6dc9357SAndroid Build Coastguard Worker
406*f6dc9357SAndroid Build Coastguard Worker AddPax_UInt32_ifBig(s, "uid", item.UID);
407*f6dc9357SAndroid Build Coastguard Worker AddPax_UInt32_ifBig(s, "gid", item.GID);
408*f6dc9357SAndroid Build Coastguard Worker
409*f6dc9357SAndroid Build Coastguard Worker const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33);
410*f6dc9357SAndroid Build Coastguard Worker const bool zero_MTime = (
411*f6dc9357SAndroid Build Coastguard Worker item.MTime < 0 ||
412*f6dc9357SAndroid Build Coastguard Worker item.MTime >= (Int64)kPax_MTime_Limit);
413*f6dc9357SAndroid Build Coastguard Worker
414*f6dc9357SAndroid Build Coastguard Worker const CPaxTime &mtime = item.PaxTimes.MTime;
415*f6dc9357SAndroid Build Coastguard Worker if (mtime.IsDefined())
416*f6dc9357SAndroid Build Coastguard Worker {
417*f6dc9357SAndroid Build Coastguard Worker bool needPax = false;
418*f6dc9357SAndroid Build Coastguard Worker if (zero_MTime)
419*f6dc9357SAndroid Build Coastguard Worker needPax = true;
420*f6dc9357SAndroid Build Coastguard Worker else if (TimeOptions.NumDigitsMax > 0)
421*f6dc9357SAndroid Build Coastguard Worker if (mtime.Ns != 0 ||
422*f6dc9357SAndroid Build Coastguard Worker (mtime.NumDigits != 0 &&
423*f6dc9357SAndroid Build Coastguard Worker TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero))
424*f6dc9357SAndroid Build Coastguard Worker needPax = true;
425*f6dc9357SAndroid Build Coastguard Worker if (needPax)
426*f6dc9357SAndroid Build Coastguard Worker AddPaxTime(s, "mtime", mtime, TimeOptions);
427*f6dc9357SAndroid Build Coastguard Worker }
428*f6dc9357SAndroid Build Coastguard Worker
429*f6dc9357SAndroid Build Coastguard Worker if (item.PaxTimes.ATime.IsDefined())
430*f6dc9357SAndroid Build Coastguard Worker AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions);
431*f6dc9357SAndroid Build Coastguard Worker if (item.PaxTimes.CTime.IsDefined())
432*f6dc9357SAndroid Build Coastguard Worker AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions);
433*f6dc9357SAndroid Build Coastguard Worker
434*f6dc9357SAndroid Build Coastguard Worker if (item.User.Len() > kUserNameSize)
435*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, "uname", item.User);
436*f6dc9357SAndroid Build Coastguard Worker if (item.Group.Len() > kGroupNameSize)
437*f6dc9357SAndroid Build Coastguard Worker AddPaxLine(s, "gname", item.Group);
438*f6dc9357SAndroid Build Coastguard Worker
439*f6dc9357SAndroid Build Coastguard Worker /*
440*f6dc9357SAndroid Build Coastguard Worker // for debug
441*f6dc9357SAndroid Build Coastguard Worker AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a);
442*f6dc9357SAndroid Build Coastguard Worker */
443*f6dc9357SAndroid Build Coastguard Worker
444*f6dc9357SAndroid Build Coastguard Worker const unsigned paxSize = s.Len();
445*f6dc9357SAndroid Build Coastguard Worker if (paxSize != 0)
446*f6dc9357SAndroid Build Coastguard Worker {
447*f6dc9357SAndroid Build Coastguard Worker CItem mi = item;
448*f6dc9357SAndroid Build Coastguard Worker mi.LinkName.Empty();
449*f6dc9357SAndroid Build Coastguard Worker // SparseBlocks will be ignored by Is_Sparse()
450*f6dc9357SAndroid Build Coastguard Worker // mi.SparseBlocks.Clear();
451*f6dc9357SAndroid Build Coastguard Worker // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder
452*f6dc9357SAndroid Build Coastguard Worker
453*f6dc9357SAndroid Build Coastguard Worker // GNU TAR writes empty for these fields;
454*f6dc9357SAndroid Build Coastguard Worker mi.User.Empty();
455*f6dc9357SAndroid Build Coastguard Worker mi.Group.Empty();
456*f6dc9357SAndroid Build Coastguard Worker mi.UID = 0;
457*f6dc9357SAndroid Build Coastguard Worker mi.GID = 0;
458*f6dc9357SAndroid Build Coastguard Worker
459*f6dc9357SAndroid Build Coastguard Worker mi.DeviceMajor_Defined = false;
460*f6dc9357SAndroid Build Coastguard Worker mi.DeviceMinor_Defined = false;
461*f6dc9357SAndroid Build Coastguard Worker
462*f6dc9357SAndroid Build Coastguard Worker mi.Name = "PaxHeader/@PaxHeader";
463*f6dc9357SAndroid Build Coastguard Worker mi.Mode = 0644; // octal
464*f6dc9357SAndroid Build Coastguard Worker if (zero_MTime)
465*f6dc9357SAndroid Build Coastguard Worker mi.MTime = 0;
466*f6dc9357SAndroid Build Coastguard Worker mi.LinkFlag = NLinkFlag::kPax;
467*f6dc9357SAndroid Build Coastguard Worker // mi.LinkFlag = 'Z'; // for debug
468*f6dc9357SAndroid Build Coastguard Worker mi.PackSize = paxSize;
469*f6dc9357SAndroid Build Coastguard Worker // for (unsigned y = 0; y < 1; y++) { // for debug
470*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteHeaderReal(mi, true)) // isPax
471*f6dc9357SAndroid Build Coastguard Worker RINOK(Write_Data_And_Residual(s, paxSize))
472*f6dc9357SAndroid Build Coastguard Worker // } // for debug
473*f6dc9357SAndroid Build Coastguard Worker /*
474*f6dc9357SAndroid Build Coastguard Worker we can send (zero_MTime) for compatibility with gnu tar output.
475*f6dc9357SAndroid Build Coastguard Worker we can send (zero_MTime = false) for better compatibility with old 7-Zip
476*f6dc9357SAndroid Build Coastguard Worker */
477*f6dc9357SAndroid Build Coastguard Worker // return WriteHeaderReal(item);
478*f6dc9357SAndroid Build Coastguard Worker /*
479*f6dc9357SAndroid Build Coastguard Worker false, // isPax
480*f6dc9357SAndroid Build Coastguard Worker false, // zero_PackSize
481*f6dc9357SAndroid Build Coastguard Worker false); // zero_MTime
482*f6dc9357SAndroid Build Coastguard Worker */
483*f6dc9357SAndroid Build Coastguard Worker }
484*f6dc9357SAndroid Build Coastguard Worker }
485*f6dc9357SAndroid Build Coastguard Worker else // !PosixMode
486*f6dc9357SAndroid Build Coastguard Worker if (!DOES_NAME_FIT_IN_FIELD(item.Name) ||
487*f6dc9357SAndroid Build Coastguard Worker !DOES_NAME_FIT_IN_FIELD(item.LinkName))
488*f6dc9357SAndroid Build Coastguard Worker {
489*f6dc9357SAndroid Build Coastguard Worker // here we can get all fields from main (item) or create new empty item
490*f6dc9357SAndroid Build Coastguard Worker /*
491*f6dc9357SAndroid Build Coastguard Worker CItem mi;
492*f6dc9357SAndroid Build Coastguard Worker mi.SetDefaultWriteFields();
493*f6dc9357SAndroid Build Coastguard Worker */
494*f6dc9357SAndroid Build Coastguard Worker CItem mi = item;
495*f6dc9357SAndroid Build Coastguard Worker mi.LinkName.Empty();
496*f6dc9357SAndroid Build Coastguard Worker // SparseBlocks will be ignored by Is_Sparse()
497*f6dc9357SAndroid Build Coastguard Worker // mi.SparseBlocks.Clear();
498*f6dc9357SAndroid Build Coastguard Worker mi.Name = kLongLink;
499*f6dc9357SAndroid Build Coastguard Worker // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug
500*f6dc9357SAndroid Build Coastguard Worker // 21.07 : we set Mode and MTime props as in GNU TAR:
501*f6dc9357SAndroid Build Coastguard Worker mi.Mode = 0644; // octal
502*f6dc9357SAndroid Build Coastguard Worker mi.MTime = 0;
503*f6dc9357SAndroid Build Coastguard Worker
504*f6dc9357SAndroid Build Coastguard Worker mi.User.Empty();
505*f6dc9357SAndroid Build Coastguard Worker mi.Group.Empty();
506*f6dc9357SAndroid Build Coastguard Worker /*
507*f6dc9357SAndroid Build Coastguard Worker gnu tar sets "root" for such items:
508*f6dc9357SAndroid Build Coastguard Worker uid_to_uname (0, &uname);
509*f6dc9357SAndroid Build Coastguard Worker gid_to_gname (0, &gname);
510*f6dc9357SAndroid Build Coastguard Worker */
511*f6dc9357SAndroid Build Coastguard Worker /*
512*f6dc9357SAndroid Build Coastguard Worker mi.User = "root";
513*f6dc9357SAndroid Build Coastguard Worker mi.Group = "root";
514*f6dc9357SAndroid Build Coastguard Worker */
515*f6dc9357SAndroid Build Coastguard Worker mi.UID = 0;
516*f6dc9357SAndroid Build Coastguard Worker mi.GID = 0;
517*f6dc9357SAndroid Build Coastguard Worker mi.DeviceMajor_Defined = false;
518*f6dc9357SAndroid Build Coastguard Worker mi.DeviceMinor_Defined = false;
519*f6dc9357SAndroid Build Coastguard Worker
520*f6dc9357SAndroid Build Coastguard Worker
521*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < 2; i++)
522*f6dc9357SAndroid Build Coastguard Worker {
523*f6dc9357SAndroid Build Coastguard Worker const AString *name;
524*f6dc9357SAndroid Build Coastguard Worker // We suppose that GNU TAR also writes item for long link before item for LongName?
525*f6dc9357SAndroid Build Coastguard Worker if (i == 0)
526*f6dc9357SAndroid Build Coastguard Worker {
527*f6dc9357SAndroid Build Coastguard Worker mi.LinkFlag = NLinkFlag::kGnu_LongLink;
528*f6dc9357SAndroid Build Coastguard Worker name = &item.LinkName;
529*f6dc9357SAndroid Build Coastguard Worker }
530*f6dc9357SAndroid Build Coastguard Worker else
531*f6dc9357SAndroid Build Coastguard Worker {
532*f6dc9357SAndroid Build Coastguard Worker mi.LinkFlag = NLinkFlag::kGnu_LongName;
533*f6dc9357SAndroid Build Coastguard Worker name = &item.Name;
534*f6dc9357SAndroid Build Coastguard Worker }
535*f6dc9357SAndroid Build Coastguard Worker if (DOES_NAME_FIT_IN_FIELD(*name))
536*f6dc9357SAndroid Build Coastguard Worker continue;
537*f6dc9357SAndroid Build Coastguard Worker // GNU TAR writes null character after NAME to file. We do same here:
538*f6dc9357SAndroid Build Coastguard Worker const unsigned nameStreamSize = name->Len() + 1;
539*f6dc9357SAndroid Build Coastguard Worker mi.PackSize = nameStreamSize;
540*f6dc9357SAndroid Build Coastguard Worker // for (unsigned y = 0; y < 3; y++) { // for debug
541*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteHeaderReal(mi))
542*f6dc9357SAndroid Build Coastguard Worker RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize))
543*f6dc9357SAndroid Build Coastguard Worker // }
544*f6dc9357SAndroid Build Coastguard Worker
545*f6dc9357SAndroid Build Coastguard Worker // for debug
546*f6dc9357SAndroid Build Coastguard Worker /*
547*f6dc9357SAndroid Build Coastguard Worker const unsigned kSize = (1 << 29) + 16;
548*f6dc9357SAndroid Build Coastguard Worker CByteBuffer buf;
549*f6dc9357SAndroid Build Coastguard Worker buf.Alloc(kSize);
550*f6dc9357SAndroid Build Coastguard Worker memset(buf, 0, kSize);
551*f6dc9357SAndroid Build Coastguard Worker memcpy(buf, name->Ptr(), name->Len());
552*f6dc9357SAndroid Build Coastguard Worker const unsigned nameStreamSize = kSize;
553*f6dc9357SAndroid Build Coastguard Worker mi.PackSize = nameStreamSize;
554*f6dc9357SAndroid Build Coastguard Worker // for (unsigned y = 0; y < 3; y++) { // for debug
555*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteHeaderReal(mi));
556*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteBytes(buf, nameStreamSize));
557*f6dc9357SAndroid Build Coastguard Worker RINOK(FillDataResidual(nameStreamSize));
558*f6dc9357SAndroid Build Coastguard Worker */
559*f6dc9357SAndroid Build Coastguard Worker }
560*f6dc9357SAndroid Build Coastguard Worker }
561*f6dc9357SAndroid Build Coastguard Worker
562*f6dc9357SAndroid Build Coastguard Worker // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR
563*f6dc9357SAndroid Build Coastguard Worker
564*f6dc9357SAndroid Build Coastguard Worker if (!DOES_NAME_FIT_IN_FIELD(item.Name))
565*f6dc9357SAndroid Build Coastguard Worker {
566*f6dc9357SAndroid Build Coastguard Worker const unsigned nameLen = item.Name.Len() - namePos;
567*f6dc9357SAndroid Build Coastguard Worker if (!needPathCut)
568*f6dc9357SAndroid Build Coastguard Worker Prefix.SetFrom(item.Name, namePos - 1);
569*f6dc9357SAndroid Build Coastguard Worker else
570*f6dc9357SAndroid Build Coastguard Worker {
571*f6dc9357SAndroid Build Coastguard Worker Glob_Name = K_PREFIX_PATH_CUT "/_pc_";
572*f6dc9357SAndroid Build Coastguard Worker
573*f6dc9357SAndroid Build Coastguard Worker if (namePos == 0)
574*f6dc9357SAndroid Build Coastguard Worker Glob_Name += "root";
575*f6dc9357SAndroid Build Coastguard Worker else
576*f6dc9357SAndroid Build Coastguard Worker {
577*f6dc9357SAndroid Build Coastguard Worker Glob_Name += "crc32/";
578*f6dc9357SAndroid Build Coastguard Worker char temp[12];
579*f6dc9357SAndroid Build Coastguard Worker ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp);
580*f6dc9357SAndroid Build Coastguard Worker Glob_Name += temp;
581*f6dc9357SAndroid Build Coastguard Worker }
582*f6dc9357SAndroid Build Coastguard Worker
583*f6dc9357SAndroid Build Coastguard Worker if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max)
584*f6dc9357SAndroid Build Coastguard Worker Glob_Name.Add_Slash();
585*f6dc9357SAndroid Build Coastguard Worker else
586*f6dc9357SAndroid Build Coastguard Worker {
587*f6dc9357SAndroid Build Coastguard Worker Prefix = Glob_Name;
588*f6dc9357SAndroid Build Coastguard Worker Glob_Name.Empty();
589*f6dc9357SAndroid Build Coastguard Worker }
590*f6dc9357SAndroid Build Coastguard Worker }
591*f6dc9357SAndroid Build Coastguard Worker Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen);
592*f6dc9357SAndroid Build Coastguard Worker }
593*f6dc9357SAndroid Build Coastguard Worker
594*f6dc9357SAndroid Build Coastguard Worker return WriteHeaderReal(item);
595*f6dc9357SAndroid Build Coastguard Worker }
596*f6dc9357SAndroid Build Coastguard Worker
597*f6dc9357SAndroid Build Coastguard Worker
Write_Data(const void * data,unsigned size)598*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::Write_Data(const void *data, unsigned size)
599*f6dc9357SAndroid Build Coastguard Worker {
600*f6dc9357SAndroid Build Coastguard Worker Pos += size;
601*f6dc9357SAndroid Build Coastguard Worker return WriteStream(Stream, data, size);
602*f6dc9357SAndroid Build Coastguard Worker }
603*f6dc9357SAndroid Build Coastguard Worker
Write_AfterDataResidual(UInt64 dataSize)604*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize)
605*f6dc9357SAndroid Build Coastguard Worker {
606*f6dc9357SAndroid Build Coastguard Worker const unsigned v = ((unsigned)dataSize & (kRecordSize - 1));
607*f6dc9357SAndroid Build Coastguard Worker if (v == 0)
608*f6dc9357SAndroid Build Coastguard Worker return S_OK;
609*f6dc9357SAndroid Build Coastguard Worker const unsigned rem = kRecordSize - v;
610*f6dc9357SAndroid Build Coastguard Worker Byte buf[kRecordSize];
611*f6dc9357SAndroid Build Coastguard Worker memset(buf, 0, rem);
612*f6dc9357SAndroid Build Coastguard Worker return Write_Data(buf, rem);
613*f6dc9357SAndroid Build Coastguard Worker }
614*f6dc9357SAndroid Build Coastguard Worker
615*f6dc9357SAndroid Build Coastguard Worker
Write_Data_And_Residual(const void * data,unsigned size)616*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size)
617*f6dc9357SAndroid Build Coastguard Worker {
618*f6dc9357SAndroid Build Coastguard Worker RINOK(Write_Data(data, size))
619*f6dc9357SAndroid Build Coastguard Worker return Write_AfterDataResidual(size);
620*f6dc9357SAndroid Build Coastguard Worker }
621*f6dc9357SAndroid Build Coastguard Worker
622*f6dc9357SAndroid Build Coastguard Worker
WriteFinishHeader()623*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::WriteFinishHeader()
624*f6dc9357SAndroid Build Coastguard Worker {
625*f6dc9357SAndroid Build Coastguard Worker Byte record[kRecordSize];
626*f6dc9357SAndroid Build Coastguard Worker memset(record, 0, kRecordSize);
627*f6dc9357SAndroid Build Coastguard Worker
628*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumFinishRecords = 2;
629*f6dc9357SAndroid Build Coastguard Worker
630*f6dc9357SAndroid Build Coastguard Worker /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB)
631*f6dc9357SAndroid Build Coastguard Worker we also can use cluster alignment:
632*f6dc9357SAndroid Build Coastguard Worker const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords;
633*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB
634*f6dc9357SAndroid Build Coastguard Worker const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1));
635*f6dc9357SAndroid Build Coastguard Worker */
636*f6dc9357SAndroid Build Coastguard Worker
637*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNumFinishRecords; i++)
638*f6dc9357SAndroid Build Coastguard Worker {
639*f6dc9357SAndroid Build Coastguard Worker RINOK(Write_Data(record, kRecordSize))
640*f6dc9357SAndroid Build Coastguard Worker }
641*f6dc9357SAndroid Build Coastguard Worker return S_OK;
642*f6dc9357SAndroid Build Coastguard Worker }
643*f6dc9357SAndroid Build Coastguard Worker
644*f6dc9357SAndroid Build Coastguard Worker }}
645