Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle AT_EMPTY_PATH for fstatat64 #1812

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fs/mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ dword_t sys_mount(addr_t source_addr, addr_t point_addr, addr_t type_addr, dword
return _EINVAL;

struct statbuf stat;
int err = generic_statat(AT_PWD, point_raw, &stat, true);
int err = generic_statat(AT_PWD, point_raw, &stat, 0);
if (err < 0)
return err;
if (!S_ISDIR(stat.mode))
Expand Down
41 changes: 31 additions & 10 deletions fs/stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,31 @@ struct newstat64 stat_convert_newstat64(struct statbuf stat) {
return newstat;
}

int generic_statat(struct fd *at, const char *path_raw, struct statbuf *stat, bool follow_links) {
int generic_statat(struct fd *at, const char *path_raw, struct statbuf *stat, int flags) {
int err;

bool empty_path = flags & AT_EMPTY_PATH_;
bool follow_links = !(flags & AT_SYMLINK_NOFOLLOW_);

char path[MAX_PATH];
int err = path_normalize(at, path_raw, path, follow_links ? N_SYMLINK_FOLLOW : N_SYMLINK_NOFOLLOW);
if (err < 0)
return err;
if (empty_path && (strcmp(path_raw, "") == 0)) {
if (at == AT_PWD) {
at = current->fs->pwd;
}

err = generic_getpath(at, path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this should be calling fstat instead

if (err < 0)
return err;

if (!path_is_normalized(path)) {
return _ENOENT;
}
} else {
err = path_normalize(at, path_raw, path, follow_links ? N_SYMLINK_FOLLOW : N_SYMLINK_NOFOLLOW);
if (err < 0)
return err;
}

struct mount *mount = find_mount_and_trim_path(path);
memset(stat, 0, sizeof(*stat));
err = mount->fs->stat(mount, path, stat);
Expand All @@ -49,17 +69,18 @@ static struct fd *at_fd(fd_t f) {
return f_get(f);
}

static dword_t sys_stat_path(fd_t at_f, addr_t path_addr, addr_t statbuf_addr, bool follow_links) {
// The `flags` parameter accepts AT_ flags
static dword_t sys_stat_path(fd_t at_f, addr_t path_addr, addr_t statbuf_addr, int flags) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function now has the exact signature of sys_fstatat64 so maybe rename to sys_fstatat64

int err;
char path[MAX_PATH];
if (user_read_string(path_addr, path, sizeof(path)))
return _EFAULT;
STRACE("stat(at=%d, path=\"%s\", statbuf=0x%x, follow_links=%d)", at_f, path, statbuf_addr, follow_links);
STRACE("stat(at=%d, path=\"%s\", statbuf=0x%x, flags=0x%x)", at_f, path, statbuf_addr, flags);
struct fd *at = at_fd(at_f);
if (at == NULL)
return _EBADF;
struct statbuf stat = {};
if ((err = generic_statat(at, path, &stat, follow_links)) < 0)
if ((err = generic_statat(at, path, &stat, flags)) < 0)
return err;
struct newstat64 newstat = stat_convert_newstat64(stat);
if (user_put(statbuf_addr, newstat))
Expand All @@ -68,15 +89,15 @@ static dword_t sys_stat_path(fd_t at_f, addr_t path_addr, addr_t statbuf_addr, b
}

dword_t sys_stat64(addr_t path_addr, addr_t statbuf_addr) {
return sys_stat_path(AT_FDCWD_, path_addr, statbuf_addr, true);
return sys_stat_path(AT_FDCWD_, path_addr, statbuf_addr, 0);
}

dword_t sys_lstat64(addr_t path_addr, addr_t statbuf_addr) {
return sys_stat_path(AT_FDCWD_, path_addr, statbuf_addr, false);
return sys_stat_path(AT_FDCWD_, path_addr, statbuf_addr, AT_SYMLINK_NOFOLLOW_);
}

dword_t sys_fstatat64(fd_t at, addr_t path_addr, addr_t statbuf_addr, dword_t flags) {
return sys_stat_path(at, path_addr, statbuf_addr, !(flags & AT_SYMLINK_NOFOLLOW_));
return sys_stat_path(at, path_addr, statbuf_addr, flags);
}

dword_t sys_fstat64(fd_t fd_no, addr_t statbuf_addr) {
Expand Down
2 changes: 1 addition & 1 deletion kernel/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ dword_t sys_getcwd(addr_t buf_addr, dword_t size) {

static struct fd *open_dir(const char *path) {
struct statbuf stat;
int err = generic_statat(AT_PWD, path, &stat, true);
int err = generic_statat(AT_PWD, path, &stat, 0);
if (err < 0)
return ERR_PTR(err);
if (!(stat.mode & S_IFDIR))
Expand Down
3 changes: 2 additions & 1 deletion kernel/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct attr {
#define make_attr(_type, thing) \
((struct attr) {.type = attr_##_type, ._type = thing})

#define AT_EMPTY_PATH_ 0x1000
#define AT_SYMLINK_NOFOLLOW_ 0x100

struct fd *generic_open(const char *path, int flags, int mode);
Expand All @@ -61,7 +62,7 @@ int generic_seek(struct fd *fd, off_t_ off, int whence, size_t size);
#define AC_X 1
#define AC_F 0
int generic_accessat(struct fd *dirfd, const char *path, int mode);
int generic_statat(struct fd *at, const char *path, struct statbuf *stat, bool follow_links);
int generic_statat(struct fd *at, const char *path, struct statbuf *stat, int flags);
int generic_setattrat(struct fd *at, const char *path, struct attr attr, bool follow_links);
int generic_utime(struct fd *at, const char *path, struct timespec atime, struct timespec mtime, bool follow_links);
ssize_t generic_readlinkat(struct fd *at, const char *path, char *buf, size_t bufsize);
Expand Down