mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-23 06:19:57 +00:00
733 lines
14 KiB
ObjectPascal
733 lines
14 KiB
ObjectPascal
unit sys_path;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
windows,
|
|
Classes,
|
|
SysUtils,
|
|
fileutil,
|
|
atomic,
|
|
RWLock,
|
|
ps4_program,
|
|
sys_kernel;
|
|
|
|
const
|
|
PT_ERR=-1;
|
|
PT_ROOT=0;
|
|
PT_FILE=1;
|
|
PT_DEV =2;
|
|
|
|
Function FetchSaveMount(path,point:PChar;mode:Integer):Integer;
|
|
Function UnMountSavePath(path:PChar):Integer;
|
|
|
|
Function FetchTmpMount(point:PChar;mode:Integer):Integer;
|
|
Function UnMountTmpPath(point:PChar):Integer;
|
|
Function FormatTmpPath(point:PChar):Integer;
|
|
|
|
Function GetTmpPathAvailableSpaceKb(point:PChar;size:PQWORD):Integer;
|
|
Function GetDownloadAvailableSpaceKb(point:PChar;size:PQWORD):Integer;
|
|
|
|
function parse_filename(filename:PChar;var r:RawByteString):Integer;
|
|
|
|
type
|
|
TFeDirCb=procedure(const S:RawByteString) of object;
|
|
|
|
Procedure ForEachRootDir(add_dir:TFeDirCb);
|
|
|
|
implementation
|
|
|
|
const
|
|
SCE_SAVE_DATA_ERROR_PARAMETER =-2137063424; // 0x809F0000
|
|
SCE_SAVE_DATA_ERROR_EXISTS =-2137063417; // 0x809F0007
|
|
SCE_SAVE_DATA_ERROR_NOT_FOUND =-2137063416; // 0x809f0008
|
|
SCE_SAVE_DATA_ERROR_MOUNT_FULL =-2137063412; // 0x809F000C
|
|
SCE_SAVE_DATA_ERROR_NOT_MOUNTED=-2137063420; // 0x809F0004
|
|
SCE_SAVE_DATA_ERROR_INTERNAL =-2137063413; // 0x809f000b
|
|
SCE_SAVE_DATA_ERROR_BUSY =-2137063421; // 0x809f0003
|
|
|
|
SCE_SAVE_DATA_MOUNT_MODE_RDONLY =1; //Read-only
|
|
SCE_SAVE_DATA_MOUNT_MODE_RDWR =2; //Read/write-enabled
|
|
SCE_SAVE_DATA_MOUNT_MODE_CREATE =4; //Create new (error if save data directory already exists)
|
|
SCE_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF=8; //Turn off corrupt flag (not recommended)
|
|
SCE_SAVE_DATA_MOUNT_MODE_COPY_ICON =16; //Copy save_data.png in package as icon when newly creating save data
|
|
SCE_SAVE_DATA_MOUNT_MODE_CREATE2 =32; //Create new (mount save data directory if it already exists)
|
|
|
|
DIRNAME_MAXSIZE=32;
|
|
MOUNT_MAXSIZE =16;
|
|
|
|
type
|
|
TMountDir=array[0..DIRNAME_MAXSIZE-1] of AnsiChar;
|
|
|
|
var
|
|
FSaveMounts_lock:TRWLock;
|
|
FSaveMounts:array[0..15] of TMountDir;
|
|
|
|
FTmpMount:Integer=0;
|
|
|
|
Procedure DoFixRelative(var Path:RawByteString);
|
|
Var
|
|
i,L,CF,PF:SizeInt;
|
|
|
|
Procedure _c; inline;
|
|
begin
|
|
Case (i-CF) of
|
|
2:if (PWORD(@Path[CF])^=$2E2E) then //..
|
|
begin
|
|
i:=i-PF+1;
|
|
Delete(Path,PF,i);
|
|
L:=Length(Path);
|
|
CF:=PF;
|
|
i:=PF-1;
|
|
end;
|
|
1:if (Path[CF]='.') then //.
|
|
begin
|
|
i:=(i-CF)+1;
|
|
Delete(Path,CF,i);
|
|
L:=Length(Path);
|
|
i:=CF-1;
|
|
end;
|
|
end;
|
|
PF:=CF;
|
|
CF:=i+1;
|
|
end;
|
|
|
|
begin
|
|
PF:=1;
|
|
CF:=1;
|
|
i:=1;
|
|
L:=Length(Path);
|
|
While (i<=L) do
|
|
begin
|
|
if (Path[i]='/') then _c;
|
|
Inc(i);
|
|
end;
|
|
_c;
|
|
end;
|
|
|
|
Procedure DoDirSeparators(var Path:RawByteString); inline;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
if ('/'<>DirectorySeparator) and (Path<>'') then
|
|
For i:=1 to Length(Path) do
|
|
if (Path[i]='/') then Path[i]:=DirectorySeparator;
|
|
end;
|
|
|
|
Function IsSep(c:AnsiChar):Boolean; inline;
|
|
begin
|
|
Result:=False;
|
|
Case c of
|
|
'\',
|
|
'/':Result:=True;
|
|
end;
|
|
end;
|
|
|
|
function IncludeTrailingPathDelimiter(Const Path:RawByteString):RawByteString; inline;
|
|
begin
|
|
Result:=Path;
|
|
if (Result='') or (not IsSep(Result[Length(Result)])) then Result:=Result+DirectorySeparator;
|
|
end;
|
|
|
|
function PathConcat(Path,filename:RawByteString;var r:RawByteString):Integer;
|
|
begin
|
|
Path:=Trim(Path);
|
|
If (Path='') then Exit(PT_ERR);
|
|
if (not IsSep(Path[Length(Path)])) then Path:=Path+DirectorySeparator;
|
|
DoDirSeparators(filename);
|
|
r:=Path+filename;
|
|
Result:=PT_FILE;
|
|
end;
|
|
|
|
Function FetchSaveMount(path,point:PChar;mode:Integer):Integer;
|
|
var
|
|
sp:RawByteString;
|
|
s:TMountDir;
|
|
i,m:Integer;
|
|
Label
|
|
_exit;
|
|
begin
|
|
Result:=0;
|
|
if (path=nil) or (point=nil) then Exit(SCE_SAVE_DATA_ERROR_PARAMETER);
|
|
|
|
s:=Default(TMountDir);
|
|
MoveChar0(path^,s,DIRNAME_MAXSIZE);
|
|
|
|
i:=IndexChar(s,MOUNT_MAXSIZE,#0);
|
|
if (i=0) then Exit(SCE_SAVE_DATA_ERROR_PARAMETER);
|
|
|
|
sp:=IncludeTrailingPathDelimiter(ps4_app.save_path)+s;
|
|
|
|
if (mode and SCE_SAVE_DATA_MOUNT_MODE_CREATE2)<>0 then
|
|
begin
|
|
if not ForceDirectories(ps4_app.save_path) then Exit(SCE_SAVE_DATA_ERROR_INTERNAL);
|
|
CreateDir(sp);
|
|
end else
|
|
if (mode and SCE_SAVE_DATA_MOUNT_MODE_CREATE)<>0 then
|
|
begin
|
|
if not ForceDirectories(ps4_app.save_path) then Exit(SCE_SAVE_DATA_ERROR_INTERNAL);
|
|
//if not CreateDir(sp) then Exit(SCE_SAVE_DATA_ERROR_EXISTS);
|
|
CreateDir(sp);
|
|
end else
|
|
begin
|
|
if not DirectoryExists(sp) then Exit(SCE_SAVE_DATA_ERROR_NOT_FOUND);
|
|
end;
|
|
|
|
rwlock_wrlock(FSaveMounts_lock);
|
|
|
|
m:=-1;
|
|
For i:=0 to 15 do
|
|
begin
|
|
if (FSaveMounts[i]='') then
|
|
begin
|
|
if (m=-1) then m:=i;
|
|
end else
|
|
begin
|
|
if (FSaveMounts[i]=s) then
|
|
begin
|
|
Result:=SCE_SAVE_DATA_ERROR_BUSY;
|
|
goto _exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if (m<>-1) then
|
|
begin
|
|
FSaveMounts[m]:=s;
|
|
s:='/savedata'+IntToStr(m);
|
|
Move(s,point^,MOUNT_MAXSIZE);
|
|
end else
|
|
begin
|
|
Result:=SCE_SAVE_DATA_ERROR_MOUNT_FULL;
|
|
end;
|
|
|
|
_exit:
|
|
rwlock_unlock(FSaveMounts_lock);
|
|
end;
|
|
|
|
Function UnMountId(id:Byte):Integer;
|
|
begin
|
|
Result:=0;
|
|
rwlock_wrlock(FSaveMounts_lock);
|
|
|
|
if (FSaveMounts[id]<>'') then
|
|
begin
|
|
FSaveMounts[id]:='';
|
|
end else
|
|
begin
|
|
Result:=SCE_SAVE_DATA_ERROR_NOT_MOUNTED;
|
|
end;
|
|
|
|
rwlock_unlock(FSaveMounts_lock);
|
|
end;
|
|
|
|
Function UnMountSavePath(path:PChar):Integer;
|
|
var
|
|
s:TMountDir;
|
|
i:Integer;
|
|
begin
|
|
Result:=SCE_SAVE_DATA_ERROR_PARAMETER;
|
|
if (path=nil) then Exit;
|
|
|
|
s:=Default(TMountDir);
|
|
MoveChar0(path^,s,MOUNT_MAXSIZE);
|
|
|
|
if (s[0]<>'/') then Exit;
|
|
|
|
i:=IndexChar(s,MOUNT_MAXSIZE,#0);
|
|
|
|
Case i of
|
|
10:Case PQWORD(@s[1])^ of
|
|
$6174616465766173: //savedata
|
|
begin
|
|
Case s[9] of
|
|
'0'..'9':
|
|
begin
|
|
Result:=UnMountId(ord(s[9])-ord('0'));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
11:Case PQWORD(@s[1])^ of
|
|
$6174616465766173: //savedata
|
|
begin
|
|
Case PWORD(PBYTE(@s)+9)^ of
|
|
$3031, //10
|
|
$3131, //11
|
|
$3231, //12
|
|
$3331, //13
|
|
$3431, //14
|
|
$3531: //15
|
|
begin
|
|
Result:=UnMountId(ord(s[10])-ord('0')+10);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
//
|
|
|
|
Function GetSaveMount(id:Byte):RawByteString;
|
|
begin
|
|
rwlock_rdlock(FSaveMounts_lock);
|
|
Result:=FSaveMounts[id];
|
|
rwlock_unlock(FSaveMounts_lock);
|
|
end;
|
|
|
|
// /app0
|
|
// /savedata0
|
|
// /savedata15
|
|
|
|
function MountSaveConcat(id:Byte;const filename:RawByteString;var r:RawByteString):Integer;
|
|
var
|
|
s:RawByteString;
|
|
begin
|
|
s:=GetSaveMount(id);
|
|
if (s='') then Exit(PT_ERR);
|
|
|
|
s:=IncludeTrailingPathDelimiter(ps4_app.save_path)+s;
|
|
|
|
Result:=PathConcat(s,filename,r);
|
|
end;
|
|
|
|
//
|
|
|
|
const
|
|
SCE_APP_CONTENT_ERROR_PARAMETER =-2133262334; //0x80D90002
|
|
SCE_APP_CONTENT_ERROR_BUSY =-2133262333; //0x80D90003
|
|
SCE_APP_CONTENT_ERROR_NOT_MOUNTED=-2133262332; //0x80D90004
|
|
SCE_APP_CONTENT_ERROR_INTERNAL =-2133262326; //0x80D9000A
|
|
|
|
function temp_path:RawByteString;
|
|
begin
|
|
Result:=IncludeTrailingPathDelimiter(GetCurrentDir)+'tmp';
|
|
end;
|
|
|
|
function download_path(id:Byte):RawByteString;
|
|
begin
|
|
Result:=IncludeTrailingPathDelimiter(GetCurrentDir)+'download'+IntToStr(id);
|
|
end;
|
|
|
|
Function FetchTmpMount(point:PChar;mode:Integer):Integer;
|
|
var
|
|
S:RawByteString;
|
|
begin
|
|
if (point=nil) then Exit(SCE_APP_CONTENT_ERROR_PARAMETER);
|
|
|
|
Case mode of
|
|
0:;
|
|
1:;
|
|
else
|
|
Exit(SCE_APP_CONTENT_ERROR_PARAMETER);
|
|
end;
|
|
|
|
if not CAS(FTmpMount,0,1) then Exit(SCE_APP_CONTENT_ERROR_BUSY);
|
|
|
|
//temp0#0
|
|
PDWORD(point)[0]:=$706D6574; //temp
|
|
PDWORD(point)[1]:=$00000030; //0#0
|
|
|
|
S:=temp_path;
|
|
|
|
if (mode=1) then //format
|
|
begin
|
|
DeleteDirectory(S,False);
|
|
end;
|
|
|
|
CreateDir(S);
|
|
|
|
XCHG(FTmpMount,2);
|
|
Result:=0;
|
|
end;
|
|
|
|
function _is_temp0(P:Pointer):Boolean; inline;
|
|
begin
|
|
Result:=(PDWORD(P)[0]=$706D6574) and ((PDWORD(P)[1] and $FFFF)=$0030);
|
|
end;
|
|
|
|
Function UnMountTmpPath(point:PChar):Integer;
|
|
begin
|
|
if (point=nil) then Exit(SCE_APP_CONTENT_ERROR_PARAMETER);
|
|
|
|
if not _is_temp0(point) then
|
|
begin
|
|
Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
end;
|
|
|
|
if not CAS(FTmpMount,2,0) then Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
Function FormatTmpPath(point:PChar):Integer;
|
|
var
|
|
S:RawByteString;
|
|
begin
|
|
if (point=nil) then Exit(SCE_APP_CONTENT_ERROR_PARAMETER);
|
|
|
|
if not _is_temp0(point) then
|
|
begin
|
|
Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
end;
|
|
|
|
if (FTmpMount<>2) then Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
|
|
S:=temp_path;
|
|
DeleteDirectory(S,False);
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function MountTmpConcat(const filename:RawByteString;var r:RawByteString):Integer;
|
|
var
|
|
S:RawByteString;
|
|
begin
|
|
if (FTmpMount<>2) then Exit(PT_ERR);
|
|
|
|
S:=temp_path;
|
|
|
|
Result:=PathConcat(s,filename,r);
|
|
end;
|
|
|
|
Function GetTmpPathAvailableSpaceKb(point:PChar;size:PQWORD):Integer;
|
|
var
|
|
S:RawByteString;
|
|
W:WideString;
|
|
bytes:Int64;
|
|
begin
|
|
if (point=nil) then Exit(SCE_APP_CONTENT_ERROR_PARAMETER);
|
|
|
|
if not _is_temp0(point) then
|
|
begin
|
|
Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
end;
|
|
|
|
if (FTmpMount<>2) then Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
|
|
S:=temp_path;
|
|
W:=UTF8Decode(S);
|
|
|
|
if GetDiskFreeSpaceExW(PWideChar(W),@bytes,nil,nil) then
|
|
begin
|
|
size^:=bytes div 1024;
|
|
Result:=0;
|
|
end else
|
|
begin
|
|
Result:=SCE_APP_CONTENT_ERROR_INTERNAL;
|
|
end;
|
|
end;
|
|
|
|
function _is_download(P:Pointer):Integer; inline;
|
|
begin
|
|
Result:=-1;
|
|
if (PQWORD(P)^=$64616F6C6E776F64) then //download
|
|
begin
|
|
Case PChar(P)[8] of
|
|
'0'..'1':Result:=ord(PChar(P)[8])-ord('0');
|
|
else;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Function GetDownloadAvailableSpaceKb(point:PChar;size:PQWORD):Integer;
|
|
var
|
|
S:RawByteString;
|
|
W:WideString;
|
|
bytes:Int64;
|
|
i:Integer;
|
|
begin
|
|
if (point=nil) then Exit(SCE_APP_CONTENT_ERROR_PARAMETER);
|
|
|
|
i:=_is_download(point);
|
|
|
|
if (i=-1) then
|
|
begin
|
|
Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
end;
|
|
|
|
if (FTmpMount<>2) then Exit(SCE_APP_CONTENT_ERROR_NOT_MOUNTED);
|
|
|
|
S:=download_path(i);
|
|
W:=UTF8Decode(S);
|
|
|
|
if GetDiskFreeSpaceExW(PWideChar(W),@bytes,nil,nil) then
|
|
begin
|
|
size^:=bytes div 1024;
|
|
Result:=0;
|
|
end else
|
|
begin
|
|
Result:=SCE_APP_CONTENT_ERROR_INTERNAL;
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
function MountDownloadConcat(id:Byte;force:Boolean;const filename:RawByteString;var r:RawByteString):Integer;
|
|
var
|
|
S:RawByteString;
|
|
begin
|
|
Case id of
|
|
0..1:;
|
|
else
|
|
Exit(PT_ERR);
|
|
end;
|
|
|
|
//param.sfo download size TODO
|
|
S:=download_path(id);
|
|
|
|
if force then
|
|
begin
|
|
if not ForceDirectories(S) then Exit(PT_ERR);
|
|
end;
|
|
|
|
Result:=PathConcat(S,filename,r);
|
|
end;
|
|
|
|
function MountMiscConcat(const dir,filename:RawByteString;var r:RawByteString):Integer;
|
|
var
|
|
s:RawByteString;
|
|
begin
|
|
s:=IncludeTrailingPathDelimiter(GetCurrentDir)+dir;
|
|
|
|
Result:=PathConcat(s,filename,r);
|
|
end;
|
|
|
|
Procedure ForEachRootDir(add_dir:TFeDirCb);
|
|
var
|
|
i:Integer;
|
|
r:RawByteString;
|
|
begin
|
|
if (add_dir=nil) then Exit;
|
|
|
|
add_dir('.');
|
|
add_dir('..');
|
|
add_dir('app0');
|
|
|
|
if (ps4_app.app1_path<>'') then
|
|
begin
|
|
add_dir('app1');
|
|
end;
|
|
|
|
r:='';
|
|
if (MountMiscConcat('data','',r)=PT_FILE) then
|
|
if DirectoryExists(r) then
|
|
begin
|
|
add_dir('data');
|
|
end;
|
|
|
|
add_dir('dev');
|
|
|
|
For i:=0 to 15 do
|
|
begin
|
|
r:='';
|
|
if (MountDownloadConcat(i,False,'',r)=PT_FILE) then
|
|
if DirectoryExists(r) then
|
|
begin
|
|
add_dir('download'+IntToStr(i));
|
|
end;
|
|
end;
|
|
|
|
For i:=0 to 1 do
|
|
begin
|
|
r:='';
|
|
if (MountSaveConcat(i,'',r)=PT_FILE) then
|
|
if DirectoryExists(r) then
|
|
begin
|
|
add_dir('savedata'+IntToStr(i));
|
|
end;
|
|
end;
|
|
|
|
add_dir('sys'); //aka sceKernelGetFsSandboxRandomWord
|
|
|
|
r:='';
|
|
if (MountTmpConcat('',r)=PT_FILE) then
|
|
if DirectoryExists(r) then
|
|
begin
|
|
add_dir('temp0');
|
|
end;
|
|
|
|
r:='';
|
|
if (MountMiscConcat('usr','',r)=PT_FILE) then
|
|
if DirectoryExists(r) then
|
|
begin
|
|
add_dir('usr');
|
|
end;
|
|
|
|
end;
|
|
|
|
//
|
|
|
|
const
|
|
PT_NEXT=PT_ROOT;
|
|
|
|
function _parse_cast(var pp,fp:PChar;var r:RawByteString):Integer;
|
|
begin
|
|
Result:=PT_NEXT;
|
|
Case (fp-pp) of
|
|
0:if (fp^<>#0) then pp:=fp+1; //next
|
|
3:Case (PDWORD(pp)^ and $00FFFFFF) of
|
|
$00766564: //dev
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
r:=fp;
|
|
Result:=PT_DEV;
|
|
end;
|
|
$00727375: //usr
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=MountMiscConcat('usr',fp,r);
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
4:Case PDWORD(pp)^ of
|
|
$30707061: //app0
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
|
|
//easy way to patch apply
|
|
Result:=PathConcat(ps4_app.app1_path,fp,r);
|
|
if (Result<>PT_ERR) then
|
|
if FileExists(r) then
|
|
begin
|
|
Exit; //done
|
|
end;
|
|
|
|
Result:=PathConcat(ps4_app.app0_path,fp,r);
|
|
end;
|
|
$31707061: //app1
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=PathConcat(ps4_app.app1_path,fp,r);
|
|
end;
|
|
$61746164: //data
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=MountMiscConcat('data',fp,r);
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
5:Case PDWORD(pp)^ of
|
|
$706D6574: //temp
|
|
begin
|
|
Case (pp+4)^ of
|
|
'0':
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=MountTmpConcat(fp,r);
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
9:Case PQWORD(pp)^ of
|
|
$64616F6C6E776F64: //download
|
|
begin
|
|
Case (pp+8)^ of
|
|
'0'..'1':
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=MountDownloadConcat(ord((pp+8)^)-ord('0'),True,fp,r);
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
end;
|
|
$6174616465766173: //savedata
|
|
begin
|
|
Case (pp+8)^ of
|
|
'0'..'9':
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=MountSaveConcat(ord((pp+8)^)-ord('0'),fp,r);
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
10:Case PQWORD(pp)^ of
|
|
$6174616465766173: //savedata
|
|
begin
|
|
Case PWORD(pp+8)^ of
|
|
$3031, //10
|
|
$3131, //11
|
|
$3231, //12
|
|
$3331, //13
|
|
$3431, //14
|
|
$3531: //15
|
|
begin
|
|
if (fp^<>#0) then Inc(fp);
|
|
Result:=MountSaveConcat(ord((pp+9)^)-ord('0')+10,fp,r);
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
end;
|
|
else
|
|
Result:=PT_ERR;
|
|
end;
|
|
else
|
|
begin
|
|
if (fp^=#0) then //root???
|
|
begin
|
|
r:=pp;
|
|
Result:=PT_ROOT;
|
|
end else
|
|
begin
|
|
//Writeln((fp-pp),'*',fp,'*',pp);
|
|
Result:=PT_ERR;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function parse_filename(filename:PChar;var r:RawByteString):Integer;
|
|
var
|
|
Path:RawByteString;
|
|
pp,fp:PChar;
|
|
|
|
begin
|
|
r:='';
|
|
//Writeln(filename);
|
|
if (filename=nil) then Exit(EINVAL);
|
|
|
|
Path:=filename;
|
|
DoFixRelative(Path);
|
|
fp:=PChar(Path);
|
|
pp:=PChar(Path);
|
|
|
|
While (fp^<>#0) do
|
|
begin
|
|
Case fp^ of
|
|
'/':
|
|
begin
|
|
Result:=_parse_cast(pp,fp,r);
|
|
if (Result<>PT_NEXT) then Exit;
|
|
end;
|
|
end;
|
|
Inc(fp);
|
|
end;
|
|
|
|
Result:=_parse_cast(pp,fp,r);
|
|
end;
|
|
|
|
initialization
|
|
rwlock_init(FSaveMounts_lock);
|
|
|
|
end.
|
|
|
|
|