mirror of https://github.com/red-prig/fpPS4.git
2732 lines
52 KiB
Plaintext
2732 lines
52 KiB
Plaintext
unit md_vnops;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
windows,
|
|
ntapi,
|
|
mqueue,
|
|
vm_pmap,
|
|
kern_param,
|
|
time,
|
|
vfile,
|
|
vmount,
|
|
vdirent,
|
|
vuio,
|
|
vnode,
|
|
vnamei,
|
|
vnode_if,
|
|
vfilio,
|
|
vfs_default,
|
|
ufs,
|
|
ufs_vnops,
|
|
kern_mtx,
|
|
kern_sx;
|
|
|
|
function md_mount(mp:p_ufs_mount):Integer;
|
|
function md_unmount(mp:p_ufs_mount):Integer;
|
|
function md_statfs(mp:p_mount;sbp:p_statfs):Integer;
|
|
|
|
function md_free_dirent(de:p_ufs_dirent):Integer;
|
|
|
|
function md_vmkdir(dmp:p_ufs_mount;name:PChar;namelen:Integer;dotdot:p_ufs_dirent):p_ufs_dirent;
|
|
|
|
function md_lookup(ap:p_vop_lookup_args):Integer;
|
|
function md_readdir(ap:p_vop_readdir_args):Integer;
|
|
function md_inactive(ap:p_vop_inactive_args):Integer;
|
|
function md_reclaim(ap:p_vop_reclaim_args):Integer;
|
|
function md_getattr(ap:p_vop_getattr_args):Integer;
|
|
|
|
function md_readlink(ap:p_vop_readlink_args):Integer;
|
|
function md_symlink(ap:p_vop_symlink_args):Integer;
|
|
function md_link(ap:p_vop_link_args):Integer;
|
|
|
|
function md_mkdir(ap:p_vop_mkdir_args):Integer;
|
|
function md_remove(ap:p_vop_remove_args):Integer;
|
|
function md_rmdir(ap:p_vop_rmdir_args):Integer;
|
|
function md_rename(ap:p_vop_rename_args):Integer;
|
|
|
|
function md_create(ap:p_vop_create_args):Integer;
|
|
function md_open(ap:p_vop_open_args):Integer;
|
|
function md_close(ap:p_vop_close_args):Integer;
|
|
function md_fsync(ap:p_vop_fsync_args):Integer;
|
|
function md_setattr(ap:p_vop_setattr_args):Integer;
|
|
|
|
function md_ioctl(ap:p_vop_ioctl_args):Integer;
|
|
|
|
function md_read(ap:p_vop_read_args):Integer;
|
|
function md_write(ap:p_vop_write_args):Integer;
|
|
|
|
function md_advlock(ap:p_vop_advlock_args):Integer;
|
|
function md_advlockpurge(ap:p_vop_advlockpurge_args):Integer;
|
|
|
|
const
|
|
md_vnodeops_host:vop_vector=(
|
|
vop_default :@ufs_vnodeops_root;
|
|
vop_bypass :nil;
|
|
|
|
vop_islocked :nil;
|
|
vop_lookup :@md_lookup;
|
|
vop_create :@md_create;
|
|
vop_whiteout :nil;
|
|
vop_mknod :nil;
|
|
vop_open :@md_open;
|
|
vop_close :@md_close;
|
|
vop_access :nil; //parent
|
|
vop_accessx :nil;
|
|
vop_getattr :@md_getattr;
|
|
vop_setattr :@md_setattr;
|
|
vop_markatime :nil;
|
|
vop_read :@md_read;
|
|
vop_write :@md_write;
|
|
vop_ioctl :@md_ioctl;
|
|
vop_poll :nil;
|
|
vop_kqfilter :nil;
|
|
vop_revoke :nil;
|
|
vop_fsync :@md_fsync;
|
|
vop_remove :@md_remove;
|
|
vop_link :@md_link;
|
|
vop_rename :@md_rename;
|
|
vop_mkdir :@md_mkdir;
|
|
vop_rmdir :@md_rmdir;
|
|
vop_symlink :@md_symlink;
|
|
vop_readdir :@md_readdir;
|
|
vop_readlink :@md_readlink;
|
|
vop_inactive :@md_inactive;
|
|
vop_reclaim :@md_reclaim;
|
|
vop_lock1 :nil;
|
|
vop_unlock :nil;
|
|
vop_bmap :nil;
|
|
vop_strategy :nil;
|
|
vop_getwritemount :nil;
|
|
vop_print :nil;
|
|
vop_pathconf :@vop_stdpathconf;
|
|
vop_advlock :@md_advlock;
|
|
vop_advlockasync :nil;
|
|
vop_advlockpurge :@md_advlockpurge;
|
|
vop_reallocblks :nil;
|
|
vop_getpages :nil;
|
|
vop_putpages :nil;
|
|
vop_vptofh :nil;
|
|
vop_vptocnp :nil;
|
|
vop_allocate :nil;
|
|
vop_unp_bind :nil;
|
|
vop_unp_connect :nil;
|
|
vop_unp_detach :nil;
|
|
);
|
|
|
|
implementation
|
|
|
|
uses
|
|
sysutils,
|
|
errno,
|
|
vfcntl,
|
|
vstat,
|
|
vfs_subr,
|
|
subr_uio,
|
|
kern_thr,
|
|
vnode_pager;
|
|
|
|
const
|
|
UFS_SET_READONLY=(not &0222);
|
|
|
|
FILE_DIR_ACCESS=SYNCHRONIZE or
|
|
FILE_LIST_DIRECTORY or
|
|
FILE_WRITE_DATA or
|
|
FILE_ADD_FILE or
|
|
FILE_ADD_SUBDIRECTORY or
|
|
FILE_TRAVERSE or
|
|
FILE_READ_ATTRIBUTES or
|
|
FILE_WRITE_ATTRIBUTES;
|
|
|
|
FILE_SHARE_ALL=FILE_SHARE_READ or
|
|
FILE_SHARE_WRITE or
|
|
FILE_SHARE_DELETE;
|
|
|
|
type
|
|
TOBJ_ATTR=packed record
|
|
OATTR:OBJECT_ATTRIBUTES;
|
|
UPATH:UNICODE_STRING;
|
|
end;
|
|
|
|
TNT_DIRENT=packed record
|
|
Info:FILE_ID_FULL_DIR_INFORMATION;
|
|
Name:array[0..260] of WCHAR;
|
|
end;
|
|
|
|
T_NT_SYMLINK=packed record
|
|
info:REPARSE_DATA_BUFFER;
|
|
Name:array[0..MAX_PATH*2] of WCHAR;
|
|
end;
|
|
|
|
T_NT_LINK=packed record
|
|
info:FILE_LINK_INFORMATION;
|
|
Name:array[0..MAX_PATH] of WCHAR;
|
|
end;
|
|
|
|
T_NT_RENAME=T_NT_LINK;
|
|
|
|
function VFSTOUFS(mp:p_mount):p_ufs_mount; inline;
|
|
begin
|
|
Result:=mp^.mnt_data;
|
|
end;
|
|
|
|
function INIT_UNICODE(FileName:PWideChar):UNICODE_STRING;
|
|
begin
|
|
Result.Length :=strlen(FileName)*SizeOf(WideChar);
|
|
Result.MaximumLength:=Result.Length+SizeOf(WideChar);
|
|
Result.Buffer :=FileName;
|
|
end;
|
|
|
|
procedure INIT_OBJ(var OBJ:TOBJ_ATTR;fd:THandle;attr:ULONG;FileName:PWideChar);
|
|
begin
|
|
OBJ.OATTR.Length:=SizeOf(OBJECT_ATTRIBUTES);
|
|
|
|
OBJ.OATTR.RootDirectory:=fd;
|
|
OBJ.OATTR.ObjectName :=@OBJ.UPATH;
|
|
OBJ.OATTR.Attributes :=attr;
|
|
|
|
OBJ.UPATH:=INIT_UNICODE(FileName);
|
|
end;
|
|
|
|
function ntf2px(n:Integer):Integer; inline;
|
|
begin
|
|
Case DWORD(n) of
|
|
STATUS_SUCCESS :Result:=0;
|
|
STATUS_PENDING :Result:=EWOULDBLOCK;
|
|
STATUS_NO_MORE_FILES :Result:=0;
|
|
STATUS_ACCESS_VIOLATION :Result:=EFAULT;
|
|
STATUS_INVALID_HANDLE :Result:=EBADF;
|
|
STATUS_NO_SUCH_FILE :Result:=ENOENT;
|
|
STATUS_END_OF_FILE :Result:=0;
|
|
STATUS_NO_MEMORY :Result:=ENOMEM;
|
|
STATUS_ACCESS_DENIED :Result:=EACCES;
|
|
STATUS_DISK_CORRUPT_ERROR :Result:=EIO;
|
|
STATUS_OBJECT_NAME_NOT_FOUND :Result:=ENOENT;
|
|
STATUS_OBJECT_NAME_COLLISION :Result:=EEXIST;
|
|
STATUS_OBJECT_PATH_NOT_FOUND :Result:=ENOENT;
|
|
STATUS_OBJECT_PATH_SYNTAX_BAD:Result:=ENOTDIR;
|
|
STATUS_SHARING_VIOLATION :Result:=EACCES;
|
|
STATUS_FILE_LOCK_CONFLICT :Result:=EWOULDBLOCK;
|
|
STATUS_LOCK_NOT_GRANTED :Result:=EWOULDBLOCK;
|
|
STATUS_RANGE_NOT_LOCKED :Result:=ENOLCK;
|
|
STATUS_DISK_FULL :Result:=ENOSPC;
|
|
STATUS_FILE_IS_A_DIRECTORY :Result:=EISDIR;
|
|
STATUS_NOT_SAME_DEVICE :Result:=EXDEV;
|
|
STATUS_INSUFFICIENT_RESOURCES:Result:=ENOMEM;
|
|
STATUS_DIRECTORY_NOT_EMPTY :Result:=ENOTEMPTY;
|
|
STATUS_FILE_CORRUPT_ERROR :Result:=EIO;
|
|
STATUS_NOT_A_DIRECTORY :Result:=ENOTDIR;
|
|
STATUS_NAME_TOO_LONG :Result:=ENAMETOOLONG;
|
|
STATUS_IO_DEVICE_ERROR :Result:=EIO;
|
|
STATUS_TOO_MANY_LINKS :Result:=EMLINK;
|
|
STATUS_CANT_CROSS_RM_BOUNDARY:Result:=EXDEV;
|
|
else
|
|
Result:=EINVAL;
|
|
end;
|
|
end;
|
|
|
|
function get_unix_file_time(time:LARGE_INTEGER):timespec; inline;
|
|
begin
|
|
Int64(time):=Int64(time)-DELTA_EPOCH_IN_UNIT;
|
|
Result.tv_sec :=(Int64(time) div UNIT_PER_SEC);
|
|
Result.tv_nsec:=(Int64(time) mod UNIT_PER_SEC)*NSEC_PER_UNIT;
|
|
end;
|
|
|
|
function get_win_file_time(time:timespec):LARGE_INTEGER; inline;
|
|
begin
|
|
Int64(Result):=(time.tv_sec*UNIT_PER_SEC)+(time.tv_nsec div NSEC_PER_UNIT);
|
|
Int64(Result):=Int64(Result)+DELTA_EPOCH_IN_UNIT;
|
|
end;
|
|
|
|
function NT_FA_TO_DT(a,e:ULONG):Byte;
|
|
begin
|
|
if ((a and FILE_ATTRIBUTE_REPARSE_POINT)<>0) and
|
|
(e=IO_REPARSE_TAG_SYMLINK) then
|
|
begin
|
|
Result:=DT_LNK;
|
|
end else
|
|
if ((a and FILE_ATTRIBUTE_DEVICE)<>0) then
|
|
begin
|
|
Result:=DT_CHR; //DT_FIFO ???
|
|
end else
|
|
if ((a and FILE_ATTRIBUTE_DIRECTORY)<>0) then
|
|
begin
|
|
Result:=DT_DIR;
|
|
end else
|
|
begin
|
|
Result:=DT_REG;
|
|
end;
|
|
end;
|
|
|
|
function get_inode(i:LARGE_INTEGER):Integer; inline;
|
|
begin
|
|
Result:=(i.LowPart+i.HighPart); //simple hash
|
|
end;
|
|
|
|
procedure fix_win_path(name:PWideChar;namelen:Integer);
|
|
begin
|
|
if (name=nil) then Exit;
|
|
while (namelen>0) do
|
|
begin
|
|
if (name[0]='/') then
|
|
begin
|
|
name[0]:='\';
|
|
end;
|
|
Inc(name);
|
|
Dec(namelen);
|
|
end;
|
|
end;
|
|
|
|
procedure fix_unix_path(name:PAnsiChar;namelen:Integer);
|
|
begin
|
|
if (name=nil) then Exit;
|
|
while (namelen>0) do
|
|
begin
|
|
if (name[0]='\') then
|
|
begin
|
|
name[0]:='/';
|
|
end;
|
|
Inc(name);
|
|
Dec(namelen);
|
|
end;
|
|
end;
|
|
|
|
function _UTF8Encode(P:PWideChar;len:SizeInt):RawByteString;
|
|
var
|
|
i:SizeInt;
|
|
hs:RawByteString;
|
|
begin
|
|
Result:='';
|
|
if (p=nil) or (len<=0) then exit;
|
|
hs:='';
|
|
SetLength(hs,len*3);
|
|
i:=UnicodeToUtf8(PAnsiChar(hs),length(hs)+1,P,len);
|
|
if (i>0) then
|
|
begin
|
|
SetLength(hs,i-1);
|
|
Result:=hs;
|
|
end;
|
|
end;
|
|
|
|
function _UTF8Decode(P:PAnsiChar;len:SizeInt):WideString;
|
|
var
|
|
i:SizeInt;
|
|
hs:WideString;
|
|
begin
|
|
Result:='';
|
|
if (p=nil) or (len<=0) then exit;
|
|
hs:='';
|
|
SetLength(hs,len);
|
|
i:=Utf8ToUnicode(PWideChar(hs),length(hs)+1,P,len);
|
|
if (i>0) then
|
|
begin
|
|
SetLength(hs,i-1);
|
|
Result:=hs;
|
|
end;
|
|
end;
|
|
|
|
function md_mount_is_valid(vp:p_vnode):Integer;
|
|
var
|
|
mp:p_mount;
|
|
begin
|
|
Result:=EXDEV;
|
|
mp:=vp^.v_mount;
|
|
if (mp=nil) then Exit;
|
|
if (mp^.mnt_vfc<>@ufs_vfsconf) then Exit;
|
|
if ((mp^.mnt_flag and MNT_ROOTFS)<>0) then Exit;
|
|
Result:=0;
|
|
end;
|
|
|
|
function md_mount(mp:p_ufs_mount):Integer;
|
|
var
|
|
w:WideString;
|
|
OBJ:TOBJ_ATTR;
|
|
BLK:IO_STATUS_BLOCK;
|
|
F:Thandle;
|
|
R:DWORD;
|
|
begin
|
|
w:=UTF8Decode(ExpandFileName(mp^.ufs_path));
|
|
w:='\??\'+w;
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,0,OBJ_CASE_INSENSITIVE,PWideChar(w));
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtOpenFile(@F,
|
|
FILE_DIR_ACCESS,
|
|
@OBJ,
|
|
@BLK,
|
|
FILE_SHARE_ALL,
|
|
FILE_OPEN_FOR_BACKUP_INTENT or
|
|
FILE_SYNCHRONOUS_IO_NONALERT or
|
|
FILE_DIRECTORY_FILE
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Exit;
|
|
|
|
mp^.ufs_md_fp:=Pointer(F);
|
|
end;
|
|
|
|
function md_unmount(mp:p_ufs_mount):Integer;
|
|
var
|
|
fd:THandle;
|
|
begin
|
|
fd:=THandle(System.InterlockedExchange(mp^.ufs_md_fp,nil));
|
|
if (fd<>0) then
|
|
begin
|
|
NtClose(fd);
|
|
end;
|
|
Result:=0;
|
|
end;
|
|
|
|
function mul_div_u64(m,d,v:QWORD):QWORD; sysv_abi_default; assembler; nostackframe;
|
|
asm
|
|
movq v,%rax
|
|
mulq m
|
|
divq d
|
|
end;
|
|
|
|
function md_statfs(mp:p_mount;sbp:p_statfs):Integer;
|
|
var
|
|
dmp:p_ufs_mount;
|
|
FFF:FILE_FS_FULL_SIZE_INFORMATION;
|
|
BLK:IO_STATUS_BLOCK;
|
|
Sector:Int64;
|
|
R:DWORD;
|
|
begin
|
|
dmp:=VFSTOUFS(mp);
|
|
if (dmp^.ufs_md_fp=nil) then Exit(0);
|
|
|
|
FFF:=Default(FILE_FS_FULL_SIZE_INFORMATION);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryVolumeInformationFile(
|
|
THandle(dmp^.ufs_md_fp),
|
|
@BLK,
|
|
@FFF,
|
|
SizeOf(FFF),
|
|
FileFsFullSizeInformation
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Exit;
|
|
|
|
Sector:=(FFF.SectorsPerAllocationUnit*FFF.BytesPerSector);
|
|
|
|
sbp^.f_bavail:=mul_div_u64(Sector,DEV_BSIZE,QWORD(FFF.CallerAvailableAllocationUnits));
|
|
sbp^.f_blocks:=mul_div_u64(Sector,DEV_BSIZE,QWORD(FFF.TotalAllocationUnits ));
|
|
sbp^.f_bfree :=mul_div_u64(Sector,DEV_BSIZE,QWORD(FFF.ActualAvailableAllocationUnits));
|
|
end;
|
|
|
|
function md_free_dirent(de:p_ufs_dirent):Integer;
|
|
var
|
|
s:Pointer;
|
|
fd:THandle;
|
|
begin
|
|
s:=System.InterlockedExchange(de^.ufs_symlink,nil);
|
|
if (s<>nil) then
|
|
begin
|
|
FreeMem(s);
|
|
end;
|
|
|
|
if ((de^.ufs_flags and UFS_DROOT)=0) then //if not root dir
|
|
begin
|
|
fd:=THandle(System.InterlockedExchange(de^.ufs_md_fp,nil));
|
|
if (fd<>0) then
|
|
begin
|
|
NtClose(fd);
|
|
end;
|
|
end;
|
|
Result:=0;
|
|
end;
|
|
|
|
function md_open_dirent(de:p_ufs_dirent):Integer;
|
|
var
|
|
w:WideString;
|
|
OBJ:TOBJ_ATTR;
|
|
BLK:IO_STATUS_BLOCK;
|
|
F:Thandle;
|
|
R:DWORD;
|
|
begin
|
|
Assert(de^.ufs_dir^.ufs_md_fp<>nil);
|
|
|
|
w:=_UTF8Decode(@de^.ufs_dirent^.d_name,de^.ufs_dirent^.d_namlen);
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,THandle(de^.ufs_dir^.ufs_md_fp),0,PWideChar(w));
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtOpenFile(@F,
|
|
FILE_DIR_ACCESS,
|
|
@OBJ,
|
|
@BLK,
|
|
FILE_SHARE_ALL,
|
|
FILE_OPEN_FOR_BACKUP_INTENT or
|
|
FILE_SYNCHRONOUS_IO_NONALERT or
|
|
FILE_DIRECTORY_FILE
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Exit;
|
|
|
|
de^.ufs_md_fp:=Pointer(F);
|
|
end;
|
|
|
|
function md_open_dirent_file(de:p_ufs_dirent;symlink:Boolean;fdr:PHandle):Integer;
|
|
var
|
|
w:WideString;
|
|
OBJ:TOBJ_ATTR;
|
|
BLK:IO_STATUS_BLOCK;
|
|
F:Thandle;
|
|
opt:DWORD;
|
|
R:DWORD;
|
|
begin
|
|
sx_assert(@de^.ufs_md_lock);
|
|
|
|
Assert(de^.ufs_dir^.ufs_md_fp<>nil);
|
|
|
|
w:=_UTF8Decode(@de^.ufs_dirent^.d_name,de^.ufs_dirent^.d_namlen);
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,THandle(de^.ufs_dir^.ufs_md_fp),0,PWideChar(w));
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
opt:=FILE_OPEN_FOR_BACKUP_INTENT or FILE_SYNCHRONOUS_IO_NONALERT;
|
|
|
|
if (de^.ufs_dirent^.d_type=DT_DIR) then
|
|
begin
|
|
opt:=opt or FILE_DIRECTORY_FILE;
|
|
end;
|
|
|
|
if symlink then
|
|
begin
|
|
opt:=opt or FILE_OPEN_REPARSE_POINT;
|
|
end;
|
|
|
|
R:=NtOpenFile(@F,
|
|
SYNCHRONIZE or
|
|
FILE_CAN_DELETE or
|
|
FILE_READ_DATA or
|
|
//FILE_WRITE_DATA or
|
|
FILE_READ_ATTRIBUTES or
|
|
FILE_WRITE_ATTRIBUTES,
|
|
@OBJ,
|
|
@BLK,
|
|
FILE_SHARE_ALL,
|
|
opt
|
|
);
|
|
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Exit;
|
|
|
|
fdr^:=F;
|
|
end;
|
|
|
|
function md_find_rel_mount_path(first:p_mount;var src:PWideChar;var len:SizeInt):Integer;
|
|
var
|
|
mp:p_mount;
|
|
W:WideString;
|
|
|
|
function compare(mp:p_mount):Boolean;
|
|
begin
|
|
Result:=False;
|
|
if (mp^.mnt_vfc=@ufs_vfsconf) then //current fstype
|
|
if ((mp^.mnt_flag and MNT_ROOTFS)=0) then //host mount
|
|
begin
|
|
W:=UTF8Decode(ExpandFileName(mp^.mnt_stat.f_mntfromname));
|
|
|
|
if (len>=Length(W)) then
|
|
begin
|
|
|
|
//compare case insensetive
|
|
if (CompareStringW(
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
PWideChar(W),
|
|
Length(W),
|
|
PWideChar(src),
|
|
Length(W)
|
|
)=2) then
|
|
begin
|
|
Inc(src,Length(W));
|
|
Dec(len,Length(W));
|
|
|
|
Result:=True;
|
|
end; //cmp
|
|
end; //len
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result:=ERESTART;
|
|
mtx_lock(mountlist_mtx);
|
|
|
|
if (first<>nil) then
|
|
if compare(first) then
|
|
begin
|
|
mtx_unlock(mountlist_mtx);
|
|
Exit(0);
|
|
end;
|
|
|
|
mp:=TAILQ_FIRST(@mountlist);
|
|
while (mp<>nil) do
|
|
begin
|
|
|
|
if (first<>mp) then
|
|
if compare(mp) then
|
|
begin
|
|
Result:=0;
|
|
Break;
|
|
end;
|
|
|
|
mp:=TAILQ_NEXT(mp,@mp^.mnt_list);
|
|
end;
|
|
|
|
mtx_unlock(mountlist_mtx);
|
|
end;
|
|
|
|
function md_update_symlink(de:p_ufs_dirent;fd:THandle):Integer;
|
|
var
|
|
NT_SYMLINK:T_NT_SYMLINK;
|
|
BLK:IO_STATUS_BLOCK;
|
|
|
|
P:PWideChar;
|
|
len:SizeInt;
|
|
|
|
U:RawByteString;
|
|
nt_abs:Boolean;
|
|
|
|
R:DWORD;
|
|
|
|
mp:p_mount;
|
|
begin
|
|
sx_assert(@de^.ufs_md_lock);
|
|
|
|
if (de^.ufs_dirent^.d_type<>DT_LNK) then Exit(EINVAL);
|
|
|
|
if (de^.ufs_symlink<>nil) then Exit(0); //cached
|
|
|
|
NT_SYMLINK:=Default(T_NT_SYMLINK);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtFsControlFile(
|
|
fd,
|
|
0,
|
|
nil,
|
|
nil,
|
|
@BLK,
|
|
FSCTL_GET_REPARSE_POINT,
|
|
nil,
|
|
0,
|
|
@NT_SYMLINK,
|
|
SizeOf(NT_SYMLINK)
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Exit;
|
|
|
|
//only symlink
|
|
if (NT_SYMLINK.info.ReparseTag<>IO_REPARSE_TAG_SYMLINK) then
|
|
begin
|
|
Exit(ERESTART);
|
|
end;
|
|
|
|
P:=@NT_SYMLINK.info.SymbolicLinkReparseBuffer.PathBuffer;
|
|
P:=Pointer(P)+NT_SYMLINK.info.SymbolicLinkReparseBuffer.SubstituteNameOffset;
|
|
len:=NT_SYMLINK.info.SymbolicLinkReparseBuffer.SubstituteNameLength div 2;
|
|
|
|
if (PQWORD(P)^=$005C003F003F005C) then // "\??\"
|
|
begin
|
|
Inc(P,4);
|
|
Dec(len,4);
|
|
|
|
nt_abs:=True;
|
|
end else
|
|
if (PWORD(P)^=$005C) then // "\"
|
|
begin
|
|
//broke struct
|
|
Dec(P,2);
|
|
Inc(len,2);
|
|
|
|
P[0]:=GetCurrentDir[1];
|
|
P[1]:=':';
|
|
|
|
nt_abs:=True;
|
|
end else
|
|
if (PWORD(P)[1]=$003A) then // "C:"
|
|
begin
|
|
nt_abs:=True;
|
|
end else
|
|
begin
|
|
nt_abs:=False;
|
|
end;
|
|
|
|
if nt_abs then
|
|
begin
|
|
mp:=nil;
|
|
|
|
if (de^.ufs_vnode<>nil) then
|
|
begin
|
|
mp:=de^.ufs_vnode^.v_mount;
|
|
end;
|
|
|
|
//find by mount points
|
|
Result:=md_find_rel_mount_path(mp,P,len);
|
|
if (Result<>0) then Exit;
|
|
end;
|
|
|
|
U:=_UTF8Encode(P,len);
|
|
|
|
fix_unix_path(PAnsiChar(U),Length(U));
|
|
|
|
//save to cache
|
|
de^.ufs_symlink:=AllocMem(Length(U)+1);
|
|
Move(PAnsiChar(U)^, de^.ufs_symlink^, Length(U));
|
|
end;
|
|
|
|
function md_update_dirent(FD:THandle;de:p_ufs_dirent;prev:PFILE_BASIC_INFORMATION):Integer;
|
|
label
|
|
_retry,
|
|
_exit;
|
|
var
|
|
RL:THandle;
|
|
|
|
FBI:FILE_BASIC_INFORMATION;
|
|
FSI:FILE_STANDARD_INFORMATION;
|
|
FII:FILE_INTERNAL_INFORMATION;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
begin
|
|
Result:=0;
|
|
if (de=nil) then Exit;
|
|
|
|
sx_assert(@de^.ufs_md_lock);
|
|
|
|
if (FD<>0) then
|
|
begin
|
|
RL:=0;
|
|
end else
|
|
if (de^.ufs_md_fp=nil) then
|
|
begin
|
|
Result:=md_open_dirent_file(de,(de^.ufs_dirent^.d_type=DT_LNK),@FD);
|
|
if (Result<>0) then Exit;
|
|
RL:=FD;
|
|
end else
|
|
begin
|
|
FD:=THandle(de^.ufs_md_fp);
|
|
RL:=0;
|
|
end;
|
|
|
|
if (prev<>nil) then
|
|
begin
|
|
//just copy
|
|
FBI:=prev^;
|
|
end else
|
|
begin
|
|
//load time and file type
|
|
FBI:=Default(FILE_BASIC_INFORMATION);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@FBI,
|
|
SizeOf(FBI),
|
|
FileBasicInformation
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _exit;
|
|
end;
|
|
|
|
de^.ufs_atime:=get_unix_file_time(FBI.LastAccessTime);
|
|
de^.ufs_mtime:=get_unix_file_time(FBI.LastWriteTime);
|
|
de^.ufs_ctime:=get_unix_file_time(FBI.ChangeTime);
|
|
de^.ufs_btime:=get_unix_file_time(FBI.CreationTime);
|
|
|
|
////
|
|
|
|
_retry:
|
|
|
|
if (de^.ufs_dirent^.d_type=DT_LNK) then
|
|
begin
|
|
//load symlink info
|
|
if (de^.ufs_symlink=nil) then
|
|
begin
|
|
Result:=md_update_symlink(de,FD);
|
|
|
|
if (Result=ERESTART) then
|
|
begin
|
|
Result:=0;
|
|
//update type
|
|
de^.ufs_dirent^.d_type:=NT_FA_TO_DT(FBI.FileAttributes,0);
|
|
goto _retry;
|
|
end;
|
|
if (Result<>0) then goto _exit;
|
|
end;
|
|
end else
|
|
if (de^.ufs_dirent^.d_type<>DT_DIR) then
|
|
begin
|
|
//load size
|
|
FSI:=Default(FILE_STANDARD_INFORMATION);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@FSI,
|
|
SizeOf(FSI),
|
|
FileStandardInformation
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _exit;
|
|
|
|
de^.ufs_links:=FSI.NumberOfLinks;
|
|
de^.ufs_size :=Int64(FSI.EndOfFile);
|
|
de^.ufs_bytes:=Int64(FSI.AllocationSize);
|
|
end;
|
|
|
|
////
|
|
|
|
if (de^.ufs_inode=0) then
|
|
begin
|
|
//load inode
|
|
FII:=Default(FILE_INTERNAL_INFORMATION);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@FII,
|
|
SizeOf(FII),
|
|
FileInternalInformation
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _exit;
|
|
|
|
de^.ufs_inode:=get_inode(FII.IndexNumber);
|
|
de^.ufs_dirent^.d_fileno:=de^.ufs_inode;
|
|
end;
|
|
|
|
_exit:
|
|
if (RL<>0) then
|
|
begin
|
|
NtClose(RL);
|
|
end;
|
|
end;
|
|
|
|
function md_newdirent(name:PChar;namelen:Integer):p_ufs_dirent;
|
|
var
|
|
i:Integer;
|
|
de:p_ufs_dirent;
|
|
d:t_dirent;
|
|
begin
|
|
d.d_namlen:=namelen;
|
|
i:=sizeof(t_ufs_dirent) + GENERIC_DIRSIZ(@d);
|
|
de:=AllocMem(i);
|
|
de^.ufs_dirent:=p_dirent(de + 1);
|
|
de^.ufs_dirent^.d_namlen:=namelen;
|
|
de^.ufs_dirent^.d_reclen:=GENERIC_DIRSIZ(@d);
|
|
|
|
Move(name^, de^.ufs_dirent^.d_name, namelen);
|
|
|
|
de^.ufs_dirent^.d_name[namelen]:=#0;
|
|
|
|
de^.ufs_links :=1;
|
|
de^.ufs_ref :=1;
|
|
|
|
sx_init(@de^.ufs_md_lock, 'md_lock');
|
|
TAILQ_INIT(@de^.ufs_dlist);
|
|
|
|
Exit(de);
|
|
end;
|
|
|
|
function md_vmkdir(dmp:p_ufs_mount;name:PChar;namelen:Integer;dotdot:p_ufs_dirent):p_ufs_dirent;
|
|
var
|
|
nd:p_ufs_dirent;
|
|
error:Integer;
|
|
begin
|
|
{ Create the new directory }
|
|
nd:=md_newdirent(name, namelen);
|
|
|
|
nd^.ufs_dirent^.d_type:=DT_DIR;
|
|
nd^.ufs_mode :=UFS_DEFAULT_MODE;
|
|
nd^.ufs_links:=2;
|
|
nd^.ufs_dir :=dotdot;
|
|
|
|
if (dotdot=nil) then
|
|
begin
|
|
//move root handle
|
|
nd^.ufs_flags:=UFS_DROOT;
|
|
nd^.ufs_md_fp:=dmp^.ufs_md_fp;
|
|
end else
|
|
begin
|
|
error:=md_open_dirent(nd);
|
|
if (error<>0) then
|
|
begin
|
|
ufs_de_drop(nd);
|
|
Exit(nil);
|
|
end;
|
|
|
|
sx_assert(@dotdot^.ufs_md_lock);
|
|
TAILQ_INSERT_TAIL(@dotdot^.ufs_dlist,nd,@nd^.ufs_list);
|
|
Inc(dotdot^.ufs_links);
|
|
ufs_de_hold(dotdot);
|
|
end;
|
|
|
|
sx_xlock(@nd^.ufs_md_lock);
|
|
error:=md_update_dirent(0,nd,nil);
|
|
sx_xunlock(@nd^.ufs_md_lock);
|
|
|
|
if (error<>0) then
|
|
begin
|
|
ufs_de_drop(nd);
|
|
Exit(nil);
|
|
end;
|
|
|
|
Exit(nd);
|
|
end;
|
|
|
|
function md_find_cache(dd:p_ufs_dirent;name:PChar;namelen:Integer;_type:Integer):p_ufs_dirent;
|
|
var
|
|
de:p_ufs_dirent;
|
|
begin
|
|
sx_assert(@dd^.ufs_md_lock);
|
|
|
|
de:=TAILQ_FIRST(@dd^.ufs_dlist);
|
|
while (de<>nil) do
|
|
begin
|
|
if (namelen<>de^.ufs_dirent^.d_namlen) then
|
|
begin
|
|
de:=TAILQ_NEXT(de,@de^.ufs_list);
|
|
continue;
|
|
end;
|
|
if (_type<>0) and (_type<>de^.ufs_dirent^.d_type) then
|
|
begin
|
|
de:=TAILQ_NEXT(de,@de^.ufs_list);
|
|
continue;
|
|
end;
|
|
|
|
if (CompareByte(name^, de^.ufs_dirent^.d_name, namelen)<>0) then
|
|
begin
|
|
de:=TAILQ_NEXT(de,@de^.ufs_list);
|
|
continue;
|
|
end;
|
|
break;
|
|
end;
|
|
|
|
Exit(de);
|
|
end;
|
|
|
|
function md_new_cache(dd:p_ufs_dirent;name:PChar;namelen:Integer;prev:PFILE_BASIC_INFORMATION;var nd:p_ufs_dirent):Integer;
|
|
var
|
|
de:p_dirent;
|
|
begin
|
|
sx_assert(@dd^.ufs_md_lock);
|
|
|
|
Result:=0;
|
|
|
|
nd:=md_newdirent(name, namelen);
|
|
|
|
nd^.ufs_mode :=UFS_DEFAULT_MODE;
|
|
nd^.ufs_dir :=dd;
|
|
|
|
if ((prev^.FileAttributes and FILE_ATTRIBUTE_READONLY)<>0) then
|
|
begin
|
|
nd^.ufs_mode:=nd^.ufs_mode and UFS_SET_READONLY;
|
|
end;
|
|
|
|
de:=nd^.ufs_dirent;
|
|
|
|
de^.d_fileno:=nd^.ufs_inode;
|
|
de^.d_type :=NT_FA_TO_DT(prev^.FileAttributes,IO_REPARSE_TAG_SYMLINK);
|
|
|
|
if (de^.d_type=DT_DIR) then
|
|
begin
|
|
nd^.ufs_links:=2;
|
|
Result:=md_open_dirent(nd);
|
|
if (Result<>0) then
|
|
begin
|
|
ufs_de_drop(nd);
|
|
nd:=nil;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
sx_xlock(@nd^.ufs_md_lock);
|
|
Result:=md_update_dirent(0,nd,prev);
|
|
sx_unlock(@nd^.ufs_md_lock);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
ufs_de_drop(nd);
|
|
nd:=nil;
|
|
Exit;
|
|
end;
|
|
|
|
//link->dir
|
|
if (nd^.ufs_md_fp=nil) and (de^.d_type=DT_DIR) then
|
|
begin
|
|
nd^.ufs_links:=2;
|
|
Result:=md_open_dirent(nd);
|
|
if (Result<>0) then
|
|
begin
|
|
ufs_de_drop(nd);
|
|
nd:=nil;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
TAILQ_INSERT_TAIL(@dd^.ufs_dlist,nd,@nd^.ufs_list);
|
|
Inc(dd^.ufs_links);
|
|
ufs_de_hold(dd);
|
|
end;
|
|
|
|
function md_lookup_dirent(dd:p_ufs_dirent;name:PChar;namelen:Integer;var nd:p_ufs_dirent):Integer;
|
|
var
|
|
w:WideString;
|
|
|
|
FBI:FILE_BASIC_INFORMATION;
|
|
OBJ:TOBJ_ATTR;
|
|
R:DWORD;
|
|
begin
|
|
sx_assert(@dd^.ufs_md_lock);
|
|
|
|
Result:=0;
|
|
nd:=nil;
|
|
|
|
w:=_UTF8Decode(name,namelen);
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,THandle(dd^.ufs_md_fp),0,PWideChar(w));
|
|
|
|
R:=NtQueryAttributesFile(@OBJ,@FBI);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=md_new_cache(dd,name,namelen,@FBI,nd);
|
|
end;
|
|
|
|
procedure md_unlink_cache(de:p_ufs_dirent;curr_locked_ownership,parent_locked:Boolean);
|
|
label
|
|
_start;
|
|
var
|
|
dd,exclude_parent:p_ufs_dirent;
|
|
curr_hold_ownership:Boolean;
|
|
begin
|
|
if (de=nil) then Exit;
|
|
|
|
exclude_parent:=nil;
|
|
curr_hold_ownership:=False;
|
|
|
|
_start:
|
|
|
|
Assert(sx_xlocked(@de^.ufs_md_lock)=curr_locked_ownership);
|
|
|
|
if not curr_locked_ownership then
|
|
begin
|
|
curr_locked_ownership:=True;
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
end;
|
|
|
|
dd:=System.InterlockedExchange(de^.ufs_dir,nil); //parent
|
|
|
|
if ((de^.ufs_flags and UFS_CREATE)<>0) then
|
|
begin
|
|
//unlink soft
|
|
de^.ufs_dir:=nil;
|
|
sx_unlock(@de^.ufs_md_lock);
|
|
ufs_de_drop(dd);
|
|
Exit;
|
|
end;
|
|
|
|
if (dd<>nil) then
|
|
begin
|
|
ufs_de_hold(dd); //hold parent
|
|
|
|
Assert(sx_xlocked(@dd^.ufs_md_lock)=parent_locked);
|
|
|
|
if parent_locked then
|
|
begin
|
|
if (exclude_parent=nil) then
|
|
begin
|
|
//exclude parent lock ownership
|
|
exclude_parent:=dd;
|
|
end;
|
|
end else
|
|
begin
|
|
parent_locked:=True;
|
|
//relock
|
|
sx_unlock(@de^.ufs_md_lock);
|
|
sx_xlock (@dd^.ufs_md_lock);
|
|
sx_xlock (@de^.ufs_md_lock);
|
|
end;
|
|
|
|
TAILQ_REMOVE(@dd^.ufs_dlist,de,@de^.ufs_list);
|
|
|
|
if curr_locked_ownership then
|
|
begin
|
|
curr_locked_ownership:=False;
|
|
if (exclude_parent<>de) then
|
|
begin
|
|
sx_unlock(@de^.ufs_md_lock);
|
|
end;
|
|
end;
|
|
|
|
if curr_hold_ownership then
|
|
begin
|
|
curr_hold_ownership:=False;
|
|
ufs_de_drop(de); //drop prev hold
|
|
end;
|
|
|
|
ufs_de_drop(dd); //drop list hold
|
|
|
|
if (TAILQ_EMPTY(@dd^.ufs_dlist) and (dd^.ufs_dir<>nil)) then
|
|
begin
|
|
//need to go down further
|
|
|
|
curr_hold_ownership :=True; //hold parent -> hold curr
|
|
curr_locked_ownership:=True; //lock parent -> lock curr
|
|
parent_locked :=False;
|
|
|
|
de:=dd;
|
|
|
|
goto _start;
|
|
end;
|
|
|
|
//end
|
|
|
|
if parent_locked and (exclude_parent<>dd) then
|
|
begin
|
|
sx_unlock(@dd^.ufs_md_lock);
|
|
end;
|
|
|
|
ufs_de_drop(dd); //drop parent
|
|
end;
|
|
|
|
if curr_locked_ownership and (exclude_parent<>de) then
|
|
begin
|
|
sx_unlock(@de^.ufs_md_lock);
|
|
end;
|
|
|
|
if curr_hold_ownership then
|
|
begin
|
|
ufs_de_drop(de); //drop prev hold
|
|
end;
|
|
end;
|
|
|
|
procedure md_delete_cache(de:p_ufs_dirent);
|
|
begin
|
|
if (de=nil) then Exit;
|
|
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Assert(de^.ufs_ref>0);
|
|
|
|
Assert((de^.ufs_flags and UFS_DOOMED)=0,'ufs_delete doomed dirent');
|
|
de^.ufs_flags:=de^.ufs_flags or UFS_DOOMED;
|
|
|
|
md_unlink_cache(de,True,False);
|
|
|
|
ufs_de_drop(de);
|
|
end;
|
|
|
|
function md_inactive(ap:p_vop_inactive_args):Integer;
|
|
begin
|
|
Exit(0);
|
|
end;
|
|
|
|
function md_reclaim(ap:p_vop_reclaim_args):Integer;
|
|
var
|
|
vp:p_vnode;
|
|
de:p_ufs_dirent;
|
|
begin
|
|
vp:=ap^.a_vp;
|
|
|
|
de:=ufs_relv(vp);
|
|
if (de<>nil) then
|
|
begin
|
|
VI_LOCK(vp);
|
|
md_delete_cache(de);
|
|
VI_UNLOCK(vp);
|
|
end;
|
|
|
|
vnode_destroy_vobject(vp);
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
function md_lookup(ap:p_vop_lookup_args):Integer;
|
|
var
|
|
cnp:p_componentname;
|
|
dvp:p_vnode;
|
|
vpp:pp_vnode;
|
|
de,dd:p_ufs_dirent;
|
|
error,flags,nameiop:Integer;
|
|
pname:PChar;
|
|
dmp:p_ufs_mount;
|
|
begin
|
|
cnp:=ap^.a_cnp;
|
|
vpp:=ap^.a_vpp;
|
|
dvp:=ap^.a_dvp;
|
|
pname:=cnp^.cn_nameptr;
|
|
flags:=cnp^.cn_flags;
|
|
nameiop:=cnp^.cn_nameiop;
|
|
|
|
dd:=dvp^.v_data;
|
|
vpp^:=nil;
|
|
|
|
if (dvp^.v_type<>VDIR) then
|
|
begin
|
|
Exit(ENOTDIR);
|
|
end;
|
|
|
|
//If read-only and op is not CREATE|LOOKUP, will return EROFS.
|
|
if ((flags and ISLASTCN)<>0) and
|
|
((p_mount(dvp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) and
|
|
(nameiop <> CREATE) and
|
|
(nameiop <> LOOKUP) then
|
|
begin
|
|
Exit(EROFS);
|
|
end;
|
|
|
|
if (((flags and ISDOTDOT)<>0) and ((dvp^.v_vflag and VV_ROOT)<>0)) then
|
|
begin
|
|
Exit(EIO);
|
|
end;
|
|
|
|
error:=VOP_ACCESS(dvp, VEXEC);
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
if (cnp^.cn_namelen=1) and (pname^='.') then
|
|
begin
|
|
if ((flags and ISLASTCN)<>0) and (nameiop<>LOOKUP) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
vpp^:=dvp;
|
|
VREF(dvp);
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
|
|
Result:=0;
|
|
de:=md_find_cache(dd, cnp^.cn_nameptr, cnp^.cn_namelen, 0);
|
|
|
|
if (de=nil) then
|
|
begin
|
|
Result:=md_lookup_dirent(dd,cnp^.cn_nameptr,cnp^.cn_namelen,de);
|
|
end;
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
|
|
if (de=nil) then
|
|
begin
|
|
//not found or access error
|
|
|
|
if (Result=ENOENT) then //only not found case
|
|
Case nameiop of
|
|
CREATE,
|
|
RENAME:
|
|
begin
|
|
|
|
//If read-only and op is CREATE|RENAME, will return EROFS.
|
|
if ((flags and ISLASTCN)<>0) and
|
|
((p_mount(dvp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) then
|
|
begin
|
|
Exit(EROFS);
|
|
end;
|
|
|
|
if ((flags and (LOCKPARENT or WANTPARENT))<>0) and
|
|
((flags and ISLASTCN)<>0) then
|
|
begin
|
|
cnp^.cn_flags:=cnp^.cn_flags or SAVENAME;
|
|
Exit(EJUSTRETURN);
|
|
end;
|
|
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
Exit; //Result:=md_lookup_dirent
|
|
end;
|
|
|
|
if (cnp^.cn_nameiop=DELETE) and ((flags and ISLASTCN)<>0) then
|
|
begin
|
|
error:=VOP_ACCESS(dvp, VWRITE);
|
|
if (error<>0) then
|
|
begin
|
|
Exit(error);
|
|
end;
|
|
|
|
if (vpp^=dvp) then
|
|
begin
|
|
VREF(dvp);
|
|
vpp^:=dvp;
|
|
Exit(0);
|
|
end;
|
|
end;
|
|
|
|
dmp:=VFSTOUFS(ap^.a_dvp^.v_mount);
|
|
sx_xlock(@dmp^.ufs_lock);
|
|
|
|
error:=ufs_allocv(de, dvp^.v_mount, cnp^.cn_lkflags and LK_TYPE_MASK, vpp); //sx_xunlock
|
|
|
|
Exit(error);
|
|
end;
|
|
|
|
function md_readdir(ap:p_vop_readdir_args):Integer;
|
|
var
|
|
uio:p_uio;
|
|
dd:p_ufs_dirent;
|
|
dt:t_dirent;
|
|
off:Int64;
|
|
i:Integer;
|
|
|
|
NT_DIRENT:TNT_DIRENT;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
restart:Boolean;
|
|
begin
|
|
if (ap^.a_vp^.v_type<>VDIR) then
|
|
begin
|
|
Exit(ENOTDIR);
|
|
end;
|
|
|
|
uio:=ap^.a_uio;
|
|
if (uio^.uio_offset < 0) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
dd:=ap^.a_vp^.v_data;
|
|
off:=0;
|
|
restart:=True;
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
|
|
repeat
|
|
NT_DIRENT:=Default(TNT_DIRENT);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryDirectoryFile(
|
|
THandle(dd^.ufs_md_fp),
|
|
0,
|
|
nil,
|
|
nil,
|
|
@BLK,
|
|
@NT_DIRENT,
|
|
SizeOf(NT_DIRENT),
|
|
FileIdFullDirectoryInformation,
|
|
True,
|
|
nil,
|
|
restart
|
|
);
|
|
restart:=false;
|
|
|
|
if (R=STATUS_NO_MORE_FILES) then Break;
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then Break;
|
|
|
|
dt:=Default(t_dirent);
|
|
|
|
i:=UnicodeToUtf8(@dt.d_name,
|
|
t_dirent.MAXNAMLEN+1,
|
|
@NT_DIRENT.Name,
|
|
NT_DIRENT.Info.FileNameLength div 2);
|
|
|
|
if (i<=0) then
|
|
begin
|
|
//skip error
|
|
Continue;
|
|
end;
|
|
|
|
dt.d_reclen:=SizeOf(t_dirent)-(t_dirent.MAXNAMLEN+1)+((i + 3) and (not 3)); //zero include
|
|
|
|
if (dt.d_reclen > uio^.uio_resid) then break;
|
|
|
|
if (off >= uio^.uio_offset) then
|
|
begin
|
|
dt.d_fileno:=get_inode(NT_DIRENT.Info.FileId);
|
|
dt.d_type :=NT_FA_TO_DT(NT_DIRENT.Info.FileAttributes,NT_DIRENT.Info.EaSize);
|
|
dt.d_namlen:=i-1; //zero exclude
|
|
|
|
Result:=vfs_read_dirent(ap, @dt, off);
|
|
if (Result<>0) then break;
|
|
end;
|
|
|
|
Inc(off,dt.d_reclen);
|
|
until false;
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
uio^.uio_offset:=off;
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
function md_getattr(ap:p_vop_getattr_args):Integer;
|
|
var
|
|
vp:p_vnode;
|
|
de:p_ufs_dirent;
|
|
|
|
begin
|
|
vp:=ap^.a_vp;
|
|
de:=vp^.v_data;
|
|
|
|
VI_LOCK(vp);
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Result:=md_update_dirent(THandle(vp^.v_un),de,nil);
|
|
|
|
vnode_pager_setsize(vp, de^.ufs_size);
|
|
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
VI_UNLOCK(vp);
|
|
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=ufs_getattr(ap);
|
|
end;
|
|
|
|
function md_readlink(ap:p_vop_readlink_args):Integer;
|
|
var
|
|
de:p_ufs_dirent;
|
|
begin
|
|
de:=ap^.a_vp^.v_data;
|
|
if (de^.ufs_dirent^.d_type<>DT_LNK) then Exit(EINVAL);
|
|
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Result:=0;
|
|
if (de^.ufs_symlink=nil) then //not cached
|
|
begin
|
|
Result:=md_update_dirent(0,de,nil);
|
|
end;
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
Exit;
|
|
end;
|
|
|
|
Result:=uiomove(de^.ufs_symlink, strlen(de^.ufs_symlink), ap^.a_uio);
|
|
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
end;
|
|
|
|
function md_symlink(ap:p_vop_symlink_args):Integer;
|
|
const
|
|
REPARSE_DATA_OFFSET=ptrint(@REPARSE_DATA_BUFFER(nil^).GenericReparseBuffer);
|
|
label
|
|
_del,
|
|
_err;
|
|
var
|
|
len,error:Integer;
|
|
dd:p_ufs_dirent;
|
|
de:p_ufs_dirent;
|
|
dmp:p_ufs_mount;
|
|
|
|
Privilege:DWORD;
|
|
PrivState:Pointer;
|
|
|
|
w:WideString;
|
|
|
|
OBJ:TOBJ_ATTR;
|
|
BLK:IO_STATUS_BLOCK;
|
|
NT_SYMLINK:T_NT_SYMLINK;
|
|
FBI:FILE_BASIC_INFORMATION;
|
|
|
|
FD:THandle;
|
|
R:DWORD;
|
|
del_on_close:Boolean;
|
|
begin
|
|
error:=0;
|
|
//error:=priv_check(curkthread, PRIV_DEVFS_SYMLINK);
|
|
if (error<>0) then Exit(error);
|
|
|
|
len:=strlen(ap^.a_target);
|
|
if (len<=0) then Exit(EINVAL);
|
|
if (len>MAX_PATH) then Exit(ENAMETOOLONG);
|
|
|
|
//Get Privilege
|
|
Privilege:=SE_CREATE_SYMBOLIC_LINK_PRIVILEGE;
|
|
R:=RtlAcquirePrivilege(@Privilege,1,0,@PrivState);
|
|
|
|
if (R<>0) then Exit(EPERM);
|
|
|
|
dd:=ap^.a_dvp^.v_data;
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
|
|
w:=_UTF8Decode(ap^.a_cnp^.cn_nameptr, ap^.a_cnp^.cn_namelen);
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,THandle(dd^.ufs_md_fp),0,PWideChar(w));
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtCreateFile(@FD,
|
|
FILE_READ_ATTRIBUTES or
|
|
FILE_WRITE_ATTRIBUTES or
|
|
FILE_CAN_DELETE or
|
|
SYNCHRONIZE,
|
|
@OBJ,
|
|
@BLK,
|
|
nil,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0,
|
|
FILE_CREATE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT or
|
|
FILE_OPEN_REPARSE_POINT or
|
|
FILE_NON_DIRECTORY_FILE {FILE_DIRECTORY_FILE}, //target dir or file ???
|
|
nil,
|
|
0);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _err;
|
|
|
|
w:=_UTF8Decode(ap^.a_target,len);
|
|
len:=Length(w);
|
|
|
|
NT_SYMLINK:=Default(T_NT_SYMLINK);
|
|
|
|
NT_SYMLINK.info.ReparseTag :=IO_REPARSE_TAG_SYMLINK;
|
|
NT_SYMLINK.info.ReparseDataLength:=(SizeOf(REPARSE_DATA_BUFFER)-REPARSE_DATA_OFFSET)+(len*4);
|
|
|
|
NT_SYMLINK.info.SymbolicLinkReparseBuffer.PrintNameOffset :=0;
|
|
NT_SYMLINK.info.SymbolicLinkReparseBuffer.PrintNameLength :=(len*SizeOf(WideChar));
|
|
NT_SYMLINK.info.SymbolicLinkReparseBuffer.SubstituteNameOffset:=(len*SizeOf(WideChar));
|
|
NT_SYMLINK.info.SymbolicLinkReparseBuffer.SubstituteNameLength:=(len*SizeOf(WideChar));
|
|
|
|
if (ap^.a_target[0]<>'/') then //is relative
|
|
begin
|
|
NT_SYMLINK.info.SymbolicLinkReparseBuffer.Flags :=SYMLINK_FLAG_RELATIVE;
|
|
//only from relative
|
|
fix_win_path(PWideChar(w),len);
|
|
end;
|
|
|
|
Move(PWideChar(w)^,NT_SYMLINK.Name[0] ,len*SizeOf(WideChar));
|
|
Move(PWideChar(w)^,NT_SYMLINK.Name[len],len*SizeOf(WideChar));
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
//Need SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
|
|
R:=NtFsControlFile(FD,
|
|
0,
|
|
nil,
|
|
nil,
|
|
@BLK,
|
|
FSCTL_SET_REPARSE_POINT,
|
|
@NT_SYMLINK,
|
|
NT_SYMLINK.info.ReparseDataLength+REPARSE_DATA_OFFSET,
|
|
nil,
|
|
0);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then
|
|
begin
|
|
//mark delete on close handle
|
|
_del:
|
|
del_on_close:=true;
|
|
NtSetInformationFile(FD,@BLK,@del_on_close,1,FileDispositionInformation);
|
|
NtClose(FD);
|
|
_err:
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
RtlReleasePrivilege(PrivState);
|
|
Exit;
|
|
end;
|
|
|
|
FBI:=Default(FILE_BASIC_INFORMATION);
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@FBI,
|
|
SizeOf(FBI),
|
|
FileBasicInformation
|
|
);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _del;
|
|
|
|
NtClose(FD);
|
|
|
|
//clear cache
|
|
de:=md_find_cache(dd,ap^.a_cnp^.cn_nameptr,ap^.a_cnp^.cn_namelen,0);
|
|
md_unlink_cache(de,False,True);
|
|
|
|
//new dirent
|
|
Result:=md_new_cache(dd,ap^.a_cnp^.cn_nameptr,ap^.a_cnp^.cn_namelen,@FBI,de);
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
RtlReleasePrivilege(PrivState);
|
|
|
|
if (de=nil) then Exit; //if new fail
|
|
|
|
dmp:=VFSTOUFS(ap^.a_dvp^.v_mount);
|
|
sx_xlock(@dmp^.ufs_lock);
|
|
|
|
Exit(ufs_allocv(de, ap^.a_dvp^.v_mount, LK_EXCLUSIVE, ap^.a_vpp)); //sx_xunlock
|
|
end;
|
|
|
|
function md_link(ap:p_vop_link_args):Integer;
|
|
var
|
|
cnp:p_componentname;
|
|
dd:p_ufs_dirent;
|
|
de:p_ufs_dirent;
|
|
|
|
i:Integer;
|
|
FD:THandle;
|
|
NT_LINK:T_NT_LINK;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
begin
|
|
Result:=md_mount_is_valid(ap^.a_tdvp);
|
|
if (Result<>0) then Exit;
|
|
|
|
cnp:=ap^.a_cnp;
|
|
dd:=ap^.a_tdvp^.v_data;
|
|
de:=ap^.a_vp^.v_data;
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Result:=md_open_dirent_file(de,True,@FD);
|
|
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
Exit;
|
|
end;
|
|
|
|
NT_LINK:=Default(T_NT_LINK);
|
|
NT_LINK.info.ReplaceIfExists:=false;
|
|
NT_LINK.info.RootDirectory :=THandle(dd^.ufs_md_fp);
|
|
|
|
i:=Utf8ToUnicode(@NT_LINK.Name,
|
|
MAX_PATH,
|
|
cnp^.cn_nameptr,
|
|
cnp^.cn_namelen);
|
|
|
|
if (i<=0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
NtClose(FD);
|
|
Exit(ENAMETOOLONG);
|
|
end;
|
|
|
|
NT_LINK.info.FileNameLength:=(i-1)*SizeOf(WideChar); //zero exclude
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtSetInformationFile(FD,
|
|
@BLK,
|
|
@NT_LINK,
|
|
NT_LINK.info.FileNameLength+24,
|
|
FileLinkInformation);
|
|
|
|
Result:=ntf2px(R);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
//clear cache
|
|
de:=md_find_cache(dd,cnp^.cn_nameptr,cnp^.cn_namelen,0);
|
|
md_unlink_cache(de,False,True);
|
|
end;
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
NtClose(FD);
|
|
end;
|
|
|
|
function md_mkdir(ap:p_vop_mkdir_args):Integer;
|
|
var
|
|
dvp:p_vnode;
|
|
cnp:p_componentname;
|
|
vap:p_vattr;
|
|
dmp:p_ufs_mount;
|
|
dd:p_ufs_dirent;
|
|
de:p_ufs_dirent;
|
|
|
|
w:WideString;
|
|
OBJ:TOBJ_ATTR;
|
|
BLK:IO_STATUS_BLOCK;
|
|
FD:Thandle;
|
|
R:DWORD;
|
|
begin
|
|
dvp:=ap^.a_dvp;
|
|
cnp:=ap^.a_cnp;
|
|
vap:=ap^.a_vap;
|
|
dmp:=VFSTOUFS(dvp^.v_mount);
|
|
|
|
dd:=dvp^.v_data;
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
|
|
de:=md_find_cache(dd, cnp^.cn_nameptr, cnp^.cn_namelen, 0);
|
|
|
|
if (de<>nil) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
Exit(EEXIST);
|
|
end;
|
|
|
|
w:=_UTF8Decode(cnp^.cn_nameptr,cnp^.cn_namelen);
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,THandle(dd^.ufs_md_fp),0,PWideChar(w));
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtCreateFile(@FD,
|
|
SYNCHRONIZE or
|
|
FILE_LIST_DIRECTORY or
|
|
FILE_READ_ATTRIBUTES or
|
|
FILE_WRITE_ATTRIBUTES,
|
|
@OBJ,
|
|
@BLK,
|
|
nil,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ or
|
|
FILE_SHARE_WRITE,
|
|
FILE_CREATE,
|
|
FILE_DIRECTORY_FILE or
|
|
FILE_SYNCHRONOUS_IO_NONALERT or
|
|
FILE_OPEN_FOR_BACKUP_INTENT or
|
|
FILE_OPEN_REPARSE_POINT,
|
|
nil,
|
|
0);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
Exit;
|
|
end;
|
|
|
|
NtClose(FD);
|
|
|
|
//clear cache
|
|
de:=md_find_cache(dd,ap^.a_cnp^.cn_nameptr,ap^.a_cnp^.cn_namelen,0);
|
|
md_unlink_cache(de,False,True);
|
|
|
|
de:=md_vmkdir(dmp,cnp^.cn_nameptr,cnp^.cn_namelen,dd);
|
|
|
|
if (de=nil) then
|
|
begin
|
|
Exit(ENOMEM);
|
|
end;
|
|
|
|
de^.ufs_mode:=vap^.va_mode;
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
|
|
sx_xlock(@dmp^.ufs_lock);
|
|
|
|
Exit(ufs_allocv(de, ap^.a_dvp^.v_mount, LK_EXCLUSIVE, ap^.a_vpp)); //sx_xunlock
|
|
end;
|
|
|
|
function md_remove(ap:p_vop_remove_args):Integer;
|
|
var
|
|
dvp,vp:p_vnode;
|
|
dd,de:p_ufs_dirent;
|
|
|
|
FD:THandle;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
|
|
del_on_close:Boolean;
|
|
begin
|
|
dvp:=ap^.a_dvp;
|
|
vp:=ap^.a_vp;
|
|
|
|
dd:=dvp^.v_data;
|
|
de:=vp^.v_data;
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Result:=md_open_dirent_file(de,True,@FD);
|
|
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
Exit;
|
|
end;
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
del_on_close:=true;
|
|
|
|
R:=NtSetInformationFile(FD,@BLK,@del_on_close,1,FileDispositionInformation);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
NtClose(FD);
|
|
Exit;
|
|
end;
|
|
|
|
//clear cache
|
|
md_unlink_cache(de,False,True);
|
|
|
|
NtClose(FD); //<-deleted
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
end;
|
|
|
|
function md_rmdir(ap:p_vop_rmdir_args):Integer;
|
|
var
|
|
dvp,vp:p_vnode;
|
|
dd,de:p_ufs_dirent;
|
|
|
|
FD:THandle;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
|
|
del_on_close:Boolean;
|
|
begin
|
|
dvp:=ap^.a_dvp;
|
|
vp:=ap^.a_vp;
|
|
|
|
dd:=dvp^.v_data;
|
|
de:=vp^.v_data;
|
|
|
|
if (de^.ufs_dirent^.d_type<>DT_DIR) then Exit(ENOTDIR);
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Result:=md_open_dirent_file(de,True,@FD);
|
|
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
Exit;
|
|
end;
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
del_on_close:=true;
|
|
|
|
R:=NtSetInformationFile(FD,@BLK,@del_on_close,1,FileDispositionInformation);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then
|
|
begin
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
NtClose(FD);
|
|
Exit;
|
|
end;
|
|
|
|
//clear cache
|
|
md_unlink_cache(de,False,True);
|
|
|
|
NtClose(FD); //<-deleted
|
|
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
end;
|
|
|
|
function md_rename(ap:p_vop_rename_args):Integer;
|
|
label
|
|
_exit;
|
|
var
|
|
dd_f,dd_t:p_ufs_dirent;
|
|
de_f,de_t:p_ufs_dirent;
|
|
cnp_t:p_componentname;
|
|
|
|
FD:THandle;
|
|
NT_RENAME:T_NT_RENAME;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
i:Integer;
|
|
|
|
begin
|
|
Result:=md_mount_is_valid(ap^.a_tdvp);
|
|
if (Result<>0) then Exit;
|
|
|
|
dd_f:=ap^.a_fdvp^.v_data;
|
|
dd_t:=ap^.a_tdvp^.v_data;
|
|
de_f:=ap^.a_fvp^.v_data;
|
|
cnp_t:=ap^.a_tcnp;
|
|
|
|
de_t:=nil;
|
|
if (ap^.a_tvp<>nil) then
|
|
begin
|
|
de_t:=ap^.a_tvp^.v_data;
|
|
end;
|
|
|
|
sx_xlock(@dd_f^.ufs_md_lock);
|
|
if (dd_f<>dd_t) then
|
|
begin
|
|
sx_xlock(@dd_t^.ufs_md_lock);
|
|
end;
|
|
|
|
sx_xlock(@de_f^.ufs_md_lock);
|
|
|
|
Result:=md_open_dirent_file(de_f,True,@FD);
|
|
if (Result<>0) then goto _exit;
|
|
|
|
NT_RENAME:=Default(T_NT_RENAME);
|
|
NT_RENAME.info.ReplaceIfExists:=True;
|
|
NT_RENAME.info.RootDirectory :=THandle(dd_t^.ufs_md_fp);
|
|
|
|
i:=Utf8ToUnicode(@NT_RENAME.Name,
|
|
MAX_PATH,
|
|
cnp_t^.cn_nameptr,
|
|
cnp_t^.cn_namelen);
|
|
|
|
if (i<=0) then
|
|
begin
|
|
Result:=ENAMETOOLONG;
|
|
goto _exit;
|
|
end;
|
|
|
|
NT_RENAME.info.FileNameLength:=(i-1)*SizeOf(WideChar); //zero exclude
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtSetInformationFile(FD,
|
|
@BLK,
|
|
@NT_RENAME,
|
|
NT_RENAME.info.FileNameLength+24,
|
|
FileRenameInformation);
|
|
|
|
Result:=ntf2px(R);
|
|
|
|
if (Result<>0) then goto _exit;
|
|
|
|
//clear cache
|
|
md_unlink_cache(de_f,True ,True);
|
|
md_unlink_cache(de_t,False,True);
|
|
|
|
de_f:=nil;
|
|
|
|
_exit:
|
|
|
|
if (de_f<>nil) then
|
|
begin
|
|
sx_xunlock(@de_f^.ufs_md_lock);
|
|
end;
|
|
|
|
sx_xunlock(@dd_f^.ufs_md_lock);
|
|
if (dd_f<>dd_t) then
|
|
begin
|
|
sx_xunlock(@dd_t^.ufs_md_lock);
|
|
end;
|
|
|
|
NtClose(FD);
|
|
end;
|
|
|
|
Function GetDesiredAccess(flags:Integer):DWORD; inline;
|
|
begin
|
|
Result:=SYNCHRONIZE or
|
|
FILE_READ_ATTRIBUTES or
|
|
FILE_WRITE_ATTRIBUTES;
|
|
|
|
if ((flags and FREAD)<>0) then
|
|
begin
|
|
Result:=Result or FILE_READ_DATA;
|
|
end;
|
|
|
|
if ((flags and FWRITE)<>0) then
|
|
begin
|
|
Result:=Result or FILE_WRITE_DATA or FILE_APPEND_DATA;
|
|
end;
|
|
end;
|
|
|
|
Function GetCreationDisposition(flags:Integer):DWORD; inline;
|
|
begin
|
|
Result:=0;
|
|
if ((flags and O_CREAT)<>0) then
|
|
begin
|
|
if ((flags and O_EXCL)<>0) then
|
|
begin
|
|
Result:=FILE_CREATE;
|
|
end else
|
|
if ((flags and O_TRUNC)<>0) then
|
|
begin
|
|
Result:=FILE_OVERWRITE_IF;
|
|
end else
|
|
begin
|
|
Result:=FILE_OPEN_IF;
|
|
end;
|
|
end else
|
|
if ((flags and O_TRUNC)<>0) then
|
|
begin
|
|
Result:=FILE_OVERWRITE;
|
|
end else
|
|
begin
|
|
Result:=FILE_OPEN;
|
|
end;
|
|
end;
|
|
|
|
Function GetFileAttrtibute(flags,mode:Integer):DWORD; inline;
|
|
begin
|
|
Result:=FILE_ATTRIBUTE_NORMAL;
|
|
if ((flags and O_CREAT)<>0) and
|
|
((mode and S_IWUSR)=0) then
|
|
begin
|
|
Result:=Result or FILE_ATTRIBUTE_READONLY;
|
|
end;
|
|
end;
|
|
|
|
Function GetCreateOptions(flags:Integer):DWORD; inline;
|
|
begin
|
|
Result:=FILE_SYNCHRONOUS_IO_NONALERT or
|
|
FILE_NON_DIRECTORY_FILE;
|
|
if ((flags and (O_FSYNC or O_DSYNC))<>0) then
|
|
begin
|
|
Result:=Result or FILE_WRITE_THROUGH;
|
|
end;
|
|
end;
|
|
|
|
function md_create(ap:p_vop_create_args):Integer;
|
|
var
|
|
dvp:p_vnode;
|
|
cnp:p_componentname;
|
|
vap:p_vattr;
|
|
dmp:p_ufs_mount;
|
|
|
|
dd:p_ufs_dirent;
|
|
nd:p_ufs_dirent;
|
|
begin
|
|
dvp:=ap^.a_dvp;
|
|
cnp:=ap^.a_cnp;
|
|
vap:=ap^.a_vap;
|
|
|
|
dd:=dvp^.v_data;
|
|
if (dd=nil) then Exit(EPERM);
|
|
|
|
nd:=md_newdirent(cnp^.cn_nameptr,cnp^.cn_namelen);
|
|
if (nd=nil) then Exit(ENOMEM);
|
|
|
|
nd^.ufs_flags:=UFS_CREATE;
|
|
nd^.ufs_mode :=vap^.va_mode;
|
|
nd^.ufs_dir :=dd;
|
|
|
|
nd^.ufs_dirent^.d_type:=DT_REG;
|
|
|
|
//link soft
|
|
ufs_de_hold(dd);
|
|
|
|
dmp:=VFSTOUFS(dvp^.v_mount);
|
|
sx_xlock(@dmp^.ufs_lock);
|
|
|
|
Exit(ufs_allocv(nd, ap^.a_dvp^.v_mount, LK_EXCLUSIVE, ap^.a_vpp)); //sx_xunlock
|
|
end;
|
|
|
|
function md_open(ap:p_vop_open_args):Integer;
|
|
var
|
|
vp:p_vnode;
|
|
flags:Integer;
|
|
|
|
DA,FA,CD,CO:DWORD;
|
|
|
|
dd:p_ufs_dirent;
|
|
de:p_ufs_dirent;
|
|
dc:p_ufs_dirent;
|
|
|
|
ufs_size:Int64;
|
|
|
|
w:WideString;
|
|
OBJ:TOBJ_ATTR;
|
|
BLK:IO_STATUS_BLOCK;
|
|
|
|
FD:THandle;
|
|
R:DWORD;
|
|
begin
|
|
vp:=ap^.a_vp;
|
|
flags:=ap^.a_mode;
|
|
|
|
if (vp=nil) then Exit(EPERM);
|
|
|
|
vp^.v_un:=nil;
|
|
|
|
case vp^.v_type of
|
|
VREG:;
|
|
VLNK:Exit(0);
|
|
VDIR:Exit(0);
|
|
else
|
|
Exit(EOPNOTSUPP);
|
|
end;
|
|
|
|
de:=vp^.v_data;
|
|
if (de=nil) then Exit(EPERM);
|
|
|
|
dd:=de^.ufs_dir;
|
|
if (dd=nil) then Exit(EPERM);
|
|
|
|
sx_xlock(@dd^.ufs_md_lock);
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
w:=_UTF8Decode(@de^.ufs_dirent^.d_name,de^.ufs_dirent^.d_namlen);
|
|
|
|
OBJ:=Default(TOBJ_ATTR);
|
|
INIT_OBJ(OBJ,THandle(dd^.ufs_md_fp),0,PWideChar(w));
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
DA:=GetDesiredAccess(flags);
|
|
FA:=GetFileAttrtibute(flags,de^.ufs_mode);
|
|
CD:=GetCreationDisposition(flags);
|
|
CO:=GetCreateOptions(flags);
|
|
|
|
R:=NtCreateFile(@FD,
|
|
DA,
|
|
@OBJ,
|
|
@BLK,
|
|
nil,
|
|
FA,
|
|
FILE_SHARE_ALL,
|
|
CD,
|
|
CO,
|
|
nil,
|
|
0);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then
|
|
begin
|
|
md_unlink_cache(de,True,True);
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
Exit;
|
|
end;
|
|
|
|
Result:=md_update_dirent(FD,de,nil);
|
|
if (Result<>0) then
|
|
begin
|
|
md_unlink_cache(de,True,True);
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
NtClose(FD);
|
|
Exit;
|
|
end;
|
|
|
|
vp^.v_un:=Pointer(FD);
|
|
|
|
ufs_size:=de^.ufs_size;
|
|
|
|
if ((de^.ufs_flags and UFS_CREATE)<>0) then
|
|
begin
|
|
if ((flags and O_EXCL)<>0) then
|
|
begin
|
|
//clear cache
|
|
dc:=md_find_cache(dd,@de^.ufs_dirent^.d_name,de^.ufs_dirent^.d_namlen,0);
|
|
md_unlink_cache(dc,False,True);
|
|
end;
|
|
//
|
|
de^.ufs_flags:=de^.ufs_flags and (not UFS_CREATE);
|
|
//link cache
|
|
TAILQ_INSERT_TAIL(@dd^.ufs_dlist,de,@de^.ufs_list);
|
|
Inc(dd^.ufs_links);
|
|
end;
|
|
|
|
sx_unlock (@de^.ufs_md_lock);
|
|
sx_xunlock(@dd^.ufs_md_lock);
|
|
|
|
vnode_create_vobject(vp, ufs_size);
|
|
end;
|
|
|
|
function md_close(ap:p_vop_close_args):Integer;
|
|
var
|
|
vp:p_vnode;
|
|
FD:THandle;
|
|
begin
|
|
vp:=ap^.a_vp;
|
|
|
|
FD:=THandle(System.InterlockedExchange(vp^.v_un,nil));
|
|
if (FD<>0) then
|
|
begin
|
|
NtClose(FD);
|
|
end;
|
|
|
|
vnode_destroy_vobject(vp);
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function md_fsync(ap:p_vop_fsync_args):Integer;
|
|
var
|
|
vp:p_vnode;
|
|
FD:THandle;
|
|
fullsync:Boolean;
|
|
|
|
BLK:IO_STATUS_BLOCK;
|
|
begin
|
|
vp:=ap^.a_vp;
|
|
FD:=THandle(vp^.v_un);
|
|
fullsync:=((ap^.a_waitfor and 2)<>0);
|
|
|
|
if (FD=0) then Exit(EINVAL);
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
//result doesn't matter
|
|
NtFlushBuffersFile(FD,@BLK);
|
|
|
|
if fullsync then
|
|
begin
|
|
//atime
|
|
//mtime
|
|
end;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function md_setattr(ap:p_vop_setattr_args):Integer;
|
|
label
|
|
_err;
|
|
var
|
|
de:p_ufs_dirent;
|
|
vap:p_vattr;
|
|
vp:p_vnode;
|
|
error:Integer;
|
|
uid:uid_t;
|
|
gid:gid_t;
|
|
|
|
change_time,change_size:Boolean;
|
|
|
|
FD,RL:THandle;
|
|
|
|
FBI:FILE_BASIC_INFORMATION;
|
|
BLK:IO_STATUS_BLOCK;
|
|
SIZE:Int64;
|
|
R:DWORD;
|
|
|
|
procedure _settime(var dst:LARGE_INTEGER;var src:timespec); inline;
|
|
begin
|
|
if (src.tv_sec<>-1) and (src.tv_nsec<>-1) then
|
|
begin
|
|
dst:=get_win_file_time(src);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result:=0;
|
|
|
|
vap:=ap^.a_vap;
|
|
vp:=ap^.a_vp;
|
|
|
|
if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_RDONLY)<>0) and
|
|
(
|
|
(vap^.va_flags <>VNOVAL) or
|
|
(vap^.va_uid <>VNOVAL) or
|
|
(vap^.va_gid <>VNOVAL) or
|
|
(vap^.va_atime.tv_sec<>VNOVAL) or
|
|
(vap^.va_mtime.tv_sec<>VNOVAL) or
|
|
(vap^.va_mode <>VNOVAL)
|
|
) then
|
|
begin
|
|
Exit(EROFS);
|
|
end;
|
|
|
|
if (vap^.va_type <>VNON) or
|
|
(vap^.va_nlink <>VNOVAL) or
|
|
(vap^.va_fsid <>VNOVAL) or
|
|
(vap^.va_fileid <>VNOVAL) or
|
|
(vap^.va_blocksize<>VNOVAL) or
|
|
((vap^.va_flags <>VNOVAL) and (vap^.va_flags<>0)) or
|
|
(vap^.va_rdev <>VNOVAL) or
|
|
(vap^.va_bytes <>VNOVAL) or
|
|
(vap^.va_gen <>VNOVAL) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
de:=vp^.v_data;
|
|
|
|
VI_LOCK(vp);
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
error:=0;
|
|
change_time:=False;
|
|
change_size:=False;
|
|
|
|
if (vap^.va_uid=VNOVAL) then
|
|
uid:=de^.ufs_uid
|
|
else
|
|
uid:=vap^.va_uid;
|
|
|
|
if (vap^.va_gid=VNOVAL) then
|
|
gid:=de^.ufs_gid
|
|
else
|
|
gid:=vap^.va_gid;
|
|
|
|
if (uid<>de^.ufs_uid) or (gid<>de^.ufs_gid) then
|
|
begin
|
|
//if ((ap^.a_cred^.cr_uid<>de^.de_uid) or uid<>de^.de_uid or
|
|
// (gid<>de^.de_gid and !groupmember(gid, ap^.a_cred))) then
|
|
//begin
|
|
// error:=priv_check(td, PRIV_VFS_CHOWN);
|
|
// if (error<>) then
|
|
// Exit(error);
|
|
//end;
|
|
de^.ufs_uid:=uid;
|
|
de^.ufs_gid:=gid;
|
|
end;
|
|
|
|
if (vap^.va_mode<>VNOVAL) then
|
|
begin
|
|
//if (ap^.a_cred^.cr_uid<>de^.de_uid) then
|
|
//begin
|
|
// error:=priv_check(td, PRIV_VFS_ADMIN);
|
|
// if (error<>0) then
|
|
// Exit(error);
|
|
//end;
|
|
de^.ufs_mode:=vap^.va_mode;
|
|
end;
|
|
|
|
if (vap^.va_atime.tv_sec<>VNOVAL) or
|
|
(vap^.va_mtime.tv_sec<>VNOVAL) or
|
|
(vap^.va_birthtime.tv_sec<>VNOVAL) then
|
|
begin
|
|
{ See the comment in ufs_vnops::ufs_setattr(). }
|
|
|
|
error:=VOP_ACCESS(vp, VADMIN);
|
|
if (error<>0) then
|
|
begin
|
|
if ((vap^.va_vaflags and VA_UTIMES_NULL)=0) then Exit(error);
|
|
error:=VOP_ACCESS(vp, VWRITE);
|
|
if (error<>0) then Exit(error);
|
|
end;
|
|
|
|
if (vap^.va_atime.tv_sec<>VNOVAL) then
|
|
begin
|
|
de^.ufs_atime:=vap^.va_atime;
|
|
end;
|
|
if (vap^.va_mtime.tv_sec<>VNOVAL) then
|
|
begin
|
|
de^.ufs_mtime:=vap^.va_mtime;
|
|
end;
|
|
if (vap^.va_birthtime.tv_sec<>VNOVAL) then
|
|
begin
|
|
de^.ufs_btime:=vap^.va_birthtime;
|
|
end;
|
|
|
|
change_time:=True;
|
|
end;
|
|
|
|
if (vap^.va_size<>VNOVAL) then
|
|
begin
|
|
change_size:=True;
|
|
end;
|
|
|
|
if change_time or change_size then
|
|
begin
|
|
|
|
if (vp^.v_un<>nil) then
|
|
begin
|
|
FD:=THandle(vp^.v_un);
|
|
RL:=0;
|
|
end else
|
|
if (de^.ufs_md_fp<>nil) then
|
|
begin
|
|
FD:=THandle(de^.ufs_md_fp);
|
|
RL:=0;
|
|
end else
|
|
begin
|
|
Result:=md_open_dirent_file(de,True,@FD);
|
|
if (Result<>0) then Exit;
|
|
RL:=FD;
|
|
end;
|
|
|
|
if change_time then
|
|
begin
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtQueryInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@FBI,
|
|
SizeOf(FBI),
|
|
FileBasicInformation);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _err;
|
|
|
|
//update
|
|
de^.ufs_ctime:=get_unix_file_time(FBI.ChangeTime);
|
|
|
|
_settime(FBI.LastAccessTime,de^.ufs_atime);
|
|
_settime(FBI.LastWriteTime ,de^.ufs_mtime);
|
|
_settime(FBI.CreationTime ,de^.ufs_btime);
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=NtSetInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@FBI,
|
|
SizeOf(FBI),
|
|
FileBasicInformation);
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _err;
|
|
end;
|
|
|
|
if change_size then
|
|
begin
|
|
SIZE:=vap^.va_size;
|
|
|
|
R:=NtSetInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@SIZE,
|
|
SizeOf(Int64),
|
|
FileEndOfFileInformation);
|
|
|
|
if (R<>0) then
|
|
begin
|
|
R:=NtSetInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@SIZE,
|
|
SizeOf(Int64),
|
|
FileAllocationInformation);
|
|
end;
|
|
|
|
Result:=ntf2px(R);
|
|
if (Result<>0) then goto _err;
|
|
|
|
de^.ufs_size:=SIZE;
|
|
|
|
vnode_pager_setsize(vp, SIZE);
|
|
end;
|
|
|
|
_err:
|
|
|
|
sx_unlock(@de^.ufs_md_lock);
|
|
VI_UNLOCK(vp);
|
|
|
|
if (RL<>0) then
|
|
begin
|
|
NtClose(RL);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function md_ioctl(ap:p_vop_ioctl_args):Integer;
|
|
begin
|
|
Result:=EOPNOTSUPP;
|
|
|
|
case ap^.a_command of
|
|
FIOSEEKDATA:Result:=0;
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
|
|
type
|
|
t_uio_cb=function(
|
|
FileHandle :THandle;
|
|
Event :THandle;
|
|
ApcRoutine :Pointer;
|
|
ApcContext :Pointer;
|
|
IoStatusBlock:PIO_STATUS_BLOCK;
|
|
Buffer :Pointer;
|
|
Length :ULONG;
|
|
ByteOffset :PLARGE_INTEGER;
|
|
Key :PULONG
|
|
):DWORD; stdcall;
|
|
|
|
t_iov_cb=procedure(iov:p_iovec);
|
|
|
|
procedure iov_null(iov:p_iovec); assembler; nostackframe;
|
|
asm
|
|
//
|
|
end;
|
|
|
|
function md_io(vp:p_vnode;uio:p_uio;ioflag:Integer):Integer;
|
|
var
|
|
td:p_kthread;
|
|
|
|
de:p_ufs_dirent;
|
|
F:Thandle;
|
|
iocb:t_uio_cb;
|
|
ioin:PInt64;
|
|
|
|
append:Boolean;
|
|
locked:Boolean;
|
|
|
|
iov:p_iovec;
|
|
vec:iovec;
|
|
iol:t_iov_cb;
|
|
|
|
OFFSET:Int64;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
begin
|
|
Result:=0;
|
|
de:=vp^.v_data;
|
|
F:=THandle(vp^.v_un);
|
|
|
|
td:=curkthread;
|
|
if (td=nil) then Exit(-1);
|
|
|
|
ioin:=nil;
|
|
case uio^.uio_rw of
|
|
UIO_READ :ioin:=@td^.td_ru.ru_inblock;
|
|
UIO_WRITE:ioin:=@td^.td_ru.ru_oublock;
|
|
end;
|
|
|
|
iocb:=nil;
|
|
case uio^.uio_rw of
|
|
UIO_READ :iocb:=@NtReadFile;
|
|
UIO_WRITE:iocb:=@NtWriteFile;
|
|
end;
|
|
|
|
iol:=nil;
|
|
case uio^.uio_segflg of
|
|
UIO_USERSPACE:iol:=@iov_uplift;
|
|
UIO_SYSSPACE :iol:=@iov_null;
|
|
end;
|
|
|
|
append:=(uio^.uio_rw=UIO_WRITE) and ((ioflag and IO_APPEND)<>0);
|
|
|
|
locked:=((ioflag and IO_UNIT)<>0) and (not append);
|
|
|
|
if locked then
|
|
begin
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
end;
|
|
|
|
while (uio^.uio_iovcnt>0) or (uio^.uio_resid>0) do
|
|
begin
|
|
iov:=uio^.uio_iov;
|
|
|
|
vec:=iov^;
|
|
iol(@vec);
|
|
|
|
if (vec.iov_len=0) then
|
|
begin
|
|
Inc(uio^.uio_iov);
|
|
Dec(uio^.uio_iovcnt);
|
|
continue;
|
|
end;
|
|
|
|
if append then
|
|
begin
|
|
OFFSET:=Int64(FILE_WRITE_TO_END_OF_FILE_L);
|
|
end else
|
|
begin
|
|
OFFSET:=uio^.uio_offset;
|
|
end;
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
|
|
R:=iocb(F,0,nil,nil,@BLK,vec.iov_base,vec.iov_len,@OFFSET,nil);
|
|
|
|
if (R=STATUS_PENDING) then
|
|
begin
|
|
R:=NtWaitForSingleObject(F,False,nil);
|
|
if (R=0) then
|
|
begin
|
|
R:=BLK.Status;
|
|
end;
|
|
end;
|
|
|
|
Result:=ntf2px(R);
|
|
|
|
System.InterlockedIncrement64(ioin^);
|
|
|
|
if (Int64(BLK.Information)<vec.iov_len) then
|
|
begin
|
|
//partial
|
|
vec.iov_len:=BLK.Information;
|
|
if (vec.iov_len<>0) then
|
|
begin
|
|
Inc(iov^.iov_base ,vec.iov_len);
|
|
Dec(iov^.iov_len ,vec.iov_len);
|
|
Dec(uio^.uio_resid ,vec.iov_len);
|
|
|
|
if not append then
|
|
begin
|
|
Inc(uio^.uio_offset,vec.iov_len);
|
|
end;
|
|
end;
|
|
Break;
|
|
end;
|
|
|
|
if (Result<>0) then Break;
|
|
|
|
Inc(iov^.iov_base ,vec.iov_len);
|
|
Dec(iov^.iov_len ,vec.iov_len);
|
|
Dec(uio^.uio_resid ,vec.iov_len);
|
|
|
|
if not append then
|
|
begin
|
|
Inc(uio^.uio_offset,vec.iov_len);
|
|
end;
|
|
|
|
if (iov^.iov_len=0) then
|
|
begin
|
|
Inc(uio^.uio_iov);
|
|
Dec(uio^.uio_iovcnt);
|
|
end;
|
|
end;
|
|
|
|
if locked then
|
|
begin
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
end;
|
|
end;
|
|
|
|
function md_read(ap:p_vop_read_args):Integer;
|
|
begin
|
|
case ap^.a_vp^.v_type of
|
|
VDIR:Exit(VOP_READDIR(ap^.a_vp, ap^.a_uio, nil, nil, nil));
|
|
VREG:Exit(md_io(ap^.a_vp,ap^.a_uio,ap^.a_ioflag));
|
|
else
|
|
Exit(EBADF);
|
|
end;
|
|
end;
|
|
|
|
function md_write(ap:p_vop_write_args):Integer;
|
|
begin
|
|
case ap^.a_vp^.v_type of
|
|
VREG:Exit(md_io(ap^.a_vp,ap^.a_uio,ap^.a_ioflag));
|
|
else
|
|
Exit(EBADF);
|
|
end;
|
|
end;
|
|
|
|
function md_advlock(ap:p_vop_advlock_args):Integer;
|
|
var
|
|
vp:p_vnode;
|
|
de:p_ufs_dirent;
|
|
fp:p_file;
|
|
fl:p_flock;
|
|
op:Integer;
|
|
wf:Integer;
|
|
|
|
offset,size:Int64;
|
|
|
|
F:THandle;
|
|
BLK:IO_STATUS_BLOCK;
|
|
R:DWORD;
|
|
begin
|
|
vp:=ap^.a_vp;
|
|
if (vp^.v_type<>VREG) then Exit(EBADF);
|
|
|
|
de:=vp^.v_data;
|
|
fp:=ap^.a_id;
|
|
fl:=ap^.a_fl;
|
|
op:=ap^.a_op;
|
|
wf:=ap^.a_flags;
|
|
|
|
F:=THandle(vp^.v_un);
|
|
|
|
case op of
|
|
F_SETLK:;
|
|
else
|
|
Exit(ENOTSUP);
|
|
end;
|
|
|
|
case fl^.l_type of
|
|
F_RDLCK:;
|
|
F_UNLCK:;
|
|
F_WRLCK:;
|
|
else
|
|
Exit(ENOTSUP);
|
|
end;
|
|
|
|
case fl^.l_whence of
|
|
SEEK_SET:offset:=fl^.l_start;
|
|
SEEK_CUR:offset:=fp^.f_offset+fl^.l_start;
|
|
SEEK_END:
|
|
begin
|
|
sx_xlock(@de^.ufs_md_lock);
|
|
|
|
Result:=md_update_dirent(F,de,nil);
|
|
|
|
offset:=de^.ufs_size+fl^.l_start;
|
|
|
|
sx_xunlock(@de^.ufs_md_lock);
|
|
|
|
if (Result<>0) then Exit;
|
|
end;
|
|
else
|
|
Exit(ENOTSUP);
|
|
end;
|
|
|
|
size:=fl^.l_len;
|
|
if (size=0) then
|
|
begin
|
|
size:=-1;
|
|
end;
|
|
|
|
case fl^.l_type of
|
|
F_RDLCK:
|
|
begin
|
|
R:=NtLockFile(
|
|
F,
|
|
0,
|
|
nil,
|
|
nil,
|
|
@BLK,
|
|
@offset,
|
|
@size,
|
|
0,
|
|
((wf and F_WAIT)=0),
|
|
False
|
|
);
|
|
end;
|
|
F_WRLCK:
|
|
begin
|
|
R:=NtLockFile(
|
|
F,
|
|
0,
|
|
nil,
|
|
nil,
|
|
@BLK,
|
|
@offset,
|
|
@size,
|
|
0,
|
|
((wf and F_WAIT)=0),
|
|
True
|
|
);
|
|
end;
|
|
F_UNLCK:
|
|
begin
|
|
R:=NtUnlockFile(
|
|
F,
|
|
@BLK,
|
|
@offset,
|
|
@size,
|
|
0
|
|
);
|
|
end
|
|
else;
|
|
end;
|
|
|
|
Result:=ntf2px(R);
|
|
end;
|
|
|
|
function md_advlockpurge(ap:p_vop_advlockpurge_args):Integer;
|
|
begin
|
|
//Locks are automatically released on NtClose
|
|
Result:=0;
|
|
end;
|
|
|
|
|
|
end.
|
|
|