1 // UpdatePair.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <time.h>
6 
7 #include "../../../Common/Wildcard.h"
8 
9 #include "../../../Windows/TimeUtils.h"
10 
11 #include "SortUtils.h"
12 #include "UpdatePair.h"
13 
14 using namespace NWindows;
15 using namespace NTime;
16 
MyCompareTime(NFileTimeType::EEnum fileTimeType,const FILETIME & time1,const FILETIME & time2)17 static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)
18 {
19   switch (fileTimeType)
20   {
21     case NFileTimeType::kWindows:
22       return ::CompareFileTime(&time1, &time2);
23     case NFileTimeType::kUnix:
24       {
25         UInt32 unixTime1, unixTime2;
26         FileTimeToUnixTime(time1, unixTime1);
27         FileTimeToUnixTime(time2, unixTime2);
28         return MyCompare(unixTime1, unixTime2);
29       }
30     case NFileTimeType::kDOS:
31       {
32         UInt32 dosTime1, dosTime2;
33         FileTimeToDosTime(time1, dosTime1);
34         FileTimeToDosTime(time2, dosTime2);
35         return MyCompare(dosTime1, dosTime2);
36       }
37   }
38   throw 4191618;
39 }
40 
41 static const char *k_Duplicate_inArc_Message = "Duplicate filename in archive:";
42 static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:";
43 static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
44 
ThrowError(const char * message,const UString & s1,const UString & s2)45 static void ThrowError(const char *message, const UString &s1, const UString &s2)
46 {
47   UString m;
48   m.SetFromAscii(message);
49   m.Add_LF(); m += s1;
50   m.Add_LF(); m += s2;
51   throw m;
52 }
53 
CompareArcItemsBase(const CArcItem & ai1,const CArcItem & ai2)54 static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
55 {
56   int res = CompareFileNames(ai1.Name, ai2.Name);
57   if (res != 0)
58     return res;
59   if (ai1.IsDir != ai2.IsDir)
60     return ai1.IsDir ? -1 : 1;
61   return 0;
62 }
63 
CompareArcItems(const unsigned * p1,const unsigned * p2,void * param)64 static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
65 {
66   unsigned i1 = *p1;
67   unsigned i2 = *p2;
68   const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
69   int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
70   if (res != 0)
71     return res;
72   return MyCompare(i1, i2);
73 }
74 
GetUpdatePairInfoList(const CDirItems & dirItems,const CObjectVector<CArcItem> & arcItems,NFileTimeType::EEnum fileTimeType,CRecordVector<CUpdatePair> & updatePairs)75 void GetUpdatePairInfoList(
76     const CDirItems &dirItems,
77     const CObjectVector<CArcItem> &arcItems,
78     NFileTimeType::EEnum fileTimeType,
79     CRecordVector<CUpdatePair> &updatePairs)
80 {
81   CUIntVector dirIndices, arcIndices;
82 
83   unsigned numDirItems = dirItems.Items.Size();
84   unsigned numArcItems = arcItems.Size();
85 
86   CIntArr duplicatedArcItem(numArcItems);
87   {
88     int *vals = &duplicatedArcItem[0];
89     for (unsigned i = 0; i < numArcItems; i++)
90       vals[i] = 0;
91   }
92 
93   {
94     arcIndices.ClearAndSetSize(numArcItems);
95     if (numArcItems != 0)
96     {
97       unsigned *vals = &arcIndices[0];
98       for (unsigned i = 0; i < numArcItems; i++)
99         vals[i] = i;
100     }
101     arcIndices.Sort(CompareArcItems, (void *)&arcItems);
102     for (unsigned i = 0; i + 1 < numArcItems; i++)
103       if (CompareArcItemsBase(
104           arcItems[arcIndices[i]],
105           arcItems[arcIndices[i + 1]]) == 0)
106       {
107         duplicatedArcItem[i] = 1;
108         duplicatedArcItem[i + 1] = -1;
109       }
110   }
111 
112   UStringVector dirNames;
113   {
114     dirNames.ClearAndReserve(numDirItems);
115     unsigned i;
116     for (i = 0; i < numDirItems; i++)
117       dirNames.AddInReserved(dirItems.GetLogPath(i));
118     SortFileNames(dirNames, dirIndices);
119     for (i = 0; i + 1 < numDirItems; i++)
120     {
121       const UString &s1 = dirNames[dirIndices[i]];
122       const UString &s2 = dirNames[dirIndices[i + 1]];
123       if (CompareFileNames(s1, s2) == 0)
124         ThrowError(k_Duplicate_inDir_Message, s1, s2);
125     }
126   }
127 
128   unsigned dirIndex = 0;
129   unsigned arcIndex = 0;
130 
131   int prevHostFile = -1;
132   const UString *prevHostName = NULL;
133 
134   while (dirIndex < numDirItems || arcIndex < numArcItems)
135   {
136     CUpdatePair pair;
137 
138     int dirIndex2 = -1;
139     int arcIndex2 = -1;
140     const CDirItem *di = NULL;
141     const CArcItem *ai = NULL;
142 
143     int compareResult = -1;
144     const UString *name = NULL;
145 
146     if (dirIndex < numDirItems)
147     {
148       dirIndex2 = dirIndices[dirIndex];
149       di = &dirItems.Items[dirIndex2];
150     }
151 
152     if (arcIndex < numArcItems)
153     {
154       arcIndex2 = arcIndices[arcIndex];
155       ai = &arcItems[arcIndex2];
156       compareResult = 1;
157       if (dirIndex < numDirItems)
158       {
159         compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name);
160         if (compareResult == 0)
161         {
162           if (di->IsDir() != ai->IsDir)
163             compareResult = (ai->IsDir ? 1 : -1);
164         }
165       }
166     }
167 
168     if (compareResult < 0)
169     {
170       name = &dirNames[dirIndex2];
171       pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
172       pair.DirIndex = dirIndex2;
173       dirIndex++;
174     }
175     else if (compareResult > 0)
176     {
177       name = &ai->Name;
178       pair.State = ai->Censored ?
179           NUpdateArchive::NPairState::kOnlyInArchive:
180           NUpdateArchive::NPairState::kNotMasked;
181       pair.ArcIndex = arcIndex2;
182       arcIndex++;
183     }
184     else
185     {
186       int dupl = duplicatedArcItem[arcIndex];
187       if (dupl != 0)
188         ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name);
189 
190       name = &dirNames[dirIndex2];
191       if (!ai->Censored)
192         ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
193 
194       pair.DirIndex = dirIndex2;
195       pair.ArcIndex = arcIndex2;
196 
197       switch (ai->MTimeDefined ? MyCompareTime(
198           ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType,
199           di->MTime, ai->MTime): 0)
200       {
201         case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
202         case  1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
203         default:
204           pair.State = (ai->SizeDefined && di->Size == ai->Size) ?
205               NUpdateArchive::NPairState::kSameFiles :
206               NUpdateArchive::NPairState::kUnknowNewerFiles;
207       }
208 
209       dirIndex++;
210       arcIndex++;
211     }
212 
213     if ((di && di->IsAltStream) ||
214         (ai && ai->IsAltStream))
215     {
216       if (prevHostName)
217       {
218         unsigned hostLen = prevHostName->Len();
219         if (name->Len() > hostLen)
220           if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
221             pair.HostIndex = prevHostFile;
222       }
223     }
224     else
225     {
226       prevHostFile = updatePairs.Size();
227       prevHostName = name;
228     }
229 
230     updatePairs.Add(pair);
231   }
232 
233   updatePairs.ReserveDown();
234 }
235