mirror of
https://github.com/SmallPond/MIT6.828_OS.git
synced 2026-04-29 21:31:05 +08:00
my solution to lab5
This commit is contained in:
190
lab/lib/file.c
Normal file
190
lab/lib/file.c
Normal file
@@ -0,0 +1,190 @@
|
||||
#include <inc/fs.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
#define debug 0
|
||||
|
||||
union Fsipc fsipcbuf __attribute__((aligned(PGSIZE)));
|
||||
|
||||
// Send an inter-environment request to the file server, and wait for
|
||||
// a reply. The request body should be in fsipcbuf, and parts of the
|
||||
// response may be written back to fsipcbuf.
|
||||
// type: request code, passed as the simple integer IPC value.
|
||||
// dstva: virtual address at which to receive reply page, 0 if none.
|
||||
// Returns result from the file server.
|
||||
static int
|
||||
fsipc(unsigned type, void *dstva)
|
||||
{
|
||||
static envid_t fsenv;
|
||||
if (fsenv == 0)
|
||||
fsenv = ipc_find_env(ENV_TYPE_FS);
|
||||
|
||||
static_assert(sizeof(fsipcbuf) == PGSIZE);
|
||||
|
||||
if (debug)
|
||||
cprintf("[%08x] fsipc %d %08x\n", thisenv->env_id, type, *(uint32_t *)&fsipcbuf);
|
||||
|
||||
ipc_send(fsenv, type, &fsipcbuf, PTE_P | PTE_W | PTE_U);
|
||||
return ipc_recv(NULL, dstva, NULL);
|
||||
}
|
||||
|
||||
static int devfile_flush(struct Fd *fd);
|
||||
static ssize_t devfile_read(struct Fd *fd, void *buf, size_t n);
|
||||
static ssize_t devfile_write(struct Fd *fd, const void *buf, size_t n);
|
||||
static int devfile_stat(struct Fd *fd, struct Stat *stat);
|
||||
static int devfile_trunc(struct Fd *fd, off_t newsize);
|
||||
|
||||
struct Dev devfile =
|
||||
{
|
||||
.dev_id = 'f',
|
||||
.dev_name = "file",
|
||||
.dev_read = devfile_read,
|
||||
.dev_close = devfile_flush,
|
||||
.dev_stat = devfile_stat,
|
||||
.dev_write = devfile_write,
|
||||
.dev_trunc = devfile_trunc
|
||||
};
|
||||
|
||||
// Open a file (or directory).
|
||||
//
|
||||
// Returns:
|
||||
// The file descriptor index on success
|
||||
// -E_BAD_PATH if the path is too long (>= MAXPATHLEN)
|
||||
// < 0 for other errors.
|
||||
int
|
||||
open(const char *path, int mode)
|
||||
{
|
||||
// Find an unused file descriptor page using fd_alloc.
|
||||
// Then send a file-open request to the file server.
|
||||
// Include 'path' and 'omode' in request,
|
||||
// and map the returned file descriptor page
|
||||
// at the appropriate fd address.
|
||||
// FSREQ_OPEN returns 0 on success, < 0 on failure.
|
||||
//
|
||||
// (fd_alloc does not allocate a page, it just returns an
|
||||
// unused fd address. Do you need to allocate a page?)
|
||||
//
|
||||
// Return the file descriptor index.
|
||||
// If any step after fd_alloc fails, use fd_close to free the
|
||||
// file descriptor.
|
||||
|
||||
int r;
|
||||
struct Fd *fd;
|
||||
|
||||
if (strlen(path) >= MAXPATHLEN)
|
||||
return -E_BAD_PATH;
|
||||
|
||||
if ((r = fd_alloc(&fd)) < 0)
|
||||
return r;
|
||||
|
||||
strcpy(fsipcbuf.open.req_path, path);
|
||||
fsipcbuf.open.req_omode = mode;
|
||||
|
||||
if ((r = fsipc(FSREQ_OPEN, fd)) < 0) {
|
||||
fd_close(fd, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
return fd2num(fd);
|
||||
}
|
||||
|
||||
// Flush the file descriptor. After this the fileid is invalid.
|
||||
//
|
||||
// This function is called by fd_close. fd_close will take care of
|
||||
// unmapping the FD page from this environment. Since the server uses
|
||||
// the reference counts on the FD pages to detect which files are
|
||||
// open, unmapping it is enough to free up server-side resources.
|
||||
// Other than that, we just have to make sure our changes are flushed
|
||||
// to disk.
|
||||
static int
|
||||
devfile_flush(struct Fd *fd)
|
||||
{
|
||||
fsipcbuf.flush.req_fileid = fd->fd_file.id;
|
||||
return fsipc(FSREQ_FLUSH, NULL);
|
||||
}
|
||||
|
||||
// Read at most 'n' bytes from 'fd' at the current position into 'buf'.
|
||||
//
|
||||
// Returns:
|
||||
// The number of bytes successfully read.
|
||||
// < 0 on error.
|
||||
static ssize_t
|
||||
devfile_read(struct Fd *fd, void *buf, size_t n)
|
||||
{
|
||||
// Make an FSREQ_READ request to the file system server after
|
||||
// filling fsipcbuf.read with the request arguments. The
|
||||
// bytes read will be written back to fsipcbuf by the file
|
||||
// system server.
|
||||
int r;
|
||||
|
||||
fsipcbuf.read.req_fileid = fd->fd_file.id;
|
||||
fsipcbuf.read.req_n = n;
|
||||
if ((r = fsipc(FSREQ_READ, NULL)) < 0)
|
||||
return r;
|
||||
assert(r <= n);
|
||||
assert(r <= PGSIZE);
|
||||
memmove(buf, fsipcbuf.readRet.ret_buf, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
// Write at most 'n' bytes from 'buf' to 'fd' at the current seek position.
|
||||
//
|
||||
// Returns:
|
||||
// The number of bytes successfully written.
|
||||
// < 0 on error.
|
||||
static ssize_t
|
||||
devfile_write(struct Fd *fd, const void *buf, size_t n)
|
||||
{
|
||||
// Make an FSREQ_WRITE request to the file system server. Be
|
||||
// careful: fsipcbuf.write.req_buf is only so large, but
|
||||
// remember that write is always allowed to write *fewer*
|
||||
// bytes than requested.
|
||||
// LAB 5: Your code here
|
||||
int r;
|
||||
if ( n > sizeof (fsipcbuf.write.req_buf))
|
||||
n = sizeof (fsipcbuf.write.req_buf);
|
||||
|
||||
fsipcbuf.write.req_fileid = fd->fd_file.id;
|
||||
fsipcbuf.write.req_n = n;
|
||||
memmove(fsipcbuf.write.req_buf, buf, n);
|
||||
|
||||
return fsipc(FSREQ_WRITE, NULL);
|
||||
|
||||
// panic("devfile_write not implemented");
|
||||
}
|
||||
|
||||
static int
|
||||
devfile_stat(struct Fd *fd, struct Stat *st)
|
||||
{
|
||||
int r;
|
||||
|
||||
fsipcbuf.stat.req_fileid = fd->fd_file.id;
|
||||
if ((r = fsipc(FSREQ_STAT, NULL)) < 0)
|
||||
return r;
|
||||
strcpy(st->st_name, fsipcbuf.statRet.ret_name);
|
||||
st->st_size = fsipcbuf.statRet.ret_size;
|
||||
st->st_isdir = fsipcbuf.statRet.ret_isdir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Truncate or extend an open file to 'size' bytes
|
||||
static int
|
||||
devfile_trunc(struct Fd *fd, off_t newsize)
|
||||
{
|
||||
fsipcbuf.set_size.req_fileid = fd->fd_file.id;
|
||||
fsipcbuf.set_size.req_size = newsize;
|
||||
return fsipc(FSREQ_SET_SIZE, NULL);
|
||||
}
|
||||
|
||||
|
||||
// Synchronize disk with buffer cache
|
||||
int
|
||||
sync(void)
|
||||
{
|
||||
// Ask the file server to update the disk
|
||||
// by writing any dirty blocks in the buffer cache.
|
||||
|
||||
return fsipc(FSREQ_SYNC, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user