• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // UpdateCallback.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/ComTry.h"
6 #include "../../../Common/IntToString.h"
7 #include "../../../Common/StringConvert.h"
8 #include "../../../Common/Wildcard.h"
9 
10 #include "../../../Windows/FileDir.h"
11 #include "../../../Windows/FileName.h"
12 #include "../../../Windows/PropVariant.h"
13 #include "../../../Windows/Synchronization.h"
14 
15 #include "../../Common/FileStreams.h"
16 #include "../../Common/StreamObjects.h"
17 
18 #include "UpdateCallback.h"
19 
20 #if defined(_WIN32) && !defined(UNDER_CE)
21 #define _USE_SECURITY_CODE
22 #include "../../../Windows/SecurityUtils.h"
23 #endif
24 
25 using namespace NWindows;
26 using namespace NFile;
27 
28 #ifdef _USE_SECURITY_CODE
29 bool InitLocalPrivileges();
30 #endif
31 
CArchiveUpdateCallback()32 CArchiveUpdateCallback::CArchiveUpdateCallback():
33   Callback(0),
34   ShareForWrite(false),
35   StdInMode(false),
36   DirItems(0),
37   ArcItems(0),
38   UpdatePairs(0),
39   NewNames(0),
40   KeepOriginalItemNames(false),
41   ProcessedItemsStatuses(NULL),
42   ParentDirItem(NULL),
43   StoreNtSecurity(false),
44   StoreHardLinks(false),
45   StoreSymLinks(false),
46   _hardIndex_From((UInt32)(Int32)-1)
47 {
48   #ifdef _USE_SECURITY_CODE
49   _saclEnabled = InitLocalPrivileges();
50   #endif
51 }
52 
53 
SetTotal(UInt64 size)54 STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
55 {
56   COM_TRY_BEGIN
57   return Callback->SetTotal(size);
58   COM_TRY_END
59 }
60 
SetCompleted(const UInt64 * completeValue)61 STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
62 {
63   COM_TRY_BEGIN
64   return Callback->SetCompleted(completeValue);
65   COM_TRY_END
66 }
67 
SetRatioInfo(const UInt64 * inSize,const UInt64 * outSize)68 STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
69 {
70   COM_TRY_BEGIN
71   return Callback->SetRatioInfo(inSize, outSize);
72   COM_TRY_END
73 }
74 
75 
76 /*
77 static const STATPROPSTG kProps[] =
78 {
79   { NULL, kpidPath, VT_BSTR},
80   { NULL, kpidIsDir, VT_BOOL},
81   { NULL, kpidSize, VT_UI8},
82   { NULL, kpidCTime, VT_FILETIME},
83   { NULL, kpidATime, VT_FILETIME},
84   { NULL, kpidMTime, VT_FILETIME},
85   { NULL, kpidAttrib, VT_UI4},
86   { NULL, kpidIsAnti, VT_BOOL}
87 };
88 
89 STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
90 {
91   return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator);
92 }
93 */
94 
GetUpdateItemInfo(UInt32 index,Int32 * newData,Int32 * newProps,UInt32 * indexInArchive)95 STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
96       Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
97 {
98   COM_TRY_BEGIN
99   RINOK(Callback->CheckBreak());
100   const CUpdatePair2 &up = (*UpdatePairs)[index];
101   if (newData) *newData = BoolToInt(up.NewData);
102   if (newProps) *newProps = BoolToInt(up.NewProps);
103   if (indexInArchive)
104   {
105     *indexInArchive = (UInt32)(Int32)-1;
106     if (up.ExistInArchive())
107       *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
108   }
109   return S_OK;
110   COM_TRY_END
111 }
112 
GetRootProp(PROPID propID,PROPVARIANT * value)113 STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)
114 {
115   NCOM::CPropVariant prop;
116   switch (propID)
117   {
118     case kpidIsDir:  prop = true; break;
119     case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break;
120     case kpidCTime:  if (ParentDirItem) prop = ParentDirItem->CTime; break;
121     case kpidATime:  if (ParentDirItem) prop = ParentDirItem->ATime; break;
122     case kpidMTime:  if (ParentDirItem) prop = ParentDirItem->MTime; break;
123   }
124   prop.Detach(value);
125   return S_OK;
126 }
127 
GetParent(UInt32,UInt32 * parent,UInt32 * parentType)128 STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
129 {
130   *parentType = NParentType::kDir;
131   *parent = (UInt32)(Int32)-1;
132   return S_OK;
133 }
134 
GetNumRawProps(UInt32 * numProps)135 STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)
136 {
137   *numProps = 0;
138   if (StoreNtSecurity)
139     *numProps = 1;
140   return S_OK;
141 }
142 
GetRawPropInfo(UInt32,BSTR * name,PROPID * propID)143 STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
144 {
145   *name = NULL;
146   *propID = kpidNtSecure;
147   return S_OK;
148 }
149 
GetRootRawProp(PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType)150 STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID
151     #ifdef _USE_SECURITY_CODE
152     propID
153     #endif
154     , const void **data, UInt32 *dataSize, UInt32 *propType)
155 {
156   *data = 0;
157   *dataSize = 0;
158   *propType = 0;
159   if (!StoreNtSecurity)
160     return S_OK;
161   #ifdef _USE_SECURITY_CODE
162   if (propID == kpidNtSecure)
163   {
164     if (StdInMode)
165       return S_OK;
166 
167     if (ParentDirItem)
168     {
169       if (ParentDirItem->SecureIndex < 0)
170         return S_OK;
171       const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex];
172       *data = buf;
173       *dataSize = (UInt32)buf.Size();
174       *propType = NPropDataType::kRaw;
175       return S_OK;
176     }
177 
178     if (GetRootProps)
179       return GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
180   }
181   #endif
182   return S_OK;
183 }
184 
185 //    #ifdef _USE_SECURITY_CODE
186 //    #endif
187 
GetRawProp(UInt32 index,PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType)188 STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
189 {
190   *data = 0;
191   *dataSize = 0;
192   *propType = 0;
193 
194   if (propID == kpidNtSecure ||
195       propID == kpidNtReparse)
196   {
197     if (StdInMode)
198       return S_OK;
199 
200     const CUpdatePair2 &up = (*UpdatePairs)[index];
201     if (up.UseArcProps && up.ExistInArchive() && GetRawProps)
202       return GetRawProps->GetRawProp(
203           ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex,
204           propID, data, dataSize, propType);
205 
206     {
207       const CUpdatePair2 &up = (*UpdatePairs)[index];
208       /*
209       if (!up.NewData)
210         return E_FAIL;
211       */
212       if (up.IsAnti)
213         return S_OK;
214 
215       #ifndef UNDER_CE
216       const CDirItem &di = DirItems->Items[up.DirIndex];
217       #endif
218 
219       #ifdef _USE_SECURITY_CODE
220       if (propID == kpidNtSecure)
221       {
222         if (!StoreNtSecurity)
223           return S_OK;
224         if (di.SecureIndex < 0)
225           return S_OK;
226         const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex];
227         *data = buf;
228         *dataSize = (UInt32)buf.Size();
229         *propType = NPropDataType::kRaw;
230       }
231       else
232       #endif
233       {
234         // propID == kpidNtReparse
235         if (!StoreSymLinks)
236           return S_OK;
237         #ifndef UNDER_CE
238         const CByteBuffer *buf = &di.ReparseData2;
239         if (buf->Size() == 0)
240           buf = &di.ReparseData;
241         if (buf->Size() != 0)
242         {
243           *data = *buf;
244           *dataSize = (UInt32)buf->Size();
245           *propType = NPropDataType::kRaw;
246         }
247         #endif
248       }
249 
250       return S_OK;
251     }
252   }
253 
254   return S_OK;
255 }
256 
257 #ifndef UNDER_CE
258 
GetRelativePath(const UString & to,const UString & from)259 static UString GetRelativePath(const UString &to, const UString &from)
260 {
261   UStringVector partsTo, partsFrom;
262   SplitPathToParts(to, partsTo);
263   SplitPathToParts(from, partsFrom);
264 
265   unsigned i;
266   for (i = 0;; i++)
267   {
268     if (i + 1 >= partsFrom.Size() ||
269         i + 1 >= partsTo.Size())
270       break;
271     if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
272       break;
273   }
274 
275   if (i == 0)
276   {
277     #ifdef _WIN32
278     if (NName::IsDrivePath(to) ||
279         NName::IsDrivePath(from))
280       return to;
281     #endif
282   }
283 
284   UString s;
285   unsigned k;
286 
287   for (k = i + 1; k < partsFrom.Size(); k++)
288     s += L".." WSTRING_PATH_SEPARATOR;
289 
290   for (k = i; k < partsTo.Size(); k++)
291   {
292     if (k != i)
293       s += WCHAR_PATH_SEPARATOR;
294     s += partsTo[k];
295   }
296 
297   return s;
298 }
299 
300 #endif
301 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)302 STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
303 {
304   COM_TRY_BEGIN
305   const CUpdatePair2 &up = (*UpdatePairs)[index];
306   NCOM::CPropVariant prop;
307 
308   if (up.NewData)
309   {
310     /*
311     if (propID == kpidIsHardLink)
312     {
313       prop = _isHardLink;
314       prop.Detach(value);
315       return S_OK;
316     }
317     */
318     if (propID == kpidSymLink)
319     {
320       if (index == _hardIndex_From)
321       {
322         prop.Detach(value);
323         return S_OK;
324       }
325       if (up.DirIndex >= 0)
326       {
327         #ifndef UNDER_CE
328         const CDirItem &di = DirItems->Items[up.DirIndex];
329         // if (di.IsDir())
330         {
331           CReparseAttr attr;
332           if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
333           {
334             UString simpleName = attr.GetPath();
335             if (attr.IsRelative())
336               prop = simpleName;
337             else
338             {
339               const UString phyPath = DirItems->GetPhyPath(up.DirIndex);
340               FString fullPath;
341               if (NDir::MyGetFullPathName(us2fs(phyPath), fullPath))
342               {
343                 prop = GetRelativePath(simpleName, fs2us(fullPath));
344               }
345             }
346             prop.Detach(value);
347             return S_OK;
348           }
349         }
350         #endif
351       }
352     }
353     else if (propID == kpidHardLink)
354     {
355       if (index == _hardIndex_From)
356       {
357         const CKeyKeyValPair &pair = _map[_hardIndex_To];
358         const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
359         prop = DirItems->GetLogPath(up2.DirIndex);
360         prop.Detach(value);
361         return S_OK;
362       }
363       if (up.DirIndex >= 0)
364       {
365         prop.Detach(value);
366         return S_OK;
367       }
368     }
369   }
370 
371   if (up.IsAnti
372       && propID != kpidIsDir
373       && propID != kpidPath
374       && propID != kpidIsAltStream)
375   {
376     switch (propID)
377     {
378       case kpidSize:  prop = (UInt64)0; break;
379       case kpidIsAnti:  prop = true; break;
380     }
381   }
382   else if (propID == kpidPath && up.NewNameIndex >= 0)
383     prop = (*NewNames)[up.NewNameIndex];
384   else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
385   {
386     // we can generate new ShortName here;
387   }
388   else if ((up.UseArcProps
389       || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
390       && up.ExistInArchive() && Archive)
391     return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value);
392   else if (up.ExistOnDisk())
393   {
394     const CDirItem &di = DirItems->Items[up.DirIndex];
395     switch (propID)
396     {
397       case kpidPath:  prop = DirItems->GetLogPath(up.DirIndex); break;
398       case kpidIsDir:  prop = di.IsDir(); break;
399       case kpidSize:  prop = di.Size; break;
400       case kpidAttrib:  prop = di.Attrib; break;
401       case kpidCTime:  prop = di.CTime; break;
402       case kpidATime:  prop = di.ATime; break;
403       case kpidMTime:  prop = di.MTime; break;
404       case kpidIsAltStream:  prop = di.IsAltStream; break;
405       #if defined(_WIN32) && !defined(UNDER_CE)
406       // case kpidShortName:  prop = di.ShortName; break;
407       #endif
408     }
409   }
410   prop.Detach(value);
411   return S_OK;
412   COM_TRY_END
413 }
414 
415 static NSynchronization::CCriticalSection CS;
416 
GetStream(UInt32 index,ISequentialInStream ** inStream)417 STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
418 {
419   COM_TRY_BEGIN
420   *inStream = NULL;
421   const CUpdatePair2 &up = (*UpdatePairs)[index];
422   if (!up.NewData)
423     return E_FAIL;
424 
425   RINOK(Callback->CheckBreak());
426   RINOK(Callback->Finilize());
427 
428   bool isDir = IsDir(up);
429 
430   if (up.IsAnti)
431   {
432     UString name;
433     if (up.ArcIndex >= 0)
434       name = (*ArcItems)[up.ArcIndex].Name;
435     else if (up.DirIndex >= 0)
436       name = DirItems->GetLogPath(up.DirIndex);
437     RINOK(Callback->GetStream(name, true));
438 
439     /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
440        so we return empty stream */
441 
442     if (!isDir)
443     {
444       CBufInStream *inStreamSpec = new CBufInStream();
445       CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
446       inStreamSpec->Init(NULL, 0);
447       *inStream = inStreamLoc.Detach();
448     }
449     return S_OK;
450   }
451 
452   RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false));
453 
454   if (isDir)
455     return S_OK;
456 
457   if (StdInMode)
458   {
459     CStdInFileStream *inStreamSpec = new CStdInFileStream;
460     CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
461     *inStream = inStreamLoc.Detach();
462   }
463   else
464   {
465     CInFileStream *inStreamSpec = new CInFileStream;
466     CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
467 
468     inStreamSpec->SupportHardLinks = StoreHardLinks;
469 
470     const UString path = DirItems->GetPhyPath(up.DirIndex);
471 
472     #if defined(_WIN32) && !defined(UNDER_CE)
473     if (DirItems->Items[up.DirIndex].AreReparseData())
474     {
475       if (!inStreamSpec->File.OpenReparse(us2fs(path)))
476       {
477         return Callback->OpenFileError(path, ::GetLastError());
478       }
479     }
480     else
481     #endif
482     if (!inStreamSpec->OpenShared(us2fs(path), ShareForWrite))
483     {
484       return Callback->OpenFileError(path, ::GetLastError());
485     }
486 
487     if (StoreHardLinks)
488     {
489       CStreamFileProps props;
490       if (inStreamSpec->GetProps2(&props) == S_OK)
491       {
492         if (props.NumLinks > 1)
493         {
494           CKeyKeyValPair pair;
495           pair.Key1 = props.VolID;
496           pair.Key2 = props.FileID_Low;
497           pair.Value = index;
498           unsigned numItems = _map.Size();
499           unsigned pairIndex = _map.AddToUniqueSorted2(pair);
500           if (numItems == _map.Size())
501           {
502             // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
503             _hardIndex_From = index;
504             _hardIndex_To = pairIndex;
505             // we could return NULL as stream, but it's better to return real stream
506             // return S_OK;
507           }
508         }
509       }
510     }
511 
512     if (ProcessedItemsStatuses)
513     {
514       NSynchronization::CCriticalSectionLock lock(CS);
515       ProcessedItemsStatuses[up.DirIndex] = 1;
516     }
517     *inStream = inStreamLoc.Detach();
518   }
519 
520   return S_OK;
521   COM_TRY_END
522 }
523 
SetOperationResult(Int32 operationResult)524 STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
525 {
526   COM_TRY_BEGIN
527   return Callback->SetOperationResult(operationResult);
528   COM_TRY_END
529 }
530 
GetVolumeSize(UInt32 index,UInt64 * size)531 STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
532 {
533   if (VolumesSizes.Size() == 0)
534     return S_FALSE;
535   if (index >= (UInt32)VolumesSizes.Size())
536     index = VolumesSizes.Size() - 1;
537   *size = VolumesSizes[index];
538   return S_OK;
539 }
540 
GetVolumeStream(UInt32 index,ISequentialOutStream ** volumeStream)541 STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
542 {
543   COM_TRY_BEGIN
544   FChar temp[16];
545   ConvertUInt32ToString(index + 1, temp);
546   FString res = temp;
547   while (res.Len() < 2)
548     res.InsertAtFront(FTEXT('0'));
549   FString fileName = VolName;
550   fileName += L'.';
551   fileName += res;
552   fileName += VolExt;
553   COutFileStream *streamSpec = new COutFileStream;
554   CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
555   if (!streamSpec->Create(fileName, false))
556     return ::GetLastError();
557   *volumeStream = streamLoc.Detach();
558   return S_OK;
559   COM_TRY_END
560 }
561 
CryptoGetTextPassword2(Int32 * passwordIsDefined,BSTR * password)562 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
563 {
564   COM_TRY_BEGIN
565   return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
566   COM_TRY_END
567 }
568 
CryptoGetTextPassword(BSTR * password)569 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
570 {
571   COM_TRY_BEGIN
572   return Callback->CryptoGetTextPassword(password);
573   COM_TRY_END
574 }
575