This commit is contained in:
Igor Pavlov
2023-12-22 17:17:05 +00:00
committed by Kornel
parent ec44a8a070
commit a36c48cece
954 changed files with 42199 additions and 25482 deletions

View File

@@ -4,8 +4,6 @@
#include "../../../Common/MyWindows.h"
#include <WinBase.h>
#include "../../../Common/Defs.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/Wildcard.h"
@@ -31,6 +29,9 @@ extern bool g_IsNT;
namespace NFsFolder {
static const char * const k_CannotCopyDirToAltStream = "Cannot copy folder as alternate stream";
HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib)
{
ErrorFileIndex = -1;
@@ -82,11 +83,15 @@ HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib)
if (Progress)
{
UInt64 completed = StartPos + CurrentSize;
RINOK(Progress->SetCompleted(&completed));
RINOK(Progress->SetCompleted(&completed))
}
}
}
/* SetFileAttrib("path:alt_stream_name") sets attributes for main file "path".
But we don't want to change attributes of main file, when we write alt stream.
So we need INVALID_FILE_ATTRIBUTES for alt stream here */
if (attrib != INVALID_FILE_ATTRIBUTES)
SetFileAttrib(outPath, attrib);
@@ -174,7 +179,7 @@ static DWORD CALLBACK CopyProgressRoutine(
pi.FileSize = (UInt64)TotalFileSize.QuadPart;
pi.ProgressResult = pi.Progress->SetTotal(pi.TotalSize);
}
UInt64 completed = pi.StartPos + TotalBytesTransferred.QuadPart;
const UInt64 completed = pi.StartPos + (UInt64)TotalBytesTransferred.QuadPart;
pi.ProgressResult = pi.Progress->SetCompleted(&completed);
return (pi.ProgressResult == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL);
}
@@ -211,6 +216,7 @@ struct CCopyState
IFolderOperationsExtractCallback *Callback;
bool MoveMode;
bool UseReadWriteMode;
bool IsAltStreamsDest;
Func_CopyFileExW my_CopyFileExW;
#ifndef UNDER_CE
@@ -245,21 +251,27 @@ void CCopyState::Prepare()
my_CopyFileExA = NULL;
if (!g_IsNT)
{
my_CopyFileExA = (Func_CopyFileExA)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA");
my_CopyFileExA = Z7_GET_PROC_ADDRESS(
Func_CopyFileExA, ::GetModuleHandleA("kernel32.dll"),
"CopyFileExA");
}
else
#endif
{
HMODULE module = ::GetModuleHandleW(
const HMODULE module = ::GetModuleHandleW(
#ifdef UNDER_CE
L"coredll.dll"
#else
L"kernel32.dll"
#endif
);
my_CopyFileExW = (Func_CopyFileExW)My_GetProcAddress(module, "CopyFileExW");
my_CopyFileExW = Z7_GET_PROC_ADDRESS(
Func_CopyFileExW, module,
"CopyFileExW");
#ifndef UNDER_CE
my_MoveFileWithProgressW = (Func_MoveFileWithProgressW)My_GetProcAddress(module, "MoveFileWithProgressW");
my_MoveFileWithProgressW = Z7_GET_PROC_ADDRESS(
Func_MoveFileWithProgressW, module,
"MoveFileWithProgressW");
#endif
}
}
@@ -303,7 +315,7 @@ bool CCopyState::CopyFile_Sys(CFSTR oldFile, CFSTR newFile)
if (CopyFile_NT(fs2us(oldFile), fs2us(newFile)))
return true;
}
#ifdef WIN_LONG_PATH
#ifdef Z7_LONG_PATH
if (USE_SUPER_PATH_2)
{
if (IsCallbackProgressError())
@@ -332,7 +344,7 @@ bool CCopyState::MoveFile_Sys(CFSTR oldFile, CFSTR newFile)
&ProgressInfo, MOVEFILE_COPY_ALLOWED))
return true;
}
#ifdef WIN_LONG_PATH
#ifdef Z7_LONG_PATH
if ((!(USE_MAIN_PATH_2) || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) && USE_SUPER_PATH_2)
{
if (IsCallbackProgressError())
@@ -399,7 +411,7 @@ static HRESULT CopyFile_Ask(
state.MoveMode ?
"Cannot move file onto itself" :
"Cannot copy file onto itself"
, destPath));
, destPath))
return E_ABORT;
}
@@ -411,12 +423,12 @@ static HRESULT CopyFile_Ask(
&srcFileInfo.MTime, &srcFileInfo.Size,
fs2us(destPath),
&destPathResult,
&writeAskResult));
&writeAskResult))
if (IntToBool(writeAskResult))
{
FString destPathNew = us2fs((LPCOLESTR)destPathResult);
RINOK(state.Callback->SetCurrentFilePath(fs2us(srcPath)));
RINOK(state.Callback->SetCurrentFilePath(fs2us(srcPath)))
if (state.UseReadWriteMode)
{
@@ -426,7 +438,8 @@ static HRESULT CopyFile_Ask(
state2.TotalSize = state.ProgressInfo.TotalSize;
state2.StartPos = state.ProgressInfo.StartPos;
RINOK(state2.MyCopyFile(srcPath, destPathNew, srcFileInfo.Attrib));
RINOK(state2.MyCopyFile(srcPath, destPathNew,
state.IsAltStreamsDest ? INVALID_FILE_ATTRIBUTES: srcFileInfo.Attrib))
if (state2.ErrorFileIndex >= 0)
{
@@ -437,7 +450,7 @@ static HRESULT CopyFile_Ask(
errorName = srcPath;
else
errorName = destPathNew;
RINOK(SendMessageError(state.Callback, state2.ErrorMessage, errorName));
RINOK(SendMessageError(state.Callback, state2.ErrorMessage, errorName))
return E_ABORT;
}
state.ProgressInfo.StartPos += state2.CurrentSize;
@@ -450,11 +463,11 @@ static HRESULT CopyFile_Ask(
res = state.MoveFile_Sys(srcPath, destPathNew);
else
res = state.CopyFile_Sys(srcPath, destPathNew);
RINOK(state.ProgressInfo.ProgressResult);
RINOK(state.ProgressInfo.ProgressResult)
if (!res)
{
// GetLastError() is ERROR_REQUEST_ABORTED in case of PROGRESS_CANCEL.
RINOK(SendMessageError(state.Callback, GetLastErrorMessage(), destPathNew));
RINOK(SendMessageError(state.Callback, GetLastErrorMessage(), destPathNew))
return E_ABORT;
}
state.ProgressInfo.StartPos += state.ProgressInfo.FileSize;
@@ -465,7 +478,7 @@ static HRESULT CopyFile_Ask(
if (state.ProgressInfo.TotalSize >= srcFileInfo.Size)
{
state.ProgressInfo.TotalSize -= srcFileInfo.Size;
RINOK(state.ProgressInfo.Progress->SetTotal(state.ProgressInfo.TotalSize));
RINOK(state.ProgressInfo.Progress->SetTotal(state.ProgressInfo.TotalSize))
}
}
return state.CallProgress();
@@ -494,7 +507,7 @@ static HRESULT CopyFolder(
const FString &srcPath, // without TAIL separator
const FString &destPath) // without TAIL separator
{
RINOK(state.CallProgress());
RINOK(state.CallProgress())
if (IsDestChild(srcPath, destPath))
{
@@ -502,7 +515,7 @@ static HRESULT CopyFolder(
state.MoveMode ?
"Cannot copy folder onto itself" :
"Cannot move folder onto itself"
, destPath));
, destPath))
return E_ABORT;
}
@@ -516,7 +529,7 @@ static HRESULT CopyFolder(
if (!CreateComplexDir(destPath))
{
RINOK(SendMessageError(state.Callback, "Cannot create folder", destPath));
RINOK(SendMessageError(state.Callback, "Cannot create folder", destPath))
return E_ABORT;
}
@@ -542,7 +555,7 @@ static HRESULT CopyFolder(
}
else
{
RINOK(CopyFile_Ask(state, srcPath2, fi, destPath2));
RINOK(CopyFile_Ask(state, srcPath2, fi, destPath2))
}
}
@@ -550,7 +563,7 @@ static HRESULT CopyFolder(
{
if (!RemoveDir(srcPath))
{
RINOK(SendMessageError(state.Callback, "Cannot remove folder", srcPath));
RINOK(SendMessageError(state.Callback, "Cannot remove folder", srcPath))
return E_ABORT;
}
}
@@ -558,38 +571,67 @@ static HRESULT CopyFolder(
return S_OK;
}
STDMETHODIMP CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
Z7_COM7F_IMF(CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
const wchar_t *path, IFolderOperationsExtractCallback *callback)
const wchar_t *path, IFolderOperationsExtractCallback *callback))
{
if (numItems == 0)
return S_OK;
FString destPath = us2fs(path);
const FString destPath = us2fs(path);
if (destPath.IsEmpty())
return E_INVALIDARG;
bool isAltDest = NName::IsAltPathPrefix(destPath);
bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
const bool isAltDest = NName::IsAltPathPrefix(destPath);
const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
if (isDirectPath)
{
if (numItems > 1)
return E_INVALIDARG;
}
CFsFolderStat stat;
stat.Progress = callback;
RINOK(GetItemsFullSize(indices, numItems, stat));
UInt32 i;
for (i = 0; i < numItems; i++)
{
const UInt32 index = indices[i];
/*
if (index >= Files.Size())
{
size += Streams[index - Files.Size()].Size;
// numFiles++;
continue;
}
*/
const CDirItem &fi = Files[index];
if (fi.IsDir())
{
if (!isAltDest)
{
stat.Path = _path;
stat.Path += GetRelPath(fi);
RINOK(stat.Enumerate())
}
stat.NumFolders++;
}
else
{
stat.NumFiles++;
stat.Size += fi.Size;
}
}
/*
if (stat.NumFolders != 0 && isAltDest)
return E_NOTIMPL;
*/
RINOK(callback->SetTotal(stat.Size));
RINOK(callback->SetNumFiles(stat.NumFiles));
RINOK(callback->SetTotal(stat.Size))
RINOK(callback->SetNumFiles(stat.NumFiles))
UInt64 completedSize = 0;
RINOK(callback->SetCompleted(&completedSize));
RINOK(callback->SetCompleted(&completedSize))
CCopyState state;
state.ProgressInfo.TotalSize = stat.Size;
@@ -598,12 +640,16 @@ STDMETHODIMP CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num
state.ProgressInfo.Init();
state.Callback = callback;
state.MoveMode = IntToBool(moveMode);
state.IsAltStreamsDest = isAltDest;
/* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER,
if there are alt streams in fromFile.
So we don't use CopyFileW() for alt Streams. */
state.UseReadWriteMode = isAltDest;
state.Prepare();
for (UInt32 i = 0; i < numItems; i++)
for (i = 0; i < numItems; i++)
{
UInt32 index = indices[i];
const UInt32 index = indices[i];
if (index >= (UInt32)Files.Size())
continue;
const CDirItem &fi = Files[index];
@@ -615,57 +661,148 @@ STDMETHODIMP CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 num
if (fi.IsDir())
{
RINOK(CopyFolder(state, srcPath, destPath2));
if (isAltDest)
{
RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, srcPath))
}
else
{
RINOK(CopyFolder(state, srcPath, destPath2))
}
}
else
{
RINOK(CopyFile_Ask(state, srcPath, fi, destPath2));
RINOK(CopyFile_Ask(state, srcPath, fi, destPath2))
}
}
return S_OK;
}
STDMETHODIMP CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)
{
/*
UInt64 numFolders, numFiles, totalSize;
numFiles = numFolders = totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
{
UString path = (UString)fromFolderPath + itemsPaths[i];
/* we can call CopyFileSystemItems() from CDropTarget::Drop() */
HRESULT CopyFileSystemItems(
const UStringVector &itemsPaths,
const FString &destDirPrefix,
bool moveMode,
IFolderOperationsExtractCallback *callback)
{
if (itemsPaths.IsEmpty())
return S_OK;
if (destDirPrefix.IsEmpty())
return E_INVALIDARG;
const bool isAltDest = NName::IsAltPathPrefix(destDirPrefix);
CFsFolderStat stat;
stat.Progress = callback;
{
FOR_VECTOR (i, itemsPaths)
{
const UString &path = itemsPaths[i];
CFileInfo fi;
if (!FindFile(path, fi))
return ::GetLastError();
if (!fi.Find(us2fs(path)))
continue;
if (fi.IsDir())
{
UInt64 subFolders, subFiles, subSize;
RINOK(GetFolderSize(CombinePath(path, fi.Name), subFolders, subFiles, subSize, progress));
numFolders += subFolders;
numFolders++;
numFiles += subFiles;
totalSize += subSize;
if (!isAltDest)
{
stat.Path = us2fs(path);
RINOK(stat.Enumerate())
}
stat.NumFolders++;
}
else
{
numFiles++;
totalSize += fi.Size;
stat.NumFiles++;
stat.Size += fi.Size;
}
}
RINOK(progress->SetTotal(totalSize));
RINOK(callback->SetNumFiles(numFiles));
for (i = 0; i < numItems; i++)
}
/*
if (stat.NumFolders != 0 && isAltDest)
return E_NOTIMPL;
*/
RINOK(callback->SetTotal(stat.Size))
// RINOK(progress->SetNumFiles(stat.NumFiles));
UInt64 completedSize = 0;
RINOK(callback->SetCompleted(&completedSize))
CCopyState state;
state.ProgressInfo.TotalSize = stat.Size;
state.ProgressInfo.StartPos = 0;
state.ProgressInfo.Progress = callback;
state.ProgressInfo.Init();
state.Callback = callback;
state.MoveMode = moveMode;
state.IsAltStreamsDest = isAltDest;
/* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER,
if there are alt streams in fromFile.
So we don't use CopyFileW() for alt Streams. */
state.UseReadWriteMode = isAltDest;
state.Prepare();
FOR_VECTOR (i, itemsPaths)
{
UString path = (UString)fromFolderPath + itemsPaths[i];
const UString path = itemsPaths[i];
CFileInfo fi;
if (!fi.Find(us2fs(path)))
{
RINOK(SendMessageError(callback, "Cannot find the file", us2fs(path)))
continue;
}
FString destPath = destDirPrefix;
destPath += fi.Name;
if (fi.IsDir())
{
if (isAltDest)
{
RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, us2fs(path)))
}
else
{
RINOK(CopyFolder(state, us2fs(path), destPath))
}
}
else
{
RINOK(CopyFile_Ask(state, us2fs(path), fi, destPath))
}
}
return S_OK;
}
/* we don't use CFSFolder::CopyFrom() because the caller of CopyFrom()
is optimized for IFolderArchiveUpdateCallback interface,
but we want to use IFolderOperationsExtractCallback interface instead */
Z7_COM7F_IMF(CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
{
/*
Z7_DECL_CMyComPtr_QI_FROM(
IFolderOperationsExtractCallback,
callback, progress)
if (!callback)
return E_NOTIMPL;
return CopyFileSystemItems(_path,
moveMode, fromDirPrefix,
itemsPaths, numItems, callback);
*/
return E_NOTIMPL;
}
STDMETHODIMP CFSFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)
Z7_COM7F_IMF(CFSFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
{
return E_NOTIMPL;
}