mirror of https://github.com/red-prig/fpPS4.git
256 lines
5.5 KiB
Plaintext
256 lines
5.5 KiB
Plaintext
unit devfs;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
devfs_int,
|
|
mqueue,
|
|
kern_param,
|
|
vnode,
|
|
vmount,
|
|
sys_conf,
|
|
kern_mtx;
|
|
|
|
function rid2rsn(rid:devfs_rid):devfs_rsnum;
|
|
function rid2rn (rid:devfs_rid):devfs_rnum;
|
|
function mkrid (rsn:devfs_rsnum;rn:devfs_rnum):devfs_rid;
|
|
|
|
procedure DEVFS_DE_HOLD(de:p_devfs_dirent);
|
|
function DEVFS_DE_DROP(de:p_devfs_dirent):Boolean;
|
|
|
|
procedure DEVFS_DMP_HOLD(dmp:p_devfs_mount);
|
|
function DEVFS_DMP_DROP(dmp:p_devfs_mount):Boolean;
|
|
|
|
//
|
|
|
|
function devfs_dir_find(path:PChar):Integer;
|
|
procedure devfs_dir_ref_de(dm:p_devfs_mount;de:p_devfs_dirent);
|
|
procedure devfs_dir_unref_de(dm:p_devfs_mount;de:p_devfs_dirent);
|
|
function devfs_pathpath(p1,p2:PChar):Integer;
|
|
procedure devfs_mtx_init;
|
|
|
|
procedure devfs_rules_apply(dm:p_devfs_mount;de:p_devfs_dirent); external;
|
|
procedure devfs_rules_cleanup(dm:p_devfs_mount); external;
|
|
function devfs_rules_ioctl(dm:p_devfs_mount;cmd:QWORD;data:Pointer):Integer; external;
|
|
|
|
procedure devfs_ruleset_set(rsnum:devfs_rsnum;dm:p_devfs_mount); external;
|
|
procedure devfs_ruleset_apply(dm:p_devfs_mount); external;
|
|
function devfs_allocv(de:p_devfs_dirent;mp:p_mount;lockmode:Integer;vpp:pp_vnode):Integer; external;
|
|
function devfs_fqpn(buf:PChar;dmp:p_devfs_mount;dd:p_devfs_dirent;cnp:Pointer):PChar; external;
|
|
|
|
procedure devfs_delete(dm:p_devfs_mount;de:p_devfs_dirent;flags:Integer); external;
|
|
procedure devfs_dirent_free(de:p_devfs_dirent); external;
|
|
procedure devfs_populate(dm:p_devfs_mount); external;
|
|
procedure devfs_cleanup(dm:p_devfs_mount); external;
|
|
|
|
procedure devfs_unmount_final(fmp:p_devfs_mount); external;
|
|
|
|
function devfs_newdirent(name:PChar;namelen:Integer):p_devfs_dirent; external;
|
|
function devfs_parent_dirent(de:p_devfs_dirent):p_devfs_dirent; external;
|
|
function devfs_vmkdir(dmp:p_devfs_mount;
|
|
name:PChar;namelen:Integer;
|
|
dotdot:p_devfs_dirent;
|
|
inode:DWORD):p_devfs_dirent; external;
|
|
function devfs_find(dd:p_devfs_dirent;
|
|
name:PChar;namelen:Integer;
|
|
_type:Integer):p_devfs_dirent; external;
|
|
|
|
implementation
|
|
|
|
{
|
|
* Identifier manipulators.
|
|
}
|
|
function rid2rsn(rid:devfs_rid):devfs_rsnum;
|
|
begin
|
|
Result:=rid shr 16;
|
|
end;
|
|
|
|
function rid2rn(rid:devfs_rid):devfs_rnum;
|
|
begin
|
|
Result:=rid and $ffff;
|
|
end;
|
|
|
|
function mkrid(rsn:devfs_rsnum;rn:devfs_rnum):devfs_rid;
|
|
begin
|
|
Result:=rn or (rsn shl 16);
|
|
end;
|
|
|
|
procedure DEVFS_DE_HOLD(de:p_devfs_dirent);
|
|
begin
|
|
Inc(de^.de_holdcnt);
|
|
end;
|
|
|
|
function DEVFS_DE_DROP(de:p_devfs_dirent):Boolean;
|
|
begin
|
|
Dec(de^.de_holdcnt);
|
|
Result:=(de^.de_holdcnt=0);
|
|
end;
|
|
|
|
procedure DEVFS_DMP_HOLD(dmp:p_devfs_mount);
|
|
begin
|
|
Inc(dmp^.dm_holdcnt);
|
|
end;
|
|
|
|
function DEVFS_DMP_DROP(dmp:p_devfs_mount):Boolean;
|
|
begin
|
|
Dec(dmp^.dm_holdcnt);
|
|
Result:=(dmp^.dm_holdcnt=0);
|
|
end;
|
|
|
|
//
|
|
|
|
{ Exits 1 if the path is in the directory list. }
|
|
function devfs_dir_find(path:PChar):Integer; public;
|
|
var
|
|
dle:p_dirlistent;
|
|
begin
|
|
mtx_lock(dirlist_mtx);
|
|
|
|
dle:=LIST_FIRST(@devfs_dirlist);
|
|
while (dle<>nil) do
|
|
begin
|
|
if (devfs_pathpath(dle^.dir, path)<>0) then
|
|
begin
|
|
mtx_unlock(dirlist_mtx);
|
|
Exit(1);
|
|
end;
|
|
//
|
|
dle:=LIST_NEXT(dle,@dle^.link);
|
|
end;
|
|
mtx_unlock(dirlist_mtx);
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
function devfs_dir_findent_locked(dir:PChar):p_dirlistent;
|
|
var
|
|
dle:p_dirlistent;
|
|
begin
|
|
mtx_assert(dirlist_mtx);
|
|
|
|
dle:=LIST_FIRST(@devfs_dirlist);
|
|
while (dle<>nil) do
|
|
begin
|
|
if (strcomp(dir, dle^.dir)=0) then
|
|
Exit(dle);
|
|
//
|
|
dle:=LIST_NEXT(dle,@dle^.link);
|
|
end;
|
|
|
|
Exit(nil);
|
|
end;
|
|
|
|
function strdup(src:PChar):PChar; inline;
|
|
var
|
|
i:ptrint;
|
|
begin
|
|
i:=strlen(src);
|
|
Result:=AllocMem(i+1);
|
|
Move(src^,Result^,i);
|
|
end;
|
|
|
|
procedure devfs_dir_ref(dir:PChar);
|
|
var
|
|
dle,dle_new:p_dirlistent;
|
|
begin
|
|
if (dir^=#0) then Exit;
|
|
|
|
dle_new:=AllocMem(sizeof(t_dirlistent));
|
|
dle_new^.dir:=strdup(dir);
|
|
dle_new^.refcnt:=1;
|
|
|
|
mtx_lock(dirlist_mtx);
|
|
dle:=devfs_dir_findent_locked(dir);
|
|
if (dle<>nil) then
|
|
begin
|
|
Inc(dle^.refcnt);
|
|
mtx_unlock(dirlist_mtx);
|
|
FreeMem(dle_new^.dir);
|
|
FreeMem(dle_new);
|
|
Exit;
|
|
end;
|
|
LIST_INSERT_HEAD(@devfs_dirlist,dle_new,@dle_new^.link);
|
|
mtx_unlock(dirlist_mtx);
|
|
end;
|
|
|
|
procedure devfs_dir_ref_de(dm:p_devfs_mount;de:p_devfs_dirent);
|
|
var
|
|
dirname:array[0..SPECNAMELEN] of AnsiChar;
|
|
namep:PChar;
|
|
begin
|
|
namep:=devfs_fqpn(dirname, dm, de, nil);
|
|
Assert(namep<>nil,'devfs_ref_dir_de: nil namep');
|
|
|
|
devfs_dir_ref(namep);
|
|
end;
|
|
|
|
procedure devfs_dir_unref(dir:PChar);
|
|
var
|
|
dle:p_dirlistent;
|
|
begin
|
|
if (dir^=#0) then Exit;
|
|
|
|
mtx_lock(dirlist_mtx);
|
|
dle:=devfs_dir_findent_locked(dir);
|
|
Assert(dle<>nil, 'devfs_dir_unref: dir %s not referenced');
|
|
Dec(dle^.refcnt);
|
|
Assert(dle^.refcnt >= 0, 'devfs_dir_unref: negative refcnt');
|
|
if (dle^.refcnt=0) then
|
|
begin
|
|
LIST_REMOVE(dle,@dle^.link);
|
|
mtx_unlock(dirlist_mtx);
|
|
FreeMem(dle^.dir);
|
|
FreeMem(dle);
|
|
end else
|
|
begin
|
|
mtx_unlock(dirlist_mtx);
|
|
end;
|
|
end;
|
|
|
|
procedure devfs_dir_unref_de(dm:p_devfs_mount;de:p_devfs_dirent); public;
|
|
var
|
|
dirname:array[0..SPECNAMELEN] of AnsiChar;
|
|
namep:PChar;
|
|
begin
|
|
namep:=devfs_fqpn(dirname, dm, de, nil);
|
|
Assert(namep<>nil, 'devfs_unref_dir_de: nil namep');
|
|
|
|
devfs_dir_unref(namep);
|
|
end;
|
|
|
|
{ Exits 1 if the path p1 contains the path p2. }
|
|
function devfs_pathpath(p1,p2:PChar):Integer; public;
|
|
begin
|
|
repeat
|
|
if (p1^<>p2^) then
|
|
begin
|
|
if (p1^='/') and (p2^=#0) then
|
|
Exit(1)
|
|
else
|
|
Exit(0);
|
|
end else
|
|
if (p1^=#0) then
|
|
Exit(1);
|
|
Inc(p1);
|
|
Inc(p2);
|
|
until false;
|
|
{ NOTREACHED }
|
|
end;
|
|
|
|
procedure devfs_mtx_init;
|
|
begin
|
|
mtx_init(devmtx,'cdev');
|
|
mtx_init(dirlist_mtx,'devfs dirlist lock');
|
|
mtx_init(devfs_de_interlock,'devfs interlock');
|
|
mtx_init(cdevpriv_mtx,'cdevpriv lock');
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|