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