Skip to content

Commit f9d4685

Browse files
authored
Merge pull request #990 from cla7aye15I4nd/riscv
Handle the dir_fd argument of stat syscall
2 parents 1ab8f61 + 80f9dac commit f9d4685

File tree

3 files changed

+50
-26
lines changed

3 files changed

+50
-26
lines changed

qiling/os/posix/const.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@
559559

560560
FD_CLOEXEC = 1
561561

562+
AT_FDCWD = 0xffffff9c # -100
563+
562564
# error code
563565
EPERM = 1
564566
ENOENT = 2

qiling/os/posix/stat.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ def __getattr__(self, key):
2323
return self.__getitem__(key)
2424

2525
class Stat(StatBase):
26-
def __init__(self, path):
27-
super().__init__(os.stat(path))
26+
def __init__(self, path, dirfd=None):
27+
super().__init__(os.stat(path, dir_fd=dirfd))
2828

2929
class Fstat(StatBase):
3030
def __init__(self, fd: int):
3131
super().__init__(os.fstat(fd))
3232

3333
class Lstat(StatBase):
34-
def __init__(self, path):
35-
super().__init__(os.lstat(path))
34+
def __init__(self, path, dirfd=None):
35+
super().__init__(os.lstat(path, dir_fd=dirfd))

qiling/os/posix/syscall/stat.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from qiling import Qiling
1111
from 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
1313
from 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+
10281058
def 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

10391069
def 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

10571082
def 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

10751095
def ql_syscall_fstat64(ql: Qiling, fd, buf_ptr):
@@ -1123,6 +1143,10 @@ def ql_syscall_stat(ql: Qiling, path: int, buf_ptr: int):
11231143
def 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

11271151
def 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

Comments
 (0)