From 6132c2ef3066e813acb1237afeca266f32c53a21 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sat, 28 Nov 2009 16:00:34 +0100 Subject: Engine and VFS API cleanup * also split threaded operations into UCoreWorkers.pas * symlinks should be properly resolved now, even in archives * no more relative/absolute path confusion * moved FillDirFiles outside engines, made it more universal --- UEngines.pas | 765 +++++++++++++++++++++-------------------------------------- 1 file changed, 272 insertions(+), 493 deletions(-) (limited to 'UEngines.pas') diff --git a/UEngines.pas b/UEngines.pas index dd35d44..5e3909c 100644 --- a/UEngines.pas +++ b/UEngines.pas @@ -45,28 +45,24 @@ type FDisplayName: PChar; // always-valid UTF-8 LnkPointTo: PChar; // ANSI ColumnData: array[0..9] of PChar; - Size: Int64; + Size: cuLongLong; + PackedSize: Int64; UpDir: boolean; - Mode, UID, GID: Cardinal; - IsDir, IsLnk, IsBlk, IsChr, IsFIFO, IsSock, Selected, IsDotFile: boolean; - ModifyTime: time_t; + Mode, UID, GID: cuLong; + IsDir, IsLnk, IsBlk, IsChr, IsFIFO, IsSock: boolean; + Selected, IsDotFile, IsExecutable: boolean; + atime, mtime, ctime: time_t; Icon: Pointer; ItemColor: PGdkColor; end; PDataItemSL = ^TDataItemSL; TDataItemSL = record + DataItem: PDataItem; Stage1: boolean; - FName: PChar; // ANSI - FDisplayName: PChar; // always-valid UTF-8 - LnkPointTo: PChar; // ANSI - ADestination: PChar; - Size, PackedSize: Int64; - Mode, UID, GID: Cardinal; - IsDir, IsLnk, ForceMove, IsOnRO, IsExecutable: boolean; - ModifyTime: time_t; Level: word; - atime, mtime: Int64; + ADestination: PChar; + ForceMove, IsOnRO: boolean; end; TEngineProgressFunc = function (Sender: Pointer; BytesDone: Int64): boolean; cdecl; // Return False to break the copy process @@ -81,45 +77,45 @@ type LastHighlightItem, SavePath: string; constructor Create; destructor Destroy; override; - function GetListing(var List: TList; const AddDotFiles: boolean): integer; overload; virtual; abstract; // Returns errorcode - function GetListing(var List: TList; const AddDotFiles: boolean; APath: string): integer; overload; virtual; abstract; // Returns errorcode + + function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; virtual; abstract; // Returns errorcode + function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; virtual; abstract; + function ChangeDir(const NewPath: string): integer; virtual; abstract; // Returns errorcode - function ExplicitChDir(const NewPath: string): integer; virtual; abstract; // Returns errorcode - function GetFileSystemSize: Int64; overload; virtual; abstract; - function GetFileSystemSize(const APath: string): Int64; overload; virtual; abstract; - function GetFileSystemFree: Int64; overload; virtual; abstract; - function GetFileSystemFree(const APath: string): Int64; overload; virtual; abstract; - function MakeDir(const NewDir: string): integer; virtual; abstract; // Returns errorcode - function GetDirSize(APath: string): Int64; virtual; abstract; // Returns size or 0 if fails - function Remove(APath: string): integer; virtual; abstract; // Returns errorcode - procedure FillDirFiles(APath: string; List: TList; ALevel: word); virtual; abstract; - function GetFileInfoSL(APath: string): PDataItemSL; virtual; abstract; - function FileExists(const FileName: string; const Use_lstat: boolean = False): Boolean; virtual; abstract; - function DirectoryExists(const FileName: string; const Use_lstat: boolean = False): Boolean; virtual; abstract; - function MakeSymLink(const NewFileName, PointTo: string): integer; virtual; abstract; // Returns errorcode - function Chmod(const FileName: string; const Mode: integer): integer; virtual; abstract; // Returns errorcode - function Chown(const FileName: string; const UID, GID: integer): integer; virtual; abstract; // Returns errorcode + function GetPath: string; virtual; abstract; + procedure SetPath(Value: string); virtual; abstract; + + function GetDirSize(const APath: string): Int64; virtual; abstract; // Returns size or 0 if fails procedure BreakProcessing(ProcessingKind: integer); virtual; abstract; // 1 = GetDirSize, 2 = GetListing - function RenameFile(SourceFile, DestFile: string): integer; virtual; abstract; // Returns errorcode - function ChangeTimes(APath: string; mtime, atime: Int64): integer; virtual; abstract; // Returns errorcode + function FileExists(const FileName: string; FollowSymlinks: boolean): boolean; virtual; abstract; + function DirectoryExists(const FileName: string; FollowSymlinks: boolean): boolean; virtual; abstract; procedure GetFileSystemInfo(const APath: string; var FSSize, FSFree: Int64; var FSName: string); virtual; abstract; - function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; virtual; abstract; // Returns filedescriptor - function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; virtual; abstract; // Returns number of bytes read - function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; virtual; abstract; // Returns number of bytes written - function CloseFile(const FileDescriptor: TEngineFileDes): integer; virtual; abstract; // Returns errorcode - function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; virtual; abstract; // Returns errorcode function IsOnROMedium(const FileName: string): boolean; virtual; abstract; function FileCanRun(const FileName: string): boolean; virtual; abstract; - function GetPath: string; virtual; abstract; - procedure SetPath(Value: string); virtual; abstract; + + // Operations + function MakeDir(const NewDir: string): integer; virtual; abstract; // Returns errorcode + function Remove(const APath: string): integer; virtual; abstract; // Returns errorcode + function MakeSymLink(const NewFileName, PointTo: string): integer; virtual; abstract; // Returns errorcode + function Chmod(const FileName: string; Mode: cuLong): integer; virtual; abstract; // Returns errorcode + function Chown(const FileName: string; UID, GID: cuLong): integer; virtual; abstract; // Returns errorcode + function RenameFile(const SourceFile, DestFile: string): integer; virtual; abstract; // Returns errorcode + function ChangeTimes(const APath: string; mtime, atime: time_t): integer; virtual; abstract; // Returns errorcode // Copy-related routines function GetBlockSize: guint32; virtual; abstract; procedure SetBlockSize(Value: guint32); virtual; abstract; - function CopyFileIn(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; virtual; abstract; // returns True if file is successfully copied - function CopyFileOut(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; virtual; abstract; // returns True if file is successfully copied - function IsOnSameFS(const Path1, Path2: string): boolean; virtual; abstract; - function TwoSameFiles(const Path1, Path2: string): boolean; virtual; abstract; + function CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; virtual; abstract; // returns True if file is successfully copied + function CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; virtual; abstract; // returns True if file is successfully copied + function IsOnSameFS(const Path1, Path2: string; FollowSymlinks: boolean): boolean; virtual; abstract; + function TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; virtual; abstract; + + // Separate file read/write routines, not supported on most backends + function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; virtual; abstract; // Returns filedescriptor + function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; virtual; abstract; // Returns number of bytes read + function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; virtual; abstract; // Returns number of bytes written + function CloseFile(const FileDescriptor: TEngineFileDes): integer; virtual; abstract; // Returns errorcode + function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; virtual; abstract; // Returns errorcode published property Path: string read GetPath write SetPath; property BlockSize: guint32 read GetBlockSize write SetBlockSize; @@ -132,45 +128,45 @@ type public constructor Create; destructor Destroy; override; - function GetListing(var List: TList; const AddDotFiles: boolean): integer; override; - function GetListing(var List: TList; const AddDotFiles: boolean; APath: string): integer; override; + + function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; override; + function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; override; + function ChangeDir(const NewPath: string): integer; override; - function ExplicitChDir(const NewPath: string): integer; override; - function GetFileSystemSize: Int64; override; - function GetFileSystemSize(const APath: string): Int64; override; - function GetFileSystemFree: Int64; override; - function GetFileSystemFree(const APath: string): Int64; override; - function MakeDir(const NewDir: string): integer; override; - function GetDirSize(APath: string): Int64; override; - function Remove(APath: string): integer; override; - procedure FillDirFiles(APath: string; List: TList; ALevel: word); override; - function GetFileInfoSL(APath: string): PDataItemSL; override; - function FileExists(const FileName: string; const Use_lstat: boolean = False): Boolean; override; - function DirectoryExists(const FileName: string; const Use_lstat: boolean = False): Boolean; override; - function MakeSymLink(const NewFileName, PointTo: string): integer; override; - function Chmod(const FileName: string; const Mode: integer): integer; override; - function Chown(const FileName: string; const UID, GID: integer): integer; override; + function GetPath: string; override; + procedure SetPath(Value: string); override; + + function GetDirSize(const APath: string): Int64; override; procedure BreakProcessing(ProcessingKind: integer); override; - function RenameFile(SourceFile, DestFile: string): integer; override; - function ChangeTimes(APath: string; mtime, atime: Int64): integer; override; + function FileExists(const FileName: string; FollowSymlinks: boolean): boolean; override; + function DirectoryExists(const FileName: string; FollowSymlinks: boolean): boolean; override; procedure GetFileSystemInfo(const APath: string; var FSSize, FSFree: Int64; var FSName: string); override; - function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; override; - function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; override; - function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; override; - function CloseFile(const FileDescriptor: TEngineFileDes): integer; override; - function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; override; function IsOnROMedium(const FileName: string): boolean; override; function FileCanRun(const FileName: string): boolean; override; - function GetPath: string; override; - procedure SetPath(Value: string); override; + + function MakeDir(const NewDir: string): integer; override; + function Remove(const APath: string): integer; override; + function MakeSymLink(const NewFileName, PointTo: string): integer; override; + function Chmod(const FileName: string; Mode: cuLong): integer; override; + function Chown(const FileName: string; UID, GID: cuLong): integer; override; + function RenameFile(const SourceFile, DestFile: string): integer; override; + function ChangeTimes(const APath: string; mtime, atime: time_t): integer; override; function GetBlockSize: guint32; override; procedure SetBlockSize(Value: guint32); override; - function CopyFileIn(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; - function CopyFileOut(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; - function CopyFile(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; - function IsOnSameFS(const Path1, Path2: string): boolean; override; - function TwoSameFiles(const Path1, Path2: string): boolean; override; + function CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; + function CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; + function IsOnSameFS(const Path1, Path2: string; FollowSymlinks: boolean): boolean; override; + function TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; override; + + function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; override; + function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; override; + function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; override; + function CloseFile(const FileDescriptor: TEngineFileDes): integer; override; + function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; override; + + // Local extra functions + function CopyFile(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; published property Path; property BlockSize; @@ -179,6 +175,8 @@ type procedure FreeDataItem(DataItem: PDataItemSL); overload; procedure FreeDataItem(DataItem: PDataItem); overload; +function DuplicateDataItem(DataItem: PDataItem): PDataItem; overload; +function DuplicateDataItem(DataItem: PDataItemSL): PDataItemSL; overload; implementation @@ -236,112 +234,40 @@ begin end; end; -function TLocalTreeEngine.GetListing(var List: TList; const AddDotFiles: boolean; APath: string): integer; -var Item : PDataItem; - Handle : PDIR; - DirEnt : PDirent64; - Buf : PChar; -// StatBuf : TStatBuf64; - StatBuf : Pstat64; - i: integer; - LnkBuf : array[0..1000] of char; +function TLocalTreeEngine.GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; +var Item: PDataItem; + Handle: PDIR; + DirEnt: PDirent64; + Buf: PChar; begin Result := 0; try - APath := IncludeTrailingPathDelimiter(APath); - if libc_chdir(PChar(APath)) <> 0 then begin - Result := errno; - DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): chdir error: ', strerror(Result)]); - Exit; - end; - Handle := opendir(PChar(APath)); - if not Assigned(Handle) then begin - DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): opendir() handle == NULL: ', strerror(errno)]); - Result := ERRNoAccess; - Exit; - end; - repeat -// DebugMsg(['x1']); - DirEnt := readdir64(Handle); -// DebugMsg(['x2']); - if Assigned(DirEnt) and Assigned(PChar(@DirEnt^.d_name[0])) then begin -// DebugMsg(['x3']); - Buf := Pchar(@DirEnt^.d_name[0]); -// DebugMsg(['x4']); - if (Buf <> '.') and (Buf <> '..') and (DirEnt^.d_name[0] <> #0) and - (AddDotFiles or (Length(Buf) = 1) or ((Length(Buf) > 1) and (not ((Buf[0] = '.') and (Buf[1] <> '.'))))) then - begin -// DebugMsg(['x5']); - Item := malloc(SizeOf(TDataItem)); -// DebugMsg(['x6']); - memset(Item, 0, SizeOf(TDataItem)); -// DebugMsg(['x7']); - with Item^ do begin -// DebugMsg(['x8']); - FName := nil; - FDisplayName := nil; - LnkPointTo := nil; - for i := 0 to Length(ColumnData) - 1 do ColumnData[i] := nil; - FName := strdup(Buf); - FDisplayName := StrToUTF8(Buf); -// FDisplayName := strdup(Buf); -// DebugMsg(['x']); - StatBuf := malloc(sizeof(Tstat64)); - memset(StatBuf, 0, sizeof(Tstat64)); -// DebugMsg(['(II) TLocalTreeEngine.GetListing(APath=', APath, '): lstat(Buf = ', Buf, ')']); - if lstat64(Buf, StatBuf) <> 0 then begin - DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): Error reading file via lstat64: ', strerror(errno)]); - Continue; - end; - Mode := StatBuf^.st_mode; - IsDotFile := (Length(Buf) > 1) and (Buf[0] = '.') and (Buf[1] <> '.'); - IsDir := __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR); - IsLnk := __S_ISTYPE(StatBuf^.st_mode, __S_IFLNK); - IsBlk := __S_ISTYPE(StatBuf^.st_mode, __S_IFBLK); - IsChr := __S_ISTYPE(StatBuf^.st_mode, __S_IFCHR); - IsFIFO := __S_ISTYPE(StatBuf^.st_mode, __S_IFIFO); - IsSock := __S_ISTYPE(StatBuf^.st_mode, __S_IFSOCK); - ModifyTime := StatBuf^.st_mtime; - if StatBuf^.st_uid = 4294967295 then UID := getuid - else UID := StatBuf^.st_uid; - if StatBuf^.st_gid = 4294967295 then GID := getgid - else GID := StatBuf^.st_gid; - UpDir := False; - Selected := False; -// DebugMsg(['(II) TLocalTreeEngine.GetListing(APath=', APath, '): freeing StatBuf...']); - libc_free(StatBuf); -// DebugMsg([' done.']); - if IsLnk then begin -// DebugMsg(['aaaax']); - i := readlink(PChar(APath + String(Buf)), LnkBuf, SizeOf(LnkBuf)); - if i > 0 then begin - LnkBuf[i] := #0; - LnkPointTo := malloc(i + 1); - memset(LnkPointTo, 0, i + 1); - LnkPointTo := strncpy(LnkPointTo, @LnkBuf[0], i); - end; + if libc_chdir(PChar(APath)) <> 0 then begin + Result := errno; + DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): chdir error: ', strerror(Result)]); + Exit; + end; + Handle := opendir(PChar(APath)); + if Handle = nil then begin + DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): opendir() handle == NULL: ', strerror(errno)]); + Result := ERRNoAccess; + Exit; + end; - StatBuf := malloc(sizeof(Tstat64)); - memset(StatBuf, 0, sizeof(Tstat64)); - if stat64(Buf, StatBuf) = 0 then begin - IsDir := __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR); - Mode := StatBuf^.st_mode; - end; -// DebugMsg(['(II) TLocalTreeEngine.GetListing(APath=', APath, '): freeing StatBuf...']); - libc_free(StatBuf); -// DebugMsg([' done.']); - end; -// DebugMsg(['xdffffffff']); - if not IsDir then Size := StatBuf^.st_size - else Size := -1; -// DebugMsg(['xxsdfsf']); + repeat + DirEnt := readdir64(Handle); + if (DirEnt <> nil) and (DirEnt^.d_name[0] <> #0) then begin + Buf := PChar(@DirEnt^.d_name[0]); + if (Buf <> '.') and (Buf <> '..') and (strlen(Buf) > 0) and + (AddDotFiles or (Buf[0] <> '.')) then + begin + Item := GetFileInfo(IncludeTrailingPathDelimiter(APath) + string(Buf), FollowSymlinks, AddFullPath); List.Add(Item); -// DebugMsg(['x1123']); end; end; - end; - until DirEnt = nil; - closedir(Handle); + until DirEnt = nil; + // TODO: check errno? + closedir(Handle); except on E: Exception do begin Result := ERRException; @@ -351,9 +277,66 @@ begin end; end; -function TLocalTreeEngine.GetListing(var List: TList; const AddDotFiles: boolean): integer; +function TLocalTreeEngine.GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; +var Item: PDataItem; + StatBuf: Pstat64; + LnkBuf: array[0..65535] of char; + i: integer; begin - Result := GetListing(List, AddDotFiles, FPath); + StatBuf := malloc(sizeof(Tstat64)); + memset(StatBuf, 0, sizeof(Tstat64)); + if lstat64(PChar(APath), StatBuf) <> 0 then begin + DebugMsg(['*** TLocalTreeEngine.GetFileInfo(APath=', APath, '): Error reading file via lstat64: ', strerror(errno)]); + libc_free(StatBuf); + Result := nil; + Exit; + end; + + Item := malloc(sizeof(TDataItem)); + memset(Item, 0, sizeof(TDataItem)); + Item^.UpDir := False; + Item^.LnkPointTo := nil; + Item^.Selected := False; + + if AddFullPath then Item^.FName := strdup(PChar(APath)) + else Item^.FName := strdup(PChar(ExtractFileName(APath))); + Item^.FDisplayName := StrToUTF8(Item^.FName); + + Item^.Mode := StatBuf^.st_mode; + Item^.IsDotFile := (Length(ExtractFileName(APath)) > 0) and (ExtractFileName(APath)[1] = '.'); + Item^.IsExecutable := (StatBuf^.st_mode and S_IXUSR) = S_IXUSR; + Item^.IsDir := __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR); + Item^.IsLnk := __S_ISTYPE(StatBuf^.st_mode, __S_IFLNK); + Item^.IsBlk := __S_ISTYPE(StatBuf^.st_mode, __S_IFBLK); + Item^.IsChr := __S_ISTYPE(StatBuf^.st_mode, __S_IFCHR); + Item^.IsFIFO := __S_ISTYPE(StatBuf^.st_mode, __S_IFIFO); + Item^.IsSock := __S_ISTYPE(StatBuf^.st_mode, __S_IFSOCK); + Item^.mtime := StatBuf^.st_mtime; + Item^.atime := StatBuf^.st_atime; + Item^.ctime := StatBuf^.st_ctime; + Item^.UID := StatBuf^.st_uid; + Item^.GID := StatBuf^.st_gid; + Item^.Size := StatBuf^.st_size; + Item^.PackedSize := -1; + libc_free(StatBuf); + + if Item^.IsLnk then begin + i := readlink(PChar(APath), LnkBuf, sizeof(LnkBuf)); + if i >= 0 then + Item^.LnkPointTo := g_strdup(@LnkBuf[0]); + if FollowSymlinks then begin + StatBuf := malloc(sizeof(Tstat64)); + memset(StatBuf, 0, sizeof(Tstat64)); + if stat64(PChar(APath), StatBuf) = 0 then begin + Item^.IsDir := __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR); + Item^.Mode := StatBuf^.st_mode; + Item^.Size := StatBuf^.st_size; + end; + libc_free(StatBuf); + end; + end; + + Result := Item; end; function TLocalTreeEngine.ChangeDir(const NewPath: string): integer; @@ -389,55 +372,6 @@ begin end; end; -(********************************************************************************************************************************) -function TLocalTreeEngine.ExplicitChDir(const NewPath: string): integer; -begin - Result := libc_chdir(PChar(NewPath)); - if Result <> 0 then Result := errno; -end; - -(********************************************************************************************************************************) -function TLocalTreeEngine.GetFileSystemSize(const APath: string): Int64; -var Stat: Pstatfs64; -begin - Result := 0; - try - Stat := malloc(sizeof(Tstatfs64)); - memset(Stat, 0, sizeof(Tstatfs64)); - if statfs64(PChar(APath), Stat) <> 0 then Exit; - Result := Stat^.f_bsize * Stat^.f_blocks; - libc_free(Stat); - except - on E: Exception do DebugMsg(['*** TLocalTreeEngine.GetFileSystemSize(APath=', APath, ') -Exception: ', E.Message]); - end; -end; - -function TLocalTreeEngine.GetFileSystemSize: Int64; -begin - Result := GetFileSystemSize(FPath); -end; - -(********************************************************************************************************************************) -function TLocalTreeEngine.GetFileSystemFree(const APath: string): Int64; -var Stat: Pstatfs64; -begin - Result := 0; - try - Stat := malloc(sizeof(Tstatfs64)); - memset(Stat, 0, sizeof(Tstatfs64)); - if statfs64(PChar(APath), Stat) <> 0 then Exit; - Result := Stat^.f_bsize * Stat^.f_bavail; - libc_free(Stat); - except - on E: Exception do DebugMsg(['*** TLocalTreeEngine.GetFileSystemFree(APath=', APath, ') -Exception: ', E.Message]); - end; -end; - -function TLocalTreeEngine.GetFileSystemFree: Int64; -begin - Result := GetFileSystemFree(FPath); -end; - (********************************************************************************************************************************) function TLocalTreeEngine.MakeDir(const NewDir: string): integer; begin @@ -447,7 +381,7 @@ begin // if Result <> 0 then Result := errno; if Result <> 0 then try - if Self.DirectoryExists(NewDir) or (g_mkdir_with_parents(PChar(NewDir), OctalToAttr(ConfDefaultDirCreationMask)) <> 0) {ForceDirectories(NewDir))} + if Self.DirectoryExists(NewDir, False) or (g_mkdir_with_parents(PChar(NewDir), OctalToAttr(ConfDefaultDirCreationMask)) <> 0) {ForceDirectories(NewDir))} then Result := errno else Result := 0; except @@ -459,40 +393,36 @@ begin end; (********************************************************************************************************************************) - -function TLocalTreeEngine.GetDirSize(APath: string): Int64; +function TLocalTreeEngine.GetDirSize(const APath: string): Int64; function InternalGetDirSize(APath: string): Int64; - var Handle : PDIR; - DirEnt : PDirent64; - StatBuf : Pstat64; + var Handle: PDIR; + DirEnt: PDirent64; + StatBuf: Pstat64; + Buf: PChar; begin Result := 0; try if BreakProcessingType = 1 then Exit; APath := IncludeTrailingPathDelimiter(APath); - if libc_chdir(PChar(APath)) <> 0 then begin - Result := 0; - Exit; - end; - Handle := OpenDir(PChar(APath)); - if not Assigned(Handle) then begin - Result := 0; - Exit; - end; + if libc_chdir(PChar(APath)) <> 0 then Exit; + Handle := opendir(PChar(APath)); + if not Assigned(Handle) then Exit; repeat DirEnt := readdir64(Handle); - if Assigned(DirEnt) and Assigned(PChar(@DirEnt^.d_name[0])) and (PChar(@DirEnt^.d_name[0]) <> '.') and - (PChar(@DirEnt^.d_name[0]) <> '..') and (DirEnt^.d_name[0] <> #0) then - begin - StatBuf := malloc(sizeof(Tstat64)); - memset(StatBuf, 0, sizeof(Tstat64)); - if lstat64(PChar(@DirEnt^.d_name[0]), StatBuf) <> 0 then Continue; - if __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR) then begin - Inc(Result, InternalGetDirSize(APath + String(PChar(@DirEnt^.d_name[0])))); - libc_chdir(PChar(APath)); - end else Inc(Result, StatBuf^.st_size); - libc_free(StatBuf); + if DirEnt <> nil then begin + Buf := PChar(@DirEnt^.d_name[0]); + if (strlen(Buf) > 0) and (Buf <> '.') and (Buf <> '..') then begin + StatBuf := malloc(sizeof(Tstat64)); + memset(StatBuf, 0, sizeof(Tstat64)); + if lstat64(Buf, StatBuf) = 0 then begin + if __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR) then begin + Inc(Result, InternalGetDirSize(APath + string(Buf))); + libc_chdir(PChar(APath)); + end else Inc(Result, StatBuf^.st_size); + end; + libc_free(StatBuf); + end; end; until DirEnt = nil; closedir(Handle); @@ -514,206 +444,25 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.Remove(APath: string): integer; +function TLocalTreeEngine.Remove(const APath: string): integer; begin - APath := ExcludeTrailingPathDelimiter(APath); - Result := libc_remove(PChar(APath)); + Result := libc_remove(PChar(ExcludeTrailingPathDelimiter(APath))); if Result <> 0 then Result := errno; end; (********************************************************************************************************************************) -procedure TLocalTreeEngine.FillDirFiles(APath: string; List: TList; ALevel: word); -var Handle : PDIR; - DirEnt : PDirent64; - StatBuf_global : Pstat64; - Item: PDataItemSL; - i: integer; - LnkBuf : array[0..1000] of char; - FilesList: TList; - - - procedure AddEntry(FPath: string; AddCurrDirStage, AStage1: boolean); - var StatBuf_local : Pstat64; - begin -// DebugMsg(['TLocalTreeEngine.FillDirFiles: addding "', FPath, '"']); - FPath := ExcludeTrailingPathDelimiter(FPath); - StatBuf_local := malloc(sizeof(Tstat64)); - memset(StatBuf_local, 0, sizeof(Tstat64)); - if lstat64(PChar(FPath), StatBuf_local) <> 0 then begin - DebugMsg(['*** TLocalTreeEngine.FillDirFiles: Error reading file stat AddEntry("', FPath, '"): ', strerror(errno)]); - Exit; - end; - Item := malloc(SizeOf(TDataItemSL)); - memset(Item, 0, SizeOf(TDataItemSL)); - with Item^ do begin - FName := nil; - FDisplayName := nil; - LnkPointTo := nil; - ADestination := nil; - Stage1 := AStage1; - FName := strdup(PChar(FPath)); - FDisplayName := StrToUTF8(PChar(FPath)); - Size := StatBuf_local^.st_size; - PackedSize := -1; - Mode := StatBuf_local^.st_mode; - IsDir := __S_ISTYPE(StatBuf_local^.st_mode, __S_IFDIR); - IsLnk := __S_ISTYPE(StatBuf_local^.st_mode, __S_IFLNK); - IsExecutable := AddCurrDirStage or (StatBuf_local^.st_mode and S_IXUSR = S_IXUSR); - IsOnRO := IsOnROMedium(FPath); - ForceMove := False; - if StatBuf_local^.st_uid = 4294967295 then UID := getuid - else UID := StatBuf_local^.st_uid; - if StatBuf_local^.st_gid = 4294967295 then GID := getgid - else GID := StatBuf_local^.st_gid; - atime := StatBuf_local^.st_atime; - mtime := StatBuf_local^.st_mtime; - if IsLnk and AddCurrDirStage then DebugMsg(['*** Assertion failed AddEntry: Item^.IsLnk = True']); - if IsLnk and (not AddCurrDirStage) then begin - i := readlink(PChar(APath + String(PChar(@DirEnt^.d_name[0]))), LnkBuf, SizeOf(LnkBuf)); - if i > 0 then begin - LnkBuf[i] := #0; - LnkPointTo := malloc(i + 1); - memset(LnkPointTo, 0, i + 1); - LnkPointTo := strncpy(LnkPointTo, @LnkBuf[0], i); -// StrLCopy(LnkPointTo, @LnkBuf[0], i); - end; - end; - ModifyTime := StatBuf_local^.st_mtime; -// DebugMsg([FormatDateTime('c', ModifyTime)]); - Level := ALevel + Ord(not AddCurrDirStage); - libc_free(StatBuf_local); - end; - if AddCurrDirStage then List.Add(Item) - else FilesList.Add(Item); - end; - -begin - if not Assigned(List) then Exit; - try - AddEntry(APath, True, True); - FilesList := TList.Create; - APath := IncludeTrailingPathDelimiter(APath); - if libc_chdir(PChar(APath)) <> 0 then begin - DebugMsg(['*** TLocalTreeEngine.FillDirFiles: chdir to "', APath, '" failed: ', strerror(errno)]); - Exit; - end; - Handle := OpenDir(PChar(APath)); - if Assigned(Handle) then - repeat - DirEnt := readdir64(Handle); - if Assigned(DirEnt) and Assigned(PChar(@DirEnt^.d_name[0])) and (PChar(@DirEnt^.d_name[0]) <> '.') and (PChar(@DirEnt^.d_name[0]) <> '..') then begin - StatBuf_global := malloc(sizeof(Tstat64)); - memset(StatBuf_global, 0, sizeof(Tstat64)); - if lstat64(PChar(@DirEnt^.d_name[0]), StatBuf_global) <> 0 then begin - DebugMsg(['*** TLocalTreeEngine.FillDirFiles: Error lstat-ing ("', PChar(@DirEnt^.d_name[0]), '"): ', strerror(errno)]); - Continue; - end; - if __S_ISTYPE(StatBuf_global^.st_mode, __S_IFDIR) then begin - FillDirFiles(APath + String(PChar(@DirEnt^.d_name[0])), List, ALevel + 1); - libc_chdir(PChar(APath)); - end else AddEntry(APath + String(PChar(@DirEnt^.d_name[0])), False, True); - libc_free(StatBuf_global); - end; - until DirEnt = nil; - CloseDir(Handle); - if FilesList.Count > 0 then - for i := 0 to FilesList.Count - 1 do - List.Add(FilesList[i]); - FilesList.Free; - AddEntry(APath, True, False); - except - on E: Exception do DebugMsg(['*** TLocalTreeEngine.FillDirFiles(APath=', APath, ', Level=', ALevel, ') -Exception: ', E.Message]); - end; -end; - -(********************************************************************************************************************************) -function TLocalTreeEngine.GetFileInfoSL(APath: string): PDataItemSL; -var StatBuf : Pstat64; - i : integer; - LnkBuf : array[0..1000] of char; -begin - Result := nil; - try - StatBuf := malloc(sizeof(Tstat64)); - memset(StatBuf, 0, sizeof(Tstat64)); - if lstat64(PChar(APath), StatBuf) <> 0 then begin - DebugMsg(['*** Error reading file stat GetFileInfoSL(lstat): ', strerror(errno)]); - Exit; - end; -// DebugMsg(['x1']); - Result := malloc(SizeOf(TDataItemSL)); - memset(Result, 0, SizeOf(TDataItemSL)); -// DebugMsg(['x1']); - with Result^ do begin - FName := nil; - FDisplayName := nil; - LnkPointTo := nil; - ADestination := nil; - Stage1 := True; -// DebugMsg(['x1']); - FName := strdup(PChar(APath)); - FDisplayName := StrToUTF8(PChar(APath)); - Size := StatBuf^.st_size; - PackedSize := -1; - Mode := StatBuf^.st_mode; - IsDir := __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR); - IsLnk := __S_ISTYPE(StatBuf^.st_mode, __S_IFLNK); -// DebugMsg(['x1']); - IsExecutable := StatBuf^.st_mode and S_IXUSR = S_IXUSR; -// DebugMsg(['x2']); - IsOnRO := IsOnROMedium(APath); -// DebugMsg(['x2']); - ForceMove := False; -// DebugMsg(['x2']); - ModifyTime := StatBuf^.st_mtime; -// DebugMsg(['x2']); - if StatBuf^.st_uid = 4294967295 then UID := getuid - else UID := StatBuf^.st_uid; - if StatBuf^.st_gid = 4294967295 then GID := getgid - else GID := StatBuf^.st_gid; - atime := StatBuf^.st_atime; - mtime := StatBuf^.st_mtime; -// DebugMsg(['x1']); - libc_free(StatBuf); -// DebugMsg(['x1']); - Level := 1; -// DebugMsg(['x1']); - if IsLnk then begin - i := readlink(PChar(APath), LnkBuf, SizeOf(LnkBuf)); - if i > 0 then begin - LnkBuf[i] := #0; - LnkPointTo := malloc(i + 1); - memset(LnkPointTo, 0, i + 1); -// StrLCopy(LnkPointTo, @LnkBuf[0], i); - LnkPointTo := strncpy(LnkPointTo, @LnkBuf[0], i); - end; - StatBuf := malloc(sizeof(Tstat64)); - memset(StatBuf, 0, sizeof(Tstat64)); - if stat64(PChar(APath), StatBuf) = 0 then begin - IsDir := __S_ISTYPE(StatBuf^.st_mode, __S_IFDIR); - Mode := StatBuf^.st_mode; - end; - libc_free(StatBuf); - end; - end; -// DebugMsg(['x1']); - except - on E: Exception do DebugMsg(['*** TLocalTreeEngine.GetFileInfoSL(APath=', APath, ') -Exception: ', E.Message]); - end; -end; -(********************************************************************************************************************************) -function TLocalTreeEngine.CopyFileIn(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +function TLocalTreeEngine.CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; begin Result := CopyFile(Sender, SourceFile, DestFile, ProgressFunc, ErrorFunc, Append); end; -function TLocalTreeEngine.CopyFileOut(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +function TLocalTreeEngine.CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; begin Result := CopyFile(Sender, SourceFile, DestFile, ProgressFunc, ErrorFunc, Append); end; -function TLocalTreeEngine.CopyFile(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +function TLocalTreeEngine.CopyFile(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; var fsrc, fdest: PFILE; BytesDone, BytesRead: Int64; // offset: __off_t; @@ -849,26 +598,25 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.FileExists(const FileName: string; const Use_lstat: boolean = False): Boolean; +function TLocalTreeEngine.FileExists(const FileName: string; FollowSymlinks: boolean): boolean; var st: Pstat64; begin st := malloc(sizeof(Tstat64)); memset(st, 0, sizeof(Tstat64)); - if Use_lstat then Result := lstat64(PChar(FileName), st) = 0 - else Result := stat64(PChar(FileName), st) = 0; + if not FollowSymlinks then Result := lstat64(PChar(FileName), st) = 0 + else Result := stat64(PChar(FileName), st) = 0; libc_free(st); end; (********************************************************************************************************************************) -function TLocalTreeEngine.DirectoryExists(const FileName: string; const Use_lstat: boolean = False): Boolean; +function TLocalTreeEngine.DirectoryExists(const FileName: string; FollowSymlinks: boolean): boolean; var st: Pstat64; begin st := malloc(sizeof(Tstat64)); memset(st, 0, sizeof(Tstat64)); - if Use_lstat then Result := lstat64(PChar(FileName), st) = 0 else - if stat64(PChar(FileName), st) = 0 - then Result := S_ISDIR(st^.st_mode) - else Result := False; + if not FollowSymlinks then Result := lstat64(PChar(FileName), st) = 0 + else Result := stat64(PChar(FileName), st) = 0; + Result := Result and S_ISDIR(st^.st_mode); libc_free(st); end; @@ -881,14 +629,14 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.Chmod(const FileName: string; const Mode: integer): integer; +function TLocalTreeEngine.Chmod(const FileName: string; Mode: cuLong): integer; begin Result := libc_chmod(PChar(FileName), Mode); if Result <> 0 then Result := errno; end; (********************************************************************************************************************************) -function TLocalTreeEngine.Chown(const FileName: string; const UID, GID: integer): integer; +function TLocalTreeEngine.Chown(const FileName: string; UID, GID: cuLong): integer; begin Result := libc_chown(PChar(FileName), UID, GID); if Result <> 0 then Result := errno; @@ -901,8 +649,9 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.IsOnSameFS(const Path1, Path2: string): boolean; +function TLocalTreeEngine.IsOnSameFS(const Path1, Path2: string; FollowSymlinks: boolean): boolean; var FStat1, FStat2: Pstat64; + Res1, Res2: integer; begin // DebugMsg(['** TLocalTreeEngine.IsOnSameFS("', Path1, '", "', Path2, '")']); Result := False; // Default fallback result (forces copy + delete) @@ -910,29 +659,50 @@ begin FStat2 := malloc(sizeof(Tstat64)); memset(FStat1, 0, sizeof(Tstat64)); memset(FStat2, 0, sizeof(Tstat64)); - if lstat64(PChar(Path1), FStat1) <> 0 then begin - DebugMsg(['** TLocalTreeEngine.IsOnSameFS: stat(', Path1, ') error: ', strerror(errno)]); - Exit; - end; - if lstat64(PChar(Path2), FStat2) <> 0 then begin - DebugMsg(['** TLocalTreeEngine.IsOnSameFS: stat(', Path2, ') error: ', strerror(errno)]); - Exit; - end; - Result := FStat1^.st_dev = FStat2^.st_dev; + if FollowSymlinks then Res1 := stat64(PChar(Path1), FStat1) + else Res1 := lstat64(PChar(Path1), FStat1); + if Res1 <> 0 then DebugMsg(['** TLocalTreeEngine.IsOnSameFS: stat(', Path1, ') error: ', strerror(errno)]); + if FollowSymlinks then Res2 := stat64(PChar(Path2), FStat2) + else Res2 := lstat64(PChar(Path2), FStat2); + if Res2 <> 0 then DebugMsg(['** TLocalTreeEngine.IsOnSameFS: stat(', Path2, ') error: ', strerror(errno)]); + if (Res1 = 0) and (Res2 = 0) then + Result := FStat1^.st_dev = FStat2^.st_dev; libc_free(FStat1); libc_free(FStat2); // DebugMsg(['** TLocalTreeEngine.IsOnSameFS("', Path1, '", "', Path2, '") Result = ', Result]); end; (********************************************************************************************************************************) -function TLocalTreeEngine.RenameFile(SourceFile, DestFile: string): integer; +function TLocalTreeEngine.TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; +var FStat1, FStat2: Pstat64; + Res1, Res2: integer; +begin + Result := False; + FStat1 := malloc(sizeof(Tstat64)); + FStat2 := malloc(sizeof(Tstat64)); + memset(FStat1, 0, sizeof(Tstat64)); + memset(FStat2, 0, sizeof(Tstat64)); + if FollowSymlinks then Res1 := stat64(PChar(Path1), FStat1) + else Res1 := lstat64(PChar(Path1), FStat1); + if Res1 <> 0 then DebugMsg(['** TLocalTreeEngine.TwoSameFiles: stat(', Path1, ') error: ', strerror(errno)]); + if FollowSymlinks then Res2 := stat64(PChar(Path2), FStat2) + else Res2 := lstat64(PChar(Path2), FStat2); + if Res2 <> 0 then DebugMsg(['** TLocalTreeEngine.TwoSameFiles: stat(', Path2, ') error: ', strerror(errno)]); + if (Res1 = 0) and (Res2 = 0) then + Result := FStat1^.st_ino = FStat2^.st_ino; + libc_free(FStat1); + libc_free(FStat2); +end; + +(********************************************************************************************************************************) +function TLocalTreeEngine.RenameFile(const SourceFile, DestFile: string): integer; begin Result := libc_rename(PChar(SourceFile), PChar(DestFile)); if Result <> 0 then Result := errno; end; (********************************************************************************************************************************) -function TLocalTreeEngine.ChangeTimes(APath: string; mtime, atime: Int64): integer; +function TLocalTreeEngine.ChangeTimes(const APath: string; mtime, atime: time_t): integer; var timebuf: Putimbuf; begin Result := errno; @@ -966,7 +736,7 @@ begin memset(Stat, 0, sizeof(Tstatfs64)); if statfs64(PChar(APath), Stat) <> 0 then Exit; FSSize := Stat^.f_bsize * Stat^.f_blocks; - FSFree := Stat^.f_bsize * Stat^.f_bavail; + FSFree := Stat^.f_bsize * Stat^.f_bfree; fd := setmntent(_PATH_MOUNTED, 'r'); if fd = nil then Exit; // Get mount name @@ -986,10 +756,12 @@ begin if Stat^.f_type = $9660 then begin { ISOFS_SUPER_MAGIC } if Assigned(mntdev) and (mntdev <> '') then begin fd := fopen(mntdev, 'r'); - if fd = nil then Exit; - if fseek(fd, 32808, SEEK_SET) <> 0 then Exit; - if fread(@Buffer[0], 1, 32, fd) <> 0 then FSName := Trim(String(Buffer)); - fclose(fd); + if fd <> nil then begin + if fseek(fd, 32808, SEEK_SET) = 0 then + if fread(@Buffer[0], 1, 32, fd) <> 0 then + FSName := Trim(String(Buffer)); + fclose(fd); + end; end; end; libc_free(Stat); @@ -1054,8 +826,8 @@ begin try Stat := malloc(sizeof(Tstatfs64)); memset(Stat, 0, sizeof(Tstatfs64)); - if statfs64(PChar(FileName), Stat) <> 0 then Exit; - Result := (Stat^.f_type = $9660); { ISOFS_SUPER_MAGIC } + if statfs64(PChar(FileName), Stat) = 0 then + Result := (Stat^.f_type = $9660); { ISOFS_SUPER_MAGIC } libc_free(Stat); except on E: Exception do DebugMsg(['*** TLocalTreeEngine.IsOnROMedium(FileName=', FileName, ') -Exception: ', E.Message]); @@ -1068,59 +840,66 @@ begin Result := access(PChar(FileName), R_OK or X_OK) = 0; end; -(********************************************************************************************************************************) -function TLocalTreeEngine.TwoSameFiles(const Path1, Path2: string): boolean; -var st1, st2: Pstat64; -begin - Result := False; - st1 := malloc(sizeof(Tstat64)); - st2 := malloc(sizeof(Tstat64)); - memset(st1, 0, sizeof(Tstat64)); - memset(st2, 0, sizeof(Tstat64)); - if lstat64(PChar(Path1), st1) <> 0 then Exit; - if lstat64(PChar(Path2), st2) <> 0 then Exit; -// DebugMsg(['*** TLocalTreeEngine.TwoSameFiles: ', st1^.st_ino, ' ', st2^.st_ino]); - Result := st1^.st_ino = st2^.st_ino; - libc_free(st1); - libc_free(st2); -end; - (********************************************************************************************************************************) (********************************************************************************************************************************) -procedure FreeDataItem(DataItem: PDataItemSL); +procedure FreeDataItem(DataItem: PDataItem); +var i : integer; begin try - if Assigned(DataItem) then begin + if DataItem <> nil then begin with DataItem^ do begin if FName <> nil then libc_free(FName); if FDisplayName <> nil then libc_free(FDisplayName); -// if Assigned(ADestination) then Dispose(ADestination); if LnkPointTo <> nil then libc_free(LnkPointTo); + for i := 0 to Length(ColumnData) - 1 do + if ColumnData[i] <> nil then libc_free(ColumnData[i]); end; libc_free(DataItem); end; except + on E: Exception do DebugMsg(['*** FreeDataItem: Exception: ', E.Message]); end; end; -procedure FreeDataItem(DataItem: PDataItem); -var i : integer; +procedure FreeDataItem(DataItem: PDataItemSL); begin try - if Assigned(DataItem) then begin + if DataItem <> nil then begin with DataItem^ do begin - if FName <> nil then libc_free(FName); - if FDisplayName <> nil then libc_free(FDisplayName); - if LnkPointTo <> nil then libc_free(LnkPointTo); - for i := 0 to Length(ColumnData) - 1 do - if ColumnData[i] <> nil then libc_free(ColumnData[i]); + if ADestination <> nil then libc_free(ADestination); + FreeDataItem(DataItem); end; libc_free(DataItem); end; except + on E: Exception do DebugMsg(['*** FreeDataItem: Exception: ', E.Message]); end; end; +function DuplicateDataItem(DataItem: PDataItem): PDataItem; +var NewDataItem: PDataItem; + i: integer; +begin + NewDataItem := malloc(sizeof(TDataItem)); + memcpy(NewDataItem, DataItem, sizeof(TDataItem)); + NewDataItem^.FName := g_strdup(DataItem^.FName); + NewDataItem^.FDisplayName := g_strdup(DataItem^.FDisplayName); + NewDataItem^.LnkPointTo := g_strdup(DataItem^.LnkPointTo); + for i := 0 to Length(DataItem^.ColumnData) - 1 do + NewDataItem^.ColumnData[i] := g_strdup(DataItem^.ColumnData[i]); + Result := NewDataItem; +end; + +function DuplicateDataItem(DataItem: PDataItemSL): PDataItemSL; +var NewDataItem: PDataItemSL; +begin + NewDataItem := malloc(sizeof(TDataItemSL)); + memcpy(NewDataItem, DataItem, sizeof(TDataItemSL)); + NewDataItem^.ADestination := g_strdup(DataItem^.ADestination); + NewDataItem^.DataItem := DuplicateDataItem(DataItem^.DataItem); + Result := NewDataItem; +end; + end. -- cgit v1.2.3