summaryrefslogtreecommitdiff
path: root/UCoreWorkers.pas
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2024-10-11 23:38:44 +0200
committerTomas Bzatek <tbzatek@redhat.com>2024-10-23 18:13:05 +0200
commit7d757b8452daed2575e3a9cc300459d7e8674345 (patch)
tree1b4c0107964cc871dc6e2d732c615af710592c4c /UCoreWorkers.pas
parent81c8cd22e61701c1145dc267b0925add6cc0e78a (diff)
downloadtuxcmd-7d757b8452daed2575e3a9cc300459d7e8674345.tar.xz
Full port to GErrorv0.6.81
Started 15 years ago, picking up on that work. Introduced the new TUXCMD_ERROR domain to distinguish between operations or their steps. Plugins may continue reporting the G_IO_ERROR domain.
Diffstat (limited to 'UCoreWorkers.pas')
-rw-r--r--UCoreWorkers.pas781
1 files changed, 402 insertions, 379 deletions
diff --git a/UCoreWorkers.pas b/UCoreWorkers.pas
index 7c0fb02..3ff94f8 100644
--- a/UCoreWorkers.pas
+++ b/UCoreWorkers.pas
@@ -20,7 +20,7 @@
unit UCoreWorkers;
interface
-uses glib2, gtk2, SyncObjs, Classes, GTKForms, GTKView, ULibc, UEngines, UCoreUtils, UVFSCore, uVFSprototypes, UCore, UDirDelete;
+uses glib2, gtk2, SyncObjs, Classes, GTKForms, ULibc, UEngines, UCoreUtils, UVFSCore, uVFSprototypes, UCore, UDirDelete;
type TWorkerThreadJobType = (WORKER_JOB_DUMMY, WORKER_JOB_DELETE, WORKER_JOB_COPY, WORKER_JOB_MOVE, WORKER_JOB_EXTRACT_TO_TEMP,
@@ -80,7 +80,10 @@ type TVFSCallbackThread = class(TThread)
// Copy worker progress values
FTotalSize, FTotalDone, FFileSize: cuLongLong;
FCopySkipAllErrors: boolean;
+ FCopyErrorHandledInProgress: boolean;
+ FCopySilentCancel: boolean;
FCopyProgressFunc: TEngineProgressFunc;
+ FCopySourceFile, FCopyDestFile: string;
// Dialogs
FCancelMessage: string;
@@ -95,8 +98,7 @@ type TVFSCallbackThread = class(TThread)
FGUIChanged: boolean;
FDirDeleteButtonsType: TFDirDeleteButtonSet;
- FDirDeleteTitle, FDirDeleteFileName: string;
- FDirDeleteError: PGError;
+ FDirDeleteText1, FDirDeleteFileName, FDirDeleteText2: string;
FOverwriteShowAppend: boolean;
FOverwriteSourceItem, FOverwriteDestItem: PDataItem;
@@ -117,7 +119,7 @@ type TVFSCallbackThread = class(TThread)
procedure SetProgress2Params(const ProgressMax: Int64);
procedure UpdateCaption1(const CaptionText: string);
procedure UpdateCaption2(const CaptionText: string);
- function ShowDirDeleteDialog(ButtonsType: TFDirDeleteButtonSet; const Title, FileName: string; Error: PGError): integer;
+ function ShowDirDeleteDialog(ButtonsType: TFDirDeleteButtonSet; const Text1, FileName, Text2: string): integer;
function ShowOverwriteDialog(ShowAppend: boolean; SourceItem, DestItem: PDataItem; const SourceFile, DestFile: string; var RenameStr: string): integer;
function ShowInaccessibleDialog(InaccessiblePaths: TStringList): integer;
function ShowNewDirDialog(Caption, LabelCaption, Edit: string): integer;
@@ -137,7 +139,7 @@ type TVFSCallbackThread = class(TThread)
public
JobType: TWorkerThreadJobType;
SrcEngine, DestEngine: TPanelEngine;
- ErrorHappened: boolean;
+ ErrorHappened: boolean; // checked in UMain
// For getting list of selected items in the panel
DataList: TList;
@@ -214,8 +216,8 @@ procedure ProcessThreadEvents(SenderThread: TVFSCallbackThread);
implementation
uses SysUtils, DateUtils, StrUtils, UConfig, UOverwrite, ULocale,
- UFileAssoc, UCoreClasses, URemoteWait, UMain, UGnome, UNewDir, UProgress,
- crc;
+ UCoreClasses, URemoteWait, UMain, UGnome, UNewDir, UProgress,
+ UError, crc;
@@ -502,12 +504,12 @@ begin
FGUIMutex.Release;
end;
-function TWorkerThread.ShowDirDeleteDialog(ButtonsType: TFDirDeleteButtonSet; const Title, FileName: string; Error: PGError): integer;
+function TWorkerThread.ShowDirDeleteDialog(ButtonsType: TFDirDeleteButtonSet; const Text1, FileName, Text2: string): integer;
begin
FDialogResultDirDelete := DIR_DELETE_CANCEL;
- FDirDeleteTitle := Title;
+ FDirDeleteText1 := Text1;
FDirDeleteFileName := FileName;
- FDirDeleteError := Error;
+ FDirDeleteText2 := Text2;
FDirDeleteButtonsType := ButtonsType;
FDialogShowDirDelete := True;
FCallbackLockEvent.ResetEvent;
@@ -579,11 +581,11 @@ begin
with PDataItem(DataList[i])^ do
if (not UpDir) and Selected then
InputFiles.Add(CurrPath + String(FName));
- // If not files are selected, take into account the current active item
+ // If no files are selected, take into account the current active item
if (InputFiles.Count = 0) and Assigned(SelectedItem) and (not SelectedItem^.UpDir) then
InputFiles.Add(CurrPath + String(SelectedItem^.FName));
- FillDirFiles(AEngine, AList, InputFiles, DoNotRecurse, True, InaccessiblePaths);
+ FillDirFiles(AEngine, AList, InputFiles, DoNotRecurse, True, InaccessiblePaths, @FCancelled);
InputFiles.Free;
end;
@@ -709,10 +711,10 @@ begin
try
AFDirDelete := TFDirDelete.Create(ParentDialogForm);
AFDirDelete.AddButtons(FDirDeleteButtonsType);
- AFDirDelete.Label1.Caption := FDirDeleteTitle;
+ AFDirDelete.Label1.Caption := FDirDeleteText1;
AFDirDelete.Label2.Caption := FDirDeleteFileName;
- if FDirDeleteError <> nil then
- AFDirDelete.Label3.Caption := FDirDeleteError^.message;
+ AFDirDelete.Label3.Caption := FDirDeleteText2;
+ AFDirDelete.Label3.Visible := Length(FDirDeleteText2) > 0;
FDialogResultDirDelete := Integer(AFDirDelete.Run);
if (FDirDeleteButtonsType = DIR_DELETE_SET_COPY_ERROR) and (FDialogResultDirDelete = DIR_DELETE_IGNORE) and (JobType = WORKER_JOB_MOVE)
then case Application.MessageBox(LANGIgnoreError, [mbYes, mbNo{, mbCancel}], mbWarning, mbYes, mbNo) of
@@ -830,21 +832,17 @@ var SkipAll: boolean;
// DebugMsg(['Debug: IsDir: ', AFileRec^.IsDir, ', Stage1: ', AFileRec^.Stage1, ', IsLnk: ', AFileRec^.IsLnk, '; Result = ', AFileRec^.IsDir and AFileRec^.Stage1 and (not AFileRec^.IsLnk)]);
if AFileRec^.DataItem^.IsDir and AFileRec^.Stage1 and (not AFileRec^.DataItem^.IsLnk) then Exit;
Res := AEngine.Remove(String(AFileRec^.DataItem^.FName), @Error);
-// DebugMsg(['Result : ', Res]);
- if not Res then
- if SkipAll then Result := True else
- begin
- Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error deleting file/directory:', String(AFileRec^.DataItem^.FDisplayName), Error);
- if Error <> nil then
+ if not Res then begin
+ if SkipAll then Result := True
+ else begin
+ Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error deleting file/directory', AFileRec^.DataItem^.FDisplayName, Error^.message);
g_error_free(Error);
- case Response of
- DIR_DELETE_SKIP : Result := True;
- DIR_DELETE_SKIP_ALL : begin
- SkipAll := True;
- Result := True;
- end;
- DIR_DELETE_RETRY : Result := HandleDelete(AFileRec);
- else Result := False;
+ case Response of
+ DIR_DELETE_SKIP : Result := True;
+ DIR_DELETE_SKIP_ALL : begin SkipAll := True; Result := True; end;
+ DIR_DELETE_RETRY : Result := HandleDelete(AFileRec);
+ else Result := False;
+ end;
end;
end;
end;
@@ -893,7 +891,7 @@ begin
if (not DeleteAll) and (PDataItemSL(AList[i])^.Level = 1) and PDataItemSL(AList[i])^.Stage1 and PDataItemSL(AList[i])^.DataItem^.IsDir and
(not PDataItemSL(AList[i])^.DataItem^.IsLnk) and (i < AList.Count - 2) and (PDataItemSL(AList[i + 1])^.Level = 2) then
begin
- Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_NON_EMPTY, 'The directory is not empty, do you want to delete it with all its files and subdirectories?', string(PDataItemSL(AList[i])^.DataItem^.FDisplayName), nil);
+ Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_NON_EMPTY, 'The directory is not empty, do you want to delete it with all its files and subdirectories?', PDataItemSL(AList[i])^.DataItem^.FDisplayName, '');
case Response of
DIR_DELETE_DELETE : ; // Do nothing in this case - I will not bother with changing the structure; it works :-)
DIR_DELETE_ALL : DeleteAll := True;
@@ -925,6 +923,35 @@ end;
(********************************************************************************************************************************)
(********************************************************************************************************************************)
+ procedure GetCopyProgressErrorLabels(Thread: TWorkerThread; Error: PGError; var s1, s2: string);
+ begin
+ if (Thread.JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) then s1 := LANGCopyError
+ else s1 := LANGMoveError;
+ s2 := Thread.FCopySourceFile;
+ if (Error^.domain = TUXCMD_ERROR) then
+ case TuxcmdErrorEnum(Error^.code) of
+ TUXCMD_ERROR_ALLOC_FAILED: s1 := LANGMemoryAllocationFailed;
+ TUXCMD_ERROR_SOURCE_OPEN: s1 := LANGCannotOpenSourceFile;
+ TUXCMD_ERROR_TARGET_OPEN: begin
+ s1 := LANGCannotOpenDestinationFile;
+ s2 := Thread.FCopyDestFile;
+ end;
+ TUXCMD_ERROR_SOURCE_READ: s1 := LANGCannotReadFromSourceFile;
+ TUXCMD_ERROR_TARGET_WRITE: begin
+ s1 := LANGCannotWriteToDestinationFile;
+ s2 := Thread.FCopyDestFile;
+ end;
+ TUXCMD_ERROR_SOURCE_CLOSE: s1 := LANGCannotCloseSourceFile;
+ TUXCMD_ERROR_TARGET_CLOSE: begin
+ s1 := LANGCannotCloseDestinationFile;
+ s2 := Thread.FCopyDestFile;
+ end;
+ TUXCMD_ERROR_RENAME: begin
+ s1 := 'Cannot move the file to';
+ s2 := Thread.FCopyDestFile;
+ end;
+ end;
+ end;
// Keep in sync with uVFSprototypes.pas/TVFSProgressCallback
function vfs_copy_progress_callback(position: guint64; error: PGError; user_data: Pointer): gboolean; cdecl;
@@ -941,147 +968,146 @@ end;
// Keep in sync with UEngines.pas/TEngineProgressFunc
function CopyFilesWorker_ProgressFunc(Sender: Pointer; BytesDone: Int64; Error: PGError): boolean; cdecl;
+ var s, s2: string;
begin
Result := True;
try
if Assigned(Sender) and (TObject(Sender) is TWorkerThread) then
with TWorkerThread(Sender) do begin
- if BytesDone = 0 then UpdateProgress1(0, '0%')
- else UpdateProgress1(BytesDone, Format('%d%%', [Round(BytesDone / FFileSize * 100)]));
- UpdateProgress2(FTotalDone + BytesDone, Format('%d%%', [Round((FTotalDone + BytesDone) / FTotalSize * 100)]));
Result := not FCancelled;
- CommitGUIUpdate;
+ if Error <> nil then begin
+ // Error handling
+ if FCopySkipAllErrors then Exit;
+ GetCopyProgressErrorLabels(TWorkerThread(Sender), Error, s, s2);
+ case ShowDirDeleteDialog(DIR_DELETE_SET_COPY_ERROR, s, s2, StrToUTF8(Error^.message)) of
+ DIR_DELETE_IGNORE : Result := True;
+ DIR_DELETE_SKIP : Result := False;
+ DIR_DELETE_SKIP_ALL : begin
+ FCopySkipAllErrors := True;
+ Result := False;
+ end;
+ DIR_DELETE_CANCEL, 124, 255 : begin
+ Result := False;
+ FCancelled := True;
+ end;
+ else begin
+ Result := False; // Cancel
+ FCopySilentCancel := True;
+ end;
+ end;
+ FCopyErrorHandledInProgress := not Result;
+ end else begin
+ // Progress update
+ if BytesDone = 0 then UpdateProgress1(0, '0%')
+ else UpdateProgress1(BytesDone, Format('%d%%', [Round(BytesDone / FFileSize * 100)]));
+ UpdateProgress2(FTotalDone + BytesDone, Format('%d%%', [Round((FTotalDone + BytesDone) / FTotalSize * 100)]));
+ CommitGUIUpdate;
+ end;
end else DebugMsg(['*** CopyFilesWorker: Sender is not TWorkerThread']);
except
on E: Exception do DebugMsg(['*** Exception raised in ProgressFunc(Sender=', Sender, ', BytesDone=', BytesDone, '): (', E.ClassName, '): ', E.Message]);
end;
end;
- // Return True to ignore the error (Skip, Skip All, Ignore, Cancel)
- function CopyFilesWorker_ErrorFunc(Sender: Pointer; ErrorType, ErrorNum: integer; FileName: string): boolean; cdecl;
- var s, s2, s3: string;
- begin
- Result := False;
- with TWorkerThread(Sender) do begin
- if FCopySkipAllErrors then begin
- Result := True;
- Exit;
- end;
- case ErrorType of
- 0 : begin
- FCancelled := True;
- Exit;
- end;
- 1 : s := LANGMemoryAllocationFailed;
- 2 : s := LANGCannotOpenSourceFile;
- 3 : s := LANGCannotOpenDestinationFile;
- 4 : s := LANGCannotCloseDestinationFile;
- 5 : s := LANGCannotCloseSourceFile;
- 6 : s := LANGCannotReadFromSourceFile;
- 7 : s := LANGCannotWriteToDestinationFile;
- end;
- if (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) then s2 := LANGCopyError
- else s2 := LANGMoveError;
- if ErrorType <> 1 then s3 := StrToUTF8(FileName)
- else s3 := '';
-
- // * TODO: fix error string, port to GError
- case ShowDirDeleteDialog(DIR_DELETE_SET_COPY_ERROR, s, s3, nil) of
- DIR_DELETE_CANCEL : begin
- Result := False;
- FCancelled := True;
- end;
- DIR_DELETE_IGNORE : Result := True;
- DIR_DELETE_SKIP_ALL : begin
- FCopySkipAllErrors := True; { Skip All Err }
- Result := False; //** True?
- end;
- else Result := False; // Skip
- end;
- end;
- end;
-
procedure TWorkerThread.CopyFilesWorker;
var DefResponse: integer; // Global variables for this function
- SkipAll: boolean;
// Returns True if file was successfully copied, if not, the file will be deleted in LocalCopyFile
- function ManualCopyFile(SourceFile, DestFile: string; Append: boolean): boolean;
+ function ManualCopyFile(SourceFile, DestFile: string; Append: boolean; Error: PPGError): boolean;
var fsrc, fdst: TEngineFileDes;
BSize: integer;
Buffer: Pointer;
BytesDone, BytesRead, BytesWritten: Int64;
- Res: boolean;
- Error: PGError;
+ LocalError: PGError;
begin
- DebugMsg(['ManualCopyFile: ', SourceFile, ' ---> ', DestFile]);
Result := False;
- Error := nil;
- fsrc := SrcEngine.OpenFile(SourceFile, omRead, @Error);
+ LocalError := nil;
+ DebugMsg(['ManualCopyFile: ', SourceFile, ' ---> ', DestFile]);
+ fsrc := SrcEngine.OpenFile(SourceFile, omRead, @LocalError);
if fsrc = nil then begin
- // * TODO: set real error, also free it
- CopyFilesWorker_ErrorFunc(Self, 2, 1 { Error }, SourceFile); // Cannot open source file
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_OPEN), LocalError^.message);
+ g_error_free(LocalError);
+ CopyFilesWorker_ProgressFunc(Self, 0, Error^); // Cannot open source file
Exit;
end;
- if Append then fdst := DestEngine.OpenFile(DestFile, omAppend, @Error)
- else fdst := DestEngine.OpenFile(DestFile, omWrite, @Error);
+ if Append then fdst := DestEngine.OpenFile(DestFile, omAppend, @LocalError)
+ else fdst := DestEngine.OpenFile(DestFile, omWrite, @LocalError);
if fdst = nil then begin
- // * TODO: set real error, also free it
SrcEngine.CloseFile(fsrc, nil);
- CopyFilesWorker_ErrorFunc(Self, 3, 1 { Error }, SourceFile); // Cannot open target file
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_TARGET_OPEN), LocalError^.message);
+ g_error_free(LocalError);
+ CopyFilesWorker_ProgressFunc(Self, 0, Error^); // Cannot open target file
Exit;
end;
BytesDone := 0;
- Res := True;
-
BSize := DestEngine.GetBlockSize;
Buffer := malloc(BSize);
if Buffer = nil then begin
- CopyFilesWorker_ErrorFunc(Self, 1, errno, SourceFile); // Memory allocation failed
- libc_free(Buffer);
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_ALLOC_FAILED), '%m');
+ CopyFilesWorker_ProgressFunc(Self, 0, Error^); // Memory allocation failed
Exit;
end;
memset(Buffer, 0, BSize);
BytesWritten := 0;
repeat
- BytesRead := SrcEngine.ReadFile(fsrc, Buffer, BSize, @Error);
- if (BytesRead = 0) and (Error <> nil) then
- // * TODO: set real error, also free it
- Res := CopyFilesWorker_ErrorFunc(Self, 6, 1 { Error }, SourceFile); // Cannot read from source file
+ BytesRead := SrcEngine.ReadFile(fsrc, Buffer, BSize, @LocalError);
+ if (BytesRead = 0) and (Error^ <> nil) then begin
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_READ), LocalError^.message);
+ g_error_free(LocalError);
+ LocalError := nil;
+ Result := CopyFilesWorker_ProgressFunc(Self, BytesWritten, Error^); // Cannot read from source file
+ if Result then begin
+ g_error_free(Error^);
+ Error^ := nil;
+ Continue;
+ end else Break;
+ end;
if BytesRead > 0 then begin
- Error := nil;
- BytesWritten := DestEngine.WriteFile(fdst, Buffer, BytesRead, @Error);
- if (BytesWritten < BytesRead) then
- // * TODO: set real error, also free it
- Res := CopyFilesWorker_ErrorFunc(Self, 7, 1 { Error }, DestFile); // Cannot write to source file
+ BytesWritten := DestEngine.WriteFile(fdst, Buffer, BytesRead, @LocalError);
+ if (BytesWritten < BytesRead) then begin
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_TARGET_WRITE), LocalError^.message);
+ g_error_free(LocalError);
+ LocalError := nil;
+ Result := CopyFilesWorker_ProgressFunc(Self, BytesWritten, Error^); // Cannot write to target file
+ if Result then begin
+ g_error_free(Error^);
+ Error^ := nil;
+ Continue;
+ end else Break;
+ end;
end;
BytesDone := BytesDone + BytesRead;
- if not CopyFilesWorker_ProgressFunc(Self, BytesDone, nil) then begin
- Res := False;
- Break;
- end;
+ Result := CopyFilesWorker_ProgressFunc(Self, BytesDone, nil);
+ if not Result then Break;
until (BytesRead = 0) or (BytesWritten < BytesRead);
libc_free(Buffer);
- // * TODO: set real error, also free it
- if not DestEngine.CloseFile(fdst, nil) then begin
- CopyFilesWorker_ErrorFunc(Self, 4, errno, DestFile); // Cannot close target file
+ if not DestEngine.CloseFile(fdst, @LocalError) then begin
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_TARGET_CLOSE), LocalError^.message);
+ g_error_free(LocalError);
+ Result := False;
+ SrcEngine.CloseFile(fsrc, nil);
+ CopyFilesWorker_ProgressFunc(Self, BytesDone, Error^); // Cannot close target file
Exit;
end;
- // * TODO: set real error, also free it
- if not SrcEngine.CloseFile(fsrc, nil) then begin
- CopyFilesWorker_ErrorFunc(Self, 5, errno, SourceFile); // Cannot close source file
- Exit;
+ if not SrcEngine.CloseFile(fsrc, @LocalError) then begin
+ g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_CLOSE), LocalError^.message);
+ g_error_free(LocalError);
+ Result := CopyFilesWorker_ProgressFunc(Self, BytesDone, Error^); // Cannot close source file
+ if Result then begin
+ // user has chosen to ignore the error
+ g_error_free(Error^);
+ Error^ := nil;
+ end else Exit;
end;
- Result := Res;
end;
// Returns True if the file was successfully copied and will be deleted on move
- function LocalCopyFile(SourceFile, DestFile: string; Append: boolean): boolean;
+ function LocalCopyFile(SourceFile, DestFile: string; Append: boolean; Error: PPGError): boolean;
var DataSrc, DataDest: PDataItem;
begin
Result := False;
@@ -1091,28 +1117,28 @@ var DefResponse: integer; // Global variables for this function
// local -> local
if (SrcEngine is TLocalTreeEngine) and (DestEngine is TLocalTreeEngine)
- then Result := DestEngine.CopyFileIn(SourceFile, DestFile, Append, @CopyFilesWorker_ProgressFunc, Self)
+ then Result := DestEngine.CopyFileIn(SourceFile, DestFile, Append, @CopyFilesWorker_ProgressFunc, Self, Error)
else
// from local engine to VFS engine
if (SrcEngine is TLocalTreeEngine) and (DestEngine is TVFSEngine) then
begin
AEngine := DestEngine;
- Result := (DestEngine as TVFSEngine).CopyFileInEx(SourceFile, DestFile, Append);
+ Result := (DestEngine as TVFSEngine).CopyFileInEx(SourceFile, DestFile, Append, Error);
end else
// from VFS engine to local (most common use)
if (SrcEngine is TVFSEngine) and (DestEngine is TLocalTreeEngine) then
begin
AEngine := SrcEngine;
- Result := (SrcEngine as TVFSEngine).CopyFileOutEx(SourceFile, DestFile, Append);
+ Result := (SrcEngine as TVFSEngine).CopyFileOutEx(SourceFile, DestFile, Append, Error);
end
- // VFS to VFS (not supported yet)
+ // VFS to VFS (mostly unsupported)
else
begin
AEngine := SrcEngine;
- Result := ManualCopyFile(SourceFile, DestFile, Append);
+ Result := ManualCopyFile(SourceFile, DestFile, Append, Error);
end;
AEngine := nil;
@@ -1130,7 +1156,11 @@ var DefResponse: integer; // Global variables for this function
FreeDataItem(DataDest);
end;
except
- on E: Exception do DebugMsg(['*** Exception raised in LocalCopyFile(SourceFile=', SourceFile, ', DestFile=', DestFile, ', Append=', Append, '): (', E.ClassName, '): ', E.Message]);
+ on E: Exception do begin
+ Result := False;
+ tuxcmd_set_error_from_exception(Error, E);
+ DebugMsg(['*** Exception raised in LocalCopyFile(SourceFile=', SourceFile, ', DestFile=', DestFile, ', Append=', Append, '): (', E.ClassName, '): ', E.Message]);
+ end;
end;
end;
@@ -1161,31 +1191,24 @@ var DefResponse: integer; // Global variables for this function
Result := TestCaseInsensitiveFS and DestEngine.TwoSameFiles(Path1, Path2, False);
end;
- function DoOperation(AFileRec: PDataItemSL; const Dst: string; var ErrorKind: integer; const Append: boolean): integer;
+ function DoOperation(AFileRec: PDataItemSL; const Dst: string; const Append: boolean; Error: PPGError): boolean;
begin
- ErrorKind := 0;
- Result := 0;
+ Result := False;
try
with AFileRec^ do begin
if DataItem^.IsLnk then begin
// Explicit copy the file
if (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) or (not IsOnSameFS(String(DataItem^.FName), ExtractFileDir(Dst))) then begin
- // * TODO: check error
- ErrorKind := Ord(DestEngine.MakeSymLink(Dst, String(DataItem^.LnkPointTo), nil));
-// if ErrorKind <> 0 then Result := ERRCreateLink;
- if JobType = WORKER_JOB_MOVE then begin
- // * TODO: check error
- ErrorKind := Ord(SrcEngine.Remove(String(DataItem^.FName), nil));
-// if ErrorKind <> 0 then Result := ERRRemove;
- end;
+ Result := DestEngine.MakeSymLink(Dst, String(DataItem^.LnkPointTo), Error);
+ if Result and (JobType = WORKER_JOB_MOVE) then
+ Result := SrcEngine.Remove(String(DataItem^.FName), Error);
end else begin // Move the file
- // * TODO: check error
- ErrorKind := Ord(DestEngine.RenameFile(String(DataItem^.FName), Dst, nil));
-// if ErrorKind <> 0 then Result := ERRCopyMove;
+ Result := DestEngine.RenameFile(String(DataItem^.FName), Dst, Error);
end;
- end else // is not link
+ end else // is not a symlink
if (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) then begin // Copy mode
- if LocalCopyFile(String(DataItem^.FName), Dst, Append) then begin
+ Result := LocalCopyFile(String(DataItem^.FName), Dst, Append, Error);
+ if Result then begin
if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR;
// * TODO: check error
DestEngine.Chmod(Dst, DataItem^.Mode, nil);
@@ -1196,187 +1219,179 @@ var DefResponse: integer; // Global variables for this function
if IsOnSameFS(String(DataItem^.FName), ExtractFileDir(Dst)) then begin
if TwoSameFiles(String(DataItem^.FName), Dst, True) and (not TwoSameFiles(String(DataItem^.FName), Dst, False)) then begin
DebugMsg(['*** Activating double-rename due to renaming on case-insensitive FS']);
- // * TODO: check error
- ErrorKind := Ord(DestEngine.RenameFile(String(DataItem^.FName), Dst + '_tcmd', nil));
- if ErrorKind = 0 then ErrorKind := Ord(DestEngine.RenameFile(Dst + '_tcmd', Dst, nil));
- end else ErrorKind := Ord(DestEngine.RenameFile(String(DataItem^.FName), Dst, nil));
-// if ErrorKind <> 0 then Result := ERRCopyMove;
+ Result := DestEngine.RenameFile(String(DataItem^.FName), Dst + '_tcmd', Error);
+ if Result then
+ Result := DestEngine.RenameFile(Dst + '_tcmd', Dst, Error);
+ end else Result := DestEngine.RenameFile(String(DataItem^.FName), Dst, Error);
end else begin
- if LocalCopyFile(String(DataItem^.FName), Dst, Append) then begin
+ Result := LocalCopyFile(String(DataItem^.FName), Dst, Append, Error);
+ if Result then begin
if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR;
// * TODO: check error
DestEngine.Chmod(Dst, DataItem^.Mode, nil);
DestEngine.Chown(Dst, DataItem^.UID, DataItem^.GID, nil);
DestEngine.ChangeTimes(Dst, DataItem^.mtime, DataItem^.atime, nil);
- if not FCancelled then begin
- ErrorKind := Ord(SrcEngine.Remove(String(DataItem^.FName), nil));
-// if ErrorKind <> 0 then Result := ERRRemove;
- end;
+ Result := SrcEngine.Remove(String(DataItem^.FName), Error);
end;
end;
end;
// DebugMsg(['(II) CopyFilesWorker.DoOperation: finished']);
except
- on E: Exception do DebugMsg(['*** Exception raised in DoOperation(AFileRec=', AFileRec, ', Dst=', Dst, ', ErrorKind=', ErrorKind, ', Append=', Append, '): (', E.ClassName, '): ', E.Message]);
+ on E: Exception do begin
+ Result := False;
+ tuxcmd_set_error_from_exception(Error, E);
+ DebugMsg(['*** Exception raised in DoOperation(AFileRec=', AFileRec, ', Dst=', Dst, ', Append=', Append, '): (', E.ClassName, '): ', E.Message]);
+ end;
end;
end;
// Return False to break the processing (Cancel)
function HandleCopy(AFileRec: PDataItemSL; NewFilePath: string): boolean;
- var Res, Response, ErrorKind, r: integer;
+ var Response: integer;
+ Res: boolean;
Item: PDataItem;
- s, s1, s3, cap: string;
- FromInfoLabel, ToInfoLabel, InfoLabelFormat: string;
+ s, s2, s3: string;
RenameStr: string;
+ Error: PGError;
begin
Result := True;
+ Res := True;
+ Error := nil;
try
+ // Second stage - change permissions
+ if (not AFileRec^.Stage1) and ((JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) or (not AFileRec^.ForceMove)) then begin
+ with AFileRec^ do begin
+ if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR;
+ // * TODO: check error
+ DestEngine.Chmod(NewFilePath, DataItem^.Mode, nil);
+ DestEngine.Chown(NewFilePath, DataItem^.UID, DataItem^.GID, nil);
+ DestEngine.ChangeTimes(NewFilePath, DataItem^.mtime, DataItem^.atime, nil);
+ if JobType = WORKER_JOB_MOVE then
+ Res := SrcEngine.Remove(String(DataItem^.FName), @Error); // Remove directory
+ end;
+ end else
- // Second stage - change permissions
- if (not AFileRec^.Stage1) and ((JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) or (not AFileRec^.ForceMove)) then
- with AFileRec^ do begin
- if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR;
- // * TODO: check error
- DestEngine.Chmod(NewFilePath, DataItem^.Mode, nil);
- DestEngine.Chown(NewFilePath, DataItem^.UID, DataItem^.GID, nil);
- DestEngine.ChangeTimes(NewFilePath, DataItem^.mtime, DataItem^.atime, nil);
- if JobType = WORKER_JOB_MOVE then
- SrcEngine.Remove(String(DataItem^.FName), nil); // Remove directory
- Exit;
- end;
-
- // First stage - copy data
- if AFileRec^.DataItem^.IsDir then begin
- Res := 0;
- if AFileRec^.ForceMove and (JobType = WORKER_JOB_MOVE)
+ // First stage - copy data
+ if AFileRec^.DataItem^.IsDir then begin
+ if AFileRec^.ForceMove and (JobType = WORKER_JOB_MOVE)
then begin
if TwoSameFiles(ExcludeTrailingPathDelimiter(string(AFileRec^.DataItem^.FName)), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)), True) and (not
TwoSameFiles(ExcludeTrailingPathDelimiter(string(AFileRec^.DataItem^.FName)), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)), False)) then
begin
DebugMsg(['*** Activating double-rename due to renaming on case-insensitive FS']);
- // * TODO: check error
- ErrorKind := Ord(DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', nil));
- if ErrorKind = 0 then ErrorKind := ord(DestEngine.RenameFile(ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)), nil));
- end else ErrorKind := Ord(DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), string(AFileRec^.ADestination), nil));
-{ if ErrorKind <> 0 then Res := ERRCopyMove
- else Res := 0; }
+ Res := DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', @Error);
+ if Res then Res := DestEngine.RenameFile(ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)), @Error);
+ end else Res := DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), string(AFileRec^.ADestination), @Error);
end else
if not DestEngine.DirectoryExists(NewFilePath, False) then begin
- // * TODO: check error
- ErrorKind := Ord(DestEngine.MakeDir(NewFilePath, nil));
-{ if ErrorKind <> 0 then Res := ERRMkDir
- else Res := 0; }
- end;
- end else begin // not a directory
- if not DestEngine.DirectoryExists(ExtractFileDir(NewFilePath), False) then
- // * TODO: check error
- DestEngine.MakeDir(ExtractFileDir(NewFilePath), nil);
- SetProgress1Params(AFileRec^.DataItem^.Size + Ord(AFileRec^.DataItem^.Size = 0));
- FFileSize := AFileRec^.DataItem^.Size;
- CopyFilesWorker_ProgressFunc(Self, 0, nil);
- Res := 0;
- if DestEngine.FileExists(NewFilePath, False) and
- (not ((JobType = WORKER_JOB_MOVE) and (not TwoSameFiles(NewFilePath, AFileRec^.DataItem^.FName, False)) and TwoSameFiles(NewFilePath, AFileRec^.DataItem^.FName, True)))
- then begin
- Response := DefResponse;
- // * TODO: check error --> display dialog
- // * TODO: should be SrcEngine?
- Item := DestEngine.GetFileInfo(NewFilePath, False, True, nil);
- if Item = nil then begin
- DebugMsg(['Something went terribly wrong during copy - Item := DestEngine.GetFileInfoSL(NewFilePath) == NULL!']);
- Result := False;
- Exit;
- end;
- if Response = 0 then begin
- case ConfSizeFormat of
- 5: InfoLabelFormat := '%s, %s';
- else InfoLabelFormat := LANGOvewriteSBytesS;
- end;
- RenameStr := ExtractFileName(NewFilePath);
- Response := ShowOverwriteDialog(JobType in [WORKER_JOB_COPY], Item, AFileRec^.DataItem, NewFilePath, AFileRec^.DataItem^.FName, RenameStr);
- case Response of
- // OVERWRITE_OVERWRITE
- // OVERWRITE_SKIP
- OVERWRITE_OVERWRITE_ALL, OVERWRITE_OVERWRITE_ALL_OLDER, OVERWRITE_SKIP_ALL: DefResponse := Response;
- OVERWRITE_CANCEL, 124 {Close Window}, 255: begin
- Result := False;
- Exit;
- end;
- OVERWRITE_RENAME: begin
- NewFilePath := Copy(NewFilePath, 1, LastDelimiter(PathDelim, NewFilePath)) + RenameStr;
- Result := HandleCopy(AFileRec, NewFilePath);
- Exit;
- end;
- OVERWRITE_APPEND: begin
- Res := DoOperation(AFileRec, NewFilePath, ErrorKind, True);
- end;
+ Res := DestEngine.MakeDir(NewFilePath, @Error);
end;
- end;
-
- // Remove destination file if exists and should be overwritten
- if (Response in [OVERWRITE_OVERWRITE, OVERWRITE_OVERWRITE_ALL]) or ((Response = OVERWRITE_OVERWRITE_ALL_OLDER) and (Item^.mtime < AFileRec^.DataItem^.mtime)) then begin
+ end else begin // not a directory
+ if not DestEngine.DirectoryExists(ExtractFileDir(NewFilePath), False) then
// * TODO: check error
- r := ord(DestEngine.Remove(NewFilePath, nil));
- while r <> 0 do begin
- // * TODO: check error, port to GError
- Res := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'The file could not be deleted', StrToUTF8(String(NewFilePath)), nil);
- case Res of
- DIR_DELETE_SKIP: begin
- Result := True;
- Exit;
- end;
- // * TODO: check error
- DIR_DELETE_RETRY: r := Ord(DestEngine.Remove(NewFilePath, nil));
- DIR_DELETE_CANCEL, 124, 255: begin
- Result := False;
- Exit;
- end;
+ DestEngine.MakeDir(ExtractFileDir(NewFilePath), nil);
+ SetProgress1Params(AFileRec^.DataItem^.Size + Ord(AFileRec^.DataItem^.Size = 0));
+ FFileSize := AFileRec^.DataItem^.Size;
+ CopyFilesWorker_ProgressFunc(Self, 0, nil);
+ // Overwrite handling
+ if DestEngine.FileExists(NewFilePath, False) and
+ (not ((JobType = WORKER_JOB_MOVE) and (not TwoSameFiles(NewFilePath, AFileRec^.DataItem^.FName, False)) and TwoSameFiles(NewFilePath, AFileRec^.DataItem^.FName, True)))
+ then begin
+ Response := DefResponse;
+ Item := DestEngine.GetFileInfo(NewFilePath, False, True, @Error);
+ if Item = nil then begin
+ // Display an error and bail out
+ Res := False;
+ end else begin
+ if Response = 0 then begin
+ RenameStr := ExtractFileName(NewFilePath);
+ Response := ShowOverwriteDialog(JobType in [WORKER_JOB_COPY], Item, AFileRec^.DataItem, NewFilePath, AFileRec^.DataItem^.FName, RenameStr);
+ case Response of
+ // OVERWRITE_OVERWRITE
+ // OVERWRITE_SKIP
+ OVERWRITE_OVERWRITE_ALL, OVERWRITE_OVERWRITE_ALL_OLDER, OVERWRITE_SKIP_ALL: DefResponse := Response;
+ OVERWRITE_RENAME: begin
+ NewFilePath := Copy(NewFilePath, 1, LastDelimiter(PathDelim, NewFilePath)) + RenameStr;
+ FCopyDestFile := NewFilePath; // ... for the label
+ Result := HandleCopy(AFileRec, NewFilePath);
+ Exit;
+ end;
+ OVERWRITE_APPEND: Res := DoOperation(AFileRec, NewFilePath, True, @Error);
+ OVERWRITE_CANCEL, 124 {Close Window}, 255, 252: begin
+ Result := False;
+ Exit;
+ end;
+ end;
+ end;
+
+ // Remove destination file if exists and should be overwritten
+ if (Response in [OVERWRITE_OVERWRITE, OVERWRITE_OVERWRITE_ALL]) or ((Response = OVERWRITE_OVERWRITE_ALL_OLDER) and (Item^.mtime < AFileRec^.DataItem^.mtime)) then begin
+ while not DestEngine.Remove(NewFilePath, @Error) do begin
+ Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error deleting file', StrToUTF8(String(NewFilePath)), Error^.message);
+ g_error_free(Error);
+ Error := nil;
+ case Response of
+ DIR_DELETE_SKIP: begin
+ Result := True;
+ Exit;
+ end;
+ DIR_DELETE_RETRY: ; // Continue
+ DIR_DELETE_CANCEL, 124, 255: begin
+ Result := False;
+ Exit;
+ end;
+ else begin // Cancel
+ Result := False;
+ Exit;
+ end;
+ end;
+ end;
+ Res := DoOperation(AFileRec, NewFilePath, False, @Error);
end;
end;
- Res := DoOperation(AFileRec, NewFilePath, ErrorKind, False);
- end;
- end else Res := DoOperation(AFileRec, NewFilePath, ErrorKind, False);
- end;
+ end else Res := DoOperation(AFileRec, NewFilePath, False, @Error);
+ end;
// Error handling
- if (Res <> 0) and (not SkipAll) then begin
- if (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP]) then cap := LANGCopy
- else cap := LANGMove;
- // * TODO: port to GError
-{ case Res of
- ERRCreateLink: begin
- s1 := LANGTheSymbolicLink;
- if ErrorKind = 0 then s3 := LANGCouldNotBeCreated else
- s3 := Format(LANGCouldNotBeCreatedS, [GetErrorString(ErrorKind)]);
- end;
- ERRMkDir: begin
- s1 := LANGTheDirectory;
- if ErrorKind = 0 then s3 := LANGCouldNotBeCreated else
- s3 := Format(LANGCouldNotBeCreatedS, [GetErrorString(ErrorKind)]);
- end;
- ERRRemove: begin
- if AFileRec^.DataItem^.IsDir then s1 := LANGTheDirectory else
- if AFileRec^.DataItem^.IsLnk then s1 := LANGTheSymbolicLink else
- s1 := LANGTheFile;
- if ErrorKind = 0 then s3 := LANGCouldNotBeDeleted else
- s3 := Format(LANGCouldNotBeDeletedS, [GetErrorString(ErrorKind)]);
- end;
- ERRCopyMove: begin
- if ParamBool3 then s1 := LANGCannotCopyFile else
- s1 := LANGCannotMoveFile;
- if ErrorKind = 0 then s3 := '' else
- s3 := GetErrorString(ErrorKind);
- end;
- end; }
- Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, s1, StrToUTF8(String(NewFilePath)), nil);
+ if (not Res) and (not FCopySkipAllErrors) then begin
+ if FCopyErrorHandledInProgress then begin
+ if FCopySilentCancel then Result := False; // Break the processing
+ Exit;
+ end;
+ GetCopyProgressErrorLabels(Self, Error, s, s2);
+ s3 := StrToUTF8(Error^.message);
+ if (Error^.domain = TUXCMD_ERROR) then
+ case TuxcmdErrorEnum(Error^.code) of
+ TUXCMD_ERROR_SYMLINK: begin
+ s := LANGTheSymbolicLink;
+ s2 := FCopyDestFile;
+ s3 := Format(LANGCouldNotBeCreatedS, [StrToUTF8(Error^.message)]);
+ end;
+ TUXCMD_ERROR_MKDIR: begin
+ s := LANGTheDirectory;
+ s2 := FCopyDestFile;
+ s3 := Format(LANGCouldNotBeCreatedS, [StrToUTF8(Error^.message)]);
+ end;
+ TUXCMD_ERROR_REMOVE: begin
+ if AFileRec^.DataItem^.IsDir then s := LANGTheDirectory else
+ if AFileRec^.DataItem^.IsLnk then s := LANGTheSymbolicLink else
+ s := LANGTheFile;
+ s2 := FCopyDestFile;
+ s3 := Format(LANGCouldNotBeDeletedS, [StrToUTF8(Error^.message)]);
+ end;
+ end;
+ Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, s, s2, s3);
case Response of
DIR_DELETE_SKIP : Result := True; // Skip
DIR_DELETE_RETRY : Result := HandleCopy(AFileRec, NewFilePath); // Retry
DIR_DELETE_SKIP_ALL : begin // Skip All
- SkipAll := True;
+ FCopySkipAllErrors := True;
Result := True;
end;
0, 124, 255 : Result := False; // Cancel
+ else begin
+ Result := False;
+ end;
end;
end;
// DebugMsg(['(II) CopyFilesWorker.HandleCopy: finished']);
@@ -1417,7 +1432,6 @@ var DefResponse: integer; // Global variables for this function
if Info = nil then begin
InaccessiblePaths.Add(FullPath);
DebugMsg(['$$$ Copy: Something went wrong while building the filelist...']);
- // TODO: ?
ErrorHappened := True;
end else begin
Info^.ADestination := strdup(PChar(s));
@@ -1426,17 +1440,18 @@ var DefResponse: integer; // Global variables for this function
end;
end else InputFiles.Add(FullPath);
end;
- FillDirFiles(SrcEngine, AList, InputFiles, False, True, InaccessiblePaths);
+ FillDirFiles(SrcEngine, AList, InputFiles, False, True, InaccessiblePaths, @FCancelled);
InputFiles.Free;
end;
var i: longint;
List: TList;
InaccessiblePaths: TStringList;
+ SkipInaccessible: boolean;
CurrPath, SaveDestPath, SaveSrcPath, s: string;
StartPassed: boolean;
- SkipInaccessible: boolean;
begin
+ FCopySilentCancel := False;
List := TList.Create;
InaccessiblePaths := TStringList.Create;
ErrorHappened := False;
@@ -1448,13 +1463,13 @@ begin
// Prepare list of files to copy
if JobType = WORKER_JOB_EXTRACT_TO_TEMP then begin
- if not ExtractFromVFSAll then HandleProcessPattern(List, InaccessiblePaths, CurrPath, ExtractFile, ExtractFileName(ExtractFile), False, False)
- else begin
- SaveSrcPath := IncludeTrailingPathDelimiter(SrcEngine.Path);
- SrcEngine.SetPath('/');
- CurrPath := '/';
- HandleProcessPattern(List, InaccessiblePaths, '/', '/', '', True, False);
- end;
+ if not ExtractFromVFSAll then HandleProcessPattern(List, InaccessiblePaths, CurrPath, ExtractFile, ExtractFileName(ExtractFile), False, False)
+ else begin
+ SaveSrcPath := IncludeTrailingPathDelimiter(SrcEngine.Path);
+ SrcEngine.SetPath('/');
+ CurrPath := '/';
+ HandleProcessPattern(List, InaccessiblePaths, '/', '/', '', True, False);
+ end;
end else
if QuickRenameDataItem <> nil then begin // Quick-Rename
with QuickRenameDataItem^ do
@@ -1482,6 +1497,8 @@ begin
end;
end;
+ // * TODO: cancellation check
+
{ if DestEngine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour may occur.']);
if SrcEngine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour may occur.']); }
DebugWriteListSL(List);
@@ -1509,7 +1526,6 @@ begin
CommitGUIUpdate;
DefResponse := 0;
- SkipAll := False;
FCopySkipAllErrors := False;
if List.Count > 0 then begin
@@ -1530,12 +1546,14 @@ begin
// DebugMsg(['s2 = ', Copy(PDataItemSL(List[i])^.AName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.AName) - Length(CurrPath)), ', s = ', s]);
end;
- if not (SrcEngine is TVFSEngine) then UpdateCaption1(Format(LANGFromS, [string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])) else
- if (SrcEngine as TVFSEngine).ArchiveMode then UpdateCaption1(Format(LANGFromS, [Format(ConstFullPathFormatStr, [(SrcEngine as TVFSEngine).ArchivePath, string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])]))
- else UpdateCaption1(Format(LANGFromS, [GetURIPrefix((SrcEngine as TVFSEngine).GetPathURI) + StrToUTF8(string(PDataItemSL(List[i])^.DataItem^.FDisplayName))]));
- if not (DestEngine is TVFSEngine) then UpdateCaption2(Format(LANGToS, [StrToUTF8(s)])) else
- if (DestEngine as TVFSEngine).ArchiveMode then UpdateCaption2(Format(LANGToS, [Format(ConstFullPathFormatStr, [(DestEngine as TVFSEngine).ArchivePath, StrToUTF8(s)])]))
- else UpdateCaption2(Format(LANGToS, [GetURIPrefix((DestEngine as TVFSEngine).GetPathURI) + StrToUTF8(s)]));
+ if not (SrcEngine is TVFSEngine) then FCopySourceFile := string(PDataItemSL(List[i])^.DataItem^.FDisplayName) else
+ if (SrcEngine as TVFSEngine).ArchiveMode then FCopySourceFile := Format(ConstFullPathFormatStr, [(SrcEngine as TVFSEngine).ArchivePath, string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])
+ else FCopySourceFile := GetURIPrefix((SrcEngine as TVFSEngine).GetPathURI) + StrToUTF8(string(PDataItemSL(List[i])^.DataItem^.FDisplayName));
+ if not (DestEngine is TVFSEngine) then FCopyDestFile := StrToUTF8(s) else
+ if (DestEngine as TVFSEngine).ArchiveMode then FCopyDestFile := Format(ConstFullPathFormatStr, [(DestEngine as TVFSEngine).ArchivePath, StrToUTF8(s)])
+ else FCopyDestFile := GetURIPrefix((DestEngine as TVFSEngine).GetPathURI) + StrToUTF8(s);
+ UpdateCaption1(Format(LANGFromS, [FCopySourceFile]));
+ UpdateCaption2(Format(LANGToS, [FCopyDestFile]));
CommitGUIUpdate;
if TwoSameFiles(s, string(PDataItemSL(List[i])^.DataItem^.FName), (JobType in [WORKER_JOB_COPY, WORKER_JOB_EXTRACT_TO_TEMP])) and (not PDataItemSL(List[i])^.DataItem^.IsDir) then begin
FCancelMessage := LANGCannotCopyFileToItself;
@@ -1547,7 +1565,7 @@ begin
// if s <> string(PDataItemSL(List[i])^.DataItem^.FName) then
if not HandleCopy(List[i], s) then begin
ErrorHappened := True;
- Break;
+ Break; // Cancelled
end;
if (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk)
then FTotalDone := FTotalDone + PDataItemSL(List[i])^.DataItem^.Size;
@@ -1596,42 +1614,39 @@ var FD: TEngineFileDes;
PrivateCancel: boolean;
SizeDone: Int64;
TargetName: string;
- Error: PGError;
function PasteFile(FName: string): boolean;
var FDR: TEngineFileDes;
wCount: integer;
Stat: PDataItem;
+ Error: PGError;
begin
Result := False;
+ Error := nil;
if MergeHasInitialCRC then UpdateCaption2(Format(LANGToS, [StrToUTF8(FName)]))
- else UpdateCaption1(Format(LANGFromS, [StrToUTF8(FName)]));
+ else UpdateCaption1(Format(LANGFromS, [StrToUTF8(FName)]));
UpdateProgress1(0, '0 %');
CommitGUIUpdate;
- // * TODO: check error
Stat := AEngine.GetFileInfo(FName, True, True, nil);
if not Assigned(Stat) then Exit;
SetProgress1Params(Stat^.Size);
FreeDataItem(Stat);
- // * TODO: check error
- Error := nil;
FDR := AEngine.OpenFile(FName, omRead, @Error);
if FDR = nil then Exit;
repeat
- // * TODO: check error
Count := AEngine.ReadFile(FDR, Buffer, MergeBlockSize, @Error);
if Error <> nil then begin
AEngine.CloseFile(FD, nil);
Exit;
end;
- // * TODO: check error
wCount := AEngine.WriteFile(FD, Buffer, Count, @Error);
if (Error <> nil) or (Count <> wCount) then begin
FCancelMessage := Format(LANGAnErrorOccuredWhileWritingFileSS, [ExtractFileName(TargetName), Error^.message]);
FShowCancelMessage := True;
PrivateCancel := True;
Result := True; // Fake this to don't show next disc dialog
+ g_error_free(Error);
Exit;
end;
CurrentCRC := CRC32(CurrentCRC, Buffer, Count);
@@ -1640,7 +1655,6 @@ var FD: TEngineFileDes;
if MergeHasInitialCRC then UpdateProgress2(SizeDone, Format('%d %%', [Trunc(SizeDone / FProgress2Max * 100)]));
CommitGUIUpdate;
until (Count < MergeBlockSize) or FCancelled;
- // * TODO: set real error, also free it
AEngine.CloseFile(FDR, nil);
Result := True;
end;
@@ -1649,7 +1663,9 @@ var FD: TEngineFileDes;
var CurrFile, SourcePath, TargetFinalName: string;
HasFinalCRC, b: boolean;
Stat: PDataItem;
+ Error: PGError;
begin
+ Error := nil;
HasFinalCRC := MergeHasInitialCRC;
TargetFinalName := MergeTargetFinalName;
if (Length(MergeSourceFile) > 4) and (WideUpperCase(RightStr(MergeSourceFile, 4)) = '.CRC')
@@ -1661,16 +1677,14 @@ begin
if AEngine.FileExists(TargetName, False) then
if ShowMessageBox(Format(LANGTheTargetFileSAlreadyExistsDoYouWantToOverwriteIt, [StrToUTF8(TargetName)]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes then
begin
- // * TODO: check error
-{ Error := Ord(Engine.Remove(TargetName, nil));
- if Error <> 0 then begin
- FCancelMessage := Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(ExtractFileName(TargetName)), GetErrorString(Error)]);
+ if not AEngine.Remove(TargetName, @Error) then begin
+ FCancelMessage := Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(ExtractFileName(TargetName)), Error^.message]);
FShowCancelMessage := True;
+ g_error_free(Error);
Exit;
- end; }
+ end;
end else Exit;
- // * TODO: check error
Stat := AEngine.GetFileInfo(MergeSourceFile, True, True, nil);
if Assigned(Stat) then MergeBlockSize := ComputeBlockSize(Stat^.Size)
else MergeBlockSize := 65536*4;
@@ -1683,12 +1697,12 @@ begin
FShowCancelMessage := True;
Exit;
end;
- // * TODO: check error
FD := AEngine.OpenFile(TargetName, omWrite, @Error);
if Error <> nil then begin
FCancelMessage := Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(TargetName), Error^.message]);
FShowCancelMessage := True;
libc_free(Buffer);
+ g_error_free(Error);
Exit;
end;
@@ -1723,8 +1737,16 @@ begin
CurrFile := '';
end;
until (SizeDone = MergeTargetSize) or FCancelled or PrivateCancel {or ((not b) and (not HasInitialCRC))} or (CurrFile = '');
- // * TODO: check error
- if (not MergeHasInitialCRC) and HasFinalCRC then AEngine.RenameFile(TargetName, IncludeTrailingPathDelimiter(ExtractFilePath(TargetName)) + TargetFinalName, nil);
+ libc_free(Buffer);
+ if (not MergeHasInitialCRC) and HasFinalCRC then begin
+ if not AEngine.RenameFile(TargetName, IncludeTrailingPathDelimiter(ExtractFilePath(TargetName)) + TargetFinalName, @Error) then begin
+ FCancelMessage := Format(LANGAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(TargetName)), Error^.message]);
+ FShowCancelMessage := True;
+ g_error_free(Error);
+ AEngine.CloseFile(FD, nil);
+ Exit;
+ end;
+ end;
if FCancelled and (not PrivateCancel) then begin
FCancelMessage := LANGUserCancelled;
FShowCancelMessage := True;
@@ -1735,9 +1757,11 @@ begin
then ShowMessageBox(Format(LANGMergeOfSSucceeded, [StrToUTF8(ExtractFileName(TargetFinalName))]), [mbOK], mbInfo, mbNone, mbOK)
else ShowMessageBox(LANGWarningCreatedFileFailsCRCCheck, [mbOK], mbWarning, mbNone, mbOK);
end else ShowMessageBox(Format(LANGMergeOfSSucceeded_NoCRCFileAvailable, [StrToUTF8(ExtractFileName(TargetFinalName))]), [mbOK], mbInfo, mbNone, mbOK);
- // * TODO: set real error, also free it
- AEngine.CloseFile(FD, nil);
- libc_free(Buffer);
+ if not AEngine.CloseFile(FD, @Error) then begin
+ FCancelMessage := Format(LANGAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(TargetName)), Error^.message]);
+ FShowCancelMessage := True;
+ g_error_free(Error);
+ end;
end;
@@ -1748,12 +1772,12 @@ end;
procedure TWorkerThread.SplitFilesWorker;
const SplitBlockSize = 65536*4;
var FD: TEngineFileDes;
- Error: PGError;
FileCRC: LongWord;
Buffer: Pointer;
PrivateCancel: boolean;
FilePath: string;
SizeDone, TDF, FileSize, CurrSize: Int64;
+ Error: PGError;
function WriteSplitPart(TargetFile: string; PartSize: Int64; var Written: Int64): boolean;
@@ -1762,9 +1786,8 @@ var FD: TEngineFileDes;
begin
Result := False;
Written := 0;
- // * TODO: check error
- FDW := AEngine.OpenFile(TargetFile, omWrite, @Error);
DebugMsg(['-- Opening file ', ExtractFileName(TargetFile), ', PartSize = ', PartSize]);
+ FDW := AEngine.OpenFile(TargetFile, omWrite, @Error);
if Error <> nil then Exit;
if SplitMaxSize > 0 then begin
UpdateCaption2(Format(LANGToS, [StrToUTF8(TargetFile)]));
@@ -1773,37 +1796,34 @@ var FD: TEngineFileDes;
end else UpdateCaption1(Format(LANGToS, [StrToUTF8(TargetFile)]));
CommitGUIUpdate;
repeat
- // * TODO: check error
DebugMsg(['Seek to ', AEngine.FileSeek(FD, SizeDone + Written, @Error), ', Written = ', Written]);
+ if Error <> nil then begin
+ AEngine.CloseFile(FDW, nil);
+ Exit;
+ end;
if Written + SplitBlockSize > PartSize then bl := PartSize - Written
else bl := SplitBlockSize;
- // * TODO: check error
Count := AEngine.ReadFile(FD, Buffer, bl, @Error);
if (Error <> nil) or (Count <> bl) then begin
- // * TODO: set real error, also free it
AEngine.CloseFile(FDW, nil);
- DebugMsg(['Read Error: ', Error^.message, ', Count = ', Count, ', bl = ', bl]);
-// if (Count <> bl) and (Error = 0) then Error := EIO;
+ if Error <> nil then
+ DebugMsg(['Read Error: ', Error^.message, ', Count = ', Count, ', bl = ', bl]);
Exit;
end;
- // * TODO: check error
wCount := AEngine.WriteFile(FDW, Buffer, Count, @Error);
Written := Written + wCount;
FileCRC := CRC32(FileCRC, Buffer, wCount);
if (Error <> nil) or (Count <> wCount) then begin
- // * TODO: set real error, also free it
AEngine.CloseFile(FDW, nil);
- // * TODO: check error
- DebugMsg(['Write Error: ', Error^.message, ', Count = ', Count, ', wCount = ', wCount]);
-// if (wCount <> Count) and (Error = 0) then Error := ENOSPC;
+ if Error <> nil then
+ DebugMsg(['Write Error: ', Error^.message, ', Count = ', Count, ', wCount = ', wCount]);
Exit;
end;
UpdateProgress1(FProgress1Pos + wCount, Format('%d %%', [Trunc((FProgress1Pos + wCount) / FProgress1Max * 100)]));
if SplitMaxSize > 0 then UpdateProgress2(FProgress2Pos + wCount, Format('%d %%', [Trunc((FProgress2Pos + wCount) / FProgress2Max * 100)]));
CommitGUIUpdate;
until (Written = PartSize) or FCancelled or PrivateCancel;
- // * TODO: set real error, also free it
- AEngine.CloseFile(FDW, nil);
+ if not AEngine.CloseFile(FDW, @Error) then Exit;
DebugMsg(['-- Closing file ', ExtractFileName(TargetFile), ', PartSize = ', PartSize, ', Written = ', Written]);
Result := True;
end;
@@ -1842,11 +1862,12 @@ var i: integer;
x: Int64;
xx: string;
begin
- // * TODO: check error
- Stat := AEngine.GetFileInfo(SplitSourceFile, True, True, nil);
+ Error := nil;
+ Stat := AEngine.GetFileInfo(SplitSourceFile, True, True, @Error);
if not Assigned(Stat) then begin
- FCancelMessage := Format(LANGCannotOpenFileS, [StrToUTF8(SplitSourceFile)]);
+ FCancelMessage := Format('Cannot open file ''%s'': %s', [StrToUTF8(SplitSourceFile), Error^.message]);
FShowCancelMessage := True;
+ g_error_free(Error);
Exit;
end;
if (SplitMaxSize > 0) and (Stat^.Size > SplitMaxSize * 999) then begin
@@ -1868,11 +1889,11 @@ begin
FShowCancelMessage := True;
Exit;
end;
- // * TODO: check error
FD := AEngine.OpenFile(SplitSourceFile, omRead, @Error);
if Error <> nil then begin
FCancelMessage := Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(SplitSourceFile), Error^.message]);
libc_free(Buffer);
+ g_error_free(Error);
Exit;
end;
FilePath := IncludeTrailingPathDelimiter(ProcessPattern(AEngine, SplitTargetPath, AEngine.Path, '', True));
@@ -1900,9 +1921,8 @@ begin
for i := List.Count - 1 downto 0 do
FreeDataItem(PDataItem(List[i]));
List.Clear;
- // * TODO: check error
-{ Error := Engine.GetListing(List, FilePath, ConfShowDotFiles, False, False, nil);
- if (Error = 0) and (List.Count > 0) then begin
+ b := AEngine.GetListing(List, FilePath, ConfShowDotFiles, False, False, nil);
+ if b and (List.Count > 0) then begin
st := '';
if List.Count < 6 then begin
for i := 0 to List.Count - 1 do
@@ -1911,23 +1931,26 @@ begin
end else b := ShowMessageBox(Format(LANGThereAreDFilesInTheTargetDirectoryDoYouWantToDeleteThem, [List.Count]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes;
if b then
for i := 0 to List.Count - 1 do begin
- Error := Engine.Remove(IncludeTrailingPathDelimiter(FilePath) + string(PDataItem(List[i])^.FName));
- if Error <> 0 then ShowMessageBox(Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath)) + string(PDataItem(List[i])^.FDisplayName), GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK);
+ if not AEngine.Remove(IncludeTrailingPathDelimiter(FilePath) + string(PDataItem(List[i])^.FName), @Error) then begin
+ ShowMessageBox(Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath)) + string(PDataItem(List[i])^.FDisplayName), Error^.message]), [mbOK], mbError, mbNone, mbOK);
+ g_error_free(Error);
+ Error := nil;
+ end;
end;
- end; }
+ end;
except end;
// Test for target file existence
if AEngine.FileExists(IncludeTrailingPathDelimiter(FilePath) + FileName, False) then begin
b := ShowMessageBox(Format(LANGTheTargetFileSAlreadyExistsDoYouWantToOverwriteIt, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath) + FileName)]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes;
if b then begin
- // * TODO: check error
-{ Error := Engine.Remove(IncludeTrailingPathDelimiter(FilePath) + FileName);
- if Error <> 0 then begin
- FCancelMessage := Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath) + FileName), GetErrorString(Error)]);
+ if not AEngine.Remove(IncludeTrailingPathDelimiter(FilePath) + FileName, @Error) then begin
+ FCancelMessage := Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath) + FileName), Error^.message]);
FShowCancelMessage := True;
PrivateCancel := True;
+ g_error_free(Error);
+ Error := nil;
Break;
- end; }
+ end;
end else begin
PrivateCancel := True;
Break;
@@ -1940,7 +1963,12 @@ begin
if (CurrSize >= 512) and (TDF >= CurrSize) then begin
b := WriteSplitPart(IncludeTrailingPathDelimiter(FilePath) + FileName, CurrSize, ws);
if (not b) and (SplitMaxSize > 0) then begin
- FCancelMessage := Format(LANGAnErrorOccuredWhileOperationS, [Error^.message]);
+ if Error <> nil then begin
+ FCancelMessage := Format(LANGAnErrorOccuredWhileOperationS, [Error^.message]);
+ g_error_free(Error);
+ Error := nil;
+ end else
+ FCancelMessage := Format(LANGAnErrorOccuredWhileOperationS, ['(unknown)']);
FShowCancelMessage := True;
PrivateCancel := True;
Break;
@@ -1977,7 +2005,6 @@ begin
FShowCancelMessage := True;
end;
end;
- // * TODO: set real error, also free it
AEngine.CloseFile(FD, nil);
if List.Count > 0 then
for i := List.Count - 1 downto 0 do
@@ -1999,31 +2026,25 @@ var SkipAll: boolean;
Error: PGError;
begin
Result := True;
+ Error := nil;
// DebugMsg(['Chmod Debug: IsDir: ', AFileRec^.IsDir, ', Stage1: ', AFileRec^.Stage1, ', IsLnk: ', AFileRec^.IsLnk, '; Result = ', AFileRec^.IsDir and AFileRec^.Stage1 and (not AFileRec^.IsLnk)]);
if AFileRec^.DataItem^.IsDir and (ChmodRecurseType >= 0) and AFileRec^.Stage1 and (not AFileRec^.DataItem^.IsLnk) then Exit;
if (not AFileRec^.DataItem^.IsDir) and (ChmodRecurseType >= 0) and (ChmodRecurseType = 1) then Exit; // Directories only
if AFileRec^.DataItem^.IsDir and (ChmodRecurseType >= 0) and (ChmodRecurseType = 2) then Exit; // Files only
- // * TODO: check error
- Error := nil;
Res := AEngine.Chmod(String(AFileRec^.DataItem^.FName), ChmodMode, @Error);
-// DebugMsg(['Result : ', Res]);
- if not Res then
- if SkipAll then Result := True else
- begin
- // * TODO: check error
- Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error changing permissions', String(AFileRec^.DataItem^.FDisplayName), Error);
- if Error <> nil then
- g_error_free(Error);
+ if not Res then begin
+ if SkipAll then Result := True
+ else begin
+ Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error changing permissions', AFileRec^.DataItem^.FDisplayName, Error^.message);
+ g_error_free(Error);
case Response of
DIR_DELETE_SKIP : Result := True;
- DIR_DELETE_SKIP_ALL : begin
- SkipAll := True;
- Result := True;
- end;
+ DIR_DELETE_SKIP_ALL : begin SkipAll := True; Result := True; end;
DIR_DELETE_RETRY : Result := HandleChmod(AFileRec);
else Result := False;
end;
end;
+ end;
end;
var i: longint;
@@ -2086,30 +2107,24 @@ var SkipAll: boolean;
Error: PGError;
begin
Result := True;
+ Error := nil;
// DebugMsg(['Chown Debug: IsDir: ', AFileRec^.IsDir, ', Stage1: ', AFileRec^.Stage1, ', IsLnk: ', AFileRec^.IsLnk, '; Result = ', AFileRec^.IsDir and AFileRec^.Stage1 and (not AFileRec^.IsLnk)]);
if (AFileRec^.DataItem^.IsDir and ChownRecursive and AFileRec^.Stage1 and (not AFileRec^.DataItem^.IsLnk)) or
((not AFileRec^.DataItem^.IsDir) and ChownRecursive) then Exit;
- // * TODO: check error
- Error := nil;
Res := AEngine.Chown(String(AFileRec^.DataItem^.FName), ChownUID, ChownGID, @Error);
-// DebugMsg(['Result : ', Res]);
- if not Res then
- if SkipAll then Result := True else
- begin
- // * TODO: check error
- Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error changing owner', String(AFileRec^.DataItem^.FDisplayName), Error);
- if Error <> nil then
- g_error_free(Error);
+ if not Res then begin
+ if SkipAll then Result := True
+ else begin
+ Response := ShowDirDeleteDialog(DIR_DELETE_SET_DELETE_ERROR, 'Error changing owner', AFileRec^.DataItem^.FDisplayName, Error^.message);
+ g_error_free(Error);
case Response of
DIR_DELETE_SKIP : Result := True;
- DIR_DELETE_SKIP_ALL : begin
- SkipAll := True;
- Result := True;
- end;
+ DIR_DELETE_SKIP_ALL : begin SkipAll := True; Result := True; end;
DIR_DELETE_RETRY : Result := HandleChown(AFileRec);
else Result := False;
end;
end;
+ end;
end;
var i: longint;
@@ -2246,11 +2261,17 @@ begin
// AutoFallback loop
repeat
+ if ChDirError <> nil then begin
+ g_error_free(ChDirError);
+ ChDirError := nil;
+ end;
if Engine is TVFSEngine
then Result := (Engine as TVFSEngine).ChangeDirEx(APath, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self, @ChDirError)
else Result := Engine.ChangeDir(APath, @ChDirError);
- if not Result then
- GoUp(APath);
+ if not Result then begin
+ PrefixTuxcmdError(@ChDirError, ExcludeTrailingPathDelimiter(APath));
+ GoUp(APath);
+ end;
until Result or (not AutoFallback) or (Length(APath) <= 1);
if Result then
Engine.Path := APath;
@@ -2282,8 +2303,10 @@ begin
if VFSOpenResult and (not FCancelled) then begin
ChDirResult := ChangeDir(AEngine, APath, ASelItem, AAutoFallBack);
- if ChDirResult and (not FCancelled) then
+ if ChDirResult and (not FCancelled) then begin
ListingResult := AEngine.GetListing(ADirList, AEngine.GetPath, ConfShowDotFiles, True, False, @ListingError);
+ if not ListingResult then PrefixTuxcmdError(@ListingError, AEngine.GetPath);
+ end;
end;
except
on E: Exception do DebugMsg(['*** Exception raised in TOpenDirThread.Execute (', E.ClassName, '): ', E.Message]);