mirror of https://github.com/red-prig/fpPS4.git
380 lines
7.3 KiB
Plaintext
380 lines
7.3 KiB
Plaintext
unit vfs_cache;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
vnode;
|
|
|
|
function vn_fullpath1(vp,rdir:p_vnode;buf:PChar;retbuf:PPChar;buflen:DWORD):Integer;
|
|
function vn_fullpath(vn:p_vnode;retbuf,freebuf:PPChar):Integer;
|
|
function vn_fullpath_global(vn:p_vnode;retbuf,freebuf:PPChar):Integer;
|
|
function vn_path_to_global_path(vp:p_vnode;path:PChar;pathlen:DWORD):Integer;
|
|
function vn_vptocnp(vp:pp_vnode;buf:PChar;buflen:PDWORD):Integer;
|
|
|
|
function sys___getcwd(buf:PChar;buflen:DWORD):Integer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
sysutils,
|
|
systm,
|
|
errno,
|
|
vuio,
|
|
vmount,
|
|
vnamei,
|
|
vfiledesc,
|
|
vfs_subr,
|
|
vfs_vnops,
|
|
vfs_lookup,
|
|
vnode_if,
|
|
kern_thr,
|
|
kern_mtx;
|
|
|
|
{
|
|
* Retrieve the full filesystem path that correspond to a vnode from the name
|
|
* cache (if available)
|
|
}
|
|
function vn_fullpath(vn:p_vnode;retbuf,freebuf:PPChar):Integer;
|
|
var
|
|
buf:PChar;
|
|
rdir:p_vnode;
|
|
error,vfslocked:Integer;
|
|
begin
|
|
//if (disablefullpath) then Exit(ENODEV);
|
|
|
|
if (vn=nil) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
buf:=AllocMem(MAXPATHLEN);
|
|
|
|
FILEDESC_SLOCK(@fd_table);
|
|
rdir:=fd_table.fd_rdir;
|
|
VREF(rdir);
|
|
FILEDESC_SUNLOCK(@fd_table);
|
|
|
|
error:=vn_fullpath1(vn, rdir, buf, retbuf, MAXPATHLEN);
|
|
vfslocked:=VFS_LOCK_GIANT(rdir^.v_mount);
|
|
vrele(rdir);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
|
|
if (error=0) then
|
|
freebuf^:=buf
|
|
else
|
|
FreeMem(buf);
|
|
|
|
Exit(error);
|
|
end;
|
|
|
|
{
|
|
* This function is similar to vn_fullpath, but it attempts to lookup the
|
|
* pathname relative to the global root mount point. This is required for the
|
|
* auditing sub-system, as audited pathnames must be absolute, relative to the
|
|
* global root mount point.
|
|
}
|
|
function vn_fullpath_global(vn:p_vnode;retbuf,freebuf:PPChar):Integer;
|
|
var
|
|
buf:PChar;
|
|
error:Integer;
|
|
begin
|
|
//if (disablefullpath) then Exit(ENODEV);
|
|
|
|
if (vn=nil) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
buf:=AllocMem(MAXPATHLEN);
|
|
|
|
error:=vn_fullpath1(vn, rootvnode, buf, retbuf, MAXPATHLEN);
|
|
|
|
if (error=0) then
|
|
freebuf^:=buf
|
|
else
|
|
FreeMem(buf);
|
|
|
|
Exit(error);
|
|
end;
|
|
|
|
|
|
|
|
{
|
|
* This function updates path string to vnode's full global path
|
|
* and checks the size of the new path string against the pathlen argument.
|
|
*
|
|
* Requires a locked, referenced vnode and GIANT lock held.
|
|
* Vnode is re-locked on success or ENODEV, otherwise unlocked.
|
|
*
|
|
* If sysctl debug.disablefullpath is set, ENODEV is returned,
|
|
* vnode is left locked and path remain untouched.
|
|
*
|
|
* If vp is a directory, the call to vn_fullpath_global() always succeeds
|
|
* because it falls back to the ".." lookup if the namecache lookup fails.
|
|
}
|
|
function vn_path_to_global_path(vp:p_vnode;path:PChar;pathlen:DWORD):Integer;
|
|
label
|
|
_out;
|
|
var
|
|
nd:t_nameidata;
|
|
vp1:p_vnode;
|
|
rpath,fbuf:PChar;
|
|
error,vfslocked:Integer;
|
|
begin
|
|
VFS_ASSERT_GIANT(vp^.v_mount);
|
|
ASSERT_VOP_ELOCKED(vp, 'vn_path_to_global_path');
|
|
|
|
{ Return ENODEV if sysctl debug.disablefullpath==1 }
|
|
//if (disablefullpath) then Exit(ENODEV);
|
|
|
|
{ Construct global filesystem path from vp. }
|
|
VOP_UNLOCK(vp, 0);
|
|
|
|
error:=vn_fullpath_global(vp, @rpath, @fbuf);
|
|
if (error<>0) then
|
|
begin
|
|
vrele(vp);
|
|
Exit(error);
|
|
end;
|
|
|
|
if (strlen(rpath) >= pathlen) then
|
|
begin
|
|
vrele(vp);
|
|
error:=ENAMETOOLONG;
|
|
goto _out;
|
|
end;
|
|
|
|
{
|
|
* Re-lookup the vnode by path to detect a possible rename.
|
|
* As a side effect, the vnode is relocked.
|
|
* If vnode was renamed, return ENOENT.
|
|
}
|
|
NDINIT(@nd, LOOKUP, FOLLOW or LOCKLEAF or MPSAFE or AUDITVNODE1, UIO_SYSSPACE, path, curkthread);
|
|
|
|
error:=nd_namei(@nd);
|
|
if (error<>0) then
|
|
begin
|
|
vrele(vp);
|
|
goto _out;
|
|
end;
|
|
|
|
vfslocked:=NDHASGIANT(@nd);
|
|
NDFREE(@nd, NDF_ONLY_PNBUF);
|
|
vp1:=nd.ni_vp;
|
|
vrele(vp);
|
|
if (vp1=vp) then
|
|
begin
|
|
strcopy(path, rpath);
|
|
end else
|
|
begin
|
|
vput(vp1);
|
|
error:=ENOENT;
|
|
end;
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
|
|
_out:
|
|
FreeMem(fbuf);
|
|
Exit(error);
|
|
end;
|
|
|
|
function vn_vptocnp(vp:pp_vnode;buf:PChar;buflen:PDWORD):Integer;
|
|
var
|
|
dvp:p_vnode;
|
|
error,vfslocked:Integer;
|
|
begin
|
|
//no cache
|
|
|
|
vfslocked:=VFS_LOCK_GIANT((vp^)^.v_mount);
|
|
vn_lock(vp^, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
|
|
error:=VOP_VPTOCNP(vp^, @dvp, buf, PInteger(buflen));
|
|
vput(vp^);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
vp^:=dvp;
|
|
|
|
if ((dvp^.v_iflag and VI_DOOMED)<>0) then
|
|
begin
|
|
{ forced unmount }
|
|
vfslocked:=VFS_LOCK_GIANT(dvp^.v_mount);
|
|
vrele(dvp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
error:=ENOENT;
|
|
Exit(error);
|
|
end;
|
|
{
|
|
* *vp has its use count incremented still.
|
|
}
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
{
|
|
* The magic behind kern___getcwd() and vn_fullpath().
|
|
}
|
|
function vn_fullpath1(vp,rdir:p_vnode;buf:PChar;retbuf:PPChar;buflen:DWORD):Integer;
|
|
var
|
|
error,slash_prefixed,vfslocked:Integer;
|
|
vp1:p_vnode;
|
|
begin
|
|
Dec(buflen);
|
|
buf[buflen]:=#0;
|
|
error:=0;
|
|
slash_prefixed:=0;
|
|
|
|
vref(vp);
|
|
|
|
if (vp^.v_type<>VDIR) then
|
|
begin
|
|
error:=vn_vptocnp(@vp, buf, @buflen);
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
if (buflen=0) then
|
|
begin
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
Exit(ENOMEM);
|
|
end;
|
|
Dec(buflen);
|
|
buf[buflen]:='/';
|
|
slash_prefixed:=1;
|
|
end;
|
|
while (vp<>rdir) and (vp<>rootvnode) do
|
|
begin
|
|
if ((vp^.v_vflag and VV_ROOT)<>0) then
|
|
begin
|
|
if ((vp^.v_iflag and VI_DOOMED)<>0) then
|
|
begin { forced unmount }
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
error:=ENOENT;
|
|
break;
|
|
end;
|
|
vp1:=p_mount(vp^.v_mount)^.mnt_vnodecovered;
|
|
vref(vp1);
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
vp:=vp1;
|
|
continue;
|
|
end;
|
|
if (vp^.v_type<>VDIR) then
|
|
begin
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
error:=ENOTDIR;
|
|
break;
|
|
end;
|
|
error:=vn_vptocnp(@vp, buf, @buflen);
|
|
if (error<>0) then
|
|
begin
|
|
break;
|
|
end;
|
|
|
|
if (buflen=0) then
|
|
begin
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
error:=ENOMEM;
|
|
break;
|
|
end;
|
|
Dec(buflen);
|
|
buf[buflen]:='/';
|
|
slash_prefixed:=1;
|
|
end;
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
if (slash_prefixed=0) then
|
|
begin
|
|
if (buflen=0) then
|
|
begin
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
Exit(ENOMEM);
|
|
end;
|
|
Dec(buflen);
|
|
buf[buflen]:='/';
|
|
end;
|
|
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
|
|
vrele(vp);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
|
|
retbuf^:=buf + buflen;
|
|
Exit(0);
|
|
end;
|
|
|
|
function kern___getcwd(buf:PChar;bufseg:uio_seg;buflen:DWORD):Integer;
|
|
var
|
|
bp,tmpbuf:PChar;
|
|
cdir,rdir:p_vnode;
|
|
error,vfslocked:Integer;
|
|
begin
|
|
//if (disablecwd) then Exit(ENODEV);
|
|
|
|
if (buflen < 2) then Exit(EINVAL);
|
|
|
|
if (buflen > MAXPATHLEN) then
|
|
begin
|
|
buflen:=MAXPATHLEN;
|
|
end;
|
|
|
|
tmpbuf:=AllocMem(buflen);
|
|
|
|
FILEDESC_SLOCK(@fd_table);
|
|
cdir:=fd_table.fd_cdir;
|
|
VREF(cdir);
|
|
rdir:=fd_table.fd_rdir;
|
|
VREF(rdir);
|
|
FILEDESC_SUNLOCK(@fd_table);
|
|
|
|
error:=vn_fullpath1(cdir, rdir, tmpbuf, @bp, buflen);
|
|
vfslocked:=VFS_LOCK_GIANT(rdir^.v_mount);
|
|
vrele(rdir);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
vfslocked:=VFS_LOCK_GIANT(cdir^.v_mount);
|
|
vrele(cdir);
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
|
|
if (error=0) then
|
|
begin
|
|
if (bufseg=UIO_SYSSPACE) then
|
|
Move(bp^, buf^, strlen(bp) + 1)
|
|
else
|
|
error:=copyout(bp, buf, strlen(bp) + 1);
|
|
end;
|
|
|
|
FreeMem(tmpbuf);
|
|
|
|
Exit(error);
|
|
end;
|
|
|
|
{ Implementation of the getcwd syscall. }
|
|
function sys___getcwd(buf:PChar;buflen:DWORD):Integer;
|
|
begin
|
|
//priv_check(td,683);
|
|
Exit(EPERM);
|
|
|
|
Exit(kern___getcwd(buf, UIO_USERSPACE, buflen));
|
|
end;
|
|
|
|
end.
|
|
|