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 * const k_Duplicate_inArc_Message = "Duplicate filename in archive:";
42 static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:";
43 static const char * const 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 (message);
48   m.Add_LF(); m += s1;
49   m.Add_LF(); m += s2;
50   throw m;
51 }
52 
CompareArcItemsBase(const CArcItem & ai1,const CArcItem & ai2)53 static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
54 {
55   int res = CompareFileNames(ai1.Name, ai2.Name);
56   if (res != 0)
57     return res;
58   if (ai1.IsDir != ai2.IsDir)
59     return ai1.IsDir ? -1 : 1;
60   return 0;
61 }
62 
CompareArcItems(const unsigned * p1,const unsigned * p2,void * param)63 static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
64 {
65   unsigned i1 = *p1;
66   unsigned i2 = *p2;
67   const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
68   int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
69   if (res != 0)
70     return res;
71   return MyCompare(i1, i2);
72 }
73 
GetUpdatePairInfoList(const CDirItems & dirItems,const CObjectVector<CArcItem> & arcItems,NFileTimeType::EEnum fileTimeType,CRecordVector<CUpdatePair> & updatePairs)74 void GetUpdatePairInfoList(
75     const CDirItems &dirItems,
76     const CObjectVector<CArcItem> &arcItems,
77     NFileTimeType::EEnum fileTimeType,
78     CRecordVector<CUpdatePair> &updatePairs)
79 {
80   CUIntVector dirIndices, arcIndices;
81 
82   unsigned numDirItems = dirItems.Items.Size();
83   unsigned numArcItems = arcItems.Size();
84 
85   CIntArr duplicatedArcItem(numArcItems);
86   {
87     int *vals = &duplicatedArcItem[0];
88     for (unsigned i = 0; i < numArcItems; i++)
89       vals[i] = 0;
90   }
91 
92   {
93     arcIndices.ClearAndSetSize(numArcItems);
94     if (numArcItems != 0)
95     {
96       unsigned *vals = &arcIndices[0];
97       for (unsigned i = 0; i < numArcItems; i++)
98         vals[i] = i;
99     }
100     arcIndices.Sort(CompareArcItems, (void *)&arcItems);
101     for (unsigned i = 0; i + 1 < numArcItems; i++)
102       if (CompareArcItemsBase(
103           arcItems[arcIndices[i]],
104           arcItems[arcIndices[i + 1]]) == 0)
105       {
106         duplicatedArcItem[i] = 1;
107         duplicatedArcItem[i + 1] = -1;
108       }
109   }
110 
111   UStringVector dirNames;
112   {
113     dirNames.ClearAndReserve(numDirItems);
114     unsigned i;
115     for (i = 0; i < numDirItems; i++)
116       dirNames.AddInReserved(dirItems.GetLogPath(i));
117     SortFileNames(dirNames, dirIndices);
118     for (i = 0; i + 1 < numDirItems; i++)
119     {
120       const UString &s1 = dirNames[dirIndices[i]];
121       const UString &s2 = dirNames[dirIndices[i + 1]];
122       if (CompareFileNames(s1, s2) == 0)
123         ThrowError(k_Duplicate_inDir_Message, s1, s2);
124     }
125   }
126 
127   unsigned dirIndex = 0;
128   unsigned arcIndex = 0;
129 
130   int prevHostFile = -1;
131   const UString *prevHostName = NULL;
132 
133   while (dirIndex < numDirItems || arcIndex < numArcItems)
134   {
135     CUpdatePair pair;
136 
137     int dirIndex2 = -1;
138     int arcIndex2 = -1;
139     const CDirItem *di = NULL;
140     const CArcItem *ai = NULL;
141 
142     int compareResult = -1;
143     const UString *name = NULL;
144 
145     if (dirIndex < numDirItems)
146     {
147       dirIndex2 = dirIndices[dirIndex];
148       di = &dirItems.Items[dirIndex2];
149     }
150 
151     if (arcIndex < numArcItems)
152     {
153       arcIndex2 = arcIndices[arcIndex];
154       ai = &arcItems[arcIndex2];
155       compareResult = 1;
156       if (dirIndex < numDirItems)
157       {
158         compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name);
159         if (compareResult == 0)
160         {
161           if (di->IsDir() != ai->IsDir)
162             compareResult = (ai->IsDir ? 1 : -1);
163         }
164       }
165     }
166 
167     if (compareResult < 0)
168     {
169       name = &dirNames[dirIndex2];
170       pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
171       pair.DirIndex = dirIndex2;
172       dirIndex++;
173     }
174     else if (compareResult > 0)
175     {
176       name = &ai->Name;
177       pair.State = ai->Censored ?
178           NUpdateArchive::NPairState::kOnlyInArchive:
179           NUpdateArchive::NPairState::kNotMasked;
180       pair.ArcIndex = arcIndex2;
181       arcIndex++;
182     }
183     else
184     {
185       int dupl = duplicatedArcItem[arcIndex];
186       if (dupl != 0)
187         ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name);
188 
189       name = &dirNames[dirIndex2];
190       if (!ai->Censored)
191         ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
192 
193       pair.DirIndex = dirIndex2;
194       pair.ArcIndex = arcIndex2;
195 
196       switch (ai->MTimeDefined ? MyCompareTime(
197           ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType,
198           di->MTime, ai->MTime): 0)
199       {
200         case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
201         case  1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
202         default:
203           pair.State = (ai->SizeDefined && di->Size == ai->Size) ?
204               NUpdateArchive::NPairState::kSameFiles :
205               NUpdateArchive::NPairState::kUnknowNewerFiles;
206       }
207 
208       dirIndex++;
209       arcIndex++;
210     }
211 
212     if ((di && di->IsAltStream) ||
213         (ai && ai->IsAltStream))
214     {
215       if (prevHostName)
216       {
217         unsigned hostLen = prevHostName->Len();
218         if (name->Len() > hostLen)
219           if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
220             pair.HostIndex = prevHostFile;
221       }
222     }
223     else
224     {
225       prevHostFile = updatePairs.Size();
226       prevHostName = name;
227     }
228 
229     updatePairs.Add(pair);
230   }
231 
232   updatePairs.ReserveDown();
233 }
234