FPPS4/sys/vfs/vfs_syscalls.pas

3520 lines
73 KiB
Plaintext

unit vfs_syscalls;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
kern_param,
kern_proc,
time,
vmount,
vuio,
vnamei,
vstat,
vfile,
vfiledesc,
vcapability,
vfcntl,
vfilio,
vdisk,
vfs_mount,
vnode,
vfs_vnops,
vfs_subr;
function chroot_refuse_vdir_fds():Integer;
function getutimes(usrtvp:p_timeval;tvpseg:uio_seg;tsp:p_timespec):Integer;
function setfflags(vp:p_vnode;flags:Integer):Integer;
function setutimes(vp:p_vnode;ts:p_timespec;numtimes,nilflag:Integer):Integer;
function vn_access(vp:p_vnode;user_flags:Integer):Integer;
function setfown(vp:p_vnode;uid:uid_t;gid:gid_t):Integer;
function setfmode(vp:p_vnode;mode:Integer):Integer;
function getvnode(fd:Integer;rights:cap_rights_t;fpp:pp_file):Integer;
function sys_sync():Integer;
function sys_statfs(path:PChar;buf:Pointer):Integer;
function sys_fstatfs(fd:Integer;buf:Pointer):Integer;
function sys_getfsstat(buf:Pointer;bufsize:QWORD;flags:Integer):Integer;
function sys_fchdir(fd:Integer):Integer;
function sys_chdir(path:PChar):Integer;
function sys_chroot(path:PChar):Integer;
function sys_open(path:PChar;flags,mode:Integer):Integer;
function sys_openat(fd:Integer;path:PChar;flags,mode:Integer):Integer;
function sys_mknod(path:PChar;mode,dev:Integer):Integer;
function sys_mknodat(fd:Integer;path:PChar;mode,dev:Integer):Integer;
function sys_mkfifo(path:PChar;mode:Integer):Integer;
function sys_mkfifoat(fd:Integer;path:PChar;mode:Integer):Integer;
function sys_link(name1,name2:PChar):Integer;
function sys_linkat(fd1:Integer;path1:PChar;fd2:Integer;path2:PChar;flag:Integer):Integer;
function sys_symlink(path,link:PChar):Integer;
function sys_symlinkat(path1:PChar;fd:Integer;path2:PChar):Integer;
function sys_unlinkat(fd:Integer;path:PChar;flag:Integer):Integer;
function sys_unlink(path:PChar):Integer;
function sys_lseek(fd:Integer;offset:Int64;whence:Integer):Integer;
function sys_access(path:PChar;flags:Integer):Integer;
function sys_stat(path:PChar;ub:Pointer):Integer;
function sys_fstatat(fd:Integer;path:PChar;buf:Pointer;flag:Integer):Integer;
function sys_lstat(path:PChar;ub:Pointer):Integer;
function sys_pathconf(path:PChar;name:Integer):Integer;
function sys_readlink(path,buf:PChar;count:QWORD):Integer;
function sys_chflags(path:PChar;flags:Integer):Integer;
function sys_lchflags(path:PChar;flags:Integer):Integer;
function sys_fchflags(fd,flags:Integer):Integer;
function sys_chmod(path:PChar;mode:Integer):Integer;
function sys_fchmodat(fd:Integer;path:PChar;mode,flag:Integer):Integer;
function sys_lchmod(path:PChar;mode:Integer):Integer;
function sys_fchmod(fd,mode:Integer):Integer;
function sys_chown(path:PChar;uid,gid:Integer):Integer;
function sys_fchownat(fd:Integer;path:PChar;uid,gid,flag:Integer):Integer;
function sys_lchown(path:PChar;uid,gid:Integer):Integer;
function sys_fchown(fd,uid,gid:Integer):Integer;
function sys_utimes(path:PChar;tptr:Pointer):Integer;
function sys_futimesat(fd:Integer;path:PChar;times:Pointer):Integer;
function sys_lutimes(path:PChar;tptr:Pointer):Integer;
function sys_futimes(fd:Integer;tptr:Pointer):Integer;
function sys_truncate(path:PChar;length:Int64):Integer;
function sys_fsync(fd:Integer):Integer;
function sys_fdatasync(fd:Integer):Integer;
function sys_rename(from,_to:PChar):Integer;
function sys_renameat(oldfd:Integer;old:PChar;newfd:Integer;new:PChar):Integer;
function sys_mkdir(path:PChar;mode:Integer):Integer;
function sys_mkdirat(fd:Integer;path:PChar;mode:Integer):Integer;
function sys_rmdir(path:PChar):Integer;
function sys_getdirentries(fd:Integer;buf:Pointer;count:DWORD;basep:PInt64):Integer;
function sys_getdents(fd:Integer;buf:Pointer;count:DWORD):Integer;
function sys_umask(newmask:Integer):Integer;
function sys_revoke(path:PChar):Integer;
function kern_statfs(path:PChar;pathseg:uio_seg;buf:p_statfs):Integer;
function kern_fstatfs(fd:Integer;buf:p_statfs):Integer;
function kern_getfsstat(buf:pp_statfs;bufsize:QWORD;bufseg:uio_seg;flags:Integer):Integer;
function kern_chdir(path:PChar;pathseg:uio_seg):Integer;
function kern_openat(fd:Integer;path:PChar;pathseg:uio_seg;flags,mode:Integer):Integer;
function kern_open(path:PChar;pathseg:uio_seg;flags,mode:Integer):Integer;
function kern_mkfifoat(fd:Integer;path:PChar;pathseg:uio_seg;mode:Integer):Integer;
function kern_mknodat(fd:Integer;path:PChar;pathseg:uio_seg;mode,dev:Integer):Integer;
function kern_mknod(path:PChar;pathseg:uio_seg;mode,dev:Integer):Integer;
function kern_linkat(fd1,fd2:Integer;path1,path2:PChar;segflg:uio_seg;follow:Integer):Integer;
function kern_link(path,link:PChar;segflg:uio_seg):Integer;
function kern_symlinkat(path1:PChar;fd:Integer;path2:PChar;segflg:uio_seg):Integer;
function kern_symlink(path,link:PChar;segflg:uio_seg):Integer;
function kern_unlinkat(fd:Integer;path:PChar;pathseg:uio_seg;oldinum:Integer):Integer;
function kern_unlink(path:PChar;pathseg:uio_seg):Integer;
function kern_accessat(fd:Integer;path:PChar;pathseg:uio_seg;flags,mode:Integer):Integer;
function kern_access(path:PChar;pathseg:uio_seg;mode:Integer):Integer;
function kern_statat(flag,fd:Integer;path:PChar;pathseg:uio_seg;sbp:p_stat):Integer;
function kern_stat(path:PChar;pathseg:uio_seg;sbp:p_stat):Integer;
function kern_lstat(path:PChar;pathseg:uio_seg;sbp:p_stat):Integer;
function kern_pathconf(path:PChar;pathseg:uio_seg;name:Integer;flags:QWORD):Integer;
function kern_readlinkat(fd:Integer;path:PChar;pathseg:uio_seg;buf:PChar;bufseg:uio_seg;count:QWORD):Integer;
function kern_readlink(path:PChar;pathseg:uio_seg;buf:PChar;bufseg:uio_seg;count:QWORD):Integer;
function kern_fchmodat(fd:Integer;path:PChar;pathseg:uio_seg;mode,flag:Integer):Integer;
function kern_chmod(path:PChar;pathseg:uio_seg;mode:Integer):Integer;
function kern_chown(path:PChar;pathseg:uio_seg;uid,gid:Integer):Integer;
function kern_lchown(path:PChar;pathseg:uio_seg;uid,gid:Integer):Integer;
function kern_utimesat(fd:Integer;path:PChar;pathseg:uio_seg;tptr:p_timeval;tptrseg:uio_seg):Integer;
function kern_utimes(path:PChar;pathseg:uio_seg;tptr:p_timeval;tptrseg:uio_seg):Integer;
function kern_lutimes(path:PChar;pathseg:uio_seg;tptr:p_timeval;tptrseg:uio_seg):Integer;
function kern_futimes(fd:Integer;tptr:p_timeval;tptrseg:uio_seg):Integer;
function kern_truncate(path:PChar;pathseg:uio_seg;length:Int64):Integer;
function kern_fsync(fd:Integer;fullsync:Boolean):Integer;
function kern_renameat(oldfd:Integer;old:PChar;newfd:Integer;new:PChar;pathseg:uio_seg):Integer;
function kern_rename(from,_to:PChar;pathseg:uio_seg):Integer;
function kern_mkdirat(fd:Integer;path:PChar;segflg:uio_seg;mode:Integer):Integer;
function kern_mkdir(path:PChar;segflg:uio_seg;mode:Integer):Integer;
function kern_rmdirat(fd:Integer;path:PChar;pathseg:uio_seg):Integer;
function kern_rmdir(path:PChar;pathseg:uio_seg):Integer;
function kern_getdirentries(fd:Integer;buf:Pointer;count:DWORD;basep:PInt64):Integer;
/////
function sys_is_in_sandbox():Integer;
function sys_randomized_path(src,dst:pchar;plen:PQWORD):Integer;
implementation
uses
atomic,
mqueue,
systm,
errno,
kern_mtx,
kern_thr,
kern_descrip,
vnode_if,
sys_capability,
vmparam,
sys_vm_object,
vm_object;
{
* Sync each mounted filesystem.
}
function sys_sync():Integer;
var
mp,nmp:p_mount;
save, vfslocked:Integer;
begin
mtx_lock(mountlist_mtx);
mp:=TAILQ_FIRST(@mountlist);
while (mp<>nil) do
begin
if (vfs_busy(mp, MBF_NOWAIT or MBF_MNTLSTLOCK)<>0) then
begin
nmp:=TAILQ_NEXT(mp,@mp^.mnt_list);
continue;
end;
vfslocked:=VFS_LOCK_GIANT(mp);
if ((mp^.mnt_flag and MNT_RDONLY)=0) and
(vn_start_write(nil, @mp, V_NOWAIT)=0) then
begin
save:=curthread_pflags_set(TDP_SYNCIO);
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_NOWAIT);
curthread_pflags_restore(save);
vn_finished_write(mp);
end;
VFS_UNLOCK_GIANT(vfslocked);
mtx_lock(mountlist_mtx);
nmp:=TAILQ_NEXT(mp,@mp^.mnt_list);
vfs_unbusy(mp);
mp:=nmp;
end;
mtx_unlock(mountlist_mtx);
Exit(0);
end;
function kern_statfs(path:PChar;pathseg:uio_seg;buf:p_statfs):Integer;
label
_out;
var
mp:p_mount;
sp:p_statfs;
sb:t_statfs;
vfslocked:Integer;
error:Integer;
nd:t_nameidata;
begin
NDINIT(@nd, LOOKUP, FOLLOW or LOCKSHARED or LOCKLEAF or MPSAFE or AUDITVNODE1, pathseg, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
mp:=nd.ni_vp^.v_mount;
vfs_ref(mp);
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_vp);
error:=vfs_busy(mp, 0);
vfs_rel(mp);
if (error<>0) then
begin
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
//error:=mac_mount_check_stat(td^.td_ucred, mp);
//if (error<>0) then
// goto _out;
{
* Set these in case the underlying filesystem fails to do so.
}
sp:=@mp^.mnt_stat;
sp^.f_version:=STATFS_VERSION;
sp^.f_namemax:=NAME_MAX;
sp^.f_flags:=mp^.mnt_flag and MNT_VISFLAGMASK;
error:=VFS_STATFS(mp, sp);
if (error<>0) then
goto _out;
if {(priv_check(td, PRIV_VFS_GENERATION))} True then
begin
sb:=sp^;
sb.f_fsid.val[0]:=0;
sb.f_fsid.val[1]:=0;
//prison_enforce_statfs(td^.td_ucred, mp, @sb);
sp:=@sb;
end;
buf^:=sp^;
_out:
vfs_unbusy(mp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Get filesystem statistics.
}
function sys_statfs(path:PChar;buf:Pointer):Integer;
var
sf:t_statfs;
error:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=kern_statfs(path, UIO_USERSPACE, @sf);
if (error=0) then
begin
error:=copyout(@sf, buf, sizeof(sf));
end;
Exit(error);
end;
function kern_fstatfs(fd:Integer;buf:p_statfs):Integer;
label
_out;
var
fp:p_file;
mp:p_mount;
sp:p_statfs;
sb:t_statfs;
vfslocked:Integer;
vp:p_vnode;
error:Integer;
begin
error:=getvnode(fd, CAP_FSTATFS, @fp);
if (error<>0) then
begin
Exit(error);
end;
vp:=fp^.f_vnode;
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
vn_lock(vp, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
mp:=vp^.v_mount;
if (mp<>nil) then
begin
vfs_ref(mp);
end;
VOP_UNLOCK(vp, 0);
fdrop(fp);
if (mp=nil) then
begin
error:=EBADF;
goto _out;
end;
error:=vfs_busy(mp, 0);
vfs_rel(mp);
if (error<>0) then
begin
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
//error:=mac_mount_check_stat(td^.td_ucred, mp);
//if (error<>0) then
// goto _out;
{
* Set these in case the underlying filesystem fails to do so.
}
sp:=@mp^.mnt_stat;
sp^.f_version:=STATFS_VERSION;
sp^.f_namemax:=NAME_MAX;
sp^.f_flags:=mp^.mnt_flag and MNT_VISFLAGMASK;
error:=VFS_STATFS(mp, sp);
if (error<>0) then
begin
goto _out;
end;
if {(priv_check(td, PRIV_VFS_GENERATION))} True then
begin
sb:=sp^;
sb.f_fsid.val[0]:=0;
sb.f_fsid.val[1]:=0;
//prison_enforce_statfs(td^.td_ucred, mp, @sb);
sp:=@sb;
end;
buf^:=sp^;
_out:
if (mp<>nil) then
begin
vfs_unbusy(mp);
end;
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Get filesystem statistics.
}
function sys_fstatfs(fd:Integer;buf:Pointer):Integer;
var
sf:t_statfs;
error:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=kern_fstatfs(fd, @sf);
if (error=0) then
begin
error:=copyout(@sf, buf, sizeof(sf));
end;
Exit(error);
end;
{
* If (bufsize > 0 and bufseg=UIO_SYSSPACE)
* The caller is responsible for freeing memory which will be allocated
* in '*buf'.
}
function kern_getfsstat(buf:pp_statfs;bufsize:QWORD;bufseg:uio_seg;flags:Integer):Integer;
var
td:p_kthread;
mp,nmp:p_mount;
sfsp,sp:p_statfs;
sb:t_statfs;
count,maxcount:QWORD;
vfslocked:Integer;
error:Integer;
begin
td:=curkthread;
if (td=nil) then Exit(-1);
maxcount:=bufsize div sizeof(t_statfs);
if (bufsize=0) then
begin
sfsp:=nil;
end else
if (bufseg=UIO_USERSPACE) then
begin
sfsp:=buf^;
end else
begin
count:=0;
mtx_lock(mountlist_mtx);
mp:=TAILQ_FIRST(@mountlist);
while (mp<>nil) do
begin
Inc(count);
mp:=TAILQ_NEXT(mp,@mp^.mnt_list);
end;
mtx_unlock(mountlist_mtx);
if (maxcount > count) then
begin
maxcount:=count;
end;
sfsp:=AllocMem(maxcount*sizeof(t_statfs));
buf^:=sfsp;
end;
count:=0;
mtx_lock(mountlist_mtx);
mp:=TAILQ_FIRST(@mountlist);
while (mp<>nil) do
begin
if {(prison_canseemount(td^.td_ucred, mp)<>0)} True then
begin
nmp:=TAILQ_NEXT(mp,@mp^.mnt_list);
continue;
end;
//if (mac_mount_check_stat(td^.td_ucred, mp)<>0) then
//begin
// nmp:=TAILQ_NEXT(mp, mnt_list);
// continue;
//end;
if (vfs_busy(mp, MBF_NOWAIT or MBF_MNTLSTLOCK)<>0) then
begin
nmp:=TAILQ_NEXT(mp,@mp^.mnt_list);
continue;
end;
vfslocked:=VFS_LOCK_GIANT(mp);
if (sfsp<>nil) and (count<maxcount) then
begin
sp:=@mp^.mnt_stat;
{
* Set these in case the underlying filesystem
* fails to do so.
}
sp^.f_version:=STATFS_VERSION;
sp^.f_namemax:=NAME_MAX;
sp^.f_flags:=mp^.mnt_flag and MNT_VISFLAGMASK;
{
* If MNT_NOWAIT or MNT_LAZY is specified, do not
* refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
* overrides MNT_WAIT.
}
if ((flags and (MNT_LAZY or MNT_NOWAIT))=0) or
((flags and MNT_WAIT)<>0) then
begin
error:=VFS_STATFS(mp, sp);
if (error<>0) then
begin
VFS_UNLOCK_GIANT(vfslocked);
mtx_lock(mountlist_mtx);
nmp:=TAILQ_NEXT(mp,@mp^.mnt_list);
vfs_unbusy(mp);
continue;
end;
end;
if {(priv_check(td, PRIV_VFS_GENERATION))} True then
begin
sb:=sp^;
sb.f_fsid.val[0]:=0;
sb.f_fsid.val[1]:=0;
//prison_enforce_statfs(td^.td_ucred, mp, @sb);
sp:=@sb;
end;
if (bufseg=UIO_SYSSPACE) then
begin
sfsp^:=sp^;
end else
begin
error:=copyout(sp, sfsp, sizeof(sb));
if (error<>0) then
begin
vfs_unbusy(mp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
end;
Inc(sfsp);
end;
VFS_UNLOCK_GIANT(vfslocked);
Inc(count);
mtx_lock(mountlist_mtx);
nmp:=TAILQ_NEXT(mp,@mp^.mnt_list);
vfs_unbusy(mp);
mp:=nmp;
end;
mtx_unlock(mountlist_mtx);
if (sfsp<>nil) and (count>maxcount) then
td^.td_retval[0]:=maxcount
else
td^.td_retval[0]:=count;
Exit(0);
end;
{
* Get statistics on all filesystems.
}
function sys_getfsstat(buf:Pointer;bufsize:QWORD;flags:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_getfsstat(@buf, bufsize, UIO_USERSPACE, flags));
end;
function change_dir(vp:p_vnode):Integer; forward;
{
* Change current working directory to a given file descriptor.
}
function sys_fchdir(fd:Integer):Integer;
var
vp,tdp,vpold:p_vnode;
mp:p_mount;
fp:p_file;
vfslocked:Integer;
error:Integer;
tvfslocked:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=getvnode(fd, CAP_FCHDIR, @fp);
if (error<>0) then
begin
Exit(error);
end;
vp:=fp^.f_vnode;
VREF(vp);
fdrop(fp);
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
vn_lock(vp, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
error:=change_dir(vp);
mp:=vp^.v_mountedhere;
while (error=0) and (mp<>nil) do
begin
if (vfs_busy(mp, 0)<>0) then
begin
continue;
end;
tvfslocked:=VFS_LOCK_GIANT(mp);
error:=VFS_ROOT(mp, LK_SHARED, @tdp);
vfs_unbusy(mp);
if (error<>0) then
begin
VFS_UNLOCK_GIANT(tvfslocked);
break;
end;
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
vp:=tdp;
vfslocked:=tvfslocked;
mp:=vp^.v_mountedhere;
end;
if (error<>0) then
begin
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
FILEDESC_XLOCK(@fd_table);
vpold:=fd_table.fd_cdir;
fd_table.fd_cdir:=vp;
FILEDESC_XUNLOCK(@fd_table);
vfslocked:=VFS_LOCK_GIANT(vpold^.v_mount);
vrele(vpold);
VFS_UNLOCK_GIANT(vfslocked);
Exit(0);
end;
function kern_chdir(path:PChar;pathseg:uio_seg):Integer;
var
error:Integer;
nd:t_nameidata;
vp:p_vnode;
vfslocked:Integer;
begin
NDINIT(@nd, LOOKUP, FOLLOW or LOCKSHARED or LOCKLEAF or AUDITVNODE1 or MPSAFE, pathseg, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
error:=change_dir(nd.ni_vp);
if (error<>0) then
begin
vput(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
NDFREE(@nd, NDF_ONLY_PNBUF);
Exit(error);
end;
VOP_UNLOCK(nd.ni_vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
NDFREE(@nd, NDF_ONLY_PNBUF);
FILEDESC_XLOCK(@fd_table);
vp:=fd_table.fd_cdir;
fd_table.fd_cdir:=nd.ni_vp;
FILEDESC_XUNLOCK(@fd_table);
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(0);
end;
{
* Change current working directory (``.'').
}
function sys_chdir(path:PChar):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_chdir(path, UIO_USERSPACE));
end;
{
* Helper function for raised chroot(2) security function: Refuse if
* any filedescriptors are open directories.
}
function chroot_refuse_vdir_fds():Integer;
var
vp:p_vnode;
fp:p_file;
fd:Integer;
begin
//FILEDESC_LOCK_ASSERT(@fd_table);
For fd:=0 to fd_table.fd_nfiles-1 do
begin
fp:=fget_locked(@fd_table, fd);
if (fp=nil) then
begin
continue;
end;
if (fp^.f_type=DTYPE_VNODE) then
begin
vp:=fp^.f_vnode;
if (vp^.v_type=VDIR) then
begin
Exit(EPERM);
end;
end;
end;
Exit(0);
end;
{
* This sysctl determines if we will allow a process to chroot(2) if it
* has a directory open:
* 0: disallowed for all processes.
* 1: allowed for processes that were not already chroot(2)'ed.
* 2: allowed for all processes.
}
const
chroot_allow_open_directories=0;
function change_root(vp:p_vnode):Integer; forward;
{
* Change notion of root (``/'') directory.
}
function sys_chroot(path:PChar):Integer;
label
_error,
e_vunlock;
var
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
error:=EPERM;
//error:=priv_check(td, PRIV_VFS_CHROOT);
if (error<>0) then
begin
Exit(error);
end;
NDINIT(@nd, LOOKUP, FOLLOW or LOCKSHARED or LOCKLEAF or MPSAFE or AUDITVNODE1, UIO_USERSPACE, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
goto _error;
end;
vfslocked:=NDHASGIANT(@nd);
error:=change_dir(nd.ni_vp);
if (error<>0) then
begin
goto e_vunlock;
//if ((error:=mac_vnode_check_chroot(td^.td_ucred, nd.ni_vp)))
// goto e_vunlock;
end;
VOP_UNLOCK(nd.ni_vp, 0);
error:=change_root(nd.ni_vp);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
NDFREE(@nd, NDF_ONLY_PNBUF);
Exit(error);
e_vunlock:
vput(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
_error:
NDFREE(@nd, NDF_ONLY_PNBUF);
Exit(error);
end;
{
* Common routine for chroot and chdir. Callers must provide a locked vnode
* instance.
}
function change_dir(vp:p_vnode):Integer;
var
error:Integer;
begin
ASSERT_VOP_LOCKED(vp, 'change_dir(): vp not locked');
if (vp^.v_type<>VDIR) then
begin
Exit(ENOTDIR);
end;
//error:=mac_vnode_check_chdir(td^.td_ucred, vp);
//if (error<>0) then
// Exit(error);
error:=VOP_ACCESS(vp, VEXEC);
Exit(error);
end;
{
* Common routine for kern_chroot() and jail_attach(). The caller is
* responsible for invoking priv_check() and mac_vnode_check_chroot() to
* authorize this operation.
}
function change_root(vp:p_vnode):Integer;
var
oldvp:p_vnode;
vfslocked:Integer;
error:Integer;
begin
VFS_ASSERT_GIANT(vp^.v_mount);
FILEDESC_XLOCK(@fd_table);
if (chroot_allow_open_directories=0) or
((chroot_allow_open_directories=1) and (fd_table.fd_rdir<>rootvnode)) then
begin
error:=chroot_refuse_vdir_fds();
if (error<>0) then
begin
FILEDESC_XUNLOCK(@fd_table);
Exit(error);
end;
end;
oldvp:=fd_table.fd_rdir;
fd_table.fd_rdir:=vp;
VREF(fd_table.fd_rdir);
if (fd_table.fd_jdir=nil) then
begin
fd_table.fd_jdir:=vp;
VREF(fd_table.fd_jdir);
end;
FILEDESC_XUNLOCK(@fd_table);
vfslocked:=VFS_LOCK_GIANT(oldvp^.v_mount);
vrele(oldvp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(0);
end;
function flags_to_rights(flags:Integer):cap_rights_t;
var
rights:cap_rights_t;
begin
rights:=0;
case (flags and O_ACCMODE) of
O_RDONLY:
begin
rights:=rights or CAP_READ;
end;
O_RDWR:
begin
rights:=rights or CAP_READ or CAP_WRITE;
end;
O_WRONLY:
begin
rights:=rights or CAP_WRITE;
end;
O_EXEC:
begin
rights:=rights or CAP_FEXECVE;
end;
end;
if ((flags and O_CREAT)<>0) then
begin
rights:=rights or CAP_CREATE;
end;
if ((flags and O_TRUNC)<>0) then
begin
rights:=rights or CAP_FTRUNCATE;
end;
if ((flags and O_EXLOCK)<>0) or ((flags and O_SHLOCK)<>0) then
begin
rights:=rights or CAP_FLOCK;
end;
Exit(rights);
end;
function kern_openat(fd:Integer;path:PChar;pathseg:uio_seg;flags,mode:Integer):Integer;
label
success,
bad_unlocked,
bad;
var
td:p_kthread;
fp:p_file;
vp:p_vnode;
cmode:Integer;
nfp:p_file;
l_type,indx,error,error_open:Integer;
lf:t_flock;
nd:t_nameidata;
vfslocked:Integer;
rights_needed:cap_rights_t;
begin
td:=curkthread;
if (td=nil) then Exit(-1);
indx:=-1;
rights_needed:=CAP_LOOKUP;
{ XXX: audit dirfd }
rights_needed:=rights_needed or flags_to_rights(flags);
{
* Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags
* may be specified.
}
if ((flags and O_EXEC)<>0) then
begin
if ((flags and O_ACCMODE)<>0) then
begin
Exit(EINVAL);
end;
end else
if ((flags and O_ACCMODE)=O_ACCMODE) then
begin
Exit(EINVAL)
end else
begin
flags:=FFLAGS(flags);
end;
{
* allocate the file descriptor, but don't install a descriptor yet
}
error:=falloc_noinstall(@nfp);
if (error<>0) then
begin
Exit(error);
end;
{ An extra reference on `nfp' has been held for us by falloc_noinstall(). }
fp:=nfp;
{ Set the flags early so the finit in devfs can pick them up. }
fp^.f_flag:=flags and FMASK;
cmode:=((mode and (not fd_table.fd_cmask)) and ALLPERMS) and (not S_ISTXT);
NDINIT_ATRIGHTS(@nd, LOOKUP, FOLLOW or AUDITVNODE1 or MPSAFE, pathseg, path, fd, rights_needed, td);
td^.td_dupfd:=-1; { XXX check for fdopen }
error:=vn_open(@nd, @flags, cmode, fp);
if (error<>0) then
begin
{
* If the vn_open replaced the method vector, something
* wonderous happened deep below and we just pass it up
* pretending we know what we do.
}
if (error=ENXIO) and (fp^.f_ops<>@badfileops) then
begin
goto success;
end;
{
* handle special fdopen() case. bleh. dupfdopen() is
* responsible for dropping the old contents of ofiles[indx]
* if it succeeds.
*
* Don't do this for relative (capability) lookups; we don't
* understand exactly what would happen, and we don't think
* that it ever should.
}
if (nd.ni_strictrelative=0) and
((error=ENODEV) or (error=ENXIO)) and
(td^.td_dupfd >= 0) then
begin
{ XXX from fdopen }
error_open:=error;
error:=finstall(fp, @indx, flags);
if (error<>0) then
begin
goto bad_unlocked;
end;
error:=dupfdopen(indx, td^.td_dupfd, flags, error_open);
if (error=0) then
begin
goto success;
end;
end;
{
* Clean up the descriptor, but only if another thread hadn't
* replaced or closed it.
}
if (indx<>-1) then
begin
fdclose(fp, indx);
end;
fdrop(fp);
Exit(error);
end;
td^.td_dupfd:=0;
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
vp:=nd.ni_vp;
{
* Store the vnode, for any f_type. Typically, the vnode use
* count is decremented by direct call to vn_closefile() for
* files that switched _type in the cdevsw fdopen() method.
}
fp^.f_vnode:=vp;
{
* If the file wasn't claimed by devfs bind it to the normal
* vnode operations here.
}
if (fp^.f_ops=@badfileops) then
begin
Assert(vp^.v_type<>VFIFO,'Unexpected fifo.');
fp^.f_seqcount:=1;
finit(fp, flags and FMASK, DTYPE_VNODE, vp, @vnops);
end;
VOP_UNLOCK(vp, 0);
if (fp^.f_type=DTYPE_VNODE) and ((flags and (O_EXLOCK or O_SHLOCK))<>0) then
begin
lf.l_whence:=SEEK_SET;
lf.l_start:=0;
lf.l_len:=0;
if ((flags and O_EXLOCK)<>0) then
lf.l_type:=F_WRLCK
else
lf.l_type:=F_RDLCK;
l_type:=F_FLOCK;
if ((flags and FNONBLOCK)=0) then
begin
l_type:=l_type or F_WAIT;
end;
error:=VOP_ADVLOCK(vp, fp, F_SETLK, @lf, l_type);
if (error<>0) then
begin
goto bad;
end;
atomic_set_int(@fp^.f_flag, FHASLOCK);
end;
if ((flags and O_TRUNC)<>0) then
begin
error:=fo_truncate(fp, 0);
if (error<>0) then
begin
goto bad;
end;
end;
VFS_UNLOCK_GIANT(vfslocked);
success:
{
* If we haven't already installed the FD (for dupfdopen), do so now.
}
if (indx=-1) then
begin
if (nd.ni_strictrelative=1) then
begin
{
* We are doing a strict relative lookup; wrap the
* result in a capability.
}
error:=kern_capwrap(fp, nd.ni_baserights, @indx);
if (error<>0) then
begin
goto bad_unlocked;
end;
end else
begin
error:=finstall(fp, @indx, flags);
if (error<>0) then
begin
goto bad_unlocked;
end;
end;
end;
{
* Release our private reference, leaving the one associated with
* the descriptor table intact.
}
fdrop(fp);
td^.td_retval[0]:=indx;
Exit(0);
bad:
VFS_UNLOCK_GIANT(vfslocked);
bad_unlocked:
if (indx<>-1) then
begin
fdclose(fp, indx);
end;
fdrop(fp);
td^.td_retval[0]:=QWORD(-1);
Exit(error);
end;
function kern_open(path:PChar;pathseg:uio_seg;flags,mode:Integer):Integer;
begin
Exit(kern_openat(AT_FDCWD, path, pathseg, flags, mode));
end;
{
* Check permissions, allocate an open file structure, and call the device
* open routine if any.
}
function sys_open(path:PChar;flags,mode:Integer):Integer;
begin
Result:=kern_open(path, UIO_USERSPACE, flags, mode);
//
if (curkthread<>nil) then
if is_guest_addr(curkthread^.td_frame.tf_rip) then
begin
Writeln('sys_open("',path,'",0x',HexStr(flags,4),',0',OctStr(mode,3),'):',Result);
end;
end;
function sys_openat(fd:Integer;path:PChar;flags,mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Result:=kern_openat(fd, path, UIO_USERSPACE, flags, mode);
//
if (curkthread<>nil) then
if is_guest_addr(curkthread^.td_frame.tf_rip) then
begin
Writeln('sys_openat(',fd,',"',path,'",0x',HexStr(flags,4),',0',OctStr(mode,3),'):',Result);
end;
end;
function kern_mkfifoat(fd:Integer;path:PChar;pathseg:uio_seg;mode:Integer):Integer;
label
restart,
_out;
var
mp:p_mount;
vattr:t_vattr;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
restart:
//bwillwrite();
NDINIT_AT(@nd, CREATE, LOCKPARENT or SAVENAME or MPSAFE or AUDITVNODE1, pathseg, path, fd, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
if (nd.ni_vp<>nil) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
if (nd.ni_vp=nd.ni_dvp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(EEXIST);
end;
if (vn_start_write(nd.ni_dvp, @mp, V_NOWAIT)<>0) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
VFS_UNLOCK_GIANT(vfslocked);
error:=vn_start_write(nil, @mp, V_XSLEEP or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
goto restart;
end;
VATTR_NULL(@vattr);
vattr.va_type:=VFIFO;
vattr.va_mode:=(mode and ALLPERMS) and (not fd_table.fd_cmask);
//error:=mac_vnode_check_create(td^.td_ucred, nd.ni_dvp, @nd.ni_cnd, @vattr);
//if (error<>0) then
// goto _out;
error:=VOP_MKNOD(nd.ni_dvp, @nd.ni_vp, @nd.ni_cnd, @vattr);
if (error=0) then
begin
vput(nd.ni_vp);
end;
_out:
vput(nd.ni_dvp);
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
NDFREE(@nd, NDF_ONLY_PNBUF);
Exit(error);
end;
function kern_mknodat(fd:Integer;path:PChar;pathseg:uio_seg;mode,dev:Integer):Integer;
label
restart;
var
vp:p_vnode;
mp:p_mount;
vattr:t_vattr;
error:Integer;
whiteout:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
whiteout:=0;
case (mode and S_IFMT) of
S_IFCHR,
S_IFBLK:
begin
error:=EPERM;
//error:=priv_check(td, PRIV_VFS_MKNOD_DEV);
end;
S_IFMT:
begin
error:=EPERM;
//error:=priv_check(td, PRIV_VFS_MKNOD_BAD);
end;
S_IFWHT:
begin
error:=EPERM;
//error:=priv_check(td, PRIV_VFS_MKNOD_WHT);
end;
S_IFIFO:
begin
if (dev=0) then
Exit(kern_mkfifoat(fd, path, pathseg, mode));
error:=EINVAL;
end
else
error:=EINVAL;
end;
if (error<>0) then
begin
Exit(error);
end;
restart:
//bwillwrite();
NDINIT_ATRIGHTS(@nd, CREATE, LOCKPARENT or SAVENAME or MPSAFE or AUDITVNODE1, pathseg, path, fd, CAP_MKFIFO, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
if (vp<>nil) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
if (vp=nd.ni_dvp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(EEXIST);
end else
begin
VATTR_NULL(@vattr);
vattr.va_mode:=(mode and ALLPERMS) and (not fd_table.fd_cmask);
vattr.va_rdev:=dev;
whiteout:=0;
case (mode and S_IFMT) of
S_IFMT: { used by badsect to flag bad sectors }
vattr.va_type:=VBAD;
S_IFCHR:
vattr.va_type:=VCHR;
S_IFBLK:
vattr.va_type:=VBLK;
S_IFWHT:
whiteout:=1;
else
Assert(False,'kern_mknod: invalid mode');
end;
end;
if (vn_start_write(nd.ni_dvp, @mp, V_NOWAIT)<>0) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
VFS_UNLOCK_GIANT(vfslocked);
error:=vn_start_write(nil, @mp, V_XSLEEP or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
goto restart;
end;
//if (error=0) and (whiteout=0) then
// error:=mac_vnode_check_create(td^.td_ucred, nd.ni_dvp, @nd.ni_cnd, @vattr);
if (error=0) then
begin
if (whiteout<>0) then
error:=VOP_WHITEOUT(nd.ni_dvp, @nd.ni_cnd, CREATE)
else
begin
error:=VOP_MKNOD(nd.ni_dvp, @nd.ni_vp, @nd.ni_cnd, @vattr);
if (error=0) then
begin
vput(nd.ni_vp);
end;
end;
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_mknod(path:PChar;pathseg:uio_seg;mode,dev:Integer):Integer;
begin
Exit(kern_mknodat(AT_FDCWD, path, pathseg, mode, dev));
end;
{
* Create a special file.
}
function sys_mknod(path:PChar;mode,dev:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_mknod(path, UIO_USERSPACE, mode, dev));
end;
function sys_mknodat(fd:Integer;path:PChar;mode,dev:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_mknodat(fd, path, UIO_USERSPACE, mode, dev));
end;
function kern_mkfifo(path:PChar;pathseg:uio_seg;mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_mkfifoat(AT_FDCWD, path, pathseg, mode));
end;
{
* Create a named pipe.
}
function sys_mkfifo(path:PChar;mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_mkfifo(path, UIO_USERSPACE, mode));
end;
function sys_mkfifoat(fd:Integer;path:PChar;mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_mkfifoat(fd, path, UIO_USERSPACE, mode));
end;
function can_hardlink(vp:p_vnode):Integer; inline;
begin
//error = priv_check_cred(cred, PRIV_VFS_LINK, 0);
//Exit(EPERM);
Exit(0);
end;
function kern_linkat(fd1,fd2:Integer;path1,path2:PChar;segflg:uio_seg;follow:Integer):Integer;
var
vp:p_vnode;
mp:p_mount;
nd:t_nameidata;
vfslocked:Integer;
lvfslocked:Integer;
error:Integer;
begin
//bwillwrite();
NDINIT_AT(@nd, LOOKUP, follow or MPSAFE or AUDITVNODE1, segflg, path1, fd1, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
vp:=nd.ni_vp;
if (vp^.v_type=VDIR) then
begin
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(EPERM); { POSIX }
end;
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then
begin
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
NDINIT_AT(@nd, CREATE, LOCKPARENT or SAVENAME or MPSAFE or AUDITVNODE2, segflg, path2, fd2, curkthread);
error:=nd_namei(@nd);
if (error=0) then
begin
lvfslocked:=NDHASGIANT(@nd);
if (nd.ni_vp<>nil) then
begin
if (nd.ni_dvp=nd.ni_vp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
error:=EEXIST;
end else
begin
error:=vn_lock(vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
if (error=0) then
begin
error:=can_hardlink(vp);
if (error=0) then
// error:=mac_vnode_check_link(td^.td_ucred, nd.ni_dvp, vp, @nd.ni_cnd);
//if (error=0) then
begin
error:=VOP_LINK(nd.ni_dvp, vp, @nd.ni_cnd);
end;
VOP_UNLOCK(vp, 0);
vput(nd.ni_dvp);
end;
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
VFS_UNLOCK_GIANT(lvfslocked);
end;
vrele(vp);
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_link(path,link:PChar;segflg:uio_seg):Integer;
begin
Exit(kern_linkat(AT_FDCWD, AT_FDCWD, path,link, segflg, FOLLOW));
end;
{
* Make a hard file link.
}
function sys_link(name1,name2:PChar):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_link(name1,name2,UIO_USERSPACE));
end;
function sys_linkat(fd1:Integer;path1:PChar;fd2:Integer;path2:PChar;flag:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
if ((flag and (not AT_SYMLINK_FOLLOW))<>0) then
begin
Exit(EINVAL);
end;
if ((flag and AT_SYMLINK_FOLLOW)<>0) then
begin
Exit(kern_linkat(fd1, fd2, path1, path2, UIO_USERSPACE, FOLLOW));
end else
begin
Exit(kern_linkat(fd1, fd2, path1, path2, UIO_USERSPACE, NOFOLLOW));
end;
end;
function kern_symlinkat(path1:PChar;fd:Integer;path2:PChar;segflg:uio_seg):Integer;
label
_out,
restart,
out2;
var
mp:p_mount;
vattr:t_vattr;
syspath:PChar;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
if (segflg=UIO_SYSSPACE) then
begin
syspath:=path1;
end else
begin
syspath:=AllocMem(MAXPATHLEN);
error:=copyinstr(path1, syspath, MAXPATHLEN, nil);
if (error<>0) then goto _out;
end;
restart:
//bwillwrite();
NDINIT_AT(@nd, CREATE, LOCKPARENT or SAVENAME or MPSAFE or AUDITVNODE1, segflg, path2, fd, curkthread);
error:=nd_namei(@nd);
if (error<>0) then goto _out;
vfslocked:=NDHASGIANT(@nd);
if (nd.ni_vp<>nil) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
if (nd.ni_vp=nd.ni_dvp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
error:=EEXIST;
goto _out;
end;
if (vn_start_write(nd.ni_dvp, @mp, V_NOWAIT)<>0) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
VFS_UNLOCK_GIANT(vfslocked);
error:=vn_start_write(nil, @mp, V_XSLEEP or PCATCH);
if (error<>0) then goto _out;
goto restart;
end;
VATTR_NULL(@vattr);
vattr.va_mode:=ACCESSPERMS and (not fd_table.fd_cmask);
//vattr.va_type:=VLNK;
//error:=mac_vnode_check_create(td^.td_ucred, nd.ni_dvp, @nd.ni_cnd, @vattr);
//if (error)
// goto out2;
error:=VOP_SYMLINK(nd.ni_dvp, @nd.ni_vp, @nd.ni_cnd, @vattr, syspath);
if (error=0) then
begin
vput(nd.ni_vp);
end;
out2:
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
_out:
if (segflg<>UIO_SYSSPACE) then
begin
FreeMem(syspath);
end;
Exit(error);
end;
function kern_symlink(path,link:PChar;segflg:uio_seg):Integer;
begin
Exit(kern_symlinkat(path, AT_FDCWD, link, segflg));
end;
{
* Make a symbolic link.
}
function sys_symlink(path,link:PChar):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_symlink(path, link, UIO_USERSPACE));
end;
function sys_symlinkat(path1:PChar;fd:Integer;path2:PChar):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_symlinkat(path1, fd, path2, UIO_USERSPACE));
end;
function kern_unlinkat(fd:Integer;path:PChar;pathseg:uio_seg;oldinum:Integer):Integer;
label
restart,
_out;
var
mp:p_mount;
vp:p_vnode;
error:Integer;
nd:t_nameidata;
sb:t_stat;
vfslocked:Integer;
function _vn_stat:Integer; inline;
begin
error:=vn_stat(vp, @sb);
Result:=error;
end;
begin
restart:
//bwillwrite();
NDINIT_AT(@nd, DELETE, LOCKPARENT or LOCKLEAF or MPSAFE or AUDITVNODE1, pathseg, path, fd, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
if (error=EINVAL) then
begin
Exit(EPERM)
end else
begin
Exit(error);
end;
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
if (vp^.v_type=VDIR) and (oldinum=0) then
begin
error:=EPERM; { POSIX }
end else
if (oldinum<>0) and
(_vn_stat=0) and
(sb.st_ino<>oldinum) then
begin
error:=EIDRM; { Identifier removed }
end else
begin
{
* The root of a mounted filesystem cannot be deleted.
*
* XXX: can this only be a VDIR case?
}
if ((vp^.v_vflag and VV_ROOT)<>0) then
begin
error:=EBUSY;
end;
end;
if (error=0) then
begin
if (vn_start_write(nd.ni_dvp, @mp, V_NOWAIT)<>0) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if (vp=nd.ni_dvp) then
vrele(vp)
else
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
error:=vn_start_write(nil, @mp, V_XSLEEP or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
goto restart;
end;
//error:=mac_vnode_check_unlink(td^.td_ucred, nd.ni_dvp, vp, @nd.ni_cnd);
//if (error)
// goto _out;
error:=VOP_REMOVE(nd.ni_dvp, vp, @nd.ni_cnd);
_out:
vn_finished_write(mp);
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if (vp=nd.ni_dvp) then
vrele(vp)
else
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_unlink(path:PChar;pathseg:uio_seg):Integer;
begin
Exit(kern_unlinkat(AT_FDCWD, path, pathseg, 0));
end;
function sys_unlinkat(fd:Integer;path:PChar;flag:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
if ((flag and (not AT_REMOVEDIR))<>0) then
begin
Exit(EINVAL);
end;
if ((flag and AT_REMOVEDIR)<>0) then
Exit(kern_rmdirat(fd, path, UIO_USERSPACE))
else
Exit(kern_unlinkat(fd, path, UIO_USERSPACE, 0));
end;
{
* Delete a name from the filesystem.
}
function sys_unlink(path:PChar):Integer;
begin
Exit(kern_unlink(path, UIO_USERSPACE));
end;
{
* Reposition read/write file offset.
}
function sys_lseek(fd:Integer;offset:Int64;whence:Integer):Integer;
label
drop,
_break;
var
td:p_kthread;
fp:p_file;
vp:p_vnode;
vattr:t_vattr;
foffset,size:Int64;
error,noneg:Integer;
vfslocked:Integer;
begin
td:=curkthread;
if (td=nil) then Exit(-1);
error:=fget(fd, CAP_SEEK, @fp);
if (error<>0) then
begin
Exit(error);
end;
if ((fp^.f_ops^.fo_flags and DFLAG_SEEKABLE)=0) then
begin
fdrop(fp);
Exit(ESPIPE);
end;
vp:=fp^.f_vnode;
foffset:=foffset_lock(fp, 0);
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
noneg:=ord(vp^.v_type<>VCHR);
case whence of
L_INCR: //current
begin
if (noneg<>0) and
((foffset < 0) or
((offset > 0) and (foffset > (High(Int64) - offset)))) then
begin
error:=EOVERFLOW;
goto _break;
end;
Inc(offset,foffset);
end;
L_XTND: //end
begin
vn_lock(vp, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
error:=VOP_GETATTR(vp, @vattr);
VOP_UNLOCK(vp, 0);
if (error<>0) then
begin
goto _break;
end;
{
* If the file references a disk device, then fetch
* the media size and use that to determine the ending
* offset.
}
if (vattr.va_size=0) and
(vp^.v_type=VCHR) and
(fo_ioctl(fp, DIOCGMEDIASIZE, @size)=0) then
begin
vattr.va_size:=size;
end;
if (noneg<>0) and
((vattr.va_size < 0) or
((offset > 0) and (vattr.va_size > High(Int64) - offset))) then
begin
error:=EOVERFLOW;
goto _break;
end;
Inc(offset,vattr.va_size);
end;
L_SET, //absolute
SEEK_DATA:
error:=fo_ioctl(fp, FIOSEEKDATA, @offset);
SEEK_HOLE:
error:=fo_ioctl(fp, FIOSEEKHOLE, @offset);
else
error:=EINVAL;
end;
_break:
if (error=0) and (noneg<>0) and (offset < 0) then
begin
error:=EINVAL;
end;
if (error<>0) then
begin
goto drop;
end;
VFS_KNOTE_UNLOCKED(vp, 0);
td^.td_retval[0]:=offset;
drop:
fdrop(fp);
VFS_UNLOCK_GIANT(vfslocked);
if (error<>0) then
begin
foffset_unlock(fp, offset, FOF_NOUPDATE);
end else
begin
foffset_unlock(fp, offset, 0);
end;
Exit(error);
end;
{
* Check access permissions using passed credentials.
}
function vn_access(vp:p_vnode;user_flags:Integer):Integer;
var
error:Integer;
accmode:accmode_t;
function _vn_writechk:Integer; inline;
begin
error:=vn_writechk(vp);
Result:=error;
end;
begin
{ Flags=0 means only check for existence. }
error:=0;
if (user_flags<>0) then
begin
accmode:=0;
if ((user_flags and R_OK)<>0) then
accmode:=accmode or VREAD;
if ((user_flags and W_OK)<>0) then
accmode:=accmode or VWRITE;
if ((user_flags and X_OK)<>0) then
accmode:=accmode or VEXEC;
//error:=mac_vnode_check_access(cred, vp, accmode);
//if (error<>0) then
// Exit(error);
if ((accmode and VWRITE)=0) or (_vn_writechk=0) then
begin
error:=VOP_ACCESS(vp, accmode);
end;
end;
Exit(error);
end;
function kern_accessat(fd:Integer;path:PChar;pathseg:uio_seg;flags,mode:Integer):Integer;
label
out1;
var
vp:p_vnode;
nd:t_nameidata;
vfslocked:Integer;
error:Integer;
begin
NDINIT_ATRIGHTS(@nd, LOOKUP, FOLLOW or LOCKSHARED or LOCKLEAF or MPSAFE or AUDITVNODE1, pathseg, path, fd, CAP_FSTAT, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
goto out1;
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
error:=vn_access(vp, mode);
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
out1:
Exit(error);
end;
function kern_access(path:PChar;pathseg:uio_seg;mode:Integer):Integer;
begin
Exit(kern_accessat(AT_FDCWD, path, pathseg, 0, mode));
end;
{
* Check access permissions using 'real' credentials.
}
function sys_access(path:PChar;flags:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_access(path, UIO_USERSPACE, flags));
end;
type
t_statat_hook_cb=procedure(vp:p_vnode;sbp:p_stat);
function kern_statat_vnhook(flag,fd:Integer;
path:PChar;
pathseg:uio_seg;
sbp:p_stat;
hook:t_statat_hook_cb):Integer;
var
nd:t_nameidata;
sb:t_stat;
error, vfslocked:Integer;
begin
if (flag and (not AT_SYMLINK_NOFOLLOW))<>0 then
begin
Exit(EINVAL);
end;
if ((flag and AT_SYMLINK_NOFOLLOW)<>0) then
begin
NDINIT_ATRIGHTS(@nd, LOOKUP, NOFOLLOW or LOCKSHARED or LOCKLEAF or AUDITVNODE1 or MPSAFE, pathseg,
path, fd, CAP_FSTAT, curkthread);
end else
begin
NDINIT_ATRIGHTS(@nd, LOOKUP, FOLLOW or LOCKSHARED or LOCKLEAF or AUDITVNODE1 or MPSAFE, pathseg,
path, fd, CAP_FSTAT, curkthread);
end;
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
error:=vn_stat(nd.ni_vp, @sb);
if (error=0) then
begin
if (hook<>nil) then
begin
hook(nd.ni_vp, @sb);
end;
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
if (error<>0) then
begin
Exit(error);
end;
//error:=priv_check(td,683);
error:=EPERM;
if (error<>0) then
begin
sb.st_dev :=0;
sb.st_ino :=0;
sb.st_nlink :=0;
sb.st_uid :=0;
sb.st_gid :=0;
sb.st_rdev :=0;
sb.st_flags :=0;
sb.st_gen :=0;
sb.st_lspare:=0;
end;
sbp^:=sb;
Exit(0);
end;
function kern_statat(flag,fd:Integer;path:PChar;
pathseg:uio_seg;sbp:p_stat):Integer; inline;
begin
Exit(kern_statat_vnhook(flag, fd, path, pathseg, sbp, nil));
end;
function kern_stat(path:PChar;pathseg:uio_seg;sbp:p_stat):Integer; inline;
begin
Exit(kern_statat(0, AT_FDCWD, path, pathseg, sbp));
end;
{
* Get file status; this version follows links.
}
function sys_stat(path:PChar;ub:Pointer):Integer;
var
sb:t_stat;
error:Integer;
begin
begin
Writeln('sys_stat("',path,'")');
end;
error:=kern_stat(path, UIO_USERSPACE, @sb);
if (error=0) then
begin
error:=copyout(@sb, ub, sizeof(sb));
end;
Exit(error);
end;
function sys_fstatat(fd:Integer;path:PChar;buf:Pointer;flag:Integer):Integer;
var
sb:p_stat;
error:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=kern_statat(flag, fd, path, UIO_USERSPACE, @sb);
if (error=0) then
begin
error:=copyout(@sb, buf, sizeof(sb));
end;
Exit(error);
end;
function kern_lstat(path:PChar;pathseg:uio_seg;sbp:p_stat):Integer;
begin
Exit(kern_statat(AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, pathseg, sbp));
end;
{
* Get file status; this version does not follow links.
}
function sys_lstat(path:PChar;ub:Pointer):Integer;
var
sb:t_stat;
error:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=kern_lstat(path, UIO_USERSPACE, @sb);
if (error=0) then
begin
error:=copyout(@sb, ub, sizeof(sb));
end;
Exit(error);
end;
function kern_pathconf(path:PChar;pathseg:uio_seg;name:Integer;flags:QWORD):Integer;
var
td:p_kthread;
nd:t_nameidata;
error,vfslocked:Integer;
begin
td:=curkthread;
if (td=nil) then Exit(-1);
NDINIT(@nd, LOOKUP, LOCKSHARED or LOCKLEAF or MPSAFE or AUDITVNODE1 or flags, pathseg, path, td);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
{ If asynchronous I/O is available, it works for all files. }
if (name=_PC_ASYNC_IO) then
td^.td_retval[0]:=async_io_version
else
error:=VOP_PATHCONF(nd.ni_vp, name, @td^.td_retval);
vput(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Get configurable pathname variables.
}
function sys_pathconf(path:PChar;name:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_pathconf(path, UIO_USERSPACE, name, FOLLOW));
end;
function kern_readlinkat(fd:Integer;path:PChar;pathseg:uio_seg;
buf:PChar;bufseg:uio_seg;count:QWORD):Integer;
var
td:p_kthread;
vp:p_vnode;
aiov:iovec;
auio:t_uio;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
if (count > IOSIZE_MAX) then
begin
Exit(EINVAL);
end;
td:=curkthread;
if (td=nil) then Exit(-1);
NDINIT_AT(@nd, LOOKUP, NOFOLLOW or LOCKSHARED or LOCKLEAF or MPSAFE or AUDITVNODE1, pathseg, path, fd, td);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
//error:=mac_vnode_check_readlink(td^.td_ucred, vp);
//if (error<>0) then
//begin
// vput(vp);
// VFS_UNLOCK_GIANT(vfslocked);
// Exit(error);
//end;
if (vp^.v_type<>VLNK) then
error:=EINVAL
else
begin
aiov.iov_base :=buf;
aiov.iov_len :=count;
auio.uio_iov :=@aiov;
auio.uio_iovcnt:=1;
auio.uio_offset:=0;
auio.uio_rw :=UIO_READ;
auio.uio_segflg:=bufseg;
auio.uio_td :=td;
auio.uio_resid :=count;
error:=VOP_READLINK(vp, @auio);
td^.td_retval[0]:=count - auio.uio_resid;
end;
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_readlink(path:PChar;pathseg:uio_seg;buf:PChar;
bufseg:uio_seg;count:QWORD):Integer;
begin
Exit(kern_readlinkat(AT_FDCWD, path, pathseg, buf, bufseg, count));
end;
{
* Exittarget name of a symbolic link.
}
function sys_readlink(path,buf:PChar;count:QWORD):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_readlink(path, UIO_USERSPACE, buf, UIO_USERSPACE, count));
end;
{
* Common implementation code for chflags() and fchflags().
}
function setfflags(vp:p_vnode;flags:Integer):Integer;
var
error:Integer;
mp:p_mount;
vattr:t_vattr;
begin
{ We can't support the value matching VNOVAL. }
if (flags=VNOVAL) then Exit(EOPNOTSUPP);
{
* Prevent non-root users from setting flags on devices. When
* a device is reused, users can retain ownership of the device
* if they are allowed to set flags and programs assume that
* chown can't fail when done as root.
}
if (vp^.v_type=VCHR) or (vp^.v_type=VBLK) then
begin
error:=EPERM;
//error:=priv_check(td, PRIV_VFS_CHFLAGS_DEV);
if (error<>0) then
begin
Exit(error);
end;
end;
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then Exit(error);
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
VATTR_NULL(@vattr);
vattr.va_flags:=flags;
//error:=mac_vnode_check_setflags(td^.td_ucred, vp, vattr.va_flags);
//if (error=0) then
begin
error:=VOP_SETATTR(vp, @vattr);
end;
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
Exit(error);
end;
{
* Change flags of a file given a path name.
}
function sys_chflags(path:PChar;flags:Integer):Integer;
var
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
NDINIT(@nd, LOOKUP, FOLLOW or MPSAFE or AUDITVNODE1, UIO_USERSPACE, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
vfslocked:=NDHASGIANT(@nd);
error:=setfflags(nd.ni_vp, flags);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Same as chflags() but doesn't follow symlinks.
}
function sys_lchflags(path:PChar;flags:Integer):Integer;
var
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
NDINIT(@nd, LOOKUP, NOFOLLOW or MPSAFE or AUDITVNODE1, UIO_USERSPACE, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
error:=setfflags(nd.ni_vp, flags);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Change flags of a file given a file descriptor.
}
function sys_fchflags(fd,flags:Integer):Integer;
var
fp:p_file;
vfslocked:Integer;
error:Integer;
begin
error:=getvnode(fd, CAP_FCHFLAGS, @fp);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=VFS_LOCK_GIANT(fp^.f_vnode^.v_mount);
error:=setfflags(fp^.f_vnode, flags);
VFS_UNLOCK_GIANT(vfslocked);
fdrop(fp);
Exit(error);
end;
{
* Common implementation code for chmod(), lchmod() and fchmod().
}
function setfmode(vp:p_vnode;mode:Integer):Integer;
var
error:Integer;
mp:p_mount;
vattr:t_vattr;
begin
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
VATTR_NULL(@vattr);
vattr.va_mode:=mode and ALLPERMS;
//error:=mac_vnode_check_setmode(cred, vp, vattr.va_mode);
//if (error=0) then
begin
error:=VOP_SETATTR(vp, @vattr);
end;
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
Exit(error);
end;
function kern_fchmodat(fd:Integer;path:PChar;pathseg:uio_seg;mode,flag:Integer):Integer;
var
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
follow:Integer;
begin
if (flag and AT_SYMLINK_NOFOLLOW)<>0 then
begin
follow:=NOFOLLOW;
end else
begin
follow:=FOLLOW;
end;
NDINIT_ATRIGHTS(@nd, LOOKUP, follow or MPSAFE or AUDITVNODE1, pathseg, path, fd, CAP_FCHMOD, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
error:=setfmode(nd.ni_vp, mode);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_chmod(path:PChar;pathseg:uio_seg;mode:Integer):Integer;
begin
Exit(kern_fchmodat(AT_FDCWD, path, pathseg, mode, 0));
end;
{
* Change mode of a file given path name.
}
function sys_chmod(path:PChar;mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_chmod(path, UIO_USERSPACE, mode));
end;
function sys_fchmodat(fd:Integer;path:PChar;mode,flag:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
if ((flag and (not AT_SYMLINK_NOFOLLOW))<>0) then
begin
Exit(EINVAL);
end;
Exit(kern_fchmodat(fd, path, UIO_USERSPACE, mode, flag));
end;
{
* Change mode of a file given path name (don't follow links.)
}
function sys_lchmod(path:PChar;mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_fchmodat(AT_FDCWD, path, UIO_USERSPACE, mode, AT_SYMLINK_NOFOLLOW));
end;
{
* Change mode of a file given a file descriptor.
}
function sys_fchmod(fd,mode:Integer):Integer;
var
fp:p_file;
error:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=fget(fd, CAP_FCHMOD, @fp);
if (error<>0) then
begin
Exit(error);
end;
error:=fo_chmod(fp, mode);
fdrop(fp);
Exit(error);
end;
{
* Common implementation for chown(), lchown(), and fchown()
}
function setfown(vp:p_vnode;uid:uid_t;gid:gid_t):Integer;
var
error:Integer;
mp:p_mount;
vattr:t_vattr;
begin
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
VATTR_NULL(@vattr);
vattr.va_uid:=uid;
vattr.va_gid:=gid;
//error:=mac_vnode_check_setowner(cred, vp, vattr.va_uid, vattr.va_gid);
//if (error=0) then
begin
error:=VOP_SETATTR(vp, @vattr);
end;
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
Exit(error);
end;
function kern_fchownat(fd:Integer;path:PChar;pathseg:uio_seg;uid,gid,flag:Integer):Integer;
var
nd:t_nameidata;
error,vfslocked,follow:Integer;
begin
if (flag and AT_SYMLINK_NOFOLLOW)<>0 then
begin
follow:=NOFOLLOW;
end else
begin
follow:=FOLLOW;
end;
NDINIT_ATRIGHTS(@nd, LOOKUP, follow or MPSAFE or AUDITVNODE1, pathseg, path, fd, CAP_FCHOWN, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
error:=setfown(nd.ni_vp, uid, gid);
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_chown(path:PChar;pathseg:uio_seg;uid,gid:Integer):Integer;
begin
Exit(kern_fchownat(AT_FDCWD, path, pathseg, uid, gid, 0));
end;
{
* Set ownership given a path name.
}
function sys_chown(path:PChar;uid,gid:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_chown(path, UIO_USERSPACE, uid, gid));
end;
function sys_fchownat(fd:Integer;path:PChar;uid,gid,flag:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
if ((flag and (not AT_SYMLINK_NOFOLLOW))<>0) then
begin
Exit(EINVAL);
end;
Exit(kern_fchownat(fd, path, UIO_USERSPACE, uid, gid, flag));
end;
function kern_lchown(path:PChar;pathseg:uio_seg;uid,gid:Integer):Integer;
begin
Exit(kern_fchownat(AT_FDCWD, path, pathseg, uid, gid,AT_SYMLINK_NOFOLLOW));
end;
{
* Set ownership given a path name, do not cross symlinks.
}
function sys_lchown(path:PChar;uid,gid:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_lchown(path, UIO_USERSPACE, uid, gid));
end;
{
* Set ownership given a file descriptor.
}
function sys_fchown(fd,uid,gid:Integer):Integer;
var
fp:p_file;
error:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
error:=fget(fd, CAP_FCHOWN, @fp);
if (error<>0) then
begin
Exit(error);
end;
error:=fo_chown(fp, uid, gid);
fdrop(fp);
Exit(error);
end;
{
* Common implementation code for utimes(), lutimes(), and futimes().
}
function getutimes(usrtvp:p_timeval;tvpseg:uio_seg;tsp:p_timespec):Integer;
var
tv:array[0..1] of timeval;
tvp:p_timeval;
error:Integer;
begin
if (usrtvp=nil) then
begin
vfs_timestamp(@tsp[0]);
tsp[1]:=tsp[0];
end else
begin
if (tvpseg=UIO_SYSSPACE) then
begin
tvp:=usrtvp;
end else
begin
error:=copyin(usrtvp, @tv, sizeof(tv));
if (error<>0) then
begin
Exit(error);
end;
tvp:=tv;
end;
if (tvp[0].tv_usec < 0) or (tvp[0].tv_usec >= 1000000) or
(tvp[1].tv_usec < 0) or (tvp[1].tv_usec >= 1000000) then
begin
Exit(EINVAL);
end;
TIMEVAL_TO_TIMESPEC(@tvp[0], @tsp[0]);
TIMEVAL_TO_TIMESPEC(@tvp[1], @tsp[1]);
end;
Exit(0);
end;
{
* Common implementation code for utimes(), lutimes(), and futimes().
}
function setutimes(vp:p_vnode;ts:p_timespec;numtimes,nilflag:Integer):Integer;
var
error,setbirthtime:Integer;
mp:p_mount;
vattr:t_vattr;
begin
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then Exit(error);
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
setbirthtime:=0;
if (numtimes < 3) and
(VOP_GETATTR(vp, @vattr)=0) and
(timespeccmp_lt(@ts[1], @vattr.va_birthtime)<>0) then //<
begin
setbirthtime:=1;
end;
VATTR_NULL(@vattr);
vattr.va_atime:=ts[0];
vattr.va_mtime:=ts[1];
if (setbirthtime<>0) then
begin
vattr.va_birthtime:=ts[1];
end;
if (numtimes > 2) then
begin
vattr.va_birthtime:=ts[2];
end;
if (nilflag<>0) then
begin
vattr.va_vaflags:=vattr.va_vaflags or VA_UTIMES_NULL;
//error:=mac_vnode_check_setutimes(td^.td_ucred, vp, vattr.va_atime, vattr.va_mtime);
end;
if (error=0) then
begin
error:=VOP_SETATTR(vp, @vattr);
end;
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
Exit(error);
end;
function kern_utimesat(fd:Integer;path:PChar;pathseg:uio_seg;
tptr:p_timeval;tptrseg:uio_seg):Integer;
var
nd:t_nameidata;
ts:array[0..1] of timespec;
error,vfslocked:Integer;
begin
error:=getutimes(tptr, tptrseg, ts);
if (error<>0) then Exit(error);
NDINIT_ATRIGHTS(@nd, LOOKUP, FOLLOW or MPSAFE or AUDITVNODE1, pathseg, path, fd, CAP_FUTIMES, curkthread);
error:=nd_namei(@nd);
if (error<>0) then Exit(error);
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
error:=setutimes(nd.ni_vp, ts, 2, ord(tptr=nil));
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_utimes(path:PChar;pathseg:uio_seg;
tptr:p_timeval;tptrseg:uio_seg):Integer;
begin
Exit(kern_utimesat(AT_FDCWD, path, pathseg, tptr, tptrseg));
end;
{
* Set the access and modification times of a file.
}
function sys_utimes(path:PChar;tptr:Pointer):Integer;
begin
Exit(kern_utimes(path, UIO_USERSPACE, tptr, UIO_USERSPACE));
end;
function sys_futimesat(fd:Integer;path:PChar;times:Pointer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_utimesat(fd, path, UIO_USERSPACE, times, UIO_USERSPACE));
end;
function kern_lutimes(path:PChar;pathseg:uio_seg;
tptr:p_timeval;tptrseg:uio_seg):Integer;
var
ts:array[0..1] of timespec;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
error:=getutimes(tptr, tptrseg, ts);
if (error<>0) then Exit(error);
NDINIT(@nd, LOOKUP, NOFOLLOW or MPSAFE or AUDITVNODE1, pathseg, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then Exit(error);
vfslocked:=NDHASGIANT(@nd);
NDFREE(@nd, NDF_ONLY_PNBUF);
error:=setutimes(nd.ni_vp, ts, 2, ord(tptr=nil));
vrele(nd.ni_vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Set the access and modification times of a file.
}
function sys_lutimes(path:PChar;tptr:Pointer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_lutimes(path, UIO_USERSPACE, tptr, UIO_USERSPACE));
end;
function kern_futimes(fd:Integer;tptr:p_timeval;tptrseg:uio_seg):Integer;
var
ts:array[0..1] of timespec;
fp:p_file;
vfslocked:Integer;
error:Integer;
begin
error:=getutimes(tptr, tptrseg, ts);
if (error<>0) then
begin
Exit(error);
end;
error:=getvnode(fd, CAP_FUTIMES, @fp);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=VFS_LOCK_GIANT(fp^.f_vnode^.v_mount);
error:=setutimes(fp^.f_vnode, ts, 2, ord(tptr=nil));
VFS_UNLOCK_GIANT(vfslocked);
fdrop(fp);
Exit(error);
end;
{
* Set the access and modification times of a file.
}
function sys_futimes(fd:Integer;tptr:Pointer):Integer;
begin
Exit(kern_futimes(fd, tptr, UIO_USERSPACE));
end;
function kern_truncate(path:PChar;pathseg:uio_seg;length:Int64):Integer;
var
mp:p_mount;
vp:p_vnode;
rl_cookie:Pointer;
vattr:t_vattr;
nd:t_nameidata;
error,vfslocked:Integer;
begin
if (length < 0) then
begin
Exit(EINVAL);
end;
NDINIT(@nd, LOOKUP, FOLLOW or MPSAFE or AUDITVNODE1, pathseg, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
rl_cookie:=vn_rangelock_wlock(vp, 0, High(Int64));
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then
begin
vn_rangelock_unlock(vp, rl_cookie);
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
NDFREE(@nd, NDF_ONLY_PNBUF);
vn_lock(vp, LK_EXCLUSIVE or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
if (vp^.v_type=VDIR) then
error:=EISDIR
//else if ((error:=mac_vnode_check_write(td^.td_ucred, NOCRED, vp)))
//begin
//end
else
begin
error:=vn_writechk(vp);
if (error=0) then
begin
error:=VOP_ACCESS(vp, VWRITE);
if (error=0) then
begin
VATTR_NULL(@vattr);
vattr.va_size:=length;
error:=VOP_SETATTR(vp, @vattr);
end;
end;
end;
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
vn_rangelock_unlock(vp, rl_cookie);
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Truncate a file given its path name.
}
function sys_truncate(path:PChar;length:Int64):Integer;
begin
Exit(kern_truncate(path, UIO_USERSPACE, length));
end;
{
* Sync an open file.
}
function kern_fsync(fd:Integer;fullsync:Boolean):Integer;
label
drop;
var
vp:p_vnode;
mp:p_mount;
fp:p_file;
vfslocked:Integer;
error,lock_flags:Integer;
begin
error:=getvnode(fd, CAP_FSYNC, @fp);
if (error<>0) then Exit(error);
vp:=fp^.f_vnode;
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
error:=vn_start_write(vp, @mp, V_WAIT or PCATCH);
if (error<>0) then goto drop;
if MNT_SHARED_WRITES(mp) or
((mp=nil) and MNT_SHARED_WRITES(vp^.v_mount)) then
begin
lock_flags:=LK_SHARED;
end else
begin
lock_flags:=LK_EXCLUSIVE;
end;
vn_lock(vp, lock_flags or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
if (vp^.v_object<>nil) then
begin
VM_OBJECT_LOCK(vp^.v_object);
vm_object_page_clean(vp^.v_object, 0, 0, 0);
VM_OBJECT_UNLOCK(vp^.v_object);
end;
error:=VOP_FSYNC(vp, MNT_WAIT or ((ord(fullsync) and 1) shl 1));
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
drop:
VFS_UNLOCK_GIANT(vfslocked);
fdrop(fp);
Exit(error);
end;
function sys_fsync(fd:Integer):Integer;
begin
Exit(kern_fsync(fd, true));
end;
function sys_fdatasync(fd:Integer):Integer;
begin
Exit(kern_fsync(fd, false));
end;
function kern_renameat(oldfd:Integer;old:PChar;newfd:Integer;new:PChar;pathseg:uio_seg):Integer;
label
out1,
_out;
var
mp:p_mount;
tvp,fvp,tdvp:p_vnode;
fromnd,tond:t_nameidata;
tvfslocked:Integer;
fvfslocked:Integer;
error:Integer;
begin
mp:=nil;
//bwillwrite();
NDINIT_ATRIGHTS(@fromnd, DELETE, LOCKPARENT or LOCKLEAF or SAVESTART or
MPSAFE or AUDITVNODE1, pathseg, old, oldfd, CAP_DELETE, curkthread);
error:=nd_namei(@fromnd);
if (error<>0) then
begin
Exit(error);
end;
fvfslocked:=NDHASGIANT(@fromnd);
tvfslocked:=0;
//error:=mac_vnode_check_rename_from(td^.td_ucred, fromnd.ni_dvp,
// fromnd.ni_vp, @fromnd.ni_cnd);
VOP_UNLOCK(fromnd.ni_dvp, 0);
if (fromnd.ni_dvp<>fromnd.ni_vp) then
begin
VOP_UNLOCK(fromnd.ni_vp, 0);
end;
fvp:=fromnd.ni_vp;
if (error=0) then
begin
error:=vn_start_write(fvp, @mp, V_WAIT or PCATCH);
end;
if (error<>0) then
begin
NDFREE(@fromnd, NDF_ONLY_PNBUF);
vrele(fromnd.ni_dvp);
vrele(fvp);
goto out1;
end;
NDINIT_ATRIGHTS(@tond, RENAME, LOCKPARENT or LOCKLEAF or NOCACHE or
SAVESTART or MPSAFE or AUDITVNODE2, pathseg, new, newfd, CAP_CREATE,
curkthread);
if (fromnd.ni_vp^.v_type=VDIR) then
begin
tond.ni_cnd.cn_flags:=tond.ni_cnd.cn_flags or WILLBEDIR;
end;
error:=nd_namei(@tond);
if (error<>0) then
begin
{ Translate error code for rename('dir1', 'dir2/.'). }
if (error=EISDIR) and (fvp^.v_type=VDIR) then
begin
error:=EINVAL;
end;
NDFREE(@fromnd, NDF_ONLY_PNBUF);
vrele(fromnd.ni_dvp);
vrele(fvp);
vn_finished_write(mp);
goto out1;
end;
tvfslocked:=NDHASGIANT(@tond);
tdvp:=tond.ni_dvp;
tvp:=tond.ni_vp;
if (tvp<>nil) then
begin
if (fvp^.v_type=VDIR) and (tvp^.v_type<>VDIR) then
begin
error:=ENOTDIR;
goto _out;
end else
if (fvp^.v_type<>VDIR) and (tvp^.v_type=VDIR) then
begin
error:=EISDIR;
goto _out;
end;
end;
if (fvp=tdvp) then
begin
error:=EINVAL;
goto _out;
end;
{
* If the source is the same as the destination (that is, if they
* are links to the same vnode), then there is nothing to do.
}
if (fvp=tvp) then
begin
error:=-1;
end;
//else
// error:=mac_vnode_check_rename_to(td^.td_ucred, tdvp, tond.ni_vp, fromnd.ni_dvp=tdvp, @tond.ni_cnd);
_out:
if (error=0) then
begin
error:=VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, @fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, @tond.ni_cnd);
NDFREE(@fromnd, NDF_ONLY_PNBUF);
NDFREE(@tond, NDF_ONLY_PNBUF);
end else
begin
NDFREE(@fromnd, NDF_ONLY_PNBUF);
NDFREE(@tond, NDF_ONLY_PNBUF);
if (tvp<>nil) then
begin
vput(tvp);
end;
if (tdvp=tvp) then
vrele(tdvp)
else
vput(tdvp);
vrele(fromnd.ni_dvp);
vrele(fvp);
end;
vrele(tond.ni_startdir);
vn_finished_write(mp);
out1:
if (fromnd.ni_startdir<>nil) then
begin
vrele(fromnd.ni_startdir);
end;
VFS_UNLOCK_GIANT(fvfslocked);
VFS_UNLOCK_GIANT(tvfslocked);
if (error=-1) then Exit(0);
Exit(error);
end;
function kern_rename(from,_to:PChar;pathseg:uio_seg):Integer;
begin
Exit(kern_renameat(AT_FDCWD, from, AT_FDCWD, _to, pathseg));
end;
{
* Rename files. Source and destination must either both be directories, or
* both not be directories. If target is a directory, it must be empty.
}
function sys_rename(from,_to:PChar):Integer;
begin
Exit(kern_rename(from, _to, UIO_USERSPACE));
end;
function sys_renameat(oldfd:Integer;old:PChar;newfd:Integer;new:PChar):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_renameat(oldfd, old, newfd, new, UIO_USERSPACE));
end;
function kern_mkdirat(fd:Integer;path:PChar;segflg:uio_seg;mode:Integer):Integer;
label
restart,
_out;
var
mp:p_mount;
vp:p_vnode;
vattr:t_vattr;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
restart:
//bwillwrite();
NDINIT_ATRIGHTS(@nd, CREATE, LOCKPARENT or SAVENAME or MPSAFE or
AUDITVNODE1, segflg, path, fd, CAP_MKDIR, curkthread);
nd.ni_cnd.cn_flags:=nd.ni_cnd.cn_flags or WILLBEDIR;
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
if (vp<>nil) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
{
* XXX namei called with LOCKPARENT but not LOCKLEAF has
* the strange behaviour of leaving the vnode unlocked
* if the target is the same vnode as the parent.
}
if (vp=nd.ni_dvp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
vrele(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(EEXIST);
end;
if (vn_start_write(nd.ni_dvp, @mp, V_NOWAIT)<>0) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
VFS_UNLOCK_GIANT(vfslocked);
error:=vn_start_write(nil, @mp, V_XSLEEP or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
goto restart;
end;
VATTR_NULL(@vattr);
vattr.va_type:=VDIR;
vattr.va_mode:=(mode and ACCESSPERMS) and (not fd_table.fd_cmask);
//error:=mac_vnode_check_create(td^.td_ucred, nd.ni_dvp, @nd.ni_cnd, @vattr);
//if (error)
// goto out;
error:=VOP_MKDIR(nd.ni_dvp, @nd.ni_vp, @nd.ni_cnd, @vattr);
_out:
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if (error=0) then
begin
vput(nd.ni_vp);
end;
vn_finished_write(mp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_mkdir(path:PChar;segflg:uio_seg;mode:Integer):Integer;
begin
Exit(kern_mkdirat(AT_FDCWD, path, segflg, mode));
end;
{
* Make a directory file.
}
function sys_mkdir(path:PChar;mode:Integer):Integer;
begin
Exit(kern_mkdir(path, UIO_USERSPACE, mode));
end;
function sys_mkdirat(fd:Integer;path:PChar;mode:Integer):Integer;
begin
//priv_check(td,683);
Exit(EPERM);
Exit(kern_mkdirat(fd, path, UIO_USERSPACE, mode));
end;
function kern_rmdirat(fd:Integer;path:PChar;pathseg:uio_seg):Integer;
label
restart,
_out;
var
mp:p_mount;
vp:p_vnode;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
restart:
//bwillwrite();
NDINIT_ATRIGHTS(@nd, DELETE, LOCKPARENT or LOCKLEAF or MPSAFE or
AUDITVNODE1, pathseg, path, fd, CAP_RMDIR, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
if (vp^.v_type<>VDIR) then
begin
error:=ENOTDIR;
goto _out;
end;
{
* No rmdir '.' please.
}
if (nd.ni_dvp=vp) then
begin
error:=EINVAL;
goto _out;
end;
{
* The root of a mounted filesystem cannot be deleted.
}
if ((vp^.v_vflag and VV_ROOT)<>0) then
begin
error:=EBUSY;
goto _out;
end;
//error:=mac_vnode_check_unlink(td^.td_ucred, nd.ni_dvp, vp, @nd.ni_cnd);
//if (error<>0) then
// goto _out;
if (vn_start_write(nd.ni_dvp, @mp, V_NOWAIT)<>0) then
begin
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(vp);
if (nd.ni_dvp=vp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
VFS_UNLOCK_GIANT(vfslocked);
error:=vn_start_write(nil, @mp, V_XSLEEP or PCATCH);
if (error<>0) then
begin
Exit(error);
end;
goto restart;
end;
error:=VOP_RMDIR(nd.ni_dvp, nd.ni_vp, @nd.ni_cnd);
vn_finished_write(mp);
_out:
NDFREE(@nd, NDF_ONLY_PNBUF);
vput(vp);
if (nd.ni_dvp=vp) then
vrele(nd.ni_dvp)
else
vput(nd.ni_dvp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
function kern_rmdir(path:PChar;pathseg:uio_seg):Integer;
begin
Exit(kern_rmdirat(AT_FDCWD, path, pathseg));
end;
{
* Remove a directory file.
}
function sys_rmdir(path:PChar):Integer;
begin
Exit(kern_rmdir(path, UIO_USERSPACE));
end;
function kern_getdirentries(fd:Integer;buf:Pointer;count:DWORD;basep:PInt64):Integer;
label
unionread,
fail;
var
td:p_kthread;
vp:p_vnode;
fp:p_file;
auio:t_uio;
aiov:iovec;
vfslocked:Integer;
loff:Int64;
error,eofflag:Integer;
foffset:Int64;
tvp:p_vnode;
begin
td:=curkthread;
if (td=nil) then Exit(-1);
auio.uio_resid:=count;
if (auio.uio_resid > IOSIZE_MAX) then
begin
Exit(EINVAL);
end;
error:=getvnode(fd, CAP_READ or CAP_SEEK, @fp);
if (error<>0) then
begin
Exit(error);
end;
if ((fp^.f_flag and FREAD)=0) then
begin
fdrop(fp);
Exit(EBADF);
end;
vp:=fp^.f_vnode;
foffset:=foffset_lock(fp, 0);
unionread:
vfslocked:=VFS_LOCK_GIANT(vp^.v_mount);
if (vp^.v_type<>VDIR) then
begin
VFS_UNLOCK_GIANT(vfslocked);
error:=EINVAL;
goto fail;
end;
aiov.iov_base :=buf;
aiov.iov_len :=count;
auio.uio_iov :=@aiov;
auio.uio_iovcnt:=1;
auio.uio_rw :=UIO_READ;
auio.uio_segflg:=UIO_USERSPACE;
auio.uio_td :=td;
vn_lock(vp, LK_SHARED or LK_RETRY,{$INCLUDE %FILE%},{$INCLUDE %LINENUM%});
loff:=foffset;
auio.uio_offset:=foffset;
//error:=mac_vnode_check_readdir(td^.td_ucred, vp);
//if (error=0) then
begin
error:=VOP_READDIR(vp, @auio, @eofflag, nil, nil);
end;
foffset:=auio.uio_offset;
if (error<>0) then
begin
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
goto fail;
end;
if (count=auio.uio_resid) and
((vp^.v_vflag and VV_ROOT)<>0) and
((p_mount(vp^.v_mount)^.mnt_flag and MNT_UNION)<>0) then
begin
tvp:=vp;
vp:=p_mount(vp^.v_mount)^.mnt_vnodecovered;
VREF(vp);
fp^.f_vnode:=vp;
fp^.f_data:=vp;
foffset:=0;
vput(tvp);
VFS_UNLOCK_GIANT(vfslocked);
goto unionread;
end;
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
basep^:=loff;
td^.td_retval[0]:=count - auio.uio_resid;
fail:
foffset_unlock(fp, foffset, 0);
fdrop(fp);
Exit(error);
end;
{
* Read a block of directory entries in a filesystem independent format.
}
function sys_getdirentries(fd:Integer;buf:Pointer;count:DWORD;basep:PInt64):Integer;
var
base:Int64;
error:Integer;
begin
error:=kern_getdirentries(fd, buf, count, @base);
if (error<>0) then
begin
Exit(error);
end;
if (basep<>nil) then
begin
error:=copyout(@base, basep, sizeof(Int64));
end;
Exit(error);
end;
function sys_getdents(fd:Integer;buf:Pointer;count:DWORD):Integer;
begin
Exit(sys_getdirentries(fd,buf,count,nil));
end;
{
* Set the mode mask for creation of filesystem nodes.
}
function sys_umask(newmask:Integer):Integer;
var
td:p_kthread;
begin
//priv_check(td,683);
Exit(EPERM);
td:=curkthread;
if (td=nil) then Exit(-1);
FILEDESC_XLOCK(@fd_table);
td^.td_retval[0]:=fd_table.fd_cmask;
fd_table.fd_cmask:=newmask and ALLPERMS;
FILEDESC_XUNLOCK(@fd_table);
Exit(0);
end;
{
* Void all references to file by ripping underlying filesystem away from
* vnode.
}
function sys_revoke(path:PChar):Integer;
label
_out;
var
vp:p_vnode;
vattr:t_vattr;
error:Integer;
nd:t_nameidata;
vfslocked:Integer;
begin
//priv_check(td,683);
Exit(EPERM);
NDINIT(@nd, LOOKUP, FOLLOW or LOCKLEAF or MPSAFE or AUDITVNODE1,
UIO_USERSPACE, path, curkthread);
error:=nd_namei(@nd);
if (error<>0) then
begin
Exit(error);
end;
vfslocked:=NDHASGIANT(@nd);
vp:=nd.ni_vp;
NDFREE(@nd, NDF_ONLY_PNBUF);
if (vp^.v_type<>VCHR) or (vp^.v_rdev=nil) then
begin
error:=EINVAL;
goto _out;
end;
//error:=mac_vnode_check_revoke(td^.td_ucred, vp);
//if (error<>0) then
// goto _out;
error:=VOP_GETATTR(vp, @vattr);
if (error<>0) then
begin
goto _out;
end;
//if (td^.td_ucred^.cr_uid<>vattr.va_uid) then
//begin
// error:=priv_check(td, PRIV_VFS_ADMIN);
// if (error<>0) then
// goto _out;
//end;
if (vcount(vp) > 1) then
begin
VOP_REVOKE(vp, REVOKEALL);
end;
_out:
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
Exit(error);
end;
{
* Convert a user file descriptor to a kernel file entry and check that, if it
* is a capability, the correct rights are present. A reference on the file
* entry is held upon Exiting.
}
function getvnode(fd:Integer;rights:cap_rights_t;fpp:pp_file):Integer;
var
fp:p_file;
fp_fromcap:p_file;
error:Integer;
begin
error:=0;
fp:=fget_unlocked(fd);
if (fp=nil) then
begin
Exit(EBADF);
end;
{
* If the file descriptor is for a capability, test rights and use the
* file descriptor referenced by the capability.
}
error:=cap_funwrap(fp, rights, @fp_fromcap);
if (error<>0) then
begin
fdrop(fp);
Exit(error);
end;
if (fp<>fp_fromcap) then
begin
fhold(fp_fromcap);
fdrop(fp);
fp:=fp_fromcap;
end;
{
* The file could be not of the vnode type, or it may be not
* yet fully initialized, in which case the f_vnode pointer
* may be set, but f_ops is still badfileops. E.g.,
* devfs_open() transiently create such situation to
* facilitate csw d_fdopen().
*
* Dupfdopen() handling in kern_openat() installs the
* half-baked file into the process descriptor table, allowing
* other thread to dereference it. Guard against the race by
* checking f_ops.
}
if (fp^.f_vnode=nil) or (fp^.f_ops=@badfileops) then
begin
fdrop(fp);
Exit(EINVAL);
end;
fpp^:=fp;
Exit(0);
end;
//////////
function sys_is_in_sandbox():Integer;
var
td:p_kthread;
begin
td:=curkthread;
if (td=nil) then Exit(-1);
td^.td_retval[0]:=1; //only in sandbox
Result:=0;
end;
function sys_randomized_path(src,dst:pchar;plen:PQWORD):Integer;
type
t_data=array[0..255] of AnsiChar;
var
ran_len:Integer;
dst_len:QWORD;
data:t_data;
begin
Result:=0;
data:=Default(t_data);
dst_len:=0;
if (src=nil) then
begin
if (dst=nil) or (plen=nil) then
begin
//
end else
begin
dst_len:=fuword64(plen^);
end;
end else
begin
//priv_check(td,0x2af);
Exit(EPERM);
end;
MoveChar0(p_proc.p_randomized_path,data,Length(p_proc.p_randomized_path));
ran_len:=StrLen(@data);
if (0 < dst_len) and (0 < ran_len) then
begin
if (dst_len < ran_len) then
begin
Result:=copyout(@data,dst,dst_len);
end else
begin
Result:=copyout(@data,dst,ran_len);
end;
if (Result<>0) then Exit;
end;
if (plen<>nil) then
begin
dst_len:=ran_len;
Result:=suword64(plen^,dst_len);
end;
end;
end.