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 DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
391 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 *iconIndex = 0;
670 int iconIndexTemp;
671 if (GetRealIconIndex(_pathPrefix + us2fs(ss.Name),
672 0 // fi.Attrib
673 , iconIndexTemp) != 0)
674 {
675 *iconIndex = iconIndexTemp;
676 return S_OK;
677 }
678 return GetLastError_noZero_HRESULT();
679 }
680
681 /*
682 Z7_CLASS_IMP_COM_1(
683 CGetProp
684 , IGetProp
685 )
686 public:
687 // const CArc *Arc;
688 // UInt32 IndexInArc;
689 UString Name; // relative path
690 UInt64 Size;
691 };
692
693 Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
694 {
695 if (propID == kpidName)
696 {
697 COM_TRY_BEGIN
698 NCOM::CPropVariant prop;
699 prop = Name;
700 prop.Detach(value);
701 return S_OK;
702 COM_TRY_END
703 }
704 if (propID == kpidSize)
705 {
706 NCOM::CPropVariant prop = Size;
707 prop.Detach(value);
708 return S_OK;
709 }
710 NCOM::CPropVariant prop;
711 prop.Detach(value);
712 return S_OK;
713 }
714 */
715
CopyStream(NFsFolder::CCopyStateIO & state,const FString & srcPath,const CFileInfo & srcFileInfo,const CAltStream & srcAltStream,const FString & destPathSpec,IFolderOperationsExtractCallback * callback)716 static HRESULT CopyStream(
717 NFsFolder::CCopyStateIO &state,
718 const FString &srcPath,
719 const CFileInfo &srcFileInfo,
720 const CAltStream &srcAltStream,
721 const FString &destPathSpec,
722 IFolderOperationsExtractCallback *callback)
723 {
724 FString destPath = destPathSpec;
725 if (CompareFileNames(destPath, srcPath) == 0)
726 {
727 RINOK(SendMessageError(callback, "Cannot copy file onto itself", destPath))
728 return E_ABORT;
729 }
730
731 Int32 writeAskResult;
732 CMyComBSTR destPathResult;
733 RINOK(callback->AskWrite(
734 fs2us(srcPath),
735 BoolToInt(false),
736 &srcFileInfo.MTime, &srcAltStream.Size,
737 fs2us(destPath),
738 &destPathResult,
739 &writeAskResult))
740
741 if (IntToBool(writeAskResult))
742 {
743 RINOK(callback->SetCurrentFilePath(fs2us(srcPath)))
744 FString destPathNew (us2fs((LPCOLESTR)destPathResult));
745 RINOK(state.MyCopyFile(srcPath, destPathNew))
746 if (state.ErrorFileIndex >= 0)
747 {
748 if (state.ErrorMessage.IsEmpty())
749 state.ErrorMessage = GetLastErrorMessage();
750 FString errorName;
751 if (state.ErrorFileIndex == 0)
752 errorName = srcPath;
753 else
754 errorName = destPathNew;
755 RINOK(SendMessageError(callback, state.ErrorMessage, errorName))
756 return E_ABORT;
757 }
758 state.StartPos += state.CurrentSize;
759 }
760 else
761 {
762 if (state.TotalSize >= srcAltStream.Size)
763 {
764 state.TotalSize -= srcAltStream.Size;
765 RINOK(state.Progress->SetTotal(state.TotalSize))
766 }
767 }
768 return S_OK;
769 }
770
Z7_COM7F_IMF(CAltStreamsFolder::CopyTo (Int32 moveMode,const UInt32 * indices,UInt32 numItems,Int32,Int32,const wchar_t * path,IFolderOperationsExtractCallback * callback))771 Z7_COM7F_IMF(CAltStreamsFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
772 Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
773 const wchar_t *path, IFolderOperationsExtractCallback *callback))
774 {
775 if (numItems == 0)
776 return S_OK;
777
778 /*
779 Z7_DECL_CMyComPtr_QI_FROM(
780 IFolderExtractToStreamCallback,
781 ExtractToStreamCallback, callback)
782 if (ExtractToStreamCallback)
783 {
784 Int32 useStreams = 0;
785 if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK)
786 useStreams = 0;
787 if (useStreams == 0)
788 ExtractToStreamCallback.Release();
789 }
790 */
791
792 UInt64 totalSize = 0;
793 {
794 UInt32 i;
795 for (i = 0; i < numItems; i++)
796 {
797 totalSize += Streams[indices[i]].Size;
798 }
799 RINOK(callback->SetTotal(totalSize))
800 RINOK(callback->SetNumFiles(numItems))
801 }
802
803 /*
804 if (ExtractToStreamCallback)
805 {
806 CGetProp *GetProp_Spec = new CGetProp;
807 CMyComPtr<IGetProp> GetProp= GetProp_Spec;
808
809 for (UInt32 i = 0; i < numItems; i++)
810 {
811 UInt32 index = indices[i];
812 const CAltStream &ss = Streams[index];
813 GetProp_Spec->Name = ss.Name;
814 GetProp_Spec->Size = ss.Size;
815 CMyComPtr<ISequentialOutStream> outStream;
816 RINOK(ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, BoolToInt(false), &outStream,
817 NArchive::NExtract::NAskMode::kExtract, GetProp)); // isDir
818 FString srcPath;
819 GetFullPath(ss, srcPath);
820 RINOK(ExtractToStreamCallback->PrepareOperation7(NArchive::NExtract::NAskMode::kExtract));
821 RINOK(ExtractToStreamCallback->SetOperationResult7(NArchive::NExtract::NOperationResult::kOK, BoolToInt(false))); // _encrypted
822 // RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback, completedSize));
823 }
824 return S_OK;
825 }
826 */
827
828 FString destPath (us2fs(path));
829 if (destPath.IsEmpty() /* && !ExtractToStreamCallback */)
830 return E_INVALIDARG;
831
832 const bool isAltDest = NName::IsAltPathPrefix(destPath);
833 const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
834
835 if (isDirectPath)
836 {
837 if (numItems > 1)
838 return E_INVALIDARG;
839 }
840
841 CFileInfo fi;
842 if (!fi.Find(_pathBaseFile))
843 return GetLastError_noZero_HRESULT();
844
845 NFsFolder::CCopyStateIO state;
846 state.Progress = callback;
847 state.DeleteSrcFile = IntToBool(moveMode);
848 state.TotalSize = totalSize;
849
850 for (UInt32 i = 0; i < numItems; i++)
851 {
852 const UInt32 index = indices[i];
853 const CAltStream &ss = Streams[index];
854 FString destPath2 = destPath;
855 if (!isDirectPath)
856 destPath2 += us2fs(Get_Correct_FsFile_Name(ss.Name));
857 FString srcPath;
858 GetFullPath(ss, srcPath);
859 RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback))
860 }
861
862 return S_OK;
863 }
864
Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom (Int32,const wchar_t *,const wchar_t * const *,UInt32,IProgress *))865 Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
866 const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
867 {
868 /*
869 if (numItems == 0)
870 return S_OK;
871
872 CMyComPtr<IFolderArchiveUpdateCallback> callback;
873 if (progress)
874 {
875 RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback));
876 }
877
878 if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0)
879 {
880 RINOK(SendMessageError(callback, "Cannot copy file onto itself", _pathPrefix));
881 return E_ABORT;
882 }
883
884 if (callback)
885 RINOK(callback->SetNumFiles(numItems));
886
887 UInt64 totalSize = 0;
888
889 UInt32 i;
890
891 FString path;
892 for (i = 0; i < numItems; i++)
893 {
894 path = us2fs(fromFolderPath);
895 path += us2fs(itemsPaths[i]);
896
897 CFileInfo fi;
898 if (!fi.Find(path))
899 return ::GetLastError();
900 if (fi.IsDir())
901 return E_NOTIMPL;
902 totalSize += fi.Size;
903 }
904
905 RINOK(progress->SetTotal(totalSize));
906
907 // UInt64 completedSize = 0;
908
909 NFsFolder::CCopyStateIO state;
910 state.Progress = progress;
911 state.DeleteSrcFile = IntToBool(moveMode);
912 state.TotalSize = totalSize;
913
914 // we need to clear READ-ONLY of parent before creating alt stream
915 {
916 DWORD attrib = GetFileAttrib(_pathBaseFile);
917 if (attrib != INVALID_FILE_ATTRIBUTES
918 && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
919 {
920 if (!SetFileAttrib(_pathBaseFile, attrib & ~FILE_ATTRIBUTE_READONLY))
921 {
922 if (callback)
923 {
924 RINOK(SendMessageError(callback, GetLastErrorMessage(), _pathBaseFile));
925 return S_OK;
926 }
927 return Return_LastError_or_FAIL();
928 }
929 }
930 }
931
932 for (i = 0; i < numItems; i++)
933 {
934 path = us2fs(fromFolderPath);
935 path += us2fs(itemsPaths[i]);
936
937 FString destPath = _pathPrefix + us2fs(itemsPaths[i]);
938
939 RINOK(UpdateFile(state, path, destPath, callback));
940 }
941
942 return S_OK;
943 */
944 return E_NOTIMPL;
945 }
946
Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile (UInt32,const wchar_t *,IProgress *))947 Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
948 {
949 return E_NOTIMPL;
950 }
951
952 }
953