void fs_test(void) { struct File *f; int r; char *blk; uint32_t *bits; // back up bitmap if ((r = sys_page_alloc(0, (void*) PGSIZE, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc: %e", r); bits = (uint32_t*) PGSIZE; memmove(bits, bitmap, PGSIZE); // allocate block if ((r = alloc_block()) < 0) panic("alloc_block: %e", r); // check that block was free assert(bits[r/32] & (1 << (r%32))); // and is not free any more assert(!(bitmap[r/32] & (1 << (r%32)))); cprintf("alloc_block is good\n"); if ((r = file_open("/not-found", &f)) < 0 && r != -E_NOT_FOUND) panic("file_open /not-found: %e", r); else if (r == 0) panic("file_open /not-found succeeded!"); if ((r = file_open("/newmotd", &f)) < 0) panic("file_open /newmotd: %e", r); cprintf("file_open is good\n"); if ((r = file_get_block(f, 0, &blk)) < 0) panic("file_get_block: %e", r); if (strcmp(blk, msg) != 0) panic("file_get_block returned wrong data"); cprintf("file_get_block is good\n"); *(volatile char*)blk = *(volatile char*)blk; assert((vpt[PPN(blk)] & PTE_D)); file_flush(f); assert(!(vpt[PPN(blk)] & PTE_D)); cprintf("file_flush is good\n"); if ((r = file_set_size(f, 0)) < 0) panic("file_set_size: %e", r); assert(f->f_direct[0] == 0); assert(!(vpt[PPN(f)] & PTE_D)); cprintf("file_truncate is good\n"); if ((r = file_set_size(f, strlen(msg))) < 0) panic("file_set_size 2: %e", r); assert(!(vpt[PPN(f)] & PTE_D)); if ((r = file_get_block(f, 0, &blk)) < 0) panic("file_get_block 2: %e", r); strcpy(blk, msg); assert((vpt[PPN(blk)] & PTE_D)); file_flush(f); assert(!(vpt[PPN(blk)] & PTE_D)); assert(!(vpt[PPN(f)] & PTE_D)); cprintf("file rewrite is good\n"); }
void serve_set_size(u_int envid, struct Fsreq_set_size *rq) { if (debug) { writef("serve_set_size %08x %08x %08x\n", envid, rq->req_fileid, rq->req_size); } struct Open *pOpen; int r; // Your code here if ((r = open_lookup(envid, rq->req_fileid, &pOpen)) < 0) { ipc_send(envid, r, 0, 0); return; } if ((r = file_set_size(pOpen->o_file, rq->req_size)) < 0) { ipc_send(envid, r, 0, 0); return; } ipc_send(envid, 0, 0, 0);//PTE_V); return; // user_panic("serve_set_size not implemented"); }
void serve_set_size(envid_t envid, struct Fsreq_set_size *rq) { struct OpenFile *o; int r; if (debug) cprintf("serve_set_size %08x %08x %08x\n", envid, rq->req_fileid, rq->req_size); // The file system server maintains three structures // for each open file. // // 1. The on-disk 'struct File' is mapped into the part of memory // that maps the disk. This memory is kept private to the // file server. // 2. Each open file has a 'struct Fd' as well, // which sort of corresponds to a Unix file descriptor. // This 'struct Fd' is kept on *its own page* in memory, // and it is shared with any environments that // have the file open. // Part of the 'struct Fd' is a *copy* of the on-disk // 'struct File' (struct Fd::fd_file.file), except that the // block pointers are effectively garbage. // This lets environments find out a file's size by examining // struct Fd::fd_file.file.f_size, for example. // *The server must make sure to keep two copies of the // 'struct File' in sync!* // 3. 'struct OpenFile' links these other two structures, // and is kept private to the file server. // The server maintains an array of all open files, indexed // by "file ID". // (There can be at most MAXFILE files open concurrently.) // The client uses file IDs to communicate with the server. // File IDs are a lot like environment IDs in the kernel. // Use openfile_lookup to translate file IDs to struct OpenFile. // Every file system IPC call has the same general structure. // Here's how it goes. // First, use openfile_lookup to find the relevant open file. // On failure, return the error code to the client with ipc_send. if ((r = openfile_lookup(envid, rq->req_fileid, &o)) < 0) goto out; // Second, call the relevant file system function (from fs/fs.c). // On failure, return the error code to the client. if ((r = file_set_size(o->o_file, rq->req_size)) < 0) goto out; // Third, update the 'struct Fd' copy of the 'struct File' // as appropriate. o->o_fd->fd_file.file.f_size = rq->req_size; // Finally, return to the client! // (We just return r since we know it's 0 at this point.) out: ipc_send(envid, r, 0, 0); }
void serve_set_size(u_int envid, struct Fsreq_set_size *rq) { struct Open *o; int r = 0; if (debug) printf("serve_set_size %08x %08x %08x\n", envid, rq->req_fileid, rq->req_size); if((r = open_lookup(envid, rq->req_fileid, &o)) < 0) goto out_set_size; r = file_set_size(&o->o_ff->f_file, rq->req_size); if(r == 0) o->o_file->f_size = rq->req_size; out_set_size: ipc_send(envid, r, 0, 0); // Your code here // panic("serve_set_size not implemented"); }
// Set the size of req->req_fileid to req->req_size bytes, truncating // or extending the file as necessary. int serve_set_size(envid_t envid, struct Fsreq_set_size *req) { struct OpenFile *o; int r; if (debug) cprintf("serve_set_size %08x %08x %08x\n", envid, req->req_fileid, req->req_size); // Every file system IPC call has the same general structure. // Here's how it goes. // First, use openfile_lookup to find the relevant open file. // On failure, return the error code to the client with ipc_send. if ((r = openfile_lookup(envid, req->req_fileid, &o)) < 0) return r; // Second, call the relevant file system function (from fs/fs.c). // On failure, return the error code to the client. return file_set_size(o->o_file, req->req_size); }
// Write count bytes from buf into f, starting at seek position // offset. This is meant to mimic the standard pwrite function. // Extends the file if necessary. // Returns the number of bytes written, < 0 on error. int file_write(struct File *f, const void *buf, size_t count, off_t offset) { int r, bn; off_t pos; char *blk; // Extend file if necessary if (offset + count > f->f_size) if ((r = file_set_size(f, offset + count)) < 0) return r; for (pos = offset; pos < offset + count; ) { if ((r = file_get_block(f, pos / BLKSIZE, &blk)) < 0) return r; bn = MIN(BLKSIZE - pos % BLKSIZE, offset + count - pos); memmove(blk + pos % BLKSIZE, buf, bn); pos += bn; buf += bn; } return count; }
// Open req->req_path in mode req->req_omode, storing the Fd page and // permissions to return to the calling environment in *pg_store and // *perm_store respectively. int serve_open(envid_t envid, struct Fsreq_open *req, void **pg_store, int *perm_store) { char path[MAXPATHLEN]; struct File *f; int fileid; int r; struct OpenFile *o; if (debug) cprintf("serve_open %08x %s 0x%x\n", envid, req->req_path, req->req_omode); // Copy in the path, making sure it's null-terminated memmove(path, req->req_path, MAXPATHLEN); path[MAXPATHLEN-1] = 0; // Find an open file ID if ((r = openfile_alloc(&o)) < 0) { if (debug) cprintf("openfile_alloc failed: %e", r); return r; } fileid = r; // Open the file if (req->req_omode & O_CREAT) { if ((r = file_create(path, &f)) < 0) { if (!(req->req_omode & O_EXCL) && r == -E_FILE_EXISTS) goto try_open; if (debug) cprintf("file_create failed: %e", r); return r; } } else { try_open: if ((r = file_open(path, &f)) < 0) { if (debug) cprintf("file_open failed: %e", r); return r; } } // Truncate if (req->req_omode & O_TRUNC) { if ((r = file_set_size(f, 0)) < 0) { if (debug) cprintf("file_set_size failed: %e", r); return r; } } // Save the file pointer o->o_file = f; // Fill out the Fd structure o->o_fd->fd_file.id = o->o_fileid; o->o_fd->fd_omode = req->req_omode & O_ACCMODE; o->o_fd->fd_dev_id = devfile.dev_id; o->o_mode = req->req_omode; if (debug) cprintf("sending success, page %08x\n", (uintptr_t) o->o_fd); // Share the FD page with the caller *pg_store = o->o_fd; *perm_store = PTE_P|PTE_U|PTE_W; return 0; }