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