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