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 15using namespace NWindows; 16using 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 31static 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 102static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:"; 103static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:"; 104static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; 105 106Z7_ATTR_NORETURN 107static 108void 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 116static 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 126static 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 137void 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