int pipe(int pfd[2]) { int r; struct Fd *fd0, *fd1; void *va; // allocate the file descriptor table entries if ((r = fd_find_unused(&fd0)) < 0 || (r = sys_page_alloc(0, fd0, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0) goto err; if ((r = fd_find_unused(&fd1)) < 0 || (r = sys_page_alloc(0, fd1, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0) goto err1; // allocate the pipe structure as first data page in both va = fd2data(fd0); if ((r = sys_page_alloc(0, va, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0) goto err2; if ((r = sys_page_map(0, va, 0, fd2data(fd1), PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0) goto err3; // set up fd structures fd0->fd_dev_id = devpipe.dev_id; fd0->fd_omode = O_RDONLY; fd1->fd_dev_id = devpipe.dev_id; fd1->fd_omode = O_WRONLY; if (debug) cprintf("[%08x] pipecreate %08x\n", thisenv->env_id, vpt[PGNUM(va)]); pfd[0] = fd2num(fd0); pfd[1] = fd2num(fd1); return 0; err3: sys_page_unmap(0, va); err2: sys_page_unmap(0, fd1); err1: sys_page_unmap(0, fd0); err: return r; }
int opencons(void) { int r; struct Fd* fd; if ((r = fd_find_unused(&fd)) < 0) return r; if ((r = sys_page_alloc(0, fd, PTE_P|PTE_U|PTE_W|PTE_SHARE)) < 0) return r; fd->fd_dev_id = devcons.dev_id; fd->fd_omode = O_RDWR; return fd2num(fd); }
// Open a file (or directory). // // Returns: // The file descriptor index on success // -E_BAD_PATH if the path is too long (>= MAXPATHLEN) // -E_BAD_PATH if an intermediate path component is not a directory // -E_MAX_FD if no more file descriptors // -E_NOT_FOUND if the file (or a path component) was not found // (and others) int open(const char *path, int mode) { // Find an unused file descriptor page using fd_find_unused // and allocate a page there (PTE_P|PTE_U|PTE_W|PTE_SHARE). // // LAB 5: Your code here int r; struct Fd *fd; if((r = fd_find_unused(&fd)) < 0 || (r = sys_page_alloc(0, fd, PTE_P|PTE_U|PTE_W|PTE_SHARE)) < 0) goto err1; // Check the pathname. Error if too long. // Use path_walk to find the corresponding directory entry. // If '(mode & O_CREAT) == 0' (Exercise 4), // Return -E_NOT_FOUND if the file is not found. // Otherwise, use inode_open to open the inode. // If '(mode & O_CREAT) != 0' (Exercise 7), // Create the file if it doesn't exist yet. // Allocate a new inode, initialize its fields, and // reference that inode from the new directory entry. // Flush any blocks you change. // Directories can be opened, but only as read-only: // return -E_IS_DIR if '(mode & O_ACCMODE) != O_RDONLY'. // // Check for errors. On error, make sure you clean up any // allocated objects. // // The root directory is a special case -- if you aren't careful, // you will deadlock when the root directory is opened. (Why?) // // LAB 5: Your code here. int i; for(i = 0; i < MAXNAMELEN && path[i]; i++); if(i == MAXNAMELEN) { r = -E_BAD_PATH; goto err2; } struct Inode *dirino; struct Direntry *de; if((r = path_walk(path, &dirino, &de, mode & O_CREAT))) goto err2; struct Inode *fileino; if(!(mode & O_CREAT)) { if(de == &super->s_root) fileino = dirino; else if((r = inode_open(de->de_inum, &fileino)) < 0) goto err3; if(fileino->i_ftype == FTYPE_DIR && ( mode & O_ACCMODE) != O_RDONLY) { r = -E_IS_DIR; goto err4; } } else { if((r = inode_alloc(&fileino)) < 0) goto err3; fileino->i_ftype = FTYPE_REG; fileino->i_refcount = 1; fileino->i_size = 0; memset(&fileino->i_direct, 0, NDIRECT * sizeof (blocknum_t)); de->de_inum = fileino->i_inum; bcache_ipc(fileino, BCREQ_FLUSH); bcache_ipc(dirino, BCREQ_FLUSH); } // If '(mode & O_TRUNC) != 0' and the open mode is not read-only, // set the file's length to 0. Flush any blocks you change. // // LAB 5: Your code here (Exercise 8). if((mode & O_TRUNC)) { inode_set_size(fileino, 0); } // The open has succeeded. // Fill in all parts of the 'fd' appropriately. Use 'devfile.dev_id'. // Copy the file's pathname into 'fd->fd_file.open_path' to improve // error messages later. // You must account for the open file reference in the inode as well. // Clean up any open inodes. // // LAB 5: Your code here (Exercise 4). fd->fd_dev_id = devfile.dev_id; fd->fd_offset = 0; fd->fd_omode = mode; fd->fd_file.inum = fileino->i_inum; strcpy(fd->fd_file.open_path, path); fileino->i_opencount++; inode_close(dirino); inode_close(fileino); return fd2num(fd); err4: inode_close(fileino); err3: inode_close(dirino); err2: sys_page_unmap(thisenv->env_id, fd); err1: return r; }