|
- unit uvfsTarArchive;
-
- {$mode objfpc}{$H+}
-
- interface
-
- uses
- Classes, SysUtils, libtar, syncobjs,
-
- uvfsManager;
-
- type
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- TvfsTarArchive = class(TvfsProvider)
- private
- fStream: TStream;
- fOwnsStream: Boolean;
- fFileSpec: String;
- fTar: TTarArchive;
- fTarCS: TCriticalSection;
-
- private
- function FindFile(const aFilename: String; out aRec: TTarDirRec): Boolean;
- function PrepareFilename(const aFilename: String): String;
-
- public { TvfsProvider }
- class function StorageName: string; override;
-
- public { TvfsProvider }
- function StorageGetFileSpec: string; override;
- function GetFileInfo(const FileName: string; out FileInfo: TvfsFileInfo): Boolean; override;
- function Open(const FileName: string; const OpenMode: TvfsFileOpenMode; out Stream: IStreamHandle): boolean; override;
- function Rename(const OldName, NewName: string): boolean; override;
- function Delete(const aName: String): boolean; override;
- procedure DirectoryIndex(AddFunction: TvfsDirectoryAddFunc; List: TvfsDirectoryList; Path: string; Subdirs: boolean); override;
-
- public
- constructor Create(const FileSpec: string; const ExtendedData: string = ''); override;
- constructor Create(const aStream: TStream; const aOwnsStream: Boolean);
- destructor Destroy; override;
- end;
-
-
- implementation
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //TvfsTarArchive////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.FindFile(const aFilename: String; out aRec: TTarDirRec): Boolean;
- var
- fn: String;
- begin
- fn := PrepareFilename(aFilename);
- fTar.Reset;
- result := true;
- while fTar.FindNext(aRec{%H-}) do begin
- if (aRec.Name = fn) then
- exit;
- end;
- result := false;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.PrepareFilename(const aFilename: String): String;
- var
- sl: TStringList;
- i: Integer;
- begin
- sl := TStringList.Create;
- try
- sl.Delimiter := VFS_PATH_DELIM;
- sl.StrictDelimiter := true;
- sl.DelimitedText := vfsVirtualPathDelim(aFilename);
- i := 0;
- while (i < sl.Count) do begin
- if (sl[i] = '..') and (i > 0) then begin
- sl.Delete(i);
- dec(i);
- sl.Delete(i);
- end else
- inc(i);
- end;
- result := sl.DelimitedText;
- finally
- FreeAndNil(sl);
- end;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- class function TvfsTarArchive.StorageName: string;
- begin
- result := 'tar';
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.StorageGetFileSpec: string;
- begin
- result := fFileSpec;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.GetFileInfo(const FileName: string; out FileInfo: TvfsFileInfo): Boolean;
- var
- rec: TTarDirRec;
- begin
- result := FindFile(FileName, rec);
- if result then begin
- FileInfo.Size := rec.Size;
- FileInfo.ModDate := rec.DateTime;
- FileInfo.Attributes := 0;
- end;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.Open(const FileName: string; const OpenMode: TvfsFileOpenMode; out Stream: IStreamHandle): boolean;
- var
- ms: TMemoryStream;
- rec: TTarDirRec;
- begin
- result := false;
- fTarCS.Enter;
- try
- if not FindFile(FileName, rec) then
- exit;
-
- ms := TMemoryStream.Create;
- fTar.ReadFile(ms);
-
- case OpenMode of
- omReadOnly: begin
- ms.Position := 0;
- Stream := TvfsStreamHandleRead.Create(ms);
- end;
- else
- raise ENotSupportedException.Create('tar archive only supports read operations');
- end;
-
- result := Assigned(Stream);
- if not result then
- FreeAndNil(ms);
- finally
- fTarCS.Leave;
- end;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.Rename(const OldName, NewName: string): boolean;
- begin
- result := false;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TvfsTarArchive.Delete(const aName: String): boolean;
- begin
- result := false;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- procedure TvfsTarArchive.DirectoryIndex(AddFunction: TvfsDirectoryAddFunc; List: TvfsDirectoryList; Path: string; Subdirs: boolean);
- var
- rec: TTarDirRec;
- dirOK: Boolean;
- fp: String;
- a: TvfsDirectoryEntry;
- begin
- fTarCS.Enter;
- try
- fTar.Reset;
- while fTar.FindNext(rec{%H-}) do begin
- fp := ExtractFilePath(rec.Name);
- if Subdirs then
- dirOK := (AnsiCompareStr(Path, copy(fp, 1, Length(Path))) = 0)
- else
- dirOk := (AnsiCompareFileName(Path, fp) = 0);
-
- if dirOK then begin
- a := TvfsDirectoryEntry.Create;
- a.FileInfo.Size := rec.Size;
- a.FileInfo.ModDate := rec.DateTime;
- a.FileInfo.Attributes := 0;
- AddFunction(rec.Name, a, List);
- end;
- end;
- finally
- fTarCS.Leave;
- end;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- constructor TvfsTarArchive.Create(const FileSpec: string; const ExtendedData: string);
- var
- fs: TFileStream;
- begin
- fFileSpec := FileSpec;
- if not FileExists(fFileSpec) then
- EFileNotFoundException.Create(fFileSpec);
- fs := TFileStream.Create(fFileSpec, fmOpenRead);
- Create(fs, true);
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- constructor TvfsTarArchive.Create(const aStream: TStream; const aOwnsStream: Boolean);
- begin
- inherited Create('', '');
- fOwnsStream := aOwnsStream;
- fStream := aStream;
- fTar := TTarArchive.Create(fStream);
- fTarCS := TCriticalSection.Create;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- destructor TvfsTarArchive.Destroy;
- begin
- FreeAndNil(fTar);
- FreeAndNil(fTarCS);
- if (fOwnsStream) then
- FreeAndNil(fStream);
- inherited Destroy;
- end;
-
- initialization
- vfsManager.RegisterProvider(TvfsTarArchive);
-
- end.
|