1// UpdatePair.cpp
2
3#include "StdAfx.h"
4
5#include <time.h>
6
7#include "Common/Defs.h"
8#include "Common/Wildcard.h"
9
10#include "Windows/Time.h"
11
12#include "SortUtils.h"
13#include "UpdatePair.h"
14
15using namespace NWindows;
16using namespace NTime;
17
18static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)
19{
20  switch(fileTimeType)
21  {
22    case NFileTimeType::kWindows:
23      return ::CompareFileTime(&time1, &time2);
24    case NFileTimeType::kUnix:
25      {
26        UInt32 unixTime1, unixTime2;
27        FileTimeToUnixTime(time1, unixTime1);
28        FileTimeToUnixTime(time2, unixTime2);
29        return MyCompare(unixTime1, unixTime2);
30      }
31    case NFileTimeType::kDOS:
32      {
33        UInt32 dosTime1, dosTime2;
34        FileTimeToDosTime(time1, dosTime1);
35        FileTimeToDosTime(time2, dosTime2);
36        return MyCompare(dosTime1, dosTime2);
37      }
38  }
39  throw 4191618;
40}
41
42static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:";
43static const wchar_t *kNotCensoredCollisionMessaged = L"Internal file name collision (file on disk, file in archive):";
44
45static void ThrowError(const UString &message, const UString &s1, const UString &s2)
46{
47  UString m = message;
48  m += L'\n';
49  m += s1;
50  m += L'\n';
51  m += s2;
52  throw m;
53}
54
55static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
56{
57  for(int i = 0; i + 1 < indices.Size(); i++)
58    if (CompareFileNames(strings[indices[i]], strings[indices[i + 1]]) == 0)
59      ThrowError(kDuplicateFileNameMessage, strings[indices[i]], strings[indices[i + 1]]);
60}
61
62void GetUpdatePairInfoList(
63    const CDirItems &dirItems,
64    const CObjectVector<CArcItem> &arcItems,
65    NFileTimeType::EEnum fileTimeType,
66    CRecordVector<CUpdatePair> &updatePairs)
67{
68  CIntVector dirIndices, arcIndices;
69
70  int numDirItems = dirItems.Items.Size();
71  int numArcItems = arcItems.Size();
72
73
74  {
75    UStringVector arcNames;
76    arcNames.Reserve(numArcItems);
77    for (int i = 0; i < numArcItems; i++)
78      arcNames.Add(arcItems[i].Name);
79    SortFileNames(arcNames, arcIndices);
80    TestDuplicateString(arcNames, arcIndices);
81  }
82
83  UStringVector dirNames;
84  {
85    dirNames.Reserve(numDirItems);
86    for (int i = 0; i < numDirItems; i++)
87      dirNames.Add(dirItems.GetLogPath(i));
88    SortFileNames(dirNames, dirIndices);
89    TestDuplicateString(dirNames, dirIndices);
90  }
91
92  int dirIndex = 0, arcIndex = 0;
93  while (dirIndex < numDirItems && arcIndex < numArcItems)
94  {
95    CUpdatePair pair;
96    int dirIndex2 = dirIndices[dirIndex];
97    int arcIndex2 = arcIndices[arcIndex];
98    const CDirItem &di = dirItems.Items[dirIndex2];
99    const CArcItem &ai = arcItems[arcIndex2];
100    int compareResult = CompareFileNames(dirNames[dirIndex2], ai.Name);
101    if (compareResult < 0)
102    {
103      pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
104      pair.DirIndex = dirIndex2;
105      dirIndex++;
106    }
107    else if (compareResult > 0)
108    {
109      pair.State = ai.Censored ?
110          NUpdateArchive::NPairState::kOnlyInArchive:
111          NUpdateArchive::NPairState::kNotMasked;
112      pair.ArcIndex = arcIndex2;
113      arcIndex++;
114    }
115    else
116    {
117      if (!ai.Censored)
118        ThrowError(kNotCensoredCollisionMessaged, dirNames[dirIndex2], ai.Name);
119      pair.DirIndex = dirIndex2;
120      pair.ArcIndex = arcIndex2;
121      switch (ai.MTimeDefined ? MyCompareTime(
122          ai.TimeType != - 1 ? (NFileTimeType::EEnum)ai.TimeType : fileTimeType,
123          di.MTime, ai.MTime): 0)
124      {
125        case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
126        case 1:  pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
127        default:
128          pair.State = (ai.SizeDefined && di.Size == ai.Size) ?
129              NUpdateArchive::NPairState::kSameFiles :
130              NUpdateArchive::NPairState::kUnknowNewerFiles;
131      }
132      dirIndex++;
133      arcIndex++;
134    }
135    updatePairs.Add(pair);
136  }
137
138  for (; dirIndex < numDirItems; dirIndex++)
139  {
140    CUpdatePair pair;
141    pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
142    pair.DirIndex = dirIndices[dirIndex];
143    updatePairs.Add(pair);
144  }
145
146  for (; arcIndex < numArcItems; arcIndex++)
147  {
148    CUpdatePair pair;
149    int arcIndex2 = arcIndices[arcIndex];
150    pair.State = arcItems[arcIndex2].Censored ?
151        NUpdateArchive::NPairState::kOnlyInArchive:
152        NUpdateArchive::NPairState::kNotMasked;
153    pair.ArcIndex = arcIndex2;
154    updatePairs.Add(pair);
155  }
156
157  updatePairs.ReserveDown();
158}
159