Assume you've read my previous post on file operations in OS161, then everything is quite straightforward. One more thing, remember to protect every access to the file descriptor data structure using lock!
Let's get started.
We'll rely on
vfs_open to do most of the work. But before that, we need to
filenamea valid pointer? (alignment, NULL, kernel pointer, etc.)
Is flags valid? flags can only contain exactly one of
After these, we need to allocate a fd to the opened file: just scan the
curthread->t_fdtable and find a available slot (
NULL). Then we need to
actually open the file using
vfs_open. Note that we need to copy
into kernel buffer using
copyinstr, for both security reasons, and that
vfs_open may destroy the pathname passed in.
vfs_open successfully returns, we can initialize a
struct fdesc. Pay
special attention to
O_APPEND, it should be zero.
O_APPEND, it should be file size. So we need to check it and use
VOP_STAT to get file size if necessary.
sys_close is quite easy. We first decrease the file reference counter. And
close the file using
vfs_close and free the
struct fdesc if the counter
As usual, before do anything, first check the parameters.
The main work here is using
VOP_WRITE together with
kern/syscall/loadelf.c is a good start point.
However, we need to initialize the
uio for read/write for user space
buffers. That means the
uio->uio_segflg should be
uio->uio_resid is how many bytes left after the IO operation. So you
can calculate how many bytes are actually read/written by
len - uio->uio_resid.
Since we've carefully handled std files when initialization. Here we just treat them as normal files and pay no special attention to them.
The hardest thing here is not how to write
sys_dup2, but instead how
is supposed to be used. Here is a typical code snippet of how to use
int logfd = open("logfile", O_WRONLY); /* note the sequence of parameter */ dup2(logfd, STDOUT_FILENO); close(logfd); /* now all print content will go to log file */ printf("Hello, OS161.\n");
We can see that in
newfdpoints to the same file. But we can call
closeon any of them and do not influence the other.
dup2, all read/write to
newfdwill be actually performed on
oldfd. (Of course, they points to the same file!!)
newfdis previous opened, it should be closed in
dup2( according to
Once we're clear about these. Coding
sys_dup2 is a piece of cake. Just don't
forget to maintain the
Nothing to say. Use
Only one thing, if
SEEK_END is used. use
VOP_STAT to get the file size, as
we did in
64-bit parameter and return value in lseek
This is just a minor trick. Let's first see the definition of
off_t lseek (int fd, off_t pos, int whence)
$OS161_SRC/kern/include/types.h, we can see that
off_t is type-defined as
64-bit integer (
i64). So the question here is: how to pass 64-bit parameter
sys_lseek and how get the 64-bit return value of it.
Pass 64-bit argument to sys_lseek
From the comment in
$OS161_SRC/kern/arch/mips/syscall/syscall.c, we can see that,
should be in
pos should be in (
$a2 stores high 32-bit and
$a3 stores low 32-bit), and
whence should be in
$a1 is not
used due to alignment.
So in the switch branch of
sys_lseek, we should first pack (
$a2:$a3) into a 64-bit
sys_pos. Then we use
copyin to copy
whence from user stack (
Get 64-bit return value of
Also from the comment, we know that a 64-bit return value is stored in
$v0 stores high 32-bit and
$v1 stores low 32-bit). And note that
retval will be assigned to $v0, so here we just
need to copy the low 32-bit of
sys_lseek's return value to $v1, and high