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 /UEngines.pas | |
| parent | 741e1499ed55e20c136298ced705dcbb59915117 (diff) | |
| download | tuxcmd-d08636bdad4f36431bfdf07e8400d7188a2df781.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 'UEngines.pas')
| -rw-r--r-- | UEngines.pas | 140 |
1 files changed, 84 insertions, 56 deletions
diff --git a/UEngines.pas b/UEngines.pas index 8a0e9e6..8649a05 100644 --- a/UEngines.pas +++ b/UEngines.pas @@ -30,6 +30,11 @@ const omRead = 0; ConfDefaultDirCreationMask = 755; + ConfDefaultOpenFlagsRead = O_RDONLY or O_NOFOLLOW or O_CLOEXEC; + ConfDefaultOpenFlagsWrite = O_WRONLY or O_NOFOLLOW or O_CLOEXEC or O_EXCL or O_CREAT or O_TRUNC; + ConfDefaultOpenFlagsAppend = O_WRONLY or O_NOFOLLOW or O_CLOEXEC or O_EXCL or O_APPEND; + + ConfDefaultFileCreationMask = S_IRUSR or S_IWUSR or S_IRGRP or S_IROTH; type PDataItem = ^TDataItem; @@ -549,27 +554,27 @@ begin end; function TLocalTreeEngine.CopyFileOut(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer; Error: PPGError): boolean; -var fsrc, fdest: PFILE; +var fsrc, fdest: Longint; Buffer: Pointer; - BytesDone, BytesRead, BytesWritten: Int64; + BytesDone, BytesRead, BytesWritten, BytesRemaining: ssize_t; begin Result := False; BytesDone := 0; try // Open source file for reading - fsrc := fopen64(PChar(SourceFile), 'r'); - if fsrc = nil then begin + fsrc := open64(PChar(SourceFile), ConfDefaultOpenFlagsRead, 0); + if fsrc < 0 then begin g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_OPEN), '%m'); if @ProgressFunc <> nil then ProgressFunc(Sender, 0, Error^); Exit; end; // Open target file for writing/appending - if Append then fdest := fopen64(PChar(DestFile), 'a') - else fdest := fopen64(PChar(DestFile), 'w'); - if fdest = nil then begin + if Append then fdest := open64(PChar(DestFile), ConfDefaultOpenFlagsAppend, 0) + else fdest := open64(PChar(DestFile), ConfDefaultOpenFlagsWrite, ConfDefaultFileCreationMask); + if fdest < 0 then begin g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_TARGET_OPEN), '%m'); - fclose(fsrc); + libc_close(fsrc); if @ProgressFunc <> nil then ProgressFunc(Sender, 0, Error^); Exit; @@ -578,17 +583,18 @@ begin Buffer := malloc(FBlockSize); if Buffer = nil then begin g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_ALLOC_FAILED), '%m'); - fclose(fdest); - fclose(fsrc); + libc_close(fdest); + libc_close(fsrc); if @ProgressFunc <> nil then ProgressFunc(Sender, 0, Error^); Exit; end; - while feof(fsrc) = 0 do begin + Result := True; + repeat // Read block - BytesRead := fread(Buffer, 1, FBlockSize, fsrc); - if (BytesRead < FBlockSize) and (feof(fsrc) = 0) then begin + BytesRead := libc_read(fsrc, Buffer, FBlockSize); + if BytesRead < 0 then begin g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_READ), '%m'); Result := False; if @ProgressFunc <> nil then @@ -602,41 +608,51 @@ begin end; // Write block - BytesWritten := fwrite(Buffer, 1, BytesRead, fdest); - if BytesWritten < BytesRead then begin - g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_TARGET_WRITE), '%m'); - Result := False; - if @ProgressFunc <> nil then - ProgressFunc(Sender, BytesDone + BytesRead, Error^); - Break; // We cannot ignore write errors + if BytesRead > 0 then begin + BytesRemaining := BytesRead; + repeat + BytesWritten := libc_write(fdest, Buffer + (BytesRead - BytesRemaining), BytesRemaining); + 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), '%m'); + Result := False; + if @ProgressFunc <> nil then + ProgressFunc(Sender, BytesDone + BytesRead, Error^); + Break; // We cannot ignore write errors + end; end; - + // BytesRead == 0 means EOF BytesDone := BytesDone + BytesRead; - if (@ProgressFunc <> nil) and (not ProgressFunc(Sender, BytesDone, nil)) then + if (@ProgressFunc <> nil) and (not ProgressFunc(Sender, BytesDone, nil)) then begin + Result := False; Break; - end; - Result := (feof(fsrc) <> 0) and (Error^ = nil); + end; + until BytesRead <= 0; libc_free(Buffer); - if fclose(fdest) <> 0 then begin - g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_TARGET_CLOSE), '%m'); - Result := False; - if @ProgressFunc <> nil then - ProgressFunc(Sender, BytesDone, Error^); - fclose(fsrc); - Exit; - end; - if fclose(fsrc) <> 0 then begin - g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_CLOSE), '%m'); - Result := False; - if @ProgressFunc <> nil then - Result := ProgressFunc(Sender, BytesDone, Error^); + if libc_close(fdest) <> 0 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), '%m'); + Result := False; + if @ProgressFunc <> nil then + ProgressFunc(Sender, BytesDone, Error^); + libc_close(fsrc); + Exit; + end; + if libc_close(fsrc) <> 0 then + if Result then begin + g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SOURCE_CLOSE), '%m'); + Result := False; + if @ProgressFunc <> nil then + Result := ProgressFunc(Sender, BytesDone, Error^); + if Result then begin + // user has chosen to ignore the error + g_error_free(Error^); + Error^ := nil; + end else Exit; + end; except on E: Exception do begin Result := False; @@ -649,6 +665,8 @@ begin g_error_free(Error^); Error^ := nil; end; + libc_close(fdest); + libc_close(fsrc); end; end; end; @@ -781,39 +799,49 @@ end; (********************************************************************************************************************************) function TLocalTreeEngine.OpenFile(const APath: string; Mode: integer; Error: PPGError): TEngineFileDes; -var m: PChar; +var flags, m: Longint; + r: Integer; begin + Result := nil; + m := 0; case Mode of - omRead: m := 'r'; - omWrite: m := 'w'; - omAppend: m := 'a'; - else m := 'r'; + omRead: flags := ConfDefaultOpenFlagsRead; + omWrite: begin + flags := ConfDefaultOpenFlagsWrite; + m := ConfDefaultFileCreationMask; + end; + omAppend: flags := ConfDefaultOpenFlagsAppend; + else begin + g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_OPEN_FILE), 'Invalid file mode %d', Mode); + Exit; + end; end; - Result := fopen64(PChar(APath), m); - if Result = nil then - g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_OPEN_FILE), '%m'); + + r := open64(PChar(APath), flags, m); + if r < 0 then g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_OPEN_FILE), '%m') + else Result := Pointer(r); end; (********************************************************************************************************************************) function TLocalTreeEngine.ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; begin - Result := fread(Buffer, 1, ABlockSize, FileDescriptor); - if (Result = 0) and (feof(FileDescriptor) = 0) then + Result := libc_read(LongInt(FileDescriptor), Buffer, ABlockSize); + if Result < 0 then g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_READ_FILE), '%m'); end; (********************************************************************************************************************************) function TLocalTreeEngine.WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; begin - Result := fwrite(Buffer, 1, BytesCount, FileDescriptor); - if Result < BytesCount then + Result := libc_write(LongInt(FileDescriptor), Buffer, BytesCount); + if Result < 0 then g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_WRITE_FILE), '%m'); end; (********************************************************************************************************************************) function TLocalTreeEngine.CloseFile(const FileDescriptor: TEngineFileDes; Error: PPGError): boolean; begin - Result := fclose(FileDescriptor) = 0; + Result := libc_close(LongInt(FileDescriptor)) = 0; if not Result then g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_CLOSE_FILE), '%m'); end; @@ -821,7 +849,7 @@ end; (********************************************************************************************************************************) function TLocalTreeEngine.FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; begin - Result := fseeko64(FileDescriptor, AbsoluteOffset, SEEK_SET); + Result := lseek64(LongInt(FileDescriptor), AbsoluteOffset, SEEK_SET); if Result = -1 then g_set_error(Error, TUXCMD_ERROR, gint(TUXCMD_ERROR_SEEK), '%m'); end; |
