tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

UpdateCallback.cpp (19665B)


      1 // UpdateCallback.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #ifndef _7ZIP_ST
      6 #include "../../../Windows/Synchronization.h"
      7 #endif
      8 
      9 #include "../../../Common/ComTry.h"
     10 #include "../../../Common/IntToString.h"
     11 #include "../../../Common/StringConvert.h"
     12 #include "../../../Common/Wildcard.h"
     13 
     14 #include "../../../Windows/FileDir.h"
     15 #include "../../../Windows/FileName.h"
     16 #include "../../../Windows/PropVariant.h"
     17 
     18 #include "../../Common/StreamObjects.h"
     19 
     20 #include "UpdateCallback.h"
     21 
     22 #if defined(_WIN32) && !defined(UNDER_CE)
     23 #define _USE_SECURITY_CODE
     24 #include "../../../Windows/SecurityUtils.h"
     25 #endif
     26 
     27 using namespace NWindows;
     28 using namespace NFile;
     29 
     30 #ifndef _7ZIP_ST
     31 static NSynchronization::CCriticalSection g_CriticalSection;
     32 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
     33 #else
     34 #define MT_LOCK
     35 #endif
     36 
     37 
     38 #ifdef _USE_SECURITY_CODE
     39 bool InitLocalPrivileges();
     40 #endif
     41 
     42 CArchiveUpdateCallback::CArchiveUpdateCallback():
     43    _hardIndex_From((UInt32)(Int32)-1),
     44    
     45    Callback(NULL),
     46  
     47    DirItems(NULL),
     48    ParentDirItem(NULL),
     49    
     50    Arc(NULL),
     51    ArcItems(NULL),
     52    UpdatePairs(NULL),
     53    NewNames(NULL),
     54    CommentIndex(-1),
     55    Comment(NULL),
     56    
     57    ShareForWrite(false),
     58    StopAfterOpenError(false),
     59    StdInMode(false),
     60    
     61    KeepOriginalItemNames(false),
     62    StoreNtSecurity(false),
     63    StoreHardLinks(false),
     64    StoreSymLinks(false),
     65    
     66    ProcessedItemsStatuses(NULL)
     67 {
     68  #ifdef _USE_SECURITY_CODE
     69  _saclEnabled = InitLocalPrivileges();
     70  #endif
     71 }
     72 
     73 
     74 STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
     75 {
     76  COM_TRY_BEGIN
     77  return Callback->SetTotal(size);
     78  COM_TRY_END
     79 }
     80 
     81 STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
     82 {
     83  COM_TRY_BEGIN
     84  return Callback->SetCompleted(completeValue);
     85  COM_TRY_END
     86 }
     87 
     88 STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
     89 {
     90  COM_TRY_BEGIN
     91  return Callback->SetRatioInfo(inSize, outSize);
     92  COM_TRY_END
     93 }
     94 
     95 
     96 /*
     97 static const CStatProp kProps[] =
     98 {
     99  { NULL, kpidPath, VT_BSTR},
    100  { NULL, kpidIsDir, VT_BOOL},
    101  { NULL, kpidSize, VT_UI8},
    102  { NULL, kpidCTime, VT_FILETIME},
    103  { NULL, kpidATime, VT_FILETIME},
    104  { NULL, kpidMTime, VT_FILETIME},
    105  { NULL, kpidAttrib, VT_UI4},
    106  { NULL, kpidIsAnti, VT_BOOL}
    107 };
    108 
    109 STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
    110 {
    111  return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator);
    112 }
    113 */
    114 
    115 STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
    116      Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
    117 {
    118  COM_TRY_BEGIN
    119  RINOK(Callback->CheckBreak());
    120  const CUpdatePair2 &up = (*UpdatePairs)[index];
    121  if (newData) *newData = BoolToInt(up.NewData);
    122  if (newProps) *newProps = BoolToInt(up.NewProps);
    123  if (indexInArchive)
    124  {
    125    *indexInArchive = (UInt32)(Int32)-1;
    126    if (up.ExistInArchive())
    127      *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
    128  }
    129  return S_OK;
    130  COM_TRY_END
    131 }
    132 
    133 STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)
    134 {
    135  NCOM::CPropVariant prop;
    136  switch (propID)
    137  {
    138    case kpidIsDir:  prop = true; break;
    139    case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break;
    140    case kpidCTime:  if (ParentDirItem) prop = ParentDirItem->CTime; break;
    141    case kpidATime:  if (ParentDirItem) prop = ParentDirItem->ATime; break;
    142    case kpidMTime:  if (ParentDirItem) prop = ParentDirItem->MTime; break;
    143  }
    144  prop.Detach(value);
    145  return S_OK;
    146 }
    147 
    148 STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
    149 {
    150  *parentType = NParentType::kDir;
    151  *parent = (UInt32)(Int32)-1;
    152  return S_OK;
    153 }
    154 
    155 STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)
    156 {
    157  *numProps = 0;
    158  if (StoreNtSecurity)
    159    *numProps = 1;
    160  return S_OK;
    161 }
    162 
    163 STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
    164 {
    165  *name = NULL;
    166  *propID = kpidNtSecure;
    167  return S_OK;
    168 }
    169 
    170 STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID
    171    #ifdef _USE_SECURITY_CODE
    172    propID
    173    #endif
    174    , const void **data, UInt32 *dataSize, UInt32 *propType)
    175 {
    176  *data = 0;
    177  *dataSize = 0;
    178  *propType = 0;
    179  if (!StoreNtSecurity)
    180    return S_OK;
    181  #ifdef _USE_SECURITY_CODE
    182  if (propID == kpidNtSecure)
    183  {
    184    if (StdInMode)
    185      return S_OK;
    186 
    187    if (ParentDirItem)
    188    {
    189      if (ParentDirItem->SecureIndex < 0)
    190        return S_OK;
    191      const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex];
    192      *data = buf;
    193      *dataSize = (UInt32)buf.Size();
    194      *propType = NPropDataType::kRaw;
    195      return S_OK;
    196    }
    197 
    198    if (Arc && Arc->GetRootProps)
    199      return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
    200  }
    201  #endif
    202  return S_OK;
    203 }
    204 
    205 //    #ifdef _USE_SECURITY_CODE
    206 //    #endif
    207 
    208 STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
    209 {
    210  *data = 0;
    211  *dataSize = 0;
    212  *propType = 0;
    213 
    214  if (propID == kpidNtSecure ||
    215      propID == kpidNtReparse)
    216  {
    217    if (StdInMode)
    218      return S_OK;
    219 
    220    const CUpdatePair2 &up = (*UpdatePairs)[index];
    221    if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps)
    222      return Arc->GetRawProps->GetRawProp(
    223          ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex,
    224          propID, data, dataSize, propType);
    225    {
    226      /*
    227      if (!up.NewData)
    228        return E_FAIL;
    229      */
    230      if (up.IsAnti)
    231        return S_OK;
    232      
    233      #ifndef UNDER_CE
    234      const CDirItem &di = DirItems->Items[up.DirIndex];
    235      #endif
    236 
    237      #ifdef _USE_SECURITY_CODE
    238      if (propID == kpidNtSecure)
    239      {
    240        if (!StoreNtSecurity)
    241          return S_OK;
    242        if (di.SecureIndex < 0)
    243          return S_OK;
    244        const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex];
    245        *data = buf;
    246        *dataSize = (UInt32)buf.Size();
    247        *propType = NPropDataType::kRaw;
    248      }
    249      else
    250      #endif
    251      {
    252        // propID == kpidNtReparse
    253        if (!StoreSymLinks)
    254          return S_OK;
    255        #ifndef UNDER_CE
    256        const CByteBuffer *buf = &di.ReparseData2;
    257        if (buf->Size() == 0)
    258          buf = &di.ReparseData;
    259        if (buf->Size() != 0)
    260        {
    261          *data = *buf;
    262          *dataSize = (UInt32)buf->Size();
    263          *propType = NPropDataType::kRaw;
    264        }
    265        #endif
    266      }
    267 
    268      return S_OK;
    269    }
    270  }
    271 
    272  return S_OK;
    273 }
    274 
    275 #ifndef UNDER_CE
    276 
    277 static UString GetRelativePath(const UString &to, const UString &from)
    278 {
    279  UStringVector partsTo, partsFrom;
    280  SplitPathToParts(to, partsTo);
    281  SplitPathToParts(from, partsFrom);
    282 
    283  unsigned i;
    284  for (i = 0;; i++)
    285  {
    286    if (i + 1 >= partsFrom.Size() ||
    287        i + 1 >= partsTo.Size())
    288      break;
    289    if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
    290      break;
    291  }
    292 
    293  if (i == 0)
    294  {
    295    #ifdef _WIN32
    296    if (NName::IsDrivePath(to) ||
    297        NName::IsDrivePath(from))
    298      return to;
    299    #endif
    300  }
    301 
    302  UString s;
    303  unsigned k;
    304  
    305  for (k = i + 1; k < partsFrom.Size(); k++)
    306    s += ".." STRING_PATH_SEPARATOR;
    307  
    308  for (k = i; k < partsTo.Size(); k++)
    309  {
    310    if (k != i)
    311      s.Add_PathSepar();
    312    s += partsTo[k];
    313  }
    314 
    315  return s;
    316 }
    317 
    318 #endif
    319 
    320 STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
    321 {
    322  COM_TRY_BEGIN
    323  const CUpdatePair2 &up = (*UpdatePairs)[index];
    324  NCOM::CPropVariant prop;
    325 
    326  if (up.NewData)
    327  {
    328    /*
    329    if (propID == kpidIsHardLink)
    330    {
    331      prop = _isHardLink;
    332      prop.Detach(value);
    333      return S_OK;
    334    }
    335    */
    336    if (propID == kpidSymLink)
    337    {
    338      if (index == _hardIndex_From)
    339      {
    340        prop.Detach(value);
    341        return S_OK;
    342      }
    343      if (up.DirIndex >= 0)
    344      {
    345        #ifndef UNDER_CE
    346        const CDirItem &di = DirItems->Items[up.DirIndex];
    347        // if (di.IsDir())
    348        {
    349          CReparseAttr attr;
    350          DWORD errorCode = 0;
    351          if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode))
    352          {
    353            UString simpleName = attr.GetPath();
    354            if (attr.IsRelative())
    355              prop = simpleName;
    356            else
    357            {
    358              const FString phyPath = DirItems->GetPhyPath(up.DirIndex);
    359              FString fullPath;
    360              if (NDir::MyGetFullPathName(phyPath, fullPath))
    361              {
    362                prop = GetRelativePath(simpleName, fs2us(fullPath));
    363              }
    364            }
    365            prop.Detach(value);
    366            return S_OK;
    367          }
    368        }
    369        #endif
    370      }
    371    }
    372    else if (propID == kpidHardLink)
    373    {
    374      if (index == _hardIndex_From)
    375      {
    376        const CKeyKeyValPair &pair = _map[_hardIndex_To];
    377        const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
    378        prop = DirItems->GetLogPath(up2.DirIndex);
    379        prop.Detach(value);
    380        return S_OK;
    381      }
    382      if (up.DirIndex >= 0)
    383      {
    384        prop.Detach(value);
    385        return S_OK;
    386      }
    387    }
    388  }
    389  
    390  if (up.IsAnti
    391      && propID != kpidIsDir
    392      && propID != kpidPath
    393      && propID != kpidIsAltStream)
    394  {
    395    switch (propID)
    396    {
    397      case kpidSize:  prop = (UInt64)0; break;
    398      case kpidIsAnti:  prop = true; break;
    399    }
    400  }
    401  else if (propID == kpidPath && up.NewNameIndex >= 0)
    402    prop = (*NewNames)[up.NewNameIndex];
    403  else if (propID == kpidComment
    404      && CommentIndex >= 0
    405      && (unsigned)CommentIndex == index
    406      && Comment)
    407    prop = *Comment;
    408  else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
    409  {
    410    // we can generate new ShortName here;
    411  }
    412  else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
    413      && up.ExistInArchive() && Archive)
    414    return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value);
    415  else if (up.ExistOnDisk())
    416  {
    417    const CDirItem &di = DirItems->Items[up.DirIndex];
    418    switch (propID)
    419    {
    420      case kpidPath:  prop = DirItems->GetLogPath(up.DirIndex); break;
    421      case kpidIsDir:  prop = di.IsDir(); break;
    422      case kpidSize:  prop = di.IsDir() ? (UInt64)0 : di.Size; break;
    423      case kpidAttrib:  prop = di.Attrib; break;
    424      case kpidCTime:  prop = di.CTime; break;
    425      case kpidATime:  prop = di.ATime; break;
    426      case kpidMTime:  prop = di.MTime; break;
    427      case kpidIsAltStream:  prop = di.IsAltStream; break;
    428      #if defined(_WIN32) && !defined(UNDER_CE)
    429      // case kpidShortName:  prop = di.ShortName; break;
    430      #endif
    431    }
    432  }
    433  prop.Detach(value);
    434  return S_OK;
    435  COM_TRY_END
    436 }
    437 
    438 #ifndef _7ZIP_ST
    439 static NSynchronization::CCriticalSection CS;
    440 #endif
    441 
    442 STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)
    443 {
    444  COM_TRY_BEGIN
    445  *inStream = NULL;
    446  const CUpdatePair2 &up = (*UpdatePairs)[index];
    447  if (!up.NewData)
    448    return E_FAIL;
    449  
    450  RINOK(Callback->CheckBreak());
    451  // RINOK(Callback->Finalize());
    452 
    453  bool isDir = IsDir(up);
    454 
    455  if (up.IsAnti)
    456  {
    457    UString name;
    458    if (up.ArcIndex >= 0)
    459      name = (*ArcItems)[up.ArcIndex].Name;
    460    else if (up.DirIndex >= 0)
    461      name = DirItems->GetLogPath(up.DirIndex);
    462    RINOK(Callback->GetStream(name, isDir, true, mode));
    463    
    464    /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
    465       so we return empty stream */
    466 
    467    if (!isDir)
    468    {
    469      CBufInStream *inStreamSpec = new CBufInStream();
    470      CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
    471      inStreamSpec->Init(NULL, 0);
    472      *inStream = inStreamLoc.Detach();
    473    }
    474    return S_OK;
    475  }
    476  
    477  RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), isDir, false, mode));
    478 
    479  if (isDir)
    480    return S_OK;
    481 
    482  if (StdInMode)
    483  {
    484    if (mode != NUpdateNotifyOp::kAdd &&
    485        mode != NUpdateNotifyOp::kUpdate)
    486      return S_OK;
    487 
    488    CStdInFileStream *inStreamSpec = new CStdInFileStream;
    489    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
    490    *inStream = inStreamLoc.Detach();
    491  }
    492  else
    493  {
    494    CInFileStream *inStreamSpec = new CInFileStream;
    495    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
    496 
    497    inStreamSpec->SupportHardLinks = StoreHardLinks;
    498    inStreamSpec->Callback = this;
    499    inStreamSpec->CallbackRef = index;
    500 
    501    const FString path = DirItems->GetPhyPath(up.DirIndex);
    502    _openFiles_Indexes.Add(index);
    503    _openFiles_Paths.Add(path);
    504 
    505    #if defined(_WIN32) && !defined(UNDER_CE)
    506    if (DirItems->Items[up.DirIndex].AreReparseData())
    507    {
    508      if (!inStreamSpec->File.OpenReparse(path))
    509      {
    510        return Callback->OpenFileError(path, ::GetLastError());
    511      }
    512    }
    513    else
    514    #endif
    515    if (!inStreamSpec->OpenShared(path, ShareForWrite))
    516    {
    517      DWORD error = ::GetLastError();
    518      HRESULT hres = Callback->OpenFileError(path, error);
    519      if (StopAfterOpenError)
    520        if (hres == S_OK || hres == S_FALSE)
    521          return HRESULT_FROM_WIN32(error);
    522      return hres;
    523    }
    524 
    525    if (StoreHardLinks)
    526    {
    527      CStreamFileProps props;
    528      if (inStreamSpec->GetProps2(&props) == S_OK)
    529      {
    530        if (props.NumLinks > 1)
    531        {
    532          CKeyKeyValPair pair;
    533          pair.Key1 = props.VolID;
    534          pair.Key2 = props.FileID_Low;
    535          pair.Value = index;
    536          unsigned numItems = _map.Size();
    537          unsigned pairIndex = _map.AddToUniqueSorted2(pair);
    538          if (numItems == _map.Size())
    539          {
    540            // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
    541            _hardIndex_From = index;
    542            _hardIndex_To = pairIndex;
    543            // we could return NULL as stream, but it's better to return real stream
    544            // return S_OK;
    545          }
    546        }
    547      }
    548    }
    549 
    550    if (ProcessedItemsStatuses)
    551    {
    552      #ifndef _7ZIP_ST
    553      NSynchronization::CCriticalSectionLock lock(CS);
    554      #endif
    555      ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1;
    556    }
    557    *inStream = inStreamLoc.Detach();
    558  }
    559  
    560  return S_OK;
    561  COM_TRY_END
    562 }
    563 
    564 STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 opRes)
    565 {
    566  COM_TRY_BEGIN
    567  return Callback->SetOperationResult(opRes);
    568  COM_TRY_END
    569 }
    570 
    571 STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
    572 {
    573  COM_TRY_BEGIN
    574  return GetStream2(index, inStream,
    575      (*UpdatePairs)[index].ArcIndex < 0 ?
    576          NUpdateNotifyOp::kAdd :
    577          NUpdateNotifyOp::kUpdate);
    578  COM_TRY_END
    579 }
    580 
    581 STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)
    582 {
    583  COM_TRY_BEGIN
    584 
    585  bool isDir = false;
    586 
    587  if (indexType == NArchive::NEventIndexType::kOutArcIndex)
    588  {
    589    UString name;
    590    if (index != (UInt32)(Int32)-1)
    591    {
    592      const CUpdatePair2 &up = (*UpdatePairs)[index];
    593      if (up.ExistOnDisk())
    594      {
    595        name = DirItems->GetLogPath(up.DirIndex);
    596        isDir = DirItems->Items[up.DirIndex].IsDir();
    597      }
    598    }
    599    return Callback->ReportUpdateOpeartion(op, name.IsEmpty() ? NULL : name.Ptr(), isDir);
    600  }
    601  
    602  wchar_t temp[16];
    603  UString s2;
    604  const wchar_t *s = NULL;
    605  
    606  if (indexType == NArchive::NEventIndexType::kInArcIndex)
    607  {
    608    if (index != (UInt32)(Int32)-1)
    609    {
    610      if (ArcItems)
    611      {
    612        const CArcItem &ai = (*ArcItems)[index];
    613        s = ai.Name;
    614        isDir = ai.IsDir;
    615      }
    616      else if (Arc)
    617      {
    618        RINOK(Arc->GetItemPath(index, s2));
    619        s = s2;
    620        RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir));
    621      }
    622    }
    623  }
    624  else if (indexType == NArchive::NEventIndexType::kBlockIndex)
    625  {
    626    temp[0] = '#';
    627    ConvertUInt32ToString(index, temp + 1);
    628    s = temp;
    629  }
    630 
    631  if (!s)
    632    s = L"";
    633 
    634  return Callback->ReportUpdateOpeartion(op, s, isDir);
    635 
    636  COM_TRY_END
    637 }
    638 
    639 STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
    640 {
    641  COM_TRY_BEGIN
    642 
    643  bool isEncrypted = false;
    644  wchar_t temp[16];
    645  UString s2;
    646  const wchar_t *s = NULL;
    647  
    648  if (indexType == NArchive::NEventIndexType::kOutArcIndex)
    649  {
    650    /*
    651    UString name;
    652    if (index != (UInt32)(Int32)-1)
    653    {
    654      const CUpdatePair2 &up = (*UpdatePairs)[index];
    655      if (up.ExistOnDisk())
    656      {
    657        s2 = DirItems->GetLogPath(up.DirIndex);
    658        s = s2;
    659      }
    660    }
    661    */
    662    return E_FAIL;
    663  }
    664 
    665  if (indexType == NArchive::NEventIndexType::kInArcIndex)
    666  {
    667    if (index != (UInt32)(Int32)-1)
    668    {
    669      if (ArcItems)
    670        s = (*ArcItems)[index].Name;
    671      else if (Arc)
    672      {
    673        RINOK(Arc->GetItemPath(index, s2));
    674        s = s2;
    675      }
    676      if (Archive)
    677      {
    678        RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted));
    679      }
    680    }
    681  }
    682  else if (indexType == NArchive::NEventIndexType::kBlockIndex)
    683  {
    684    temp[0] = '#';
    685    ConvertUInt32ToString(index, temp + 1);
    686    s = temp;
    687  }
    688 
    689  return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s);
    690 
    691  COM_TRY_END
    692 }
    693 
    694 STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
    695 {
    696  if (VolumesSizes.Size() == 0)
    697    return S_FALSE;
    698  if (index >= (UInt32)VolumesSizes.Size())
    699    index = VolumesSizes.Size() - 1;
    700  *size = VolumesSizes[index];
    701  return S_OK;
    702 }
    703 
    704 STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
    705 {
    706  COM_TRY_BEGIN
    707  char temp[16];
    708  ConvertUInt32ToString(index + 1, temp);
    709  FString res (temp);
    710  while (res.Len() < 2)
    711    res.InsertAtFront(FTEXT('0'));
    712  FString fileName = VolName;
    713  fileName += '.';
    714  fileName += res;
    715  fileName += VolExt;
    716  COutFileStream *streamSpec = new COutFileStream;
    717  CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
    718  if (!streamSpec->Create(fileName, false))
    719    return ::GetLastError();
    720  *volumeStream = streamLoc.Detach();
    721  return S_OK;
    722  COM_TRY_END
    723 }
    724 
    725 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
    726 {
    727  COM_TRY_BEGIN
    728  return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
    729  COM_TRY_END
    730 }
    731 
    732 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
    733 {
    734  COM_TRY_BEGIN
    735  return Callback->CryptoGetTextPassword(password);
    736  COM_TRY_END
    737 }
    738 
    739 HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
    740 {
    741  if (error == ERROR_LOCK_VIOLATION)
    742  {
    743    MT_LOCK
    744    UInt32 index = (UInt32)val;
    745    FOR_VECTOR(i, _openFiles_Indexes)
    746    {
    747      if (_openFiles_Indexes[i] == index)
    748      {
    749        RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error));
    750        break;
    751      }
    752    }
    753  }
    754  return HRESULT_FROM_WIN32(error);
    755 }
    756 
    757 void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val)
    758 {
    759  MT_LOCK
    760  UInt32 index = (UInt32)val;
    761  FOR_VECTOR(i, _openFiles_Indexes)
    762  {
    763    if (_openFiles_Indexes[i] == index)
    764    {
    765      _openFiles_Indexes.Delete(i);
    766      _openFiles_Paths.Delete(i);
    767      return;
    768    }
    769  }
    770  throw 20141125;
    771 }