xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // AltStreamsFolder.cpp
2 
3 #include "StdAfx.h"
4 
5 #ifdef __MINGW32_VERSION
6 // #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
7 // for old mingw
8 #include <ddk/ntddk.h>
9 #else
10 #ifndef Z7_OLD_WIN_SDK
11   #if !defined(_M_IA64)
12     #include <winternl.h>
13   #endif
14 #else
15 typedef LONG NTSTATUS;
16 typedef struct _IO_STATUS_BLOCK {
17     union {
18         NTSTATUS Status;
19         PVOID Pointer;
20     };
21     ULONG_PTR Information;
22 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
23 #endif
24 #endif
25 
26 #include "../../../Common/ComTry.h"
27 #include "../../../Common/StringConvert.h"
28 #include "../../../Common/Wildcard.h"
29 
30 #include "../../../Windows/DLL.h"
31 #include "../../../Windows/ErrorMsg.h"
32 #include "../../../Windows/FileDir.h"
33 #include "../../../Windows/FileIO.h"
34 #include "../../../Windows/FileName.h"
35 #include "../../../Windows/PropVariant.h"
36 
37 #include "../Common/ExtractingFilePath.h"
38 
39 #include "../Agent/IFolderArchive.h"
40 
41 #include "AltStreamsFolder.h"
42 #include "FSDrives.h"
43 #include "FSFolder.h"
44 
45 #include "SysIconUtils.h"
46 
47 using namespace NWindows;
48 using namespace NFile;
49 using namespace NFind;
50 using namespace NDir;
51 using namespace NName;
52 
53 #ifndef USE_UNICODE_FSTRING
54 int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2);
55 #endif
56 
57 #ifndef UNDER_CE
58 
59 namespace NFsFolder
60 {
61 bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size);
62 }
63 
64 #endif
65 
66 namespace NAltStreamsFolder {
67 
68 static const Byte kProps[] =
69 {
70   kpidName,
71   kpidSize,
72   kpidPackSize
73 };
74 
GetFsParentPrefixSize(const FString & path)75 static unsigned GetFsParentPrefixSize(const FString &path)
76 {
77   if (IsNetworkShareRootPath(path))
78     return 0;
79   const unsigned prefixSize = GetRootPrefixSize(path);
80   if (prefixSize == 0 || prefixSize >= path.Len())
81     return 0;
82   FString parentPath = path;
83   int pos = parentPath.ReverseFind_PathSepar();
84   if (pos < 0)
85     return 0;
86   if (pos == (int)parentPath.Len() - 1)
87   {
88     parentPath.DeleteBack();
89     pos = parentPath.ReverseFind_PathSepar();
90     if (pos < 0)
91       return 0;
92   }
93   if ((unsigned)pos + 1 < prefixSize)
94     return 0;
95   return (unsigned)pos + 1;
96 }
97 
Init(const FString & path)98 HRESULT CAltStreamsFolder::Init(const FString &path /* , IFolderFolder *parentFolder */)
99 {
100    // _parentFolder = parentFolder;
101    if (path.Back() != ':')
102      return E_FAIL;
103 
104   _pathPrefix = path;
105   _pathBaseFile = path;
106   _pathBaseFile.DeleteBack();
107 
108   {
109     CFileInfo fi;
110     if (!fi.Find(_pathBaseFile))
111       return GetLastError_noZero_HRESULT();
112   }
113 
114   unsigned prefixSize = GetFsParentPrefixSize(_pathBaseFile);
115   if (prefixSize == 0)
116     return S_OK;
117   FString parentPath = _pathBaseFile;
118   parentPath.DeleteFrom(prefixSize);
119 
120   _findChangeNotification.FindFirst(parentPath, false,
121         FILE_NOTIFY_CHANGE_FILE_NAME
122       | FILE_NOTIFY_CHANGE_DIR_NAME
123       | FILE_NOTIFY_CHANGE_ATTRIBUTES
124       | FILE_NOTIFY_CHANGE_SIZE
125       | FILE_NOTIFY_CHANGE_LAST_WRITE
126       /*
127       | FILE_NOTIFY_CHANGE_LAST_ACCESS
128       | FILE_NOTIFY_CHANGE_CREATION
129       | FILE_NOTIFY_CHANGE_SECURITY
130       */
131       );
132   /*
133   if (_findChangeNotification.IsHandleAllocated())
134     return S_OK;
135   return GetLastError();
136   */
137   return S_OK;
138 }
139 
Z7_COM7F_IMF(CAltStreamsFolder::LoadItems ())140 Z7_COM7F_IMF(CAltStreamsFolder::LoadItems())
141 {
142   Int32 dummy;
143   WasChanged(&dummy);
144   Clear();
145 
146   CStreamEnumerator enumerator(_pathBaseFile);
147 
148   CStreamInfo si;
149   for (;;)
150   {
151     bool found;
152     if (!enumerator.Next(si, found))
153     {
154       // if (GetLastError() == ERROR_ACCESS_DENIED)
155       //   break;
156       // return E_FAIL;
157       break;
158     }
159     if (!found)
160       break;
161     if (si.IsMainStream())
162       continue;
163     CAltStream ss;
164     ss.Name = si.GetReducedName();
165     if (!ss.Name.IsEmpty() && ss.Name[0] == ':')
166       ss.Name.Delete(0);
167 
168     ss.Size = si.Size;
169     ss.PackSize_Defined = false;
170     ss.PackSize = si.Size;
171     Streams.Add(ss);
172   }
173 
174   return S_OK;
175 }
176 
Z7_COM7F_IMF(CAltStreamsFolder::GetNumberOfItems (UInt32 * numItems))177 Z7_COM7F_IMF(CAltStreamsFolder::GetNumberOfItems(UInt32 *numItems))
178 {
179   *numItems = Streams.Size();
180   return S_OK;
181 }
182 
183 #ifdef USE_UNICODE_FSTRING
184 
Z7_COM7F_IMF(CAltStreamsFolder::GetItemPrefix (UInt32,const wchar_t ** name,unsigned * len))185 Z7_COM7F_IMF(CAltStreamsFolder::GetItemPrefix(UInt32 /* index */, const wchar_t **name, unsigned *len))
186 {
187   *name = NULL;
188   *len = 0;
189   return S_OK;
190 }
191 
Z7_COM7F_IMF(CAltStreamsFolder::GetItemName (UInt32 index,const wchar_t ** name,unsigned * len))192 Z7_COM7F_IMF(CAltStreamsFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len))
193 {
194   *name = NULL;
195   *len = 0;
196   {
197     const CAltStream &ss = Streams[index];
198     *name = ss.Name;
199     *len = ss.Name.Len();
200   }
201   return S_OK;
202 }
203 
Z7_COM7F_IMF2(UInt64,CAltStreamsFolder::GetItemSize (UInt32 index))204 Z7_COM7F_IMF2(UInt64, CAltStreamsFolder::GetItemSize(UInt32 index))
205 {
206   return Streams[index].Size;
207 }
208 
209 #endif
210 
211 
Z7_COM7F_IMF(CAltStreamsFolder::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))212 Z7_COM7F_IMF(CAltStreamsFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
213 {
214   NCOM::CPropVariant prop;
215   {
216     CAltStream &ss = Streams[index];
217     switch (propID)
218     {
219       case kpidIsDir: prop = false; break;
220       case kpidIsAltStream: prop = true; break;
221       case kpidName: prop = ss.Name; break;
222       case kpidSize: prop = ss.Size; break;
223       case kpidPackSize:
224         #ifdef UNDER_CE
225         prop = ss.Size;
226         #else
227         if (!ss.PackSize_Defined)
228         {
229           ss.PackSize_Defined = true;
230           if (!NFsFolder::MyGetCompressedFileSizeW(_pathPrefix + us2fs(ss.Name), ss.PackSize))
231             ss.PackSize = ss.Size;
232         }
233         prop = ss.PackSize;
234         #endif
235         break;
236     }
237   }
238 
239   prop.Detach(value);
240   return S_OK;
241 }
242 
243 
244 // returns Position of extension including '.'
245 
GetExtensionPtr(const UString & name)246 static inline const wchar_t *GetExtensionPtr(const UString &name)
247 {
248   const int dotPos = name.ReverseFind_Dot();
249   return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos);
250 }
251 
Z7_COM7F_IMF2(Int32,CAltStreamsFolder::CompareItems (UInt32 index1,UInt32 index2,PROPID propID,Int32))252 Z7_COM7F_IMF2(Int32, CAltStreamsFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */))
253 {
254   const CAltStream &ss1 = Streams[index1];
255   const CAltStream &ss2 = Streams[index2];
256 
257   switch (propID)
258   {
259     case kpidName:
260     {
261       return CompareFileNames_ForFolderList(ss1.Name, ss2.Name);
262       // return MyStringCompareNoCase(ss1.Name, ss2.Name);
263     }
264     case kpidSize:
265       return MyCompare(ss1.Size, ss2.Size);
266     case kpidPackSize:
267     {
268       #ifdef UNDER_CE
269       return MyCompare(ss1.Size, ss2.Size);
270       #else
271       // PackSize can be undefined here
272       return MyCompare(
273           ss1.PackSize,
274           ss2.PackSize);
275       #endif
276     }
277 
278     case kpidExtension:
279       return CompareFileNames_ForFolderList(
280           GetExtensionPtr(ss1.Name),
281           GetExtensionPtr(ss2.Name));
282   }
283 
284   return 0;
285 }
286 
Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder (UInt32,IFolderFolder ** resultFolder))287 Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(UInt32 /* index */, IFolderFolder **resultFolder))
288 {
289   *resultFolder = NULL;
290   return E_INVALIDARG;
291 }
292 
Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder (const wchar_t *,IFolderFolder ** resultFolder))293 Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder **resultFolder))
294 {
295   *resultFolder = NULL;
296   return E_INVALIDARG;
297 }
298 
299 // static CFSTR const kSuperPrefix = FTEXT("\\\\?\\");
300 
Z7_COM7F_IMF(CAltStreamsFolder::BindToParentFolder (IFolderFolder ** resultFolder))301 Z7_COM7F_IMF(CAltStreamsFolder::BindToParentFolder(IFolderFolder **resultFolder))
302 {
303   *resultFolder = NULL;
304   /*
305   if (_parentFolder)
306   {
307     CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
308     *resultFolder = parentFolder.Detach();
309     return S_OK;
310   }
311   */
312 
313   if (IsDriveRootPath_SuperAllowed(_pathBaseFile))
314   {
315     CFSDrives *drivesFolderSpec = new CFSDrives;
316     CMyComPtr<IFolderFolder> drivesFolder = drivesFolderSpec;
317     drivesFolderSpec->Init();
318     *resultFolder = drivesFolder.Detach();
319     return S_OK;
320   }
321 
322   /*
323   parentPath.DeleteFrom(pos + 1);
324 
325   if (parentPath == kSuperPrefix)
326   {
327     #ifdef UNDER_CE
328     *resultFolder = 0;
329     #else
330     CFSDrives *drivesFolderSpec = new CFSDrives;
331     CMyComPtr<IFolderFolder> drivesFolder = drivesFolderSpec;
332     drivesFolderSpec->Init(false, true);
333     *resultFolder = drivesFolder.Detach();
334     #endif
335     return S_OK;
336   }
337 
338   FString parentPathReduced = parentPath.Left(pos);
339 
340   #ifndef UNDER_CE
341   pos = parentPathReduced.ReverseFind_PathSepar();
342   if (pos == 1)
343   {
344     if (!IS_PATH_SEPAR_CHAR(parentPath[0]))
345       return E_FAIL;
346     CNetFolder *netFolderSpec = new CNetFolder;
347     CMyComPtr<IFolderFolder> netFolder = netFolderSpec;
348     netFolderSpec->Init(fs2us(parentPath));
349     *resultFolder = netFolder.Detach();
350     return S_OK;
351   }
352   #endif
353 
354   CFSFolder *parentFolderSpec = new CFSFolder;
355   CMyComPtr<IFolderFolder> parentFolder = parentFolderSpec;
356   RINOK(parentFolderSpec->Init(parentPath, 0));
357   *resultFolder = parentFolder.Detach();
358   */
359 
360   return S_OK;
361 }
362 
363 IMP_IFolderFolder_Props(CAltStreamsFolder)
364 
Z7_COM7F_IMF(CAltStreamsFolder::GetFolderProperty (PROPID propID,PROPVARIANT * value))365 Z7_COM7F_IMF(CAltStreamsFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
366 {
367   COM_TRY_BEGIN
368   NWindows::NCOM::CPropVariant prop;
369   switch (propID)
370   {
371     case kpidType: prop = "AltStreamsFolder"; break;
372     case kpidPath: prop = fs2us(_pathPrefix); break;
373   }
374   prop.Detach(value);
375   return S_OK;
376   COM_TRY_END
377 }
378 
Z7_COM7F_IMF(CAltStreamsFolder::WasChanged (Int32 * wasChanged))379 Z7_COM7F_IMF(CAltStreamsFolder::WasChanged(Int32 *wasChanged))
380 {
381   bool wasChangedMain = false;
382   for (;;)
383   {
384     if (!_findChangeNotification.IsHandleAllocated())
385     {
386       *wasChanged = BoolToInt(false);
387       return S_OK;
388     }
389 
390     const DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
391     const bool wasChangedLoc = (waitResult == WAIT_OBJECT_0);
392     if (wasChangedLoc)
393     {
394       _findChangeNotification.FindNext();
395       wasChangedMain = true;
396     }
397     else
398       break;
399   }
400   *wasChanged = BoolToInt(wasChangedMain);
401   return S_OK;
402 }
403 
Z7_COM7F_IMF(CAltStreamsFolder::Clone (IFolderFolder ** resultFolder))404 Z7_COM7F_IMF(CAltStreamsFolder::Clone(IFolderFolder **resultFolder))
405 {
406   CAltStreamsFolder *folderSpec = new CAltStreamsFolder;
407   CMyComPtr<IFolderFolder> folderNew = folderSpec;
408   folderSpec->Init(_pathPrefix);
409   *resultFolder = folderNew.Detach();
410   return S_OK;
411 }
412 
GetAbsPath(const wchar_t * name,FString & absPath)413 void CAltStreamsFolder::GetAbsPath(const wchar_t *name, FString &absPath)
414 {
415   absPath.Empty();
416   if (!IsAbsolutePath(name))
417     absPath += _pathPrefix;
418   absPath += us2fs(name);
419 }
420 
421 
422 
SendMessageError(IFolderOperationsExtractCallback * callback,const wchar_t * message,const FString & fileName)423 static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback,
424     const wchar_t *message, const FString &fileName)
425 {
426   UString s = message;
427   s += " : ";
428   s += fs2us(fileName);
429   return callback->ShowMessage(s);
430 }
431 
SendMessageError(IFolderArchiveUpdateCallback * callback,const wchar_t * message,const FString & fileName)432 static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback,
433     const wchar_t *message, const FString &fileName)
434 {
435   UString s = message;
436   s += " : ";
437   s += fs2us(fileName);
438   return callback->UpdateErrorMessage(s);
439 }
440 
SendMessageError(IFolderOperationsExtractCallback * callback,const char * message,const FString & fileName)441 static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback,
442     const char *message, const FString &fileName)
443 {
444   return SendMessageError(callback, MultiByteToUnicodeString(message), fileName);
445 }
446 
447 /*
448 static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback,
449     const char *message, const FString &fileName)
450 {
451   return SendMessageError(callback, MultiByteToUnicodeString(message), fileName);
452 }
453 */
454 
Z7_COM7F_IMF(CAltStreamsFolder::CreateFolder (const wchar_t *,IProgress *))455 Z7_COM7F_IMF(CAltStreamsFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */))
456 {
457   return E_NOTIMPL;
458 }
459 
Z7_COM7F_IMF(CAltStreamsFolder::CreateFile (const wchar_t * name,IProgress *))460 Z7_COM7F_IMF(CAltStreamsFolder::CreateFile(const wchar_t *name, IProgress * /* progress */))
461 {
462   FString absPath;
463   GetAbsPath(name, absPath);
464   NIO::COutFile outFile;
465   if (!outFile.Create_NEW(absPath))
466     return GetLastError_noZero_HRESULT();
467   return S_OK;
468 }
469 
GetLastErrorMessage()470 static UString GetLastErrorMessage()
471 {
472   return NError::MyFormatMessage(GetLastError_noZero_HRESULT());
473 }
474 
UpdateFile(NFsFolder::CCopyStateIO & state,CFSTR inPath,CFSTR outPath,IFolderArchiveUpdateCallback * callback)475 static HRESULT UpdateFile(NFsFolder::CCopyStateIO &state, CFSTR inPath, CFSTR outPath, IFolderArchiveUpdateCallback *callback)
476 {
477   if (NFind::DoesFileOrDirExist(outPath))
478   {
479     RINOK(SendMessageError(callback, NError::MyFormatMessage(ERROR_ALREADY_EXISTS), FString(outPath)))
480     CFileInfo fi;
481     if (fi.Find(inPath))
482     {
483       if (state.TotalSize >= fi.Size)
484         state.TotalSize -= fi.Size;
485     }
486     return S_OK;
487   }
488 
489   {
490     if (callback)
491       RINOK(callback->CompressOperation(fs2us(inPath)))
492     RINOK(state.MyCopyFile(inPath, outPath))
493     if (state.ErrorFileIndex >= 0)
494     {
495       if (state.ErrorMessage.IsEmpty())
496         state.ErrorMessage = GetLastErrorMessage();
497       FString errorName;
498       if (state.ErrorFileIndex == 0)
499         errorName = inPath;
500       else
501         errorName = outPath;
502       if (callback)
503         RINOK(SendMessageError(callback, state.ErrorMessage, errorName))
504     }
505     if (callback)
506       RINOK(callback->OperationResult(0))
507   }
508 
509   return S_OK;
510 }
511 
512 EXTERN_C_BEGIN
513 
514 typedef enum
515 {
516   Z7_WIN_FileRenameInformation = 10
517 }
518 Z7_WIN_FILE_INFORMATION_CLASS;
519 
520 
521 typedef struct
522 {
523   // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1)
524   union
525   {
526     BOOLEAN ReplaceIfExists;  // FileRenameInformation
527     ULONG Flags;              // FileRenameInformationEx
528   } DUMMYUNIONNAME;
529   // #else
530   // BOOLEAN ReplaceIfExists;
531   // #endif
532   HANDLE RootDirectory;
533   ULONG FileNameLength;
534   WCHAR FileName[1];
535 } Z7_WIN_FILE_RENAME_INFORMATION;
536 
537 #if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
538 #define Z7_WIN_NTSTATUS  NTSTATUS
539 #define Z7_WIN_IO_STATUS_BLOCK  IO_STATUS_BLOCK
540 #else
541 typedef LONG Z7_WIN_NTSTATUS;
542 typedef struct
543 {
544   union
545   {
546     Z7_WIN_NTSTATUS Status;
547     PVOID Pointer;
548   } DUMMYUNIONNAME;
549   ULONG_PTR Information;
550 } Z7_WIN_IO_STATUS_BLOCK;
551 #endif
552 
553 typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)(
554     HANDLE FileHandle,
555     Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock,
556     PVOID FileInformation,
557     ULONG Length,
558     Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass);
559 
560 // NTAPI
561 typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status);
562 
563 #define MY_STATUS_SUCCESS 0
564 
565 EXTERN_C_END
566 
567 // static Func_NtSetInformationFile f_NtSetInformationFile;
568 // static bool g_NtSetInformationFile_WasRequested = false;
569 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
570 
Z7_COM7F_IMF(CAltStreamsFolder::Rename (UInt32 index,const wchar_t * newName,IProgress * progress))571 Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress))
572 {
573   const CAltStream &ss = Streams[index];
574   const FString srcPath = _pathPrefix + us2fs(ss.Name);
575 
576   const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
577   // if (!g_NtSetInformationFile_WasRequested) {
578   // g_NtSetInformationFile_WasRequested = true;
579   const
580    Func_NtSetInformationFile
581       f_NtSetInformationFile = Z7_GET_PROC_ADDRESS(
582    Func_NtSetInformationFile, ntdll,
583        "NtSetInformationFile");
584   if (f_NtSetInformationFile)
585   {
586     NIO::CInFile inFile;
587     if (inFile.Open_for_FileRenameInformation(srcPath))
588     {
589       UString destPath (':');
590       destPath += newName;
591       const ULONG len = (ULONG)sizeof(wchar_t) * destPath.Len();
592       CByteBuffer buffer(sizeof(Z7_WIN_FILE_RENAME_INFORMATION) + len);
593       // buffer is 4 bytes larger than required.
594       Z7_WIN_FILE_RENAME_INFORMATION *fri = (Z7_WIN_FILE_RENAME_INFORMATION *)(void *)(Byte *)buffer;
595       memset(fri, 0, sizeof(Z7_WIN_FILE_RENAME_INFORMATION));
596       /* DOCS: If ReplaceIfExists is set to TRUE, the rename operation will succeed only
597          if a stream with the same name does not exist or is a zero-length data stream. */
598       fri->ReplaceIfExists = FALSE;
599       fri->RootDirectory = NULL;
600       fri->FileNameLength = len;
601       memcpy(fri->FileName, destPath.Ptr(), len);
602       Z7_WIN_IO_STATUS_BLOCK iosb;
603       const Z7_WIN_NTSTATUS status = f_NtSetInformationFile (inFile.GetHandle(),
604           &iosb, fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation);
605       if (status != MY_STATUS_SUCCESS)
606       {
607         const
608          Func_RtlNtStatusToDosError
609             f_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS(
610          Func_RtlNtStatusToDosError, ntdll,
611              "RtlNtStatusToDosError");
612         if (f_RtlNtStatusToDosError)
613         {
614           const ULONG res = f_RtlNtStatusToDosError(status);
615           if (res != ERROR_MR_MID_NOT_FOUND)
616             return HRESULT_FROM_WIN32(res);
617         }
618       }
619       return status;
620     }
621   }
622 
623   CMyComPtr<IFolderArchiveUpdateCallback> callback;
624   if (progress)
625   {
626     RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback))
627   }
628 
629   if (callback)
630   {
631     RINOK(callback->SetNumFiles(1))
632     RINOK(callback->SetTotal(ss.Size))
633   }
634 
635   NFsFolder::CCopyStateIO state;
636   state.Progress = progress;
637   state.TotalSize = 0;
638   state.DeleteSrcFile = true;
639 
640   const FString destPath = _pathPrefix + us2fs(newName);
641   return UpdateFile(state, srcPath, destPath, callback);
642 }
643 
Z7_COM7F_IMF(CAltStreamsFolder::Delete (const UInt32 * indices,UInt32 numItems,IProgress * progress))644 Z7_COM7F_IMF(CAltStreamsFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress))
645 {
646   RINOK(progress->SetTotal(numItems))
647   for (UInt32 i = 0; i < numItems; i++)
648   {
649     const CAltStream &ss = Streams[indices[i]];
650     const FString fullPath = _pathPrefix + us2fs(ss.Name);
651     const bool result = DeleteFileAlways(fullPath);
652     if (!result)
653       return GetLastError_noZero_HRESULT();
654     const UInt64 completed = i;
655     RINOK(progress->SetCompleted(&completed))
656   }
657   return S_OK;
658 }
659 
Z7_COM7F_IMF(CAltStreamsFolder::SetProperty (UInt32,PROPID,const PROPVARIANT *,IProgress *))660 Z7_COM7F_IMF(CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID */,
661     const PROPVARIANT * /* value */, IProgress * /* progress */))
662 {
663   return E_NOTIMPL;
664 }
665 
Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex (UInt32 index,Int32 * iconIndex))666 Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
667 {
668   const CAltStream &ss = Streams[index];
669   return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT(
670       _pathPrefix + us2fs(ss.Name),
671       FILE_ATTRIBUTE_ARCHIVE,
672       iconIndex);
673 }
674 
675 /*
676 Z7_CLASS_IMP_COM_1(
677   CGetProp
678   , IGetProp
679 )
680 public:
681   // const CArc *Arc;
682   // UInt32 IndexInArc;
683   UString Name; // relative path
684   UInt64 Size;
685 };
686 
687 Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
688 {
689   if (propID == kpidName)
690   {
691     COM_TRY_BEGIN
692     NCOM::CPropVariant prop;
693     prop = Name;
694     prop.Detach(value);
695     return S_OK;
696     COM_TRY_END
697   }
698   if (propID == kpidSize)
699   {
700     NCOM::CPropVariant prop = Size;
701     prop.Detach(value);
702     return S_OK;
703   }
704   NCOM::CPropVariant prop;
705   prop.Detach(value);
706   return S_OK;
707 }
708 */
709 
CopyStream(NFsFolder::CCopyStateIO & state,const FString & srcPath,const CFileInfo & srcFileInfo,const CAltStream & srcAltStream,const FString & destPathSpec,IFolderOperationsExtractCallback * callback)710 static HRESULT CopyStream(
711     NFsFolder::CCopyStateIO &state,
712     const FString &srcPath,
713     const CFileInfo &srcFileInfo,
714     const CAltStream &srcAltStream,
715     const FString &destPathSpec,
716     IFolderOperationsExtractCallback *callback)
717 {
718   FString destPath = destPathSpec;
719   if (CompareFileNames(destPath, srcPath) == 0)
720   {
721     RINOK(SendMessageError(callback, "Cannot copy file onto itself", destPath))
722     return E_ABORT;
723   }
724 
725   Int32 writeAskResult;
726   CMyComBSTR destPathResult;
727   RINOK(callback->AskWrite(
728       fs2us(srcPath),
729       BoolToInt(false),
730       &srcFileInfo.MTime, &srcAltStream.Size,
731       fs2us(destPath),
732       &destPathResult,
733       &writeAskResult))
734 
735   if (IntToBool(writeAskResult))
736   {
737     RINOK(callback->SetCurrentFilePath(fs2us(srcPath)))
738     FString destPathNew (us2fs((LPCOLESTR)destPathResult));
739     RINOK(state.MyCopyFile(srcPath, destPathNew))
740     if (state.ErrorFileIndex >= 0)
741     {
742       if (state.ErrorMessage.IsEmpty())
743         state.ErrorMessage = GetLastErrorMessage();
744       FString errorName;
745       if (state.ErrorFileIndex == 0)
746         errorName = srcPath;
747       else
748         errorName = destPathNew;
749       RINOK(SendMessageError(callback, state.ErrorMessage, errorName))
750       return E_ABORT;
751     }
752     state.StartPos += state.CurrentSize;
753   }
754   else
755   {
756     if (state.TotalSize >= srcAltStream.Size)
757     {
758       state.TotalSize -= srcAltStream.Size;
759       RINOK(state.Progress->SetTotal(state.TotalSize))
760     }
761   }
762   return S_OK;
763 }
764 
Z7_COM7F_IMF(CAltStreamsFolder::CopyTo (Int32 moveMode,const UInt32 * indices,UInt32 numItems,Int32,Int32,const wchar_t * path,IFolderOperationsExtractCallback * callback))765 Z7_COM7F_IMF(CAltStreamsFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
766     Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
767     const wchar_t *path, IFolderOperationsExtractCallback *callback))
768 {
769   if (numItems == 0)
770     return S_OK;
771 
772   /*
773   Z7_DECL_CMyComPtr_QI_FROM(
774       IFolderExtractToStreamCallback,
775       ExtractToStreamCallback, callback)
776   if (ExtractToStreamCallback)
777   {
778     Int32 useStreams = 0;
779     if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK)
780       useStreams = 0;
781     if (useStreams == 0)
782       ExtractToStreamCallback.Release();
783   }
784   */
785 
786   UInt64 totalSize = 0;
787   {
788     UInt32 i;
789     for (i = 0; i < numItems; i++)
790     {
791       totalSize += Streams[indices[i]].Size;
792     }
793     RINOK(callback->SetTotal(totalSize))
794     RINOK(callback->SetNumFiles(numItems))
795   }
796 
797   /*
798   if (ExtractToStreamCallback)
799   {
800     CGetProp *GetProp_Spec = new CGetProp;
801     CMyComPtr<IGetProp> GetProp= GetProp_Spec;
802 
803     for (UInt32 i = 0; i < numItems; i++)
804     {
805       UInt32 index = indices[i];
806       const CAltStream &ss = Streams[index];
807       GetProp_Spec->Name = ss.Name;
808       GetProp_Spec->Size = ss.Size;
809       CMyComPtr<ISequentialOutStream> outStream;
810       RINOK(ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, BoolToInt(false), &outStream,
811         NArchive::NExtract::NAskMode::kExtract, GetProp)); // isDir
812       FString srcPath;
813       GetFullPath(ss, srcPath);
814       RINOK(ExtractToStreamCallback->PrepareOperation7(NArchive::NExtract::NAskMode::kExtract));
815       RINOK(ExtractToStreamCallback->SetOperationResult7(NArchive::NExtract::NOperationResult::kOK, BoolToInt(false))); // _encrypted
816       // RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback, completedSize));
817     }
818     return S_OK;
819   }
820   */
821 
822   FString destPath (us2fs(path));
823   if (destPath.IsEmpty() /* && !ExtractToStreamCallback */)
824     return E_INVALIDARG;
825 
826   const bool isAltDest = NName::IsAltPathPrefix(destPath);
827   const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
828 
829   if (isDirectPath)
830   {
831     if (numItems > 1)
832       return E_INVALIDARG;
833   }
834 
835   CFileInfo fi;
836   if (!fi.Find(_pathBaseFile))
837     return GetLastError_noZero_HRESULT();
838 
839   NFsFolder::CCopyStateIO state;
840   state.Progress = callback;
841   state.DeleteSrcFile = IntToBool(moveMode);
842   state.TotalSize = totalSize;
843 
844   for (UInt32 i = 0; i < numItems; i++)
845   {
846     const UInt32 index = indices[i];
847     const CAltStream &ss = Streams[index];
848     FString destPath2 = destPath;
849     if (!isDirectPath)
850       destPath2 += us2fs(Get_Correct_FsFile_Name(ss.Name));
851     FString srcPath;
852     GetFullPath(ss, srcPath);
853     RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback))
854   }
855 
856   return S_OK;
857 }
858 
Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom (Int32,const wchar_t *,const wchar_t * const *,UInt32,IProgress *))859 Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
860     const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
861 {
862   /*
863   if (numItems == 0)
864     return S_OK;
865 
866   CMyComPtr<IFolderArchiveUpdateCallback> callback;
867   if (progress)
868   {
869     RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback));
870   }
871 
872   if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0)
873   {
874     RINOK(SendMessageError(callback, "Cannot copy file onto itself", _pathPrefix));
875     return E_ABORT;
876   }
877 
878   if (callback)
879     RINOK(callback->SetNumFiles(numItems));
880 
881   UInt64 totalSize = 0;
882 
883   UInt32 i;
884 
885   FString path;
886   for (i = 0; i < numItems; i++)
887   {
888     path = us2fs(fromFolderPath);
889     path += us2fs(itemsPaths[i]);
890 
891     CFileInfo fi;
892     if (!fi.Find(path))
893       return ::GetLastError();
894     if (fi.IsDir())
895       return E_NOTIMPL;
896     totalSize += fi.Size;
897   }
898 
899   RINOK(progress->SetTotal(totalSize));
900 
901   // UInt64 completedSize = 0;
902 
903   NFsFolder::CCopyStateIO state;
904   state.Progress = progress;
905   state.DeleteSrcFile = IntToBool(moveMode);
906   state.TotalSize = totalSize;
907 
908   // we need to clear READ-ONLY of parent before creating alt stream
909   {
910     DWORD attrib = GetFileAttrib(_pathBaseFile);
911     if (attrib != INVALID_FILE_ATTRIBUTES
912         && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
913     {
914       if (!SetFileAttrib(_pathBaseFile, attrib & ~FILE_ATTRIBUTE_READONLY))
915       {
916         if (callback)
917         {
918           RINOK(SendMessageError(callback, GetLastErrorMessage(), _pathBaseFile));
919           return S_OK;
920         }
921         return Return_LastError_or_FAIL();
922       }
923     }
924   }
925 
926   for (i = 0; i < numItems; i++)
927   {
928     path = us2fs(fromFolderPath);
929     path += us2fs(itemsPaths[i]);
930 
931     FString destPath = _pathPrefix + us2fs(itemsPaths[i]);
932 
933     RINOK(UpdateFile(state, path, destPath, callback));
934   }
935 
936   return S_OK;
937   */
938   return E_NOTIMPL;
939 }
940 
Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile (UInt32,const wchar_t *,IProgress *))941 Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
942 {
943   return E_NOTIMPL;
944 }
945 
946 }
947