diff options
| author | Tomas Bzatek <tbzatek@redhat.com> | 2024-10-25 11:32:12 +0200 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@redhat.com> | 2024-10-25 11:32:12 +0200 |
| commit | d08636bdad4f36431bfdf07e8400d7188a2df781 (patch) | |
| tree | 841aef1904f9c87ee02e1a730ef488cc75215ec6 /UCoreWorkers.pas | |
| parent | 741e1499ed55e20c136298ced705dcbb59915117 (diff) | |
| download | tuxcmd-0.6.83.tar.xz | |
Rework file copy/open-read-write-close data handlingv0.6.83
Stick to the POSIX open(2), read(2), write(2), close(2) return values
semantics, apply on the VFS interface.
Also handle short reads and writes that are common for some gvfs
backends. This makes cross-VFS copy work.
Diffstat (limited to 'UCoreWorkers.pas')
| -rw-r--r-- | UCoreWorkers.pas | 71 |
1 files changed, 39 insertions, 32 deletions
diff --git a/UCoreWorkers.pas b/UCoreWorkers.pas index 507e2b7..75a9453 100644 --- a/UCoreWorkers.pas +++ b/UCoreWorkers.pas @@ -1019,11 +1019,12 @@ var DefResponse: integer; // Global variables for this function var fsrc, fdst: TEngineFileDes; BSize: integer; Buffer: Pointer; - BytesDone, BytesRead, BytesWritten: Int64; + BytesDone, BytesRead, BytesWritten, BytesRemaining: Int64; LocalError: PGError; begin Result := False; LocalError := nil; + BytesDone := 0; DebugMsg(['ManualCopyFile: ', SourceFile, ' ---> ', DestFile]); fsrc := SrcEngine.OpenFile(SourceFile, omRead, @LocalError); if fsrc = nil then begin @@ -1042,7 +1043,6 @@ var DefResponse: integer; // Global variables for this function Exit; end; - BytesDone := 0; BSize := DestEngine.GetBlockSize; Buffer := malloc(BSize); if Buffer = nil then begin @@ -1050,60 +1050,66 @@ var DefResponse: integer; // Global variables for this function CopyFilesWorker_ProgressFunc(Self, 0, Error^); // Memory allocation failed Exit; end; - memset(Buffer, 0, BSize); - BytesWritten := 0; repeat + // Read block BytesRead := SrcEngine.ReadFile(fsrc, Buffer, BSize, @LocalError); - if (BytesRead = 0) and (Error^ <> nil) then begin + if BytesRead < 0 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 + Result := CopyFilesWorker_ProgressFunc(Self, BytesDone, Error^); // Cannot read from source file if Result then begin g_error_free(Error^); Error^ := nil; Continue; end else Break; end; + + // Write block if BytesRead > 0 then begin - BytesWritten := DestEngine.WriteFile(fdst, Buffer, BytesRead, @LocalError); - if (BytesWritten < BytesRead) then begin + BytesRemaining := BytesRead; + repeat + BytesWritten := DestEngine.WriteFile(fdst, Buffer + (BytesRead - BytesRemaining), BytesRemaining, @LocalError); + if BytesWritten > 0 then + BytesRemaining := BytesRemaining - BytesWritten; + until (BytesRemaining = 0) or (BytesWritten <= 0); + if BytesWritten < 0 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; + Result := False; + CopyFilesWorker_ProgressFunc(Self, BytesDone, Error^); // Cannot write to target file + Break; end; end; + // BytesRead == 0 means EOF BytesDone := BytesDone + BytesRead; Result := CopyFilesWorker_ProgressFunc(Self, BytesDone, nil); if not Result then Break; - until (BytesRead = 0) or (BytesWritten < BytesRead); + until BytesRead <= 0; libc_free(Buffer); - 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; - 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 not DestEngine.CloseFile(fdst, @LocalError) then if Result then begin - // user has chosen to ignore the error - g_error_free(Error^); - Error^ := nil; - end else Exit; - end; + 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; + if not SrcEngine.CloseFile(fsrc, @LocalError) then + if Result 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; end; // Returns True if the file was successfully copied and will be deleted on move @@ -1120,6 +1126,7 @@ var DefResponse: integer; // Global variables for this function then Result := DestEngine.CopyFileIn(SourceFile, DestFile, Append, @CopyFilesWorker_ProgressFunc, Self, Error) else + // TODO: check for reported Append capability and fall back to manual copy if needed // from local engine to VFS engine if (SrcEngine is TLocalTreeEngine) and (DestEngine is TVFSEngine) then begin |
