xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Common/UpdatePair.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // UpdatePair.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <time.h>
6 // #include <stdio.h>
7 
8 #include "../../../Common/Wildcard.h"
9 
10 #include "../../../Windows/TimeUtils.h"
11 
12 #include "SortUtils.h"
13 #include "UpdatePair.h"
14 
15 using namespace NWindows;
16 using namespace NTime;
17 
18 
19 /*
20   a2.Prec =
21   {
22     0 (k_PropVar_TimePrec_0):
23        if GetProperty(kpidMTime) returned 0 and
24           GetProperty(kpidTimeType) did not returned VT_UI4.
25        7z, wim, tar in 7-Zip before v21)
26     in that case we use
27       (prec) that is set by IOutArchive::GetFileTimeType()
28   }
29 */
30 
MyCompareTime(unsigned prec,const CFiTime & f1,const CArcTime & a2)31 static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2)
32 {
33   // except of precision, we also have limitation, when timestamp is out of range
34 
35   /* if (Prec) in archive item is defined, then use global (prec) */
36   if (a2.Prec != k_PropVar_TimePrec_0)
37     prec = a2.Prec;
38 
39   CArcTime a1;
40   a1.Set_From_FiTime(f1);
41   /* Set_From_FiTime() must set full form precision:
42      k_PropVar_TimePrec_Base + numDigits
43      windows: 7 digits, non-windows: 9 digits */
44 
45   if (prec == k_PropVar_TimePrec_DOS)
46   {
47     const UInt32 dosTime1 = a1.Get_DosTime();
48     const UInt32 dosTime2 = a2.Get_DosTime();
49     return MyCompare(dosTime1, dosTime2);
50   }
51 
52   if (prec == k_PropVar_TimePrec_Unix)
53   {
54     const Int64 u2 = FileTime_To_UnixTime64(a2.FT);
55     if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF)
56     {
57       // timestamp probably was saturated in archive to 32-bit
58       // so we use saturated 32-bit value for disk file too.
59       UInt32 u1;
60       FileTime_To_UnixTime(a1.FT, u1);
61       const UInt32 u2_32 = (UInt32)u2;
62       return MyCompare(u1, u2_32);
63     }
64 
65     const Int64 u1 = FileTime_To_UnixTime64(a1.FT);
66     return MyCompare(u1, u2);
67     // prec = k_PropVar_TimePrec_Base; // for debug
68   }
69 
70   if (prec == k_PropVar_TimePrec_0)
71     prec = k_PropVar_TimePrec_Base + 7;
72   else if (prec == k_PropVar_TimePrec_HighPrec)
73     prec = k_PropVar_TimePrec_Base + 9;
74   else if (prec < k_PropVar_TimePrec_Base)
75     prec = k_PropVar_TimePrec_Base;
76   else if (prec > k_PropVar_TimePrec_Base + 9)
77     prec = k_PropVar_TimePrec_Base + 7;
78 
79   // prec now is full form: k_PropVar_TimePrec_Base + numDigits;
80   if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base)
81     prec = a1.Prec;
82 
83   const unsigned numDigits = prec - k_PropVar_TimePrec_Base;
84   if (numDigits >= 7)
85   {
86     const int comp = CompareFileTime(&a1.FT, &a2.FT);
87     if (comp != 0 || numDigits == 7)
88       return comp;
89     return MyCompare(a1.Ns100, a2.Ns100);
90   }
91   UInt32 d = 1;
92   for (unsigned k = numDigits; k < 7; k++)
93     d *= 10;
94   const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d;
95   const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d;
96   // printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits);
97   return MyCompare(v1, v2);
98 }
99 
100 
101 
102 static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:";
103 static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:";
104 static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
105 
106 Z7_ATTR_NORETURN
107 static
ThrowError(const char * message,const UString & s1,const UString & s2)108 void ThrowError(const char *message, const UString &s1, const UString &s2)
109 {
110   UString m (message);
111   m.Add_LF(); m += s1;
112   m.Add_LF(); m += s2;
113   throw m;
114 }
115 
CompareArcItemsBase(const CArcItem & ai1,const CArcItem & ai2)116 static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
117 {
118   const int res = CompareFileNames(ai1.Name, ai2.Name);
119   if (res != 0)
120     return res;
121   if (ai1.IsDir != ai2.IsDir)
122     return ai1.IsDir ? -1 : 1;
123   return 0;
124 }
125 
CompareArcItems(const unsigned * p1,const unsigned * p2,void * param)126 static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
127 {
128   const unsigned i1 = *p1;
129   const unsigned i2 = *p2;
130   const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
131   const int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
132   if (res != 0)
133     return res;
134   return MyCompare(i1, i2);
135 }
136 
GetUpdatePairInfoList(const CDirItems & dirItems,const CObjectVector<CArcItem> & arcItems,NFileTimeType::EEnum fileTimeType,CRecordVector<CUpdatePair> & updatePairs)137 void GetUpdatePairInfoList(
138     const CDirItems &dirItems,
139     const CObjectVector<CArcItem> &arcItems,
140     NFileTimeType::EEnum fileTimeType,
141     CRecordVector<CUpdatePair> &updatePairs)
142 {
143   CUIntVector dirIndices, arcIndices;
144 
145   const unsigned numDirItems = dirItems.Items.Size();
146   const unsigned numArcItems = arcItems.Size();
147 
148   CIntArr duplicatedArcItem(numArcItems);
149   {
150     int *vals = &duplicatedArcItem[0];
151     for (unsigned i = 0; i < numArcItems; i++)
152       vals[i] = 0;
153   }
154 
155   {
156     arcIndices.ClearAndSetSize(numArcItems);
157     if (numArcItems != 0)
158     {
159       unsigned *vals = &arcIndices[0];
160       for (unsigned i = 0; i < numArcItems; i++)
161         vals[i] = i;
162     }
163     arcIndices.Sort(CompareArcItems, (void *)&arcItems);
164     for (unsigned i = 0; i + 1 < numArcItems; i++)
165       if (CompareArcItemsBase(
166           arcItems[arcIndices[i]],
167           arcItems[arcIndices[i + 1]]) == 0)
168       {
169         duplicatedArcItem[i] = 1;
170         duplicatedArcItem[i + 1] = -1;
171       }
172   }
173 
174   UStringVector dirNames;
175   {
176     dirNames.ClearAndReserve(numDirItems);
177     unsigned i;
178     for (i = 0; i < numDirItems; i++)
179       dirNames.AddInReserved(dirItems.GetLogPath(i));
180     SortFileNames(dirNames, dirIndices);
181     for (i = 0; i + 1 < numDirItems; i++)
182     {
183       const UString &s1 = dirNames[dirIndices[i]];
184       const UString &s2 = dirNames[dirIndices[i + 1]];
185       if (CompareFileNames(s1, s2) == 0)
186         ThrowError(k_Duplicate_inDir_Message, s1, s2);
187     }
188   }
189 
190   unsigned dirIndex = 0;
191   unsigned arcIndex = 0;
192 
193   int prevHostFile = -1;
194   const UString *prevHostName = NULL;
195 
196   while (dirIndex < numDirItems || arcIndex < numArcItems)
197   {
198     CUpdatePair pair;
199 
200     int dirIndex2 = -1;
201     int arcIndex2 = -1;
202     const CDirItem *di = NULL;
203     const CArcItem *ai = NULL;
204 
205     int compareResult = -1;
206     const UString *name = NULL;
207 
208     if (dirIndex < numDirItems)
209     {
210       dirIndex2 = (int)dirIndices[dirIndex];
211       di = &dirItems.Items[(unsigned)dirIndex2];
212     }
213 
214     if (arcIndex < numArcItems)
215     {
216       arcIndex2 = (int)arcIndices[arcIndex];
217       ai = &arcItems[(unsigned)arcIndex2];
218       compareResult = 1;
219       if (dirIndex < numDirItems)
220       {
221         compareResult = CompareFileNames(dirNames[(unsigned)dirIndex2], ai->Name);
222         if (compareResult == 0)
223         {
224           if (di->IsDir() != ai->IsDir)
225             compareResult = (ai->IsDir ? 1 : -1);
226         }
227       }
228     }
229 
230     if (compareResult < 0)
231     {
232       name = &dirNames[(unsigned)dirIndex2];
233       pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
234       pair.DirIndex = dirIndex2;
235       dirIndex++;
236     }
237     else if (compareResult > 0)
238     {
239       name = &ai->Name;
240       pair.State = ai->Censored ?
241           NUpdateArchive::NPairState::kOnlyInArchive:
242           NUpdateArchive::NPairState::kNotMasked;
243       pair.ArcIndex = arcIndex2;
244       arcIndex++;
245     }
246     else
247     {
248       const int dupl = duplicatedArcItem[arcIndex];
249       if (dupl != 0)
250         ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name);
251 
252       name = &dirNames[(unsigned)dirIndex2];
253       if (!ai->Censored)
254         ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
255 
256       pair.DirIndex = dirIndex2;
257       pair.ArcIndex = arcIndex2;
258 
259       int compResult = 0;
260       if (ai->MTime.Def)
261       {
262         compResult = MyCompareTime((unsigned)fileTimeType, di->MTime, ai->MTime);
263       }
264       switch (compResult)
265       {
266         case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
267         case  1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
268         default:
269           pair.State = (ai->Size_Defined && di->Size == ai->Size) ?
270               NUpdateArchive::NPairState::kSameFiles :
271               NUpdateArchive::NPairState::kUnknowNewerFiles;
272       }
273 
274       dirIndex++;
275       arcIndex++;
276     }
277 
278     if (
279        #ifdef _WIN32
280         (di && di->IsAltStream) ||
281        #endif
282         (ai && ai->IsAltStream))
283     {
284       if (prevHostName)
285       {
286         const unsigned hostLen = prevHostName->Len();
287         if (name->Len() > hostLen)
288           if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
289             pair.HostIndex = prevHostFile;
290       }
291     }
292     else
293     {
294       prevHostFile = (int)updatePairs.Size();
295       prevHostName = name;
296     }
297 
298     updatePairs.Add(pair);
299   }
300 
301   updatePairs.ReserveDown();
302 }
303