xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Tar/TarHandlerOut.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // TarHandlerOut.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include <stdio.h>
6 
7 #include "../../../Common/ComTry.h"
8 #include "../../../Common/MyLinux.h"
9 #include "../../../Common/StringConvert.h"
10 
11 #include "../../../Windows/TimeUtils.h"
12 
13 #include "../Common/ItemNameUtils.h"
14 
15 #include "TarHandler.h"
16 #include "TarUpdate.h"
17 
18 using namespace NWindows;
19 
20 namespace NArchive {
21 namespace NTar {
22 
Z7_COM7F_IMF(CHandler::GetFileTimeType (UInt32 * type))23 Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
24 {
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;
40   return S_OK;
41 }
42 
43 
Get_AString_From_UString(const UString & s,AString & res,UINT codePage,unsigned utfFlags)44 void 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 
GetPropString(IArchiveUpdateCallback * callback,UInt32 index,PROPID propId,AString & res,UINT codePage,unsigned utfFlags,bool convertSlash)54 HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
55     UINT codePage, unsigned utfFlags, bool convertSlash)
56 {
57   NCOM::CPropVariant prop;
58   RINOK(callback->GetProperty(index, propId, &prop))
59 
60   if (prop.vt == VT_BSTR)
61   {
62     UString s = prop.bstrVal;
63     if (convertSlash)
64       NItemName::ReplaceSlashes_OsToUnix(s);
65     Get_AString_From_UString(s, res, codePage, utfFlags);
66   }
67   else if (prop.vt != VT_EMPTY)
68     return E_INVALIDARG;
69 
70   return S_OK;
71 }
72 
73 
74 // sort old files with original order.
75 
CompareUpdateItems(void * const * p1,void * const * p2,void *)76 static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
77 {
78   const CUpdateItem &u1 = *(*((const CUpdateItem *const *)p1));
79   const CUpdateItem &u2 = *(*((const CUpdateItem *const *)p2));
80   if (!u1.NewProps)
81   {
82     if (u2.NewProps)
83       return -1;
84     return MyCompare(u1.IndexInArc, u2.IndexInArc);
85   }
86   if (!u2.NewProps)
87     return 1;
88   return MyCompare(u1.IndexInClient, u2.IndexInClient);
89 }
90 
91 
GetTime(UInt32 i,UInt32 pid,IArchiveUpdateCallback * callback,CPaxTime & pt)92 static 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 /*
103 static 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 
GetDevice(IArchiveUpdateCallback * callback,UInt32 i,UInt32 pid,UInt32 & id,bool & defined)123 static 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 
GetUser(IArchiveUpdateCallback * callback,UInt32 i,UInt32 pidName,UInt32 pidId,AString & name,UInt32 & id,UINT codePage,unsigned utfFlags)141 static 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 
Z7_COM7F_IMF(CHandler::UpdateItems (ISequentialOutStream * outStream,UInt32 numItems,IArchiveUpdateCallback * callback))184 Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
185     IArchiveUpdateCallback *callback))
186 {
187   COM_TRY_BEGIN
188 
189   if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning
190       /* || _isSparse */
191       )) || _seqStream)
192     return E_NOTIMPL;
193   CObjectVector<CUpdateItem> updateItems;
194   const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
195   const unsigned utfFlags = g_Unicode_To_UTF8_Flags;
196   /*
197   // for debug only:
198   unsigned utfFlags = 0;
199   utfFlags |= Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE;
200   utfFlags |= Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR;
201   */
202 
203   for (UInt32 i = 0; i < numItems; i++)
204   {
205     CUpdateItem ui;
206     Int32 newData;
207     Int32 newProps;
208     UInt32 indexInArc;
209 
210     if (!callback)
211       return E_FAIL;
212 
213     RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc))
214 
215     ui.NewProps = IntToBool(newProps);
216     ui.NewData = IntToBool(newData);
217     ui.IndexInArc = (int)indexInArc;
218     ui.IndexInClient = i;
219 
220     if (IntToBool(newProps))
221     {
222       {
223         NCOM::CPropVariant prop;
224         RINOK(callback->GetProperty(i, kpidIsDir, &prop))
225         if (prop.vt == VT_EMPTY)
226           ui.IsDir = false;
227         else if (prop.vt != VT_BOOL)
228           return E_INVALIDARG;
229         else
230           ui.IsDir = (prop.boolVal != VARIANT_FALSE);
231       }
232 
233       {
234         NCOM::CPropVariant prop;
235         RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop))
236         if (prop.vt == VT_EMPTY)
237           ui.Mode =
238                 MY_LIN_S_IRWXO
239               | MY_LIN_S_IRWXG
240               | MY_LIN_S_IRWXU
241               | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
242         else if (prop.vt != VT_UI4)
243           return E_INVALIDARG;
244         else
245           ui.Mode = prop.ulVal;
246         // 21.07 : we clear high file type bits as GNU TAR.
247         // we will clear it later
248         // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
249       }
250 
251       if (_handlerTimeOptions.Write_MTime.Val)
252         RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime))
253       if (_handlerTimeOptions.Write_ATime.Val)
254         RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime))
255       if (_handlerTimeOptions.Write_CTime.Val)
256         RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime))
257 
258       RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true))
259       if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
260         ui.Name.Add_Slash();
261       // ui.Name.Add_Slash(); // for debug
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))
271     }
272 
273     if (IntToBool(newData))
274     {
275       NCOM::CPropVariant prop;
276       RINOK(callback->GetProperty(i, kpidSize, &prop))
277       if (prop.vt != VT_UI8)
278         return E_INVALIDARG;
279       ui.Size = prop.uhVal.QuadPart;
280       /*
281       // now we support GNU extension for big files
282       if (ui.Size >= ((UInt64)1 << 33))
283         return E_INVALIDARG;
284       */
285     }
286 
287     updateItems.Add(ui);
288   }
289 
290   if (_arc._are_Pax_Items)
291   {
292     // we restore original order of files, if there are pax items
293     updateItems.Sort(CompareUpdateItems, NULL);
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;
305 
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);
328 
329   COM_TRY_END
330 }
331 
332 }}
333