Skip to content

Commit

Permalink
Merge pull request ish-app#613 from saagarjha/pread
Browse files Browse the repository at this point in the history
Fix pread/pwrite; make read/write be optional
  • Loading branch information
tbodt authored Mar 9, 2020
2 parents a805534 + b2dc56f commit 29dea39
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 42 deletions.
2 changes: 2 additions & 0 deletions fs/fd.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ struct fd_ops {
// TODO make optional for non-files
ssize_t (*read)(struct fd *fd, void *buf, size_t bufsize);
ssize_t (*write)(struct fd *fd, const void *buf, size_t bufsize);
ssize_t (*pread)(struct fd *fd, void *buf, size_t bufsize, off_t off);
ssize_t (*pwrite)(struct fd *fd, const void *buf, size_t bufsize, off_t off);
off_t_ (*lseek)(struct fd *fd, off_t_ off, int whence);

// Reads a directory entry from the stream
Expand Down
43 changes: 21 additions & 22 deletions fs/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static int proc_getpath(struct fd *fd, char *buf) {
}

static int proc_stat(struct mount *UNUSED(mount), const char *path, struct statbuf *stat) {
struct proc_entry entry;
struct proc_entry entry = {};
int err = proc_lookup(path, &entry);
if (err < 0)
return err;
Expand Down Expand Up @@ -99,26 +99,6 @@ static int proc_refresh_data(struct fd *fd) {
return 0;
}

static ssize_t proc_read(struct fd *fd, void *buf, size_t bufsize) {
int err = proc_refresh_data(fd);
if (err < 0)
return err;

const char *data = fd->proc.data.data;
assert(data != NULL);

size_t remaining = fd->proc.data.size - fd->offset;
if ((size_t) fd->offset > fd->proc.data.size)
remaining = 0;
size_t n = bufsize;
if (n > remaining)
n = remaining;

memcpy(buf, data + fd->offset, n);
fd->offset += n;
return n;
}

static off_t_ proc_seek(struct fd *fd, off_t_ off, int whence) {
int err = proc_refresh_data(fd);
if (err < 0)
Expand All @@ -141,6 +121,25 @@ static off_t_ proc_seek(struct fd *fd, off_t_ off, int whence) {
return fd->offset;
}

static ssize_t proc_pread(struct fd *fd, void *buf, size_t bufsize, off_t off) {
int err = proc_refresh_data(fd);
if (err < 0)
return err;

const char *data = fd->proc.data.data;
assert(data != NULL);

size_t remaining = fd->proc.data.size - off;
if ((size_t) off > fd->proc.data.size)
remaining = 0;
size_t n = bufsize;
if (n > remaining)
n = remaining;

memcpy(buf, data + off, n);
return n;
}

static int proc_readdir(struct fd *fd, struct dir_entry *entry) {
struct proc_entry proc_entry;
bool any_left = proc_dir_read(&fd->proc.entry, &fd->offset, &proc_entry);
Expand All @@ -158,7 +157,7 @@ static int proc_close(struct fd *fd) {
}

const struct fd_ops procfs_fdops = {
.read = proc_read,
.pread = proc_pread,
.lseek = proc_seek,
.readdir = proc_readdir,
.close = proc_close,
Expand Down
16 changes: 16 additions & 0 deletions fs/real.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,20 @@ ssize_t realfs_write(struct fd *fd, const void *buf, size_t bufsize) {
return res;
}

ssize_t realfs_pread(struct fd *fd, void *buf, size_t bufsize, off_t off) {
ssize_t res = pread(fd->real_fd, buf, bufsize, off);
if (res < 0)
return errno_map();
return res;
}

ssize_t realfs_pwrite(struct fd *fd, const void *buf, size_t bufsize, off_t off) {
ssize_t res = pwrite(fd->real_fd, buf, bufsize, off);
if (res < 0)
return errno_map();
return res;
}

static void realfs_opendir(struct fd *fd) {
if (fd->dir == NULL) {
int dirfd = dup(fd->real_fd);
Expand Down Expand Up @@ -492,6 +506,8 @@ const struct fs_ops realfs = {
const struct fd_ops realfs_fdops = {
.read = realfs_read,
.write = realfs_write,
.pread = realfs_pread,
.pwrite = realfs_pwrite,
.readdir = realfs_readdir,
.telldir = realfs_telldir,
.seekdir = realfs_seekdir,
Expand Down
2 changes: 1 addition & 1 deletion fs/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ ssize_t tty_input(struct tty *tty, const char *input, size_t size, bool blocking
unlock(&tty->lock);

if (fg_group != 0) {
for (int sig = 1; sig <= NUM_SIGS; sig++) {
for (int sig = 1; sig < NUM_SIGS; sig++) {
if (sigset_has(queue, sig))
send_group_signal(fg_group, sig, SIGINFO_NIL);
}
Expand Down
75 changes: 58 additions & 17 deletions kernel/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,25 @@ dword_t sys_read(fd_t fd_no, addr_t buf_addr, dword_t size) {
return _ENOMEM;
int_t res = 0;
struct fd *fd = f_get(fd_no);
if (fd == NULL || fd->ops->read == NULL) {
if (fd == NULL) {
res = _EBADF;
goto out;
}
if (S_ISDIR(fd->type)) {
res = _EISDIR;
goto out;
}
res = fd->ops->read(fd, buf, size);
if (fd->ops->read) {
res = fd->ops->read(fd, buf, size);
} else if (fd->ops->pread) {
res = fd->ops->pread(fd, buf, size, fd->offset);
if (res > 0) {
fd->ops->lseek(fd, res, LSEEK_CUR);
}
} else {
res = _EBADF;
goto out;
}
if (res >= 0) {
buf[res] = '\0';
STRACE(" \"%.99s\"", buf);
Expand Down Expand Up @@ -276,11 +286,16 @@ dword_t sys_write(fd_t fd_no, addr_t buf_addr, dword_t size) {
buf[size] = '\0';
STRACE("write(%d, \"%.100s\", %d)", fd_no, buf, size);
struct fd *fd = f_get(fd_no);
if (fd == NULL || fd->ops->write == NULL) {
if (fd && fd->ops->write) {
res = fd->ops->write(fd, buf, size);
} else if (fd && fd->ops->pwrite) {
res = fd->ops->pwrite(fd, buf, size, fd->offset);
if (res > 0) {
fd->ops->lseek(fd, res, LSEEK_CUR);
}
} else {
res = _EBADF;
goto out;
}
res = fd->ops->write(fd, buf, size);
out:
free(buf);
return res;
Expand Down Expand Up @@ -320,7 +335,7 @@ dword_t sys__llseek(fd_t f, dword_t off_high, dword_t off_low, addr_t res_addr,
if (!fd->ops->lseek)
return _ESPIPE;
lock(&fd->lock);
off_t_ off = ((off_t_) off_high << 32) | off_low;
off_t_ off = ((qword_t) off_high << 32) | off_low;
STRACE("llseek(%d, %lu, %#x, %d)", f, off, res_addr, whence);
off_t_ res = fd->ops->lseek(fd, off, whence);
STRACE(" -> %lu", res);
Expand Down Expand Up @@ -355,11 +370,25 @@ dword_t sys_pread(fd_t f, addr_t buf_addr, dword_t size, off_t_ off) {
if (buf == NULL)
return _ENOMEM;
lock(&fd->lock);
int_t res = fd->ops->lseek(fd, off, LSEEK_SET);
if (res < 0)
goto out;
res = fd->ops->read(fd, buf, size);
ssize_t res;
if (fd->ops->pread) {
res = fd->ops->pread(fd, buf, size, off);
} else {
off_t_ saved_off = fd->ops->lseek(fd, 0, LSEEK_CUR);
if ((res = fd->ops->lseek(fd, off, LSEEK_SET)) < 0) {
goto out;
}
res = fd->ops->read(fd, buf, size);
// This really shouldn't fail. The lseek man page lists these reasons:
// EBADF, ESPIPE: can't happen because the last lseek wouldn't have succeeded.
// EOVERFLOW: can't happen for LSEEK_SET.
// EINVAL: can't happen other than typoing LSEEK_SET, because we know saved_off is not negative.
off_t_ lseek_res = fd->ops->lseek(fd, saved_off, LSEEK_SET);
assert(lseek_res >= 0);
}
if (res >= 0) {
buf[res] = '\0';
STRACE(" \"%.99s\"", buf);
if (user_write(buf_addr, buf, res))
res = _EFAULT;
}
Expand All @@ -380,9 +409,21 @@ dword_t sys_pwrite(fd_t f, addr_t buf_addr, dword_t size, off_t_ off) {
if (user_read(buf_addr, buf, size))
return _EFAULT;
lock(&fd->lock);
int_t res = fd->ops->lseek(fd, off, LSEEK_SET);
if (res >= 0)
res = fd->ops->write(fd, buf, size);
ssize_t res;
if (fd->ops->pwrite) {
res = fd->ops->pwrite(fd, buf, size, off);
} else {
off_t_ saved_off = fd->ops->lseek(fd, 0, LSEEK_CUR);
if ((res = fd->ops->lseek(fd, off, LSEEK_SET)) >= 0) {
res = fd->ops->write(fd, buf, size);
// This really shouldn't fail. The lseek man page lists these reasons:
// EBADF, ESPIPE: can't happen because the last lseek wouldn't have succeeded.
// EOVERFLOW: can't happen for LSEEK_SET.
// EINVAL: can't happen other than typoing LSEEK_SET, because we know saved_off is not negative.
off_t_ lseek_res = fd->ops->lseek(fd, saved_off, LSEEK_SET);
assert(lseek_res >= 0);
}
}
unlock(&fd->lock);
free(buf);
return res;
Expand Down Expand Up @@ -793,24 +834,24 @@ dword_t sys_lchown(addr_t path_addr, uid_t_ owner, uid_t_ group) {
}

dword_t sys_truncate64(addr_t path_addr, dword_t size_low, dword_t size_high) {
off_t_ size = ((off_t_) size_high << 32) | size_low;
off_t_ size = ((qword_t) size_high << 32) | size_low;
char path[MAX_PATH];
if (user_read_string(path_addr, path, sizeof(path)))
return _EFAULT;
return generic_setattrat(NULL, path, make_attr(size, size), true);
}

dword_t sys_ftruncate64(fd_t f, dword_t size_low, dword_t size_high) {
off_t_ size = ((off_t_) size_high << 32) | size_low;
off_t_ size = ((qword_t) size_high << 32) | size_low;
struct fd *fd = f_get(f);
if (fd == NULL)
return _EBADF;
return generic_fsetattr(fd, make_attr(size, size));
}

dword_t sys_fallocate(fd_t f, dword_t UNUSED(mode), dword_t offset_low, dword_t offset_high, dword_t len_low, dword_t len_high) {
off_t_ offset = ((off_t_) offset_high << 32) | offset_low;
off_t_ len = ((off_t_) len_high << 32) | len_low;
off_t_ offset = ((qword_t) offset_high << 32) | offset_low;
off_t_ len = ((qword_t) len_high << 32) | len_low;
struct fd *fd = f_get(f);
if (fd == NULL)
return _EBADF;
Expand Down
2 changes: 1 addition & 1 deletion kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ int_t sys_get_robust_list(pid_t_ pid, addr_t robust_list_ptr, addr_t len_ptr) {

lock(&pids_lock);
struct task *task = pid_get_task(pid);
unlock(&pids_lock);
if (task != current)
return _EPERM;
unlock(&pids_lock);

if (user_put(robust_list_ptr, current->robust_list))
return _EFAULT;
Expand Down
2 changes: 1 addition & 1 deletion kernel/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ dword_t sys_rt_sigprocmask(dword_t how, addr_t set, addr_t oldset, dword_t size)
int_t sys_rt_sigpending(addr_t set_addr);

static inline sigset_t_ sig_mask(int sig) {
assert(sig >= 1 && sig <= NUM_SIGS);
assert(sig >= 1 && sig < NUM_SIGS);
return 1l << (sig - 1);
}

Expand Down

0 comments on commit 29dea39

Please sign in to comment.