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 14using namespace NWindows; 15using namespace NTime; 16 17static 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 41static const char *k_Duplicate_inArc_Message = "Duplicate filename in archive:"; 42static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:"; 43static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; 44 45static 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 54static 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 64static 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 75void 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