99
1010from qiling import Qiling
1111from qiling .const import QL_OS , QL_ARCH , QL_ENDIAN
12- from qiling .os .posix .const import NR_OPEN , EBADF
12+ from qiling .os .posix .const import NR_OPEN , EBADF , AT_FDCWD
1313from qiling .os .posix .stat import Stat , Lstat
1414
1515# Caveat: Never use types like ctypes.c_long whose size differs across platforms.
@@ -1025,6 +1025,36 @@ def statFamily(ql: Qiling, path: int, ptr: int, name: str, stat_func, struct_fun
10251025 ql .log .debug (f'{ name } ("{ file_path } ", { ptr :#x} ) write completed' )
10261026 return regreturn
10271027
1028+ def transform_path (ql : Qiling , dirfd : int , path : int ):
1029+ """
1030+ An absolute pathname
1031+ If pathname begins with a slash, then it is an absolute pathname that identifies the target file.
1032+ In this case, dirfd is ignored.
1033+
1034+ A relative pathname
1035+ If pathname is a string that begins with a character other than a slash and dirfd is AT_FDCWD,
1036+ then pathname is a relative pathname that is interpreted relative to the process's current working directory.
1037+
1038+ A directory-relative pathname
1039+ If pathname is a string that begins with a character other than a slash and dirfd is a file descriptor that refers to a
1040+ directory, then pathname is a relative pathname that is interpreted relative to the directory referred to by dirfd.
1041+
1042+ By file descriptor
1043+ If pathname is an empty string and the AT_EMPTY_PATH flag is specified in flags (see below),
1044+ then the target file is the one referred to by the file descriptor dirfd.
1045+ """
1046+
1047+ path = ql .os .utils .read_cstring (path )
1048+
1049+ if path .startswith ('/' ):
1050+ return None , ql .os .path .transform_to_relative_path (path )
1051+
1052+ if dirfd == AT_FDCWD :
1053+ return - 100 , ql .os .path .transform_to_relative_path (os .path .join (ql .os .path .cwd , path ))
1054+
1055+ return dirfd , path
1056+
1057+
10281058def ql_syscall_chmod (ql : Qiling , filename : int , mode : int ):
10291059 ql .log .debug (f'chmod("{ ql .os .utils .read_cstring (filename )} ", { mode :d} ) = 0' )
10301060
@@ -1037,39 +1067,29 @@ def ql_syscall_fchmod(ql: Qiling, fd: int, mode: int):
10371067 return 0
10381068
10391069def ql_syscall_fstatat64 (ql : Qiling , dirfd : int , path : int , buf_ptr : int , flag : int ):
1040- # FIXME: dirfd(relative path) not implement.
1041- file_path = ql .os .utils .read_cstring (path )
1042- real_path = ql .os .path .transform_to_real_path (file_path )
1043- relative_path = ql .os .path .transform_to_relative_path (file_path )
1070+ dirfd , real_path = transform_path (ql , dirfd , path )
10441071
10451072 if os .path .exists (real_path ):
1046- buf = pack_stat64_struct (ql , Stat (real_path ))
1073+ buf = pack_stat64_struct (ql , Stat (real_path , dirfd ))
10471074 ql .mem .write (buf_ptr , buf )
10481075
10491076 regreturn = 0
10501077 else :
10511078 regreturn = - 1
10521079
1053- ql .log .debug (f'Directory { "found" if regreturn == 0 else "not found" } : { relative_path } ' )
1054-
10551080 return regreturn
10561081
10571082def ql_syscall_newfstatat (ql : Qiling , dirfd : int , path : int , buf_ptr : int , flag : int ):
1058- # FIXME: dirfd(relative path) not implement.
1059- file_path = ql .os .utils .read_cstring (path )
1060- real_path = ql .os .path .transform_to_real_path (file_path )
1061- relative_path = ql .os .path .transform_to_relative_path (file_path )
1062-
1083+ dirfd , real_path = transform_path (ql , dirfd , path )
1084+
10631085 if os .path .exists (real_path ):
1064- buf = pack_stat_struct (ql , Stat (real_path ))
1086+ buf = pack_stat_struct (ql , Stat (real_path , dirfd ))
10651087 ql .mem .write (buf_ptr , buf )
10661088
10671089 regreturn = 0
10681090 else :
10691091 regreturn = - 1
10701092
1071- ql .log .debug (f'Directory { "found" if regreturn == 0 else "not found" } : { relative_path } ' )
1072-
10731093 return regreturn
10741094
10751095def ql_syscall_fstat64 (ql : Qiling , fd , buf_ptr ):
@@ -1123,6 +1143,10 @@ def ql_syscall_stat(ql: Qiling, path: int, buf_ptr: int):
11231143def ql_syscall_stat64 (ql : Qiling , path : int , buf_ptr : int ):
11241144 return statFamily (ql , path , buf_ptr , "stat64" , Stat , pack_stat64_struct )
11251145
1146+ # int statx(int dirfd, const char *restrict pathname, int flags,
1147+ # unsigned int mask, struct statx *restrict statxbuf);
1148+ def ql_syscall_statx (ql : Qiling , dirfd : int , path : int , flags : int , mask : int , statxbuf : int ):
1149+ return 0
11261150
11271151def ql_syscall_lstat (ql : Qiling , path : int , buf_ptr : int ):
11281152 return statFamily (ql , path , buf_ptr , "lstat" , Lstat , pack_stat64_struct )
@@ -1132,14 +1156,12 @@ def ql_syscall_lstat64(ql: Qiling, path: int, buf_ptr: int):
11321156 return statFamily (ql , path , buf_ptr , "lstat64" , Lstat , pack_stat64_struct )
11331157
11341158
1135- def ql_syscall_mknodat (ql : Qiling , dirfd : int , pathname : int , mode : int , dev : int ):
1136- # FIXME: dirfd(relative path) not implement.
1137- file_path = ql .os .utils .read_cstring (pathname )
1138- real_path = ql .os .path .transform_to_real_path (file_path )
1139- regreturn = 0
1159+ def ql_syscall_mknodat (ql : Qiling , dirfd : int , path : int , mode : int , dev : int ):
1160+ dirfd , real_path = transform_path (ql , dirfd , path )
11401161
11411162 try :
1142- os .mknod (real_path , mode , dev )
1163+ os .mknod (real_path , mode , dev , dir_fd = dirfd )
1164+ regreturn = 0
11431165 except :
11441166 regreturn = - 1
11451167
0 commit comments