xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Tar/TarOut.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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