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.Add_LF(); m += s1; 50 m.Add_LF(); 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 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