// UpdatePair.cpp | |
#include "StdAfx.h" | |
#include <time.h> | |
#include "../../../Common/Wildcard.h" | |
#include "../../../Windows/TimeUtils.h" | |
#include "SortUtils.h" | |
#include "UpdatePair.h" | |
using namespace NWindows; | |
using namespace NTime; | |
static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2) | |
{ | |
switch (fileTimeType) | |
{ | |
case NFileTimeType::kWindows: | |
return ::CompareFileTime(&time1, &time2); | |
case NFileTimeType::kUnix: | |
{ | |
UInt32 unixTime1, unixTime2; | |
FileTimeToUnixTime(time1, unixTime1); | |
FileTimeToUnixTime(time2, unixTime2); | |
return MyCompare(unixTime1, unixTime2); | |
} | |
case NFileTimeType::kDOS: | |
{ | |
UInt32 dosTime1, dosTime2; | |
FileTimeToDosTime(time1, dosTime1); | |
FileTimeToDosTime(time2, dosTime2); | |
return MyCompare(dosTime1, dosTime2); | |
} | |
} | |
throw 4191618; | |
} | |
static const char *k_Duplicate_inArc_Message = "Duplicate filename in archive:"; | |
static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:"; | |
static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; | |
static void ThrowError(const char *message, const UString &s1, const UString &s2) | |
{ | |
UString m; | |
m.SetFromAscii(message); | |
m += L'\n'; m += s1; | |
m += L'\n'; m += s2; | |
throw m; | |
} | |
static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2) | |
{ | |
int res = CompareFileNames(ai1.Name, ai2.Name); | |
if (res != 0) | |
return res; | |
if (ai1.IsDir != ai2.IsDir) | |
return ai1.IsDir ? -1 : 1; | |
return 0; | |
} | |
static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) | |
{ | |
unsigned i1 = *p1; | |
unsigned i2 = *p2; | |
const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param; | |
int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); | |
if (res != 0) | |
return res; | |
return MyCompare(i1, i2); | |
} | |
void GetUpdatePairInfoList( | |
const CDirItems &dirItems, | |
const CObjectVector<CArcItem> &arcItems, | |
NFileTimeType::EEnum fileTimeType, | |
CRecordVector<CUpdatePair> &updatePairs) | |
{ | |
CUIntVector dirIndices, arcIndices; | |
unsigned numDirItems = dirItems.Items.Size(); | |
unsigned numArcItems = arcItems.Size(); | |
CIntArr duplicatedArcItem(numArcItems); | |
{ | |
int *vals = &duplicatedArcItem[0]; | |
for (unsigned i = 0; i < numArcItems; i++) | |
vals[i] = 0; | |
} | |
{ | |
arcIndices.ClearAndSetSize(numArcItems); | |
{ | |
unsigned *vals = &arcIndices[0]; | |
for (unsigned i = 0; i < numArcItems; i++) | |
vals[i] = i; | |
} | |
arcIndices.Sort(CompareArcItems, (void *)&arcItems); | |
for (unsigned i = 0; i + 1 < numArcItems; i++) | |
if (CompareArcItemsBase( | |
arcItems[arcIndices[i]], | |
arcItems[arcIndices[i + 1]]) == 0) | |
{ | |
duplicatedArcItem[i] = 1; | |
duplicatedArcItem[i + 1] = -1; | |
} | |
} | |
UStringVector dirNames; | |
{ | |
dirNames.ClearAndReserve(numDirItems); | |
unsigned i; | |
for (i = 0; i < numDirItems; i++) | |
dirNames.AddInReserved(dirItems.GetLogPath(i)); | |
SortFileNames(dirNames, dirIndices); | |
for (i = 0; i + 1 < numDirItems; i++) | |
{ | |
const UString &s1 = dirNames[dirIndices[i]]; | |
const UString &s2 = dirNames[dirIndices[i + 1]]; | |
if (CompareFileNames(s1, s2) == 0) | |
ThrowError(k_Duplicate_inDir_Message, s1, s2); | |
} | |
} | |
unsigned dirIndex = 0; | |
unsigned arcIndex = 0; | |
int prevHostFile = -1; | |
const UString *prevHostName = NULL; | |
while (dirIndex < numDirItems || arcIndex < numArcItems) | |
{ | |
CUpdatePair pair; | |
int dirIndex2 = -1; | |
int arcIndex2 = -1; | |
const CDirItem *di = NULL; | |
const CArcItem *ai = NULL; | |
int compareResult = -1; | |
const UString *name = NULL; | |
if (dirIndex < numDirItems) | |
{ | |
dirIndex2 = dirIndices[dirIndex]; | |
di = &dirItems.Items[dirIndex2]; | |
} | |
if (arcIndex < numArcItems) | |
{ | |
arcIndex2 = arcIndices[arcIndex]; | |
ai = &arcItems[arcIndex2]; | |
compareResult = 1; | |
if (dirIndex < numDirItems) | |
{ | |
compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name); | |
if (compareResult == 0) | |
{ | |
if (di->IsDir() != ai->IsDir) | |
compareResult = (ai->IsDir ? 1 : -1); | |
} | |
} | |
} | |
if (compareResult < 0) | |
{ | |
name = &dirNames[dirIndex2]; | |
pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; | |
pair.DirIndex = dirIndex2; | |
dirIndex++; | |
} | |
else if (compareResult > 0) | |
{ | |
name = &ai->Name; | |
pair.State = ai->Censored ? | |
NUpdateArchive::NPairState::kOnlyInArchive: | |
NUpdateArchive::NPairState::kNotMasked; | |
pair.ArcIndex = arcIndex2; | |
arcIndex++; | |
} | |
else | |
{ | |
int dupl = duplicatedArcItem[arcIndex]; | |
if (dupl != 0) | |
ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name); | |
name = &dirNames[dirIndex2]; | |
if (!ai->Censored) | |
ThrowError(k_NotCensoredCollision_Message, *name, ai->Name); | |
pair.DirIndex = dirIndex2; | |
pair.ArcIndex = arcIndex2; | |
switch (ai->MTimeDefined ? MyCompareTime( | |
ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType, | |
di->MTime, ai->MTime): 0) | |
{ | |
case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; | |
case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; | |
default: | |
pair.State = (ai->SizeDefined && di->Size == ai->Size) ? | |
NUpdateArchive::NPairState::kSameFiles : | |
NUpdateArchive::NPairState::kUnknowNewerFiles; | |
} | |
dirIndex++; | |
arcIndex++; | |
} | |
if ((di && di->IsAltStream) || | |
(ai && ai->IsAltStream)) | |
{ | |
if (prevHostName) | |
{ | |
unsigned hostLen = prevHostName->Len(); | |
if (name->Len() > hostLen) | |
if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0) | |
pair.HostIndex = prevHostFile; | |
} | |
} | |
else | |
{ | |
prevHostFile = updatePairs.Size(); | |
prevHostName = name; | |
} | |
updatePairs.Add(pair); | |
} | |
updatePairs.ReserveDown(); | |
} |