summaryrefslogtreecommitdiff
path: root/vfs/UVFSCore.pas
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-07 20:34:49 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-07 20:34:49 +0200
commitecde167da74c86bc047aaf84c5e548cf65a5da98 (patch)
treea015dfda84f28a65811e3aa0d369f8f211ec8c60 /vfs/UVFSCore.pas
downloadtuxcmd-release-0.6.36-dev.tar.xz
Diffstat (limited to 'vfs/UVFSCore.pas')
-rw-r--r--vfs/UVFSCore.pas1075
1 files changed, 1075 insertions, 0 deletions
diff --git a/vfs/UVFSCore.pas b/vfs/UVFSCore.pas
new file mode 100644
index 0000000..21fc21b
--- /dev/null
+++ b/vfs/UVFSCore.pas
@@ -0,0 +1,1075 @@
+(*
+ Tux Commander - UVFSCore - VFS Core utilities and management
+ Copyright (C) 2007 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ Check for updates on tuxcmd.sourceforge.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*)
+unit UVFSCore;
+
+{$IFDEF __FPC__}
+ {$M+}
+{$ENDIF}
+
+interface
+
+uses GTKForms, Libc, {$IFDEF KYLIX}UGlibC_compat,{$ENDIF} Classes, uVFSprototypes, UEngines, UCoreUtils;
+
+
+type
+ TVFSPlugin = class
+ private
+ FVFSAllocNeeded: TVFSAllocNeeded;
+ FVFSInit: TVFSInit;
+ FVFSDestroy: TVFSDestroy;
+ FVFSVersion: TVFSVersion;
+ FVFSGetInfo: TVFSGetInfo;
+ FVFSOpen: TVFSOpen;
+ FVFSClose: TVFSClose;
+ FVFSListFirst: TVFSListFirst;
+ FVFSListNext: TVFSListNext;
+ FVFSListClose: TVFSListClose;
+ FVFSChangeDir: TVFSChangeDir;
+ FVFSGetPath: TVFSGetPath;
+ FVFSGetPrefix: TVFSGetPrefix;
+ FVFSGetFileSystemSize: TVFSGetFileSystemSize;
+ FVFSGetFileSystemFree: TVFSGetFileSystemFree;
+ FVFSLogin: TVFSLogin;
+ FVFSFileExists: TVFSFileExists;
+ FVFSFileInfo: TVFSFileInfo;
+ FVFSMkDir: TVFSMkDir;
+ FVFSRemove: TVFSRemove;
+ FVFSRename: TVFSRename;
+ FVFSMakeSymLink: TVFSMakeSymLink;
+ FVFSChmod: TVFSChmod;
+ FVFSChown: TVFSChown;
+ FVFSChangeTimes: TVFSChangeTimes;
+ FVFSGetDirSize: TVFSGetDirSize;
+ FVFSBreakGetDirSize: TVFSBreakGetDirSize;
+ FVFSOpenFile: TVFSOpenFile;
+ FVFSReadFile: TVFSReadFile;
+ FVFSWriteFile: TVFSWriteFile;
+ FVFSCloseFile: TVFSCloseFile;
+ FVFSFileSeek: TVFSFileSeek;
+ FVFSSetBlockSize: TVFSSetBlockSize;
+ FVFSCopyOut: TVFSCopyOut;
+ FVFSCopyIn: TVFSCopyIn;
+ FVFSIsOnSameFS: TVFSIsOnSameFS;
+ FVFSTwoSameFiles: TVFSTwoSameFiles;
+ FVFSGetExts: TVFSGetExts;
+ FVFSGetServices: TVFSGetServices;
+ FVFSSetPassword: TVFSSetPassword;
+ FVFSGetPasswordRequired: TVFSGetPasswordRequired;
+ public
+ ModuleHandle: Pointer;
+ FullPath: string; // module path
+ Extensions, Services: TOpenStringArray; // the list of the extensions plugin can handle
+ constructor Create(PluginHandle: Pointer);
+ destructor Destroy; override;
+ published
+ function VFSVersion: integer;
+ function VFSName: PChar;
+ function VFSDescription: PChar;
+ function VFSAbout: PChar;
+ function VFSCopyright: PChar;
+ end;
+
+
+ TVFSEngine = class(TPanelEngine)
+ private
+ FGlobs: Pointer;
+ FSourcePlugin: TVFSPlugin;
+ FBlockSize: Cardinal;
+ FProgressFunc: TEngineProgressFunc;
+ FSenderThread: Pointer;
+ BreakProcessingKind: integer;
+ FPassword: string;
+ procedure SetFPassword(Value: string);
+ public
+ ArchiveMode: boolean;
+ constructor Create(SourcePlugin: TVFSPlugin);
+ function VFSOpenURI(OpenFile: string): boolean;
+ function VFSOpenEx(OpenFile: string): TVFSResult;
+ function VFSClose: boolean;
+
+ 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 ChangeDir(const NewPath: string; const ShowProgress: boolean = True): 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;
+ procedure BreakProcessing(ProcessingKind: integer); override;
+ function RenameFile(SourceFile, DestFile: string): integer; override;
+ function ChangeTimes(APath: string; mtime, atime: Int64): integer; 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 GetPrefix: string; override;
+ function Login(Username, Password: string): integer; override;
+
+ function GetBlockSize: Cardinal; override;
+ procedure SetBlockSize(Value: Cardinal); 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 IsOnSameFS(const Path1, Path2: string): boolean; override;
+ function TwoSameFiles(const Path1, Path2: string): boolean; override;
+
+ function SetPassword(Password: string): integer;
+ function GetPasswordRequired: boolean;
+ published
+ property Path: string read GetPath write SetPath;
+ property BlockSize: Cardinal read GetBlockSize write SetBlockSize;
+ property Password: string read FPassword write SetFPassword;
+ end;
+
+
+
+procedure DoInitPlugins;
+
+var PluginList: TList;
+
+implementation
+
+uses SysUtils, ModuleLoader, UConfig, ULocale;
+
+
+const ConstGlobalModulePath1 = '/usr/lib/tuxcmd';
+ ConstGlobalModulePath2 = '/usr/local/lib/tuxcmd';
+ ConstLocalModulePath1 = '~/.tuxcmd/plugins';
+ ConstLocalModulePath2 = './plugins';
+ ConstLocalModulePath3 = '../lib/tuxcmd';
+
+ ConstVFSVersionRequired = 2;
+
+var BinaryPath: string;
+
+
+procedure VFSLogFunc(s: PChar); cdecl;
+begin
+ DebugMsg([' ### VFS ###: ', s]);
+end;
+
+(********************************************************************************************************************************)
+constructor TVFSPlugin.Create(PluginHandle: Pointer);
+begin
+ inherited Create;
+ ModuleHandle := PluginHandle;
+
+ // Find the symbols
+ @FVFSAllocNeeded := GetModuleSymbol(ModuleHandle, 'VFSAllocNeeded');
+ @FVFSInit := GetModuleSymbol(ModuleHandle, 'VFSInit');
+ @FVFSDestroy := GetModuleSymbol(ModuleHandle, 'VFSDestroy');
+ @FVFSVersion := GetModuleSymbol(ModuleHandle, 'VFSVersion');
+ @FVFSGetInfo := GetModuleSymbol(ModuleHandle, 'VFSGetInfo');
+ @FVFSOpen := GetModuleSymbol(ModuleHandle, 'VFSOpen');
+ @FVFSClose := GetModuleSymbol(ModuleHandle, 'VFSClose');
+ @FVFSListFirst := GetModuleSymbol(ModuleHandle, 'VFSListFirst');
+ @FVFSListNext := GetModuleSymbol(ModuleHandle, 'VFSListNext');
+ @FVFSListClose := GetModuleSymbol(ModuleHandle, 'VFSListClose');
+ @FVFSGetPath := GetModuleSymbol(ModuleHandle, 'VFSGetPath');
+ @FVFSChangeDir := GetModuleSymbol(ModuleHandle, 'VFSChangeDir');
+ @FVFSGetPrefix := GetModuleSymbol(ModuleHandle, 'VFSGetPrefix');
+ @FVFSGetFileSystemSize := GetModuleSymbol(ModuleHandle, 'VFSGetFileSystemSize');
+ @FVFSGetFileSystemFree := GetModuleSymbol(ModuleHandle, 'VFSGetFileSystemFree');
+ @FVFSLogin := GetModuleSymbol(ModuleHandle, 'VFSLogin');
+ @FVFSFileExists := GetModuleSymbol(ModuleHandle, 'VFSFileExists');
+ @FVFSFileInfo := GetModuleSymbol(ModuleHandle, 'VFSFileInfo');
+ @FVFSMkDir := GetModuleSymbol(ModuleHandle, 'VFSMkDir');
+ @FVFSRemove := GetModuleSymbol(ModuleHandle, 'VFSRemove');
+ @FVFSRename := GetModuleSymbol(ModuleHandle, 'VFSRename');
+ @FVFSMakeSymLink := GetModuleSymbol(ModuleHandle, 'VFSMakeSymLink');
+ @FVFSChmod := GetModuleSymbol(ModuleHandle, 'VFSChmod');
+ @FVFSChown := GetModuleSymbol(ModuleHandle, 'VFSChown');
+ @FVFSChangeTimes := GetModuleSymbol(ModuleHandle, 'VFSChangeTimes');
+ @FVFSGetDirSize := GetModuleSymbol(ModuleHandle, 'VFSGetDirSize');
+ @FVFSBreakGetDirSize := GetModuleSymbol(ModuleHandle, 'VFSBreakGetDirSize');
+ @FVFSCopyOut := GetModuleSymbol(ModuleHandle, 'VFSCopyOut');
+ @FVFSCopyIn := GetModuleSymbol(ModuleHandle, 'VFSCopyIn');
+ @FVFSOpenFile := GetModuleSymbol(ModuleHandle, 'VFSOpenFile');
+ @FVFSReadFile := GetModuleSymbol(ModuleHandle, 'VFSReadFile');
+ @FVFSWriteFile := GetModuleSymbol(ModuleHandle, 'VFSWriteFile');
+ @FVFSCloseFile := GetModuleSymbol(ModuleHandle, 'VFSCloseFile');
+ @FVFSFileSeek := GetModuleSymbol(ModuleHandle, 'VFSFileSeek');
+ @FVFSSetBlockSize := GetModuleSymbol(ModuleHandle, 'VFSSetBlockSize');
+ @FVFSIsOnSameFS := GetModuleSymbol(ModuleHandle, 'VFSIsOnSameFS');
+ @FVFSTwoSameFiles := GetModuleSymbol(ModuleHandle, 'VFSTwoSameFiles');
+ @FVFSGetExts := GetModuleSymbol(ModuleHandle, 'VFSGetExts');
+ @FVFSGetServices := GetModuleSymbol(ModuleHandle, 'VFSGetServices');
+ @FVFSSetPassword := GetModuleSymbol(ModuleHandle, 'VFSSetPassword');
+ @FVFSGetPasswordRequired := GetModuleSymbol(ModuleHandle, 'VFSGetPasswordRequired');
+ // Initialize the extensions list
+ SetLength(Extensions, 0);
+ SetLength(Services, 0);
+ if @FVFSGetExts <> nil then ParseString(FVFSGetExts, ';', Extensions);
+ if @FVFSGetServices <> nil then ParseString(FVFSGetServices, ';', Services);
+end;
+
+destructor TVFSPlugin.Destroy;
+begin
+ if ModuleHandle <> nil then UnloadModule(ModuleHandle);
+ inherited Destroy;
+end;
+
+(********************************************************************************************************************************)
+function TVFSPlugin.VFSVersion: integer;
+begin
+ if @FVFSVersion <> nil then Result := FVFSVersion
+ else Result := -1;
+end;
+
+function TVFSPlugin.VFSName: PChar;
+var Info: TVFSInfo;
+begin
+ if @FVFSGetInfo <> nil then begin
+ Info := FVFSGetInfo;
+ Result := Info.Name;
+ end else Result := nil;
+end;
+
+function TVFSPlugin.VFSDescription: PChar;
+var Info: TVFSInfo;
+begin
+ if @FVFSGetInfo <> nil then begin
+ Info := FVFSGetInfo;
+ Result := Info.Description;
+ end else Result := nil;
+end;
+
+function TVFSPlugin.VFSAbout: PChar;
+var Info: TVFSInfo;
+begin
+ if @FVFSGetInfo <> nil then begin
+ Info := FVFSGetInfo;
+ Result := Info.About;
+ end else Result := nil;
+end;
+
+function TVFSPlugin.VFSCopyright: PChar;
+var Info: TVFSInfo;
+begin
+ if @FVFSGetInfo <> nil then begin
+ Info := FVFSGetInfo;
+ Result := Info.Copyright;
+ end else Result := nil;
+end;
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+constructor TVFSEngine.Create(SourcePlugin: TVFSPlugin);
+begin
+ inherited Create;
+ FSourcePlugin := SourcePlugin;
+ FBlockSize := 65536;
+ ArchiveMode := False;
+ BreakProcessingKind := 0;
+ if @FSourcePlugin.FVFSAllocNeeded <> nil then begin
+ FGlobs := Libc.malloc(FSourcePlugin.FVFSAllocNeeded);
+ Libc.memset(FGlobs, 0, FSourcePlugin.FVFSAllocNeeded);
+ end else begin
+ FGlobs := Libc.malloc(SizeOf(FGlobs));
+ Libc.memset(FGlobs, 0, SizeOf(FGlobs));
+ end;
+
+{$IFNDEF KYLIX}
+ DebugMsg(['sizeof(TVFSItem) = ', sizeof(TVFSItem)]);
+ DebugMsg(['sizeof(TVFSItem.sFileName) = ', sizeof(TVFSItem.sFileName)]);
+ DebugMsg(['sizeof(TVFSItem.iSize) = ', sizeof(TVFSItem.iSize)]);
+ DebugMsg(['sizeof(TVFSItem.m_time) = ', sizeof(TVFSItem.m_time)]);
+ DebugMsg(['sizeof(TVFSItem.a_time) = ', sizeof(TVFSItem.a_time)]);
+ DebugMsg(['sizeof(TVFSItem.c_time) = ', sizeof(TVFSItem.c_time)]);
+ DebugMsg(['sizeof(TVFSItem.iMode) = ', sizeof(TVFSItem.iMode)]);
+ DebugMsg(['sizeof(TVFSItem.sLinkTo) = ', sizeof(TVFSItem.sLinkTo)]);
+ DebugMsg(['sizeof(TVFSItem.iUID) = ', sizeof(TVFSItem.iUID)]);
+ DebugMsg(['sizeof(TVFSItem.iGID) = ', sizeof(TVFSItem.iGID)]);
+ DebugMsg(['sizeof(TVFSItem.ItemType) = ', sizeof(TVFSItem.ItemType)]);
+{$ENDIF}
+
+ if @FSourcePlugin.FVFSInit <> nil then FSourcePlugin.FVFSInit(FGlobs, @VFSLogFunc);
+ FPassword := '';
+end;
+
+function TVFSEngine.VFSOpenURI(OpenFile: string): boolean;
+begin
+ Result := False;
+ if @FSourcePlugin.FVFSOpen <> nil then Result := FSourcePlugin.FVFSOpen(FGlobs, PChar(OpenFile)) = cVFS_OK;
+end;
+
+function TVFSEngine.VFSOpenEx(OpenFile: string): TVFSResult;
+begin
+ Result := cVFS_OK;
+ if @FSourcePlugin.FVFSOpen <> nil then Result := FSourcePlugin.FVFSOpen(FGlobs, PChar(OpenFile));
+end;
+
+function TVFSEngine.VFSClose: boolean;
+begin
+ Result := False;
+ if @FSourcePlugin.FVFSClose <> nil then Result := FSourcePlugin.FVFSClose(FGlobs) = cVFS_OK;
+end;
+
+destructor TVFSEngine.Destroy;
+begin
+ try
+ if @FSourcePlugin.FVFSDestroy <> nil then FSourcePlugin.FVFSDestroy(FGlobs);
+ libc.free(FGlobs);
+ except
+ on E: Exception do DebugMsg(['*** TVFSEngine.Destroy() -Exception: ', E.Message]);
+ end;
+end;
+
+function TVFSEngine.GetListing(var List: TList; const AddDotFiles: boolean; APath: string): integer;
+var P: PVFSItem;
+ Item: PDataItem;
+ i, Res: integer;
+begin
+ DebugMsg(['^^VFS (II): GetListing begin']);
+ Result := 0;
+ try
+ if @FSourcePlugin.FVFSListFirst = nil then Exit;
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+// DebugMsg(['Item = ', Int64(P)]);
+// DebugMsg(['FVFSListFirst']);
+ Res := FSourcePlugin.FVFSListFirst(FGlobs, PChar(APath), P);
+ if Res <> cVFS_OK then begin
+ FSourcePlugin.FVFSListClose(FGlobs);
+ if Res = cVFS_Not_More_Files then Result := 0
+ else Result := Res;
+ Libc.free(P);
+ Exit;
+ end;
+
+ repeat
+// DebugMsg(['begin--']);
+ if AddDotFiles or (not ((Length(P^.sFileName) > 1) and (P^.sFileName[0] = '.') and (P^.sFileName[1] <> '.'))) then begin
+// DebugMsg(['Checkpoint 1']);
+ Item := Libc.malloc(SizeOf(TDataItem));
+ Libc.memset(Item, 0, SizeOf(TDataItem));
+// DebugMsg(['Checkpoint 2']);
+ for i := 0 to Length(Item^.ColumnData) - 1 do Item^.ColumnData[i] := nil;
+// DebugMsg(['Checkpoint 3']);
+ with Item^ do
+ try
+ AName := strdup(P^.sFileName);
+ if P^.sLinkTo <> nil
+ then begin
+ LnkPointTo := strdup(P^.sLinkTo);
+ DebugMsg(['LnkPointTo = ', P^.sLinkTo]);
+ end else LnkPointTo := nil;
+ Mode := P^.iMode;
+// DebugMsg(['Checkpoint 4']);
+ IsDotFile := (Length(AName) > 1) and (AName[0] = '.') and (AName[1] <> '.');
+ IsDir := TVFSItemType(P^.ItemType) = vDirectory;
+ IsLnk := TVFSItemType(P^.ItemType) = vSymlink;
+ IsBlk := TVFSItemType(P^.ItemType) = vBlockdev;
+ IsChr := TVFSItemType(P^.ItemType) = vChardev;
+ IsFIFO := TVFSItemType(P^.ItemType) = vFifo;
+ IsSock := TVFSItemType(P^.ItemType) = vSock;
+// DebugMsg(['Checkpoint 5']);
+ ModifyTime := UnixTimeToTDateTime(P^.m_time);
+// DebugMsg(['Returned datetime: ', Longword(P^.m_time)]);
+// DebugMsg(['Checkpoint 6']);
+ UID := P^.iUID;
+// DebugMsg(['Checkpoint 7']);
+ GID := P^.iGID;
+// DebugMsg(['Checkpoint 8']);
+ UpDir := False;
+// DebugMsg(['Checkpoint 9']);
+ Selected := False;
+// DebugMsg(['Checkpoint 10']);
+ Size := P^.iSize;
+// DebugMsg(['Checkpoint 11']);
+ List.Add(Item);
+// DebugMsg(['Checkpoint 12']);
+ except
+ on E: Exception do
+ DebugMsg(['^^VFS (EE): GetListing: Item-Exception: ', E.Message]);
+ end;
+ end; // of if AddDotFiles
+ Libc.free(P); // Not needed - just zero-erase the memory
+// DebugMsg(['Checkpoint 13']);
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+// DebugMsg(['Item = ', Int64(P)]);
+// DebugMsg(['Checkpoint 14']);
+// DebugMsg(['FVFSListNext --begin']);
+ Res := FSourcePlugin.FVFSListNext(FGlobs, PChar(APath), P);
+// DebugMsg(['FVFSListNext --end']);
+// Sleep(500);
+ until (Res <> cVFS_OK) or (BreakProcessingKind = 2);
+ if BreakProcessingKind <> 0 then DebugMsg(['^^VFS (WW): GetListing: stopped by BreakProcessing']);
+
+ Libc.free(P);
+ FSourcePlugin.FVFSListClose(FGlobs);
+ if Res <> cVFS_Not_More_Files then Result := Res;
+ except
+ on E: Exception do
+ DebugMsg(['^^VFS (EE): GetListing: Exception: ', E.Message]);
+ end;
+ BreakProcessingKind := 0;
+ DebugMsg(['^^VFS (II): GetListing end.']);
+end;
+
+function TVFSEngine.GetListing(var List: TList; const AddDotFiles: boolean): integer;
+begin
+ Result := GetListing(List, AddDotFiles, GetPath);
+end;
+
+function TVFSEngine.ExplicitChDir(const NewPath: string): integer;
+begin
+ Result := __chdir(PChar(NewPath));
+ if Result <> 0 then Result := errno;
+end;
+
+function TVFSEngine.GetFileSystemSize: Int64;
+begin
+ Result := GetFileSystemSize(GetPath);
+end;
+
+function TVFSEngine.GetFileSystemSize(const APath: string): Int64;
+begin
+ if @FSourcePlugin.FVFSGetFileSystemSize <> nil
+ then Result := FSourcePlugin.FVFSGetFileSystemSize(FGlobs, PChar(APath))
+ else Result := 0;
+end;
+
+function TVFSEngine.GetFileSystemFree: Int64;
+begin
+ Result := GetFileSystemFree(GetPath);
+end;
+
+function TVFSEngine.GetFileSystemFree(const APath: string): Int64;
+begin
+ if @FSourcePlugin.FVFSGetFileSystemFree <> nil
+ then Result := FSourcePlugin.FVFSGetFileSystemFree(FGlobs, PChar(APath))
+ else Result := 0;
+end;
+
+procedure TVFSEngine.GetFileSystemInfo(const APath: string; var FSSize, FSFree: Int64; var FSName: string);
+begin
+ FSSize := GetFileSystemSize(APath);
+ FSFree := GetFileSystemFree(APath);
+ FSName := 'plugin';
+end;
+
+function TVFSEngine.IsOnROMedium(const FileName: string): boolean;
+begin
+ Result := True;
+end;
+
+function TVFSEngine.FileCanRun(const FileName: string): boolean;
+var Item: PDataItemSL;
+begin
+ Item := GetFileInfoSL(FileName);
+ Result := Assigned(Item) and Item^.IsExecutable;
+ FreeDataItem(Item);
+end;
+
+function TVFSEngine.GetPrefix: string;
+begin
+ if @FSourcePlugin.FVFSGetPrefix <> nil then Result := URIHidePassword(FSourcePlugin.FVFSGetPrefix(FGlobs))
+ else Result := 'VFS';
+end;
+
+function TVFSEngine.GetPath: string;
+begin
+ if @FSourcePlugin.FVFSGetPath <> nil then Result := FSourcePlugin.FVFSGetPath(FGlobs)
+ else Result := '/';
+end;
+
+function TVFSEngine.ChangeDir(const NewPath: string; const ShowProgress: boolean = True): integer;
+begin
+ DebugMsg(['^^VFS (II): ChangeDir begin']);
+ Result := 0;
+ try
+ Result := FSourcePlugin.FVFSChangeDir(FGlobs, PChar(NewPath));
+// Sleep(3000);
+ except
+ on E: Exception do DebugMsg(['^^VFS (EE): ChangeDir: Exception: ', E.Message]);
+ end;
+ DebugMsg(['^^VFS (II): ChangeDir end.']);
+end;
+
+procedure TVFSEngine.SetPath(Value: string);
+begin
+ ChangeDir(Value);
+end;
+
+function TVFSEngine.Login(Username, Password: string): integer;
+begin
+ if @FSourcePlugin.FVFSLogin <> nil then Result := FSourcePlugin.FVFSLogin(FGlobs, PChar(Username), PChar(Password))
+ else Result := cVFS_OK;
+end;
+
+function TVFSEngine.FileExists(const FileName: string; const Use_lstat: boolean = False): Boolean;
+begin
+ if @FSourcePlugin.FVFSFileExists <> nil then Result := FSourcePlugin.FVFSFileExists(FGlobs, PChar(FileName), Use_lstat)
+ else Result := False;
+end;
+
+function TVFSEngine.DirectoryExists(const FileName: string; const Use_lstat: boolean = False): Boolean;
+var P: PVFSItem;
+ Res: integer;
+begin
+ if @FSourcePlugin.FVFSFileExists <> nil then begin
+ Result := FSourcePlugin.FVFSFileExists(FGlobs, PChar(FileName), Use_lstat);
+ if Result and (@FSourcePlugin.FVFSFileInfo <> nil) then begin
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+ Res := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(FileName), P);
+ if (Res <> cVFS_OK) or (P = nil) or (TVFSItemType(P^.ItemType) <> vDirectory) then Result := False;
+ Libc.free(P);
+ end;
+ end else Result := False;
+end;
+
+function TVFSEngine.GetFileInfoSL(APath: string): PDataItemSL;
+var P: PVFSItem;
+ Item: PDataItemSL;
+ Res: integer;
+begin
+ Result := nil;
+ if @FSourcePlugin.FVFSFileInfo = nil then Exit;
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+
+ Res := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(APath), P);
+ if Res <> cVFS_OK then begin
+ DebugMsg(['*** VFSFileInfo(', APath, ') failed. Code = ', Res]);
+ Exit;
+ end;
+
+ try
+ Item := Libc.malloc(SizeOf(TDataItemSL));
+ Libc.memset(Item, 0, SizeOf(TDataItemSL));
+ with Item^ do begin
+ AName := strdup(P^.sFileName);
+ if P^.sLinkTo <> nil then LnkPointTo := strdup(P^.sLinkTo)
+ else LnkPointTo := nil;
+ ADestination := nil;
+ Stage1 := True;
+ Level := 0;
+ IsDir := TVFSItemType(P^.ItemType) = vDirectory;
+ IsLnk := TVFSItemType(P^.ItemType) = vSymlink;
+ ForceMove := False;
+{***} IsOnRO := True;
+ IsExecutable := P^.iMode and S_IXUSR = S_IXUSR;
+ Mode := P^.iMode;
+ ModifyTime := UnixTimeToTDateTime(P^.m_time);
+ mtime := P^.m_time;
+ atime := P^.a_time;
+ UID := P^.iUID;
+ GID := P^.iGID;
+ Size := P^.iSize;
+ Libc.free(P);
+ end;
+ Result := Item;
+ except
+ on E: Exception do DebugMsg(['*** TVFSEngine.GetFileInfoSL(APath=', APath, ') -Exception: ', E.Message]);
+ end;
+end;
+
+function TVFSEngine.MakeDir(const NewDir: string): integer;
+begin
+ if @FSourcePlugin.FVFSMkDir <> nil then Result := FSourcePlugin.FVFSMkDir(FGlobs, PChar(NewDir))
+ else Result := cVFS_Failed;
+end;
+
+function TVFSEngine.Remove(APath: string): integer;
+begin
+ if @FSourcePlugin.FVFSRemove <> nil then Result := FSourcePlugin.FVFSRemove(FGlobs, PChar(APath))
+ else Result := cVFS_Failed;
+end;
+
+function TVFSEngine.RenameFile(SourceFile, DestFile: string): integer;
+begin
+ if @FSourcePlugin.FVFSRename <> nil then Result := FSourcePlugin.FVFSRename(FGlobs, PChar(SourceFile), PChar(DestFile))
+ else Result := cVFS_Failed;
+end;
+
+procedure TVFSEngine.FillDirFiles(APath: string; List: TList; ALevel: word);
+var Item: PDataItemSL;
+ i, Res: integer;
+ FilesList: TList;
+ LocalList: TStringList;
+ P: PVFSItem;
+
+
+ procedure AddEntry(FPath: string; AddCurrDirStage, AStage1: boolean);
+ begin
+ Item := Libc.malloc(SizeOf(TDataItemSL));
+ Libc.memset(Item, 0, SizeOf(TDataItemSL));
+ with Item^ do begin
+// AName := Libc.malloc(Length(FPath) + 1);
+// Libc.memset(AName, 0, Length(FPath) + 1);
+ AName := strdup(PChar(FPath));
+ if P^.sLinkTo <> nil then LnkPointTo := strdup(P^.sLinkTo)
+ else LnkPointTo := nil;
+ ADestination := nil;
+ Stage1 := AStage1;
+ IsDir := TVFSItemType(P^.ItemType) = vDirectory;
+ IsLnk := TVFSItemType(P^.ItemType) = vSymlink;
+ if IsLnk and AddCurrDirStage then DebugMsg(['*** Assertion failed AddEntry: Item^.IsLnk = True']);
+ ForceMove := False;
+{***} IsOnRO := True;
+ IsExecutable := AddCurrDirStage or (P^.iMode and S_IXUSR = S_IXUSR);
+ Mode := P^.iMode;
+ ModifyTime := UnixTimeToTDateTime(P^.m_time);
+ mtime := P^.m_time;
+ atime := P^.a_time;
+ UID := P^.iUID;
+ GID := P^.iGID;
+ Size := P^.iSize;
+ {$WARNINGS OFF}
+ Level := ALevel + Ord(not AddCurrDirStage);
+ {$WARNINGS ON}
+ end;
+ if AddCurrDirStage then List.Add(Item)
+ else FilesList.Add(Item);
+ end;
+
+begin
+ if not Assigned(List) then Exit;
+ FilesList := TList.Create;
+ LocalList := TStringList.Create;
+ try
+ try
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+ Res := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(APath), P);
+ if Res <> cVFS_OK then DebugMsg(['*** FillDirFiles - VFSFileInfo(', APath, ') failed. Code = ', Res]);
+ AddEntry(APath, True, True);
+ Libc.free(P);
+
+ APath := IncludeTrailingPathDelimiter(APath);
+ if @FSourcePlugin.FVFSChangeDir <> nil then Res := FSourcePlugin.FVFSChangeDir(FGlobs, PChar(APath))
+ else Exit;
+ if Res <> 0 then Exit;
+
+ if @FSourcePlugin.FVFSListFirst = nil then Exit;
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+ Res := FSourcePlugin.FVFSListFirst(FGlobs, PChar(APath), P);
+ if Res <> cVFS_OK then begin
+ FSourcePlugin.FVFSListClose(FGlobs);
+ Libc.free(P);
+ Exit;
+ end;
+
+ repeat
+ if TVFSItemType(P^.ItemType) = vDirectory
+ then LocalList.Add(APath + String(P^.sFileName))
+ else AddEntry(APath + String(P^.sFileName), False, True);
+ Libc.free(P);
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+ Res := FSourcePlugin.FVFSListNext(FGlobs, PChar(GetPath), P);
+ until (Res <> cVFS_OK);
+
+ Libc.free(P);
+ FSourcePlugin.FVFSListClose(FGlobs);
+
+ {$WARNINGS OFF}
+ if LocalList.Count > 0 then
+ for i := 0 to LocalList.Count - 1 do
+ FillDirFiles(LocalList[i], List, ALevel + 1);
+ {$WARNINGS ON}
+
+ if FilesList.Count > 0 then
+ for i := 0 to FilesList.Count - 1 do
+ List.Add(FilesList[i]);
+ except
+ on E: Exception do DebugMsg(['*** TVFSEngine.FillDirFiles(APath=', APath, ', Level=', ALevel, ') -Exception: ', E.Message]);
+ end;
+ finally
+ P := Libc.malloc(SizeOf(TVFSItem));
+ Libc.memset(P, 0, SizeOf(TVFSItem));
+ Res := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(APath), P);
+ if Res <> cVFS_OK then DebugMsg(['*** FillDirFiles - VFSFileInfo(', APath, ') failed. Code = ', Res]);
+ AddEntry(APath, True, False);
+ Libc.free(P);
+
+ LocalList.Free;
+ FilesList.Free;
+ end;
+end;
+
+function TVFSEngine.MakeSymLink(const NewFileName, PointTo: string): integer;
+begin
+ if @FSourcePlugin.FVFSMakeSymLink <> nil then Result := FSourcePlugin.FVFSMakeSymLink(FGlobs, PChar(NewFileName), PChar(PointTo))
+ else Result := cVFS_Failed;
+end;
+
+function TVFSEngine.Chmod(const FileName: string; const Mode: integer): integer;
+begin
+ if @FSourcePlugin.FVFSChmod <> nil then Result := FSourcePlugin.FVFSChmod(FGlobs, PChar(FileName), Mode)
+ else Result := cVFS_Failed;
+end;
+
+function TVFSEngine.Chown(const FileName: string; const UID, GID: integer): integer;
+begin
+ if @FSourcePlugin.FVFSChown <> nil then Result := FSourcePlugin.FVFSChown(FGlobs, PChar(FileName), UID, GID)
+ else Result := cVFS_Failed;
+end;
+
+function TVFSEngine.ChangeTimes(APath: string; mtime, atime: Int64): integer;
+begin
+ if @FSourcePlugin.FVFSChangeTimes <> nil then Result := FSourcePlugin.FVFSChangeTimes(FGlobs, PChar(APath), mtime, atime)
+ else Result := cVFS_Failed;
+end;
+
+function TVFSEngine.GetDirSize(APath: string): Int64;
+begin
+ if @FSourcePlugin.FVFSGetDirSize <> nil then Result := FSourcePlugin.FVFSGetDirSize(FGlobs, PChar(APath))
+ else Result := 0;
+end;
+
+procedure TVFSEngine.BreakProcessing(ProcessingKind: integer);
+begin
+ case ProcessingKind of
+ 1: if @FSourcePlugin.FVFSBreakGetDirSize <> nil then FSourcePlugin.FVFSBreakGetDirSize(FGlobs);
+ end;
+end;
+
+function TVFSEngine.GetBlockSize: Cardinal;
+begin
+ Result := FBlockSize;
+end;
+
+procedure TVFSEngine.SetBlockSize(Value: Cardinal);
+begin
+ if @FSourcePlugin.FVFSSetBlockSize <> nil then FSourcePlugin.FVFSSetBlockSize(FGlobs, Value);
+end;
+
+
+
+(********************************************************************************************************************************)
+function TVFSEngine.IsOnSameFS(const Path1, Path2: string): boolean;
+begin
+ if @FSourcePlugin.FVFSIsOnSameFS <> nil then Result := FSourcePlugin.FVFSIsOnSameFS(FGlobs, PChar(Path1), PChar(Path2))
+ else Result := True;
+end;
+
+function TVFSEngine.OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes;
+var i: integer;
+begin
+ if @FSourcePlugin.FVFSOpenFile <> nil then begin
+ Result := FSourcePlugin.FVFSOpenFile(FGlobs, PChar(APath), Mode, @i);
+ Error := i;
+ end else Result := nil;
+end;
+
+function TVFSEngine.ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer;
+var i: integer;
+begin
+ if @FSourcePlugin.FVFSReadFile <> nil then begin
+ Result := FSourcePlugin.FVFSReadFile(FGlobs, FileDescriptor, Buffer, ABlockSize, @i);
+ Error := i;
+ end else Result := -1;
+end;
+
+function TVFSEngine.WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer;
+var i: integer;
+begin
+ if @FSourcePlugin.FVFSWriteFile <> nil then begin
+ Result := FSourcePlugin.FVFSWriteFile(FGlobs, FileDescriptor, Buffer, BytesCount, @i);
+ Error := i;
+ end else Result := -1;
+end;
+
+function TVFSEngine.CloseFile(const FileDescriptor: TEngineFileDes): integer;
+begin
+ if @FSourcePlugin.FVFSCloseFile <> nil then Result := FSourcePlugin.FVFSCloseFile(FGlobs, FileDescriptor)
+ else Result := 0;
+end;
+
+function TVFSEngine.FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64;
+var i: integer;
+begin
+ if @FSourcePlugin.FVFSFileSeek <> nil then begin
+ Result := FSourcePlugin.FVFSFileSeek(FGlobs, FileDescriptor, AbsoluteOffset, @i);
+ Error := i;
+ end else Result := -1;
+end;
+
+function TVFSEngine.TwoSameFiles(const Path1, Path2: string): boolean;
+begin
+ if @FSourcePlugin.FVFSTwoSameFiles <> nil then Result := FSourcePlugin.FVFSTwoSameFiles(FGlobs, PChar(Path1), PChar(Path2))
+ else Result := False;
+end;
+
+
+
+(********************************************************************************************************************************)
+
+function VFSCopyCallBackFunc(iPos, iMax:Int64; data: Pointer): LongBool; cdecl;
+begin
+// DebugMsg(['VFSCopyCallBackFunc called (iPos = ', iPos, ', iMax = ', iMax, ')']);
+ Result := True;
+ if not Assigned(data) then Exit;
+ if Assigned(TVFSEngine(data).FProgressFunc) then
+ try
+ Result := TVFSEngine(data).FProgressFunc(TVFSEngine(data).FSenderThread, iPos);
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in VFSCopyCallBackFunc(iPos=', iPos, ', iMax=', iMax, ', data=', data, '): (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+function TVFSEngine.CopyFileOut(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean;
+var Res: TVFSResult;
+begin
+ try
+ if @FSourcePlugin.FVFSCopyOut <> nil then begin
+ FSenderThread := Sender;
+ FProgressFunc := ProgressFunc;
+// DebugMsg(['0 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$']);
+// DebugMsg([' Pointer(FGlobs) = 0x', IntToHex(Int64(FGlobs), 16), ', Pointer(@NewVFSCopyCallBackFunc) = 0x', IntToHex(Int64(@NewVFSCopyCallBackFunc), 16), ', Pointer(Self) = 0x', IntToHex(Int64(Self), 16)]);
+ try
+ Res := FSourcePlugin.FVFSCopyOut(FGlobs, PChar(SourceFile), PChar(DestFile), @VFSCopyCallBackFunc, Self, Append);
+ except
+ on E: Exception do begin
+ DebugMsg(['*** Exception raised in TVFSEngine.CopyFileOut(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]);
+ Res := cVFS_WriteErr;
+ end;
+ end;
+// DebugMsg(['1 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$']);
+ Result := Res = cVFS_OK;
+ if (Res <> cVFS_OK) and Assigned(ErrorFunc) then
+ case Res of
+ cVFS_ReadErr: Result := ErrorFunc(Sender, 6, 0, SourceFile);
+ cVFS_WriteErr: Result := ErrorFunc(Sender, 7, 0, DestFile);
+ cVFS_mallocFailed: ErrorFunc(Sender, 1, 0, SourceFile);
+ cVFS_Cancelled: Result := False;
+ end;
+ end else Result := False;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.CopyFileOut(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+function TVFSEngine.CopyFileIn(Sender: Pointer; SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean;
+var Res: TVFSResult;
+begin
+ try
+ if @FSourcePlugin.FVFSCopyIn <> nil then begin
+ FSenderThread := Sender;
+ FProgressFunc := ProgressFunc;
+ try
+ Res := FSourcePlugin.FVFSCopyIn(FGlobs, PChar(SourceFile), PChar(DestFile), @VFSCopyCallBackFunc, Self, Append);
+ except
+ on E: Exception do begin
+ DebugMsg(['*** Exception raised in TVFSEngine.CopyFileIn(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]);
+ Res := cVFS_WriteErr;
+ end;
+ end;
+ Result := Res = cVFS_OK;
+ if (Res <> cVFS_OK) and Assigned(ErrorFunc) then
+ case Res of
+ cVFS_ReadErr: Result := ErrorFunc(Sender, 6, 0, SourceFile);
+ cVFS_WriteErr: Result := ErrorFunc(Sender, 7, 0, DestFile);
+ cVFS_mallocFailed: ErrorFunc(Sender, 1, 0, SourceFile);
+ cVFS_Cancelled: Result := False;
+ end;
+ end else Result := False;
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.CopyFileIn(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+function TVFSEngine.SetPassword(Password: string): integer;
+begin
+ if @FSourcePlugin.FVFSSetPassword <> nil then Result := FSourcePlugin.FVFSSetPassword(FGlobs, PChar(Password))
+ else Result := 0;
+ FPassword := Password;
+end;
+
+function TVFSEngine.GetPasswordRequired: boolean;
+begin
+ if @FSourcePlugin.FVFSGetPasswordRequired <> nil then Result := FSourcePlugin.FVFSGetPasswordRequired(FGlobs)
+ else Result := False;
+end;
+
+procedure TVFSEngine.SetFPassword(Value: string);
+begin
+ SetPassword(Value);
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+function GetBinaryPath: string;
+var i: integer;
+ Buf: array[0..1024] of char;
+begin
+ Result := ParamStr(0); // Fallback
+ try
+ DebugMsg(['Trying to determine binary path...']);
+ DebugMsg(['Fallback path = ', Result]);
+ Buf[0] := #0;
+ FillChar(Buf, 1025, 0);
+ i := readlink(PChar(Format('/proc/%d/exe', [getpid])), @Buf, 1024);
+ if i < 1 then begin
+ DebugMsg(['Something went wrong during readlink: ', string(strerror(errno))]);
+ Exit;
+ end;
+ Buf[i] := #0;
+ Result := string(PChar(@Buf));
+ DebugMsg(['Path to executable = ', Result]);
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in GetBinaryPath: (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+
+procedure QueryModules(APath: string);
+var Handle: PDirectoryStream;
+ DirEnt: PDirent64;
+ s: string;
+ PluginItem: TVFSPlugin;
+ ModuleHandler: TModuleHandle;
+ VFSVersionFunc: TVFSVersion;
+ i: integer;
+ Buf: PChar;
+ b: boolean;
+begin
+ if Length(APath) < 1 then Exit;
+ try
+ try
+ APath := ReplaceStr(APath, '~', GetHomePath);
+ DebugMsg(['------------------ Querying modules in ', APath, ' ---']);
+
+ // First change to the program starting directory
+ if APath[1] <> '/' then begin
+ s := ExtractFilePath(BinaryPath);
+ DebugMsg(['----> Changing dir to ', s]);
+ i := __chdir(PChar(s));
+ if i <> 0 then DebugMsg(['Something went wrong during chdir: ', string(strerror(errno))]);
+ s := get_current_dir_name;
+ DebugMsg([' [II] Changed dir to ', s]);
+ end;
+
+ // Change to the required directory
+ s := APath;
+ DebugMsg(['----> Changing dir to ', s]);
+ i := __chdir(PChar(s));
+ if i <> 0 then begin
+ DebugMsg(['Something went wrong during chdir: ', string(strerror(errno))]);
+ Exit;
+ end;
+ s := get_current_dir_name;
+ DebugMsg([' [II] Changed dir to ', s, ', trying to list the files...']);
+
+ // Going to read the directory and search for the files...
+ Handle := opendir(PChar(s));
+ if not Assigned(Handle) then begin
+ DebugMsg(['Something went wrong during opendir: ', string(strerror(errno))]);
+ Exit;
+ end;
+ repeat
+ DirEnt := readdir64(Handle);
+ if Assigned(DirEnt) then begin
+ Buf := PChar(@DirEnt^.d_name[0]);
+ if Assigned(Buf) and (strcmp(Buf, '.') <> 0) and (strcmp(Buf, '..') <> 0) then
+ begin
+ DebugMsg(['$$$ Found ', Buf, ', trying to load...']);
+
+ // Try to find the plugin in the plugin list to prevent multiple plugin loading
+ b := False;
+ if PluginList.Count > 0 then
+ for i := 0 to PluginList.Count - 1 do
+ if CompareStr(TVFSPlugin(PluginList[i]).FullPath, IncludeTrailingPathDelimiter(s) + Buf) = 0 then begin
+ b := True;
+ Break;
+ end;
+
+ ModuleHandler := nil;
+ if b then DebugMsg(['Module ', s, ' is already loaded --> skipping...']) else
+ if not LoadModule(ModuleHandler, IncludeTrailingPathDelimiter(s) + Buf) then DebugMsg([' XXX Error loading module: ', dlerror])
+ else try
+ @VFSVersionFunc := GetModuleSymbol(ModuleHandler, 'VFSVersion');
+ if (@VFSVersionFunc <> nil) and (VFSVersionFunc >= ConstVFSVersionRequired) then begin
+ PluginItem := TVFSPlugin.Create(ModuleHandler);
+ PluginItem.FullPath := IncludeTrailingPathDelimiter(s) + Buf;
+ PluginList.Add(PluginItem);
+ end else DebugMsg([' $XXX: Error getting version info or version mismatch']);
+ except end;
+ end;
+ end;
+ until DirEnt = nil;
+ closedir(Handle);
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in QueryModules(APath = ', APath, '): (', E.ClassName, '): ', E.Message]);
+ end;
+ finally
+ DebugMsg(['------------------ Done querying modules ---------------']);
+ end;
+end;
+
+
+procedure UnloadModules;
+var i: integer;
+begin
+ if Assigned(PluginList) and (PluginList.Count > 0) then
+ for i := PluginList.Count - 1 downto 0 do
+ try
+ UnloadModule(TVFSPlugin(PluginList[i]).ModuleHandle);
+ TVFSPlugin(PluginList[i]).Free;
+ PluginList.Delete(i);
+ except
+ on E: Exception do DebugMsg(['*** Exception raised in UnloadModules(i = ', i, '): (', E.ClassName, '): ', E.Message]);
+ end;
+end;
+
+
+procedure DoInitPlugins;
+begin
+ PluginList := TList.Create;
+ if not ParamDisablePlugins then begin
+ BinaryPath := GetBinaryPath;
+ QueryModules(ConstGlobalModulePath1);
+ QueryModules(ConstGlobalModulePath2);
+ QueryModules(ConstLocalModulePath1);
+ QueryModules(ConstLocalModulePath2);
+ QueryModules(ConstLocalModulePath3);
+ end;
+end;
+
+initialization
+finalization
+ UnloadModules;
+ PluginList.Free;
+end.