mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
UPD: Handling links to directories for filesystem.
This commit is contained in:
parent
2a84b616cd
commit
6f4f382faa
2 changed files with 321 additions and 290 deletions
|
|
@ -107,7 +107,7 @@ type
|
|||
function IsDirectory: Boolean;
|
||||
function IsSysFile: Boolean;
|
||||
function IsLink: Boolean;
|
||||
function IsLinkToDirectory: Boolean;
|
||||
function IsLinkToDirectory: Boolean; virtual;
|
||||
function IsExecutable: Boolean; // for ShellExecute
|
||||
end;
|
||||
|
||||
|
|
@ -227,7 +227,7 @@ begin
|
|||
// Cache Extension and NameNoExt.
|
||||
|
||||
if (FName = '') or
|
||||
((fpAttributes in SupportedProperties) and IsDirectory) or
|
||||
((fpAttributes in SupportedProperties) and (IsDirectory or IsLinkToDirectory)) or
|
||||
(FName[1] = '.')
|
||||
then
|
||||
begin
|
||||
|
|
@ -290,14 +290,7 @@ begin
|
|||
if fpAttributes in SupportedProperties then
|
||||
begin
|
||||
FileAttributes := Properties[fpAttributes] as TFileAttributesProperty;
|
||||
Result := FileAttributes.IsDirectory
|
||||
{$IF DEFINED(MSWINDOWS)}
|
||||
//Because symbolic link works on Windows 2k/XP for directories only
|
||||
or FileAttributes.IsLink
|
||||
{$ELSEIF DEFINED(UNIX)}
|
||||
// or (IsLink and IsDirByName(sLinkTo))
|
||||
{$ENDIF}
|
||||
;
|
||||
Result := FileAttributes.IsDirectory;
|
||||
end
|
||||
else
|
||||
Result := False;
|
||||
|
|
@ -318,8 +311,7 @@ end;
|
|||
|
||||
function TFile.IsLinkToDirectory: Boolean;
|
||||
begin
|
||||
// For now IsDirectory also returns True when the link points to directory.
|
||||
// Maybe this should be changed?
|
||||
// Override in descendant classes.
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,278 +1,317 @@
|
|||
unit uFileSystemFile;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,
|
||||
uLocalFile,
|
||||
uFile,
|
||||
uFileProperty,
|
||||
uOSUtils;
|
||||
|
||||
type
|
||||
|
||||
TFileSystemFile = class(TLocalFile)
|
||||
private
|
||||
FSize: TFileSizeProperty;
|
||||
FAttributes: TFileAttributesProperty;
|
||||
FModificationTime: TFileModificationDateTimeProperty;
|
||||
|
||||
procedure AssignProperties;
|
||||
|
||||
protected
|
||||
function GetAttributes: Cardinal; virtual;
|
||||
procedure SetAttributes(NewAttributes: Cardinal); virtual;
|
||||
function GetSize: Int64; virtual;
|
||||
procedure SetSize(NewSize: Int64); virtual;
|
||||
function GetModificationTime: TDateTime; virtual;
|
||||
procedure SetModificationTime(NewTime: TDateTime); virtual;
|
||||
|
||||
public
|
||||
constructor Create; override;
|
||||
constructor Create(SearchRecord: TSearchRec); overload;
|
||||
{en
|
||||
Creates a file using an existing file as a template.
|
||||
All the properties will reflect the existing file.
|
||||
@param(FilePath denotes absolute path to a file to use as a template.)
|
||||
}
|
||||
constructor Create(FilePath: String); overload;
|
||||
|
||||
destructor Destroy; override;
|
||||
|
||||
{en
|
||||
Creates an identical copy of the object (as far as object data is concerned).
|
||||
}
|
||||
function Clone: TFileSystemFile; override;
|
||||
procedure CloneTo(AFile: TFile); override;
|
||||
|
||||
class function GetSupportedProperties: TFilePropertiesTypes; override;
|
||||
|
||||
property Size: Int64 read GetSize write SetSize;
|
||||
property Attributes: Cardinal read GetAttributes write SetAttributes;
|
||||
property ModificationTime: TDateTime read GetModificationTime write SetModificationTime;
|
||||
end;
|
||||
|
||||
TFileSystemFiles = class(TFiles)
|
||||
protected
|
||||
function Get(Index: Integer): TFileSystemFile;
|
||||
|
||||
public
|
||||
function CreateObjectOfSameType: TFiles; override;
|
||||
function Clone: TFileSystemFiles; override;
|
||||
|
||||
{en
|
||||
Fills a files list from filenames list.
|
||||
@param(FileNamesList
|
||||
A list of absolute paths to files.)
|
||||
}
|
||||
procedure LoadFromFileNames(const FileNamesList: TStringList);
|
||||
|
||||
property Items[Index: Integer]: TFileSystemFile read Get{ write Put}; default;
|
||||
end;
|
||||
|
||||
EFileSystemFileNotExists = class(Exception);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
uFindEx
|
||||
{$IFDEF UNIX}
|
||||
, BaseUnix, uUsersGroups
|
||||
{$ENDIF}
|
||||
;
|
||||
|
||||
constructor TFileSystemFile.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FSize := TFileSizeProperty.Create;
|
||||
FAttributes := TNtfsFileAttributesProperty.Create;
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create;
|
||||
|
||||
AssignProperties;
|
||||
|
||||
// Set name after assigning Attributes property, because it is used to get extension.
|
||||
Name := '';
|
||||
end;
|
||||
|
||||
constructor TFileSystemFile.Create(SearchRecord: TSearchRec);
|
||||
{$IF DEFINED(UNIX)}
|
||||
var
|
||||
sb: BaseUnix.Stat; //buffer for stat info
|
||||
{$ENDIF}
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
{$IF DEFINED(MSWINDOWS)}
|
||||
|
||||
FAttributes := TNtfsFileAttributesProperty.Create(SearchRecord.Attr);
|
||||
FSize := TFileSizeProperty.Create(SearchRecord.Size);
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create(
|
||||
FileDateToDateTime(SearchRecord.Time));
|
||||
|
||||
//Other times: SearchRecord.FindData.ftCreationTime ...?
|
||||
|
||||
{$ELSEIF DEFINED(UNIX)}
|
||||
|
||||
sb := PUnixFindData(SearchRecord.FindHandle)^.StatRec;
|
||||
|
||||
FAttributes := TUnixFileAttributesProperty.Create(sb.st_mode);
|
||||
FSize := TFileSizeProperty.Create(sb.st_size);
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create(
|
||||
FileDateToDateTime(sb.st_mtime));
|
||||
|
||||
{
|
||||
iOwner:=sb.st_uid;
|
||||
iGroup:=sb.st_gid;
|
||||
sOwner:=UIDToStr(iOwner);
|
||||
sGroup:=GIDToStr(iGroup);
|
||||
}
|
||||
|
||||
{$ELSE}
|
||||
|
||||
// Create with default values.
|
||||
FAttributes := TFileAttributesProperty.Create;
|
||||
FSize := TFileSizeProperty.Create;
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
{
|
||||
if IsLink then
|
||||
sLinkTo := ReadSymLink(SearchRecord.Name)
|
||||
else
|
||||
sLinkTo := '';
|
||||
}
|
||||
|
||||
AssignProperties;
|
||||
|
||||
// Set name after assigning Attributes property, because it is used to get extension.
|
||||
Name := SearchRecord.Name;
|
||||
end;
|
||||
|
||||
constructor TFileSystemFile.Create(FilePath: String);
|
||||
var
|
||||
SearchRecord: TSearchRec;
|
||||
begin
|
||||
if FindFirstEx(FilePath, faAnyFile, SearchRecord) <> 0 then
|
||||
begin
|
||||
FindCloseEx(SearchRecord);
|
||||
raise EFileSystemFileNotExists.Create('File ' + FilePath + ' does not exist.');
|
||||
end
|
||||
else
|
||||
Create(SearchRecord);
|
||||
|
||||
Path := ExtractFilePath(FilePath);
|
||||
|
||||
FindCloseEx(SearchRecord);
|
||||
end;
|
||||
|
||||
destructor TFileSystemFile.Destroy;
|
||||
begin
|
||||
if Assigned(FAttributes) then
|
||||
FreeAndNil(FAttributes);
|
||||
if Assigned(FSize) then
|
||||
FreeAndNil(FSize);
|
||||
if Assigned(FModificationTime) then
|
||||
FreeAndNil(FModificationTime);
|
||||
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.Clone: TFileSystemFile;
|
||||
begin
|
||||
Result := TFileSystemFile.Create;
|
||||
CloneTo(Result);
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.CloneTo(AFile: TFile);
|
||||
begin
|
||||
if Assigned(AFile) then
|
||||
begin
|
||||
inherited CloneTo(AFile);
|
||||
// All properties are cloned in base class.
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.AssignProperties;
|
||||
begin
|
||||
FProperties[fpSize] := FSize;
|
||||
FProperties[fpAttributes] := FAttributes;
|
||||
FProperties[fpModificationTime] := FModificationTime;
|
||||
end;
|
||||
|
||||
class function TFileSystemFile.GetSupportedProperties: TFilePropertiesTypes;
|
||||
begin
|
||||
Result := [{fpName, }fpSize, fpAttributes, fpModificationTime];
|
||||
end;
|
||||
|
||||
function TFileSystemFile.GetAttributes: Cardinal;
|
||||
begin
|
||||
Result := FAttributes.Value;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.SetAttributes(NewAttributes: Cardinal);
|
||||
begin
|
||||
FAttributes.Value := NewAttributes;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.GetSize: Int64;
|
||||
begin
|
||||
Result := FSize.Value;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.SetSize(NewSize: Int64);
|
||||
begin
|
||||
FSize.Value := NewSize;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.GetModificationTime: TDateTime;
|
||||
begin
|
||||
Result := FModificationTime.Value;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.SetModificationTime(NewTime: TDateTime);
|
||||
begin
|
||||
FModificationTime.Value := NewTime;
|
||||
end;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
function TFileSystemFiles.CreateObjectOfSameType: TFiles;
|
||||
begin
|
||||
Result := TFileSystemFiles.Create;
|
||||
end;
|
||||
|
||||
function TFileSystemFiles.Clone: TFileSystemFiles;
|
||||
begin
|
||||
Result := TFileSystemFiles.Create;
|
||||
CloneTo(Result);
|
||||
end;
|
||||
|
||||
procedure TFileSystemFiles.LoadFromFileNames(const FileNamesList: TStringList);
|
||||
var
|
||||
AFile: TFileSystemFile;
|
||||
i: Integer;
|
||||
begin
|
||||
Clear;
|
||||
|
||||
if not Assigned(FileNamesList) or (FileNamesList.Count <= 0) then Exit;
|
||||
|
||||
Path := ExtractFilePath(FileNamesList[0]);
|
||||
|
||||
for i := 0 to FileNamesList.Count - 1 do
|
||||
begin
|
||||
AFile := TFileSystemFile.Create(FileNamesList[i]);
|
||||
Add(AFile);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFileSystemFiles.Get(Index: Integer): TFileSystemFile;
|
||||
begin
|
||||
Result := TFileSystemFile(List.Items[Index]);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
unit uFileSystemFile;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,
|
||||
uLocalFile,
|
||||
uFile,
|
||||
uFileProperty,
|
||||
uOSUtils;
|
||||
|
||||
type
|
||||
|
||||
TFileSystemFile = class(TLocalFile)
|
||||
private
|
||||
FSize: TFileSizeProperty;
|
||||
FAttributes: TFileAttributesProperty;
|
||||
FModificationTime: TFileModificationDateTimeProperty;
|
||||
FIsLinkToDirectory: Boolean;
|
||||
|
||||
procedure AssignProperties;
|
||||
|
||||
protected
|
||||
function GetAttributes: Cardinal; virtual;
|
||||
procedure SetAttributes(NewAttributes: Cardinal); virtual;
|
||||
function GetSize: Int64; virtual;
|
||||
procedure SetSize(NewSize: Int64); virtual;
|
||||
function GetModificationTime: TDateTime; virtual;
|
||||
procedure SetModificationTime(NewTime: TDateTime); virtual;
|
||||
|
||||
public
|
||||
constructor Create; override;
|
||||
constructor Create(SearchRecord: TSearchRec); overload;
|
||||
{en
|
||||
Creates a file using an existing file as a template.
|
||||
All the properties will reflect the existing file.
|
||||
@param(FilePath denotes absolute path to a file to use as a template.)
|
||||
}
|
||||
constructor Create(FilePath: String); overload;
|
||||
|
||||
destructor Destroy; override;
|
||||
|
||||
{en
|
||||
Creates an identical copy of the object (as far as object data is concerned).
|
||||
}
|
||||
function Clone: TFileSystemFile; override;
|
||||
procedure CloneTo(AFile: TFile); override;
|
||||
|
||||
class function GetSupportedProperties: TFilePropertiesTypes; override;
|
||||
|
||||
function IsLinkToDirectory: Boolean; override;
|
||||
|
||||
property Size: Int64 read GetSize write SetSize;
|
||||
property Attributes: Cardinal read GetAttributes write SetAttributes;
|
||||
property ModificationTime: TDateTime read GetModificationTime write SetModificationTime;
|
||||
end;
|
||||
|
||||
TFileSystemFiles = class(TFiles)
|
||||
protected
|
||||
function Get(Index: Integer): TFileSystemFile;
|
||||
|
||||
public
|
||||
function CreateObjectOfSameType: TFiles; override;
|
||||
function Clone: TFileSystemFiles; override;
|
||||
|
||||
{en
|
||||
Fills a files list from filenames list.
|
||||
@param(FileNamesList
|
||||
A list of absolute paths to files.)
|
||||
}
|
||||
procedure LoadFromFileNames(const FileNamesList: TStringList);
|
||||
|
||||
property Items[Index: Integer]: TFileSystemFile read Get{ write Put}; default;
|
||||
end;
|
||||
|
||||
EFileSystemFileNotExists = class(Exception);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
uFindEx
|
||||
{$IFDEF UNIX}
|
||||
, BaseUnix, uUsersGroups, uDCUtils, FileUtil
|
||||
{$ENDIF}
|
||||
;
|
||||
|
||||
constructor TFileSystemFile.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FSize := TFileSizeProperty.Create;
|
||||
FAttributes := TNtfsFileAttributesProperty.Create;
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create;
|
||||
FIsLinkToDirectory := False;
|
||||
|
||||
AssignProperties;
|
||||
|
||||
// Set name after assigning Attributes property, because it is used to get extension.
|
||||
Name := '';
|
||||
end;
|
||||
|
||||
constructor TFileSystemFile.Create(SearchRecord: TSearchRec);
|
||||
{$IF DEFINED(UNIX)}
|
||||
var
|
||||
StatInfo: BaseUnix.Stat; //buffer for stat info
|
||||
sFullPath: String;
|
||||
{$ENDIF}
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
{$IF DEFINED(MSWINDOWS)}
|
||||
|
||||
FAttributes := TNtfsFileAttributesProperty.Create(SearchRecord.Attr);
|
||||
FSize := TFileSizeProperty.Create(SearchRecord.Size);
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create(
|
||||
FileDateToDateTime(SearchRecord.Time));
|
||||
|
||||
//Because symbolic link works on Windows 2k/XP for directories only
|
||||
FIsLinkToDirectory := True;
|
||||
|
||||
//Other times: SearchRecord.FindData.ftCreationTime ...?
|
||||
|
||||
{$ELSEIF DEFINED(UNIX)}
|
||||
|
||||
StatInfo := PUnixFindData(SearchRecord.FindHandle)^.StatRec;
|
||||
|
||||
FAttributes := TUnixFileAttributesProperty.Create(StatInfo.st_mode);
|
||||
FSize := TFileSizeProperty.Create(StatInfo.st_size);
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create(
|
||||
FileDateToDateTime(StatInfo.st_mtime));
|
||||
|
||||
if FAttributes.IsLink then
|
||||
begin
|
||||
sFullPath := PUnixFindData(SearchRecord.FindHandle)^.sPath
|
||||
+ SearchRecord.Name;
|
||||
|
||||
// Stat (as opposed to Lstat) will take info of the file that the link points to (recursively).
|
||||
fpStat(PChar(UTF8ToSys(sFullPath)), StatInfo);
|
||||
|
||||
FIsLinkToDirectory := FPS_ISDIR(StatInfo.st_mode);
|
||||
end
|
||||
else
|
||||
FIsLinkToDirectory := False;
|
||||
|
||||
{
|
||||
iOwner:=sb.st_uid;
|
||||
iGroup:=sb.st_gid;
|
||||
sOwner:=UIDToStr(iOwner);
|
||||
sGroup:=GIDToStr(iGroup);
|
||||
}
|
||||
|
||||
{$ELSE}
|
||||
|
||||
FAttributes := TFileAttributesProperty.Create(SearchRecord.Attributes);
|
||||
FSize := TFileSizeProperty.Create(SearchRecord.Size);
|
||||
FModificationTime := TFileModificationDateTimeProperty.Create(SearchRecord.Time);
|
||||
FIsLinkToDirectory := False;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
{
|
||||
if IsLink then
|
||||
begin
|
||||
sLinkTo := ReadSymLink(PUnixFindData(SearchRecord.FindHandle)^.sPath + SearchRecord.Name);
|
||||
if sLinkTo <> '' then
|
||||
begin
|
||||
case uDCUtils.GetPathType(sLinkTo) of
|
||||
ptNone, ptRelative:
|
||||
sLinkTo := PUnixFindData(SearchRecord.FindHandle)^.sPath + sLinkTo;
|
||||
end;
|
||||
end
|
||||
else
|
||||
sLinkTo := '';
|
||||
}
|
||||
|
||||
AssignProperties;
|
||||
|
||||
// Set name after assigning Attributes property, because it is used to get extension.
|
||||
Name := SearchRecord.Name;
|
||||
end;
|
||||
|
||||
constructor TFileSystemFile.Create(FilePath: String);
|
||||
var
|
||||
SearchRecord: TSearchRec;
|
||||
begin
|
||||
if FindFirstEx(FilePath, faAnyFile, SearchRecord) <> 0 then
|
||||
begin
|
||||
FindCloseEx(SearchRecord);
|
||||
raise EFileSystemFileNotExists.Create('File ' + FilePath + ' does not exist.');
|
||||
end
|
||||
else
|
||||
Create(SearchRecord);
|
||||
|
||||
Path := ExtractFilePath(FilePath);
|
||||
|
||||
FindCloseEx(SearchRecord);
|
||||
end;
|
||||
|
||||
destructor TFileSystemFile.Destroy;
|
||||
begin
|
||||
if Assigned(FAttributes) then
|
||||
FreeAndNil(FAttributes);
|
||||
if Assigned(FSize) then
|
||||
FreeAndNil(FSize);
|
||||
if Assigned(FModificationTime) then
|
||||
FreeAndNil(FModificationTime);
|
||||
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.Clone: TFileSystemFile;
|
||||
begin
|
||||
Result := TFileSystemFile.Create;
|
||||
CloneTo(Result);
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.CloneTo(AFile: TFile);
|
||||
begin
|
||||
if Assigned(AFile) then
|
||||
begin
|
||||
inherited CloneTo(AFile);
|
||||
// All properties are cloned in base class.
|
||||
|
||||
with AFile as TFileSystemFile do
|
||||
begin
|
||||
FIsLinkToDirectory := Self.FIsLinkToDirectory;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.AssignProperties;
|
||||
begin
|
||||
FProperties[fpSize] := FSize;
|
||||
FProperties[fpAttributes] := FAttributes;
|
||||
FProperties[fpModificationTime] := FModificationTime;
|
||||
end;
|
||||
|
||||
class function TFileSystemFile.GetSupportedProperties: TFilePropertiesTypes;
|
||||
begin
|
||||
Result := [{fpName, }fpSize, fpAttributes, fpModificationTime];
|
||||
end;
|
||||
|
||||
function TFileSystemFile.GetAttributes: Cardinal;
|
||||
begin
|
||||
Result := FAttributes.Value;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.SetAttributes(NewAttributes: Cardinal);
|
||||
begin
|
||||
FAttributes.Value := NewAttributes;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.GetSize: Int64;
|
||||
begin
|
||||
Result := FSize.Value;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.SetSize(NewSize: Int64);
|
||||
begin
|
||||
FSize.Value := NewSize;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.GetModificationTime: TDateTime;
|
||||
begin
|
||||
Result := FModificationTime.Value;
|
||||
end;
|
||||
|
||||
procedure TFileSystemFile.SetModificationTime(NewTime: TDateTime);
|
||||
begin
|
||||
FModificationTime.Value := NewTime;
|
||||
end;
|
||||
|
||||
function TFileSystemFile.IsLinkToDirectory: Boolean;
|
||||
begin
|
||||
Result := FIsLinkToDirectory;
|
||||
end;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
function TFileSystemFiles.CreateObjectOfSameType: TFiles;
|
||||
begin
|
||||
Result := TFileSystemFiles.Create;
|
||||
end;
|
||||
|
||||
function TFileSystemFiles.Clone: TFileSystemFiles;
|
||||
begin
|
||||
Result := TFileSystemFiles.Create;
|
||||
CloneTo(Result);
|
||||
end;
|
||||
|
||||
procedure TFileSystemFiles.LoadFromFileNames(const FileNamesList: TStringList);
|
||||
var
|
||||
AFile: TFileSystemFile;
|
||||
i: Integer;
|
||||
begin
|
||||
Clear;
|
||||
|
||||
if not Assigned(FileNamesList) or (FileNamesList.Count <= 0) then Exit;
|
||||
|
||||
Path := ExtractFilePath(FileNamesList[0]);
|
||||
|
||||
for i := 0 to FileNamesList.Count - 1 do
|
||||
begin
|
||||
AFile := TFileSystemFile.Create(FileNamesList[i]);
|
||||
Add(AFile);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFileSystemFiles.Get(Index: Integer): TFileSystemFile;
|
||||
begin
|
||||
Result := TFileSystemFile(List.Items[Index]);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue