summaryrefslogtreecommitdiff
path: root/UEngines.pas
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2024-10-25 11:32:12 +0200
committerTomas Bzatek <tbzatek@redhat.com>2024-10-25 11:32:12 +0200
commitd08636bdad4f36431bfdf07e8400d7188a2df781 (patch)
tree841aef1904f9c87ee02e1a730ef488cc75215ec6 /UEngines.pas
parent741e1499ed55e20c136298ced705dcbb59915117 (diff)
downloadtuxcmd-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 'UEngines.pas')
-rw-r--r--UEngines.pas140
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;