summaryrefslogtreecommitdiff
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
parent741e1499ed55e20c136298ced705dcbb59915117 (diff)
downloadtuxcmd-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.
-rw-r--r--UConfig.pas4
-rw-r--r--UCoreWorkers.pas71
-rw-r--r--UEngines.pas140
-rw-r--r--ULibc.pas31
-rw-r--r--vfs/uVFSprototypes.pas19
5 files changed, 159 insertions, 106 deletions
diff --git a/UConfig.pas b/UConfig.pas
index 7f1cabb..d01ae5a 100644
--- a/UConfig.pas
+++ b/UConfig.pas
@@ -25,8 +25,8 @@ uses Classes, ULocale;
resourcestring
ConstAppTitle = 'Tux Commander';
- ConstAboutVersion = '0.6.82-dev';
- ConstAboutBuildDate = '2024-10-23';
+ ConstAboutVersion = '0.6.83-dev';
+ ConstAboutBuildDate = '2024-10-25';
{$IFDEF FPC}
{$INCLUDE fpcver.inc}
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
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;
diff --git a/ULibc.pas b/ULibc.pas
index edccfc8..3b187be 100644
--- a/ULibc.pas
+++ b/ULibc.pas
@@ -631,6 +631,23 @@ const
SEEK_END = 2;
const
+ O_RDONLY = 0;
+ O_WRONLY = 1;
+ O_RDWR = 2;
+ O_CREAT = $40;
+ O_EXCL = $80;
+ O_NOCTTY = $100;
+ O_TRUNC = $200;
+ O_APPEND = $400;
+ O_NONBLOCK = $800;
+ O_NDELAY = O_NONBLOCK;
+ O_SYNC = $1000;
+ O_DIRECT = $4000;
+ O_DIRECTORY = $10000;
+ O_NOFOLLOW = $20000;
+ O_CLOEXEC = $80000;
+
+const
_STAT_VER_LINUX_OLD = 1;
_STAT_VER_KERNEL = 1;
_STAT_VER_SVR4 = 2;
@@ -872,15 +889,17 @@ function feof(stream: PFILE): Longint; cdecl; external GLIBC_LIB name 'feof';
function ferror(stream: PFILE): Longint; cdecl; external GLIBC_LIB name 'ferror';
function fcntl(fd: Longint; cmd: Longint): Longint; cdecl; varargs; external GLIBC_LIB name 'fcntl';
-function open(const pathname: PChar; flags: Longint): Longint; cdecl; varargs; external GLIBC_LIB name 'open';
-function open64(const pathname: PChar; flags: Longint): Longint; cdecl; varargs; external GLIBC_LIB name 'open64';
+function open(const pathname: PChar; flags: Longint; mode: Longint): Longint; cdecl; varargs; external GLIBC_LIB name 'open';
+function open64(const pathname: PChar; flags: Longint; mode: Longint): Longint; cdecl; varargs; external GLIBC_LIB name 'open64';
function creat(const pathname: PChar; mode: __mode_t): Longint; cdecl; external GLIBC_LIB name 'creat';
function creat64(const pathname: PChar; mode: __mode_t): Longint; cdecl; external GLIBC_LIB name 'creat64';
+function lseek(fd: longint; offset: __off_t; whence: longint):__off_t; cdecl; external GLIBC_LIB name 'lseek';
+function lseek64(fd: longint; offset: __off64_t; whence: longint):__off64_t; cdecl; external GLIBC_LIB name 'lseek64';
-function __read(Handle: Integer; var Buffer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'read';
-function libc_read(Handle: Integer; var Buffer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'read';
-function __write(Handle: Integer; const Buffer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'write';
-function libc_write(Handle: Integer; const Buffer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'write';
+function __read(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'read';
+function libc_read(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'read';
+function __write(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'write';
+function libc_write(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external GLIBC_LIB name 'write';
function __close(Handle: Integer): Integer; cdecl; external GLIBC_LIB name 'close';
function libc_close(Handle: Integer): Integer; cdecl; external GLIBC_LIB name 'close';
diff --git a/vfs/uVFSprototypes.pas b/vfs/uVFSprototypes.pas
index 9ed0844..6fbe65d 100644
--- a/vfs/uVFSprototypes.pas
+++ b/vfs/uVFSprototypes.pas
@@ -224,7 +224,7 @@ type
// Changes times for the file/directory - mtime and atime are __time_t parameters (glibc)
TVFSChangeTimes = function (g:TVFSGlobs; const APath: PChar; mtime, atime: guint32; Error: PPGError): gboolean; cdecl;
-
+
// Performs the copy process from inside of module to local filesystem
// (thus sSrcName is a path from inside of module and sDstName is path in the local filesystem where the file should be copied)
// Note: if you need to transfer a file between two VFS modules, you need to do it manually -
@@ -242,20 +242,19 @@ type
TVFSPack = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; CompressionLevel: integer; const Password: PChar; Error: PPGError): gboolean; cdecl;
- // TODO: not implemented at all
- // This is the set of basic functions which can manipulate with data
- // There is a TVFSFileDes object which identifies the processed file (filedescriptor)
- // All these functions needs a pointer to an int variable to store the error code
+ // Low-level open-read-write-close, used for e.g. cross-VFS copy
+ // An abstract TVFSFileDes object serves as a file descriptor/handle
// NOTE: not all modules could support this set of functions due to its design (unable to set a solid block size)
TVFSOpenFile = function (g:TVFSGlobs; const APath: PChar; Mode: integer; Error: PPGError): TVFSFileDes; cdecl;
// Opens a file or creates new (the values for the Mode parameter are described above) and returns the assigned filedescriptor
- TVFSReadFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; cdecl;
- // Returns number of bytes read; the buffer needs to be allocated by a blocksize (set it by VFSSetBlockSize function)
- TVFSWriteFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; cdecl;
- // Returns number of bytes written
+ TVFSReadFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; ABlockSize: guint64; Error: PPGError): gint64; cdecl;
+ // Returns number of bytes read that may be smaller than requested number of bytes. Returns 0 typically at EOF or -1 in case of an error.
+ // The buffer needs to be allocated for a blocksize (set it by VFSSetBlockSize function)
+ TVFSWriteFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; BytesCount: guint64; Error: PPGError): gint64; cdecl;
+ // Returns number of bytes written that may be smaller than requested number of bytes. Returns -1 in case of an error.
TVFSCloseFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Error: PPGError): gboolean; cdecl;
TVFSFileSeek = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; cdecl;
- // Sets the position in the file from the start and returns real current position
+ // Sets the position in the file from the start and returns real current position. Returns -1 in case of an error.
// Archive-specific routines: