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 += L'\n'; m += s1;
50 m += L'\n'; 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 {
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