int fflush(FILE *f) { if (f == NULL) { // flush all open streams for (f = &files->fd[0]; f < &files->fd[OPEN_MAX]; f++) if (filedesc_isopen(f)) fflush(f); return 0; } assert(filedesc_isopen(f)); return fileino_flush(f->ino); }
int dup2(int oldfn, int newfn) { filedesc *oldfd = &files->fd[oldfn]; filedesc *newfd = &files->fd[newfn]; assert(filedesc_isopen(oldfd)); assert(filedesc_isvalid(newfd)); if (filedesc_isopen(newfd)) close(newfn); *newfd = *oldfd; return newfn; }
int feof(FILE *fd) { assert(filedesc_isopen(fd)); fileinode *fi = &files->fi[fd->ino]; return fd->ofs >= fi->size && !(fi->mode & S_IFPART); }
int isatty(int fn) { assert(filedesc_isopen(&files->fd[fn])); return files->fd[fn].ino == FILEINO_CONSIN || files->fd[fn].ino == FILEINO_CONSOUT; }
void filedesc_close(filedesc *fd) { assert(filedesc_isopen(fd)); assert(fileino_isvalid(fd->ino)); fd->ino = FILEINO_NULL; // mark the fd free }
// Find or create and open a file, optionally using a given file descriptor. // The argument 'fd' must point to a currently unused file descriptor, // or may be NULL, in which case this function finds an unused file descriptor. // The 'openflags' determines whether the file is created, truncated, etc. // Returns the opened file descriptor on success, // or returns NULL and sets errno on failure. filedesc * filedesc_open(filedesc *fd, const char *path, int openflags, mode_t mode) { if (!fd && !(fd = filedesc_alloc())) return NULL; assert(fd->ino == FILEINO_NULL); // Determine the complete file mode if it is to be created. mode_t createmode = (openflags & O_CREAT) ? S_IFREG | (mode & 0777) : 0; // Walk the directory tree to find the desired directory entry, // creating an entry if it doesn't exist and O_CREAT is set. int ino = dir_walk(path, createmode); if (ino < 0) return NULL; assert(fileino_exists(ino)); // Refuse to open conflict-marked files; // the user needs to resolve the conflict and clear the conflict flag, // or just delete the conflicted file. if (files->fi[ino].mode & S_IFCONF) { errno = ECONFLICT; return NULL; } // Truncate the file if we were asked to if (openflags & O_TRUNC) { if (!(openflags & O_WRONLY)) { warn("filedesc_open: can't truncate non-writable file"); errno = EINVAL; return NULL; } if (fileino_truncate(ino, 0) < 0) return NULL; } // Initialize the file descriptor fd->ino = ino; fd->flags = openflags; fd->ofs = (openflags & O_APPEND) ? files->fi[ino].size : 0; fd->err = 0; assert(filedesc_isopen(fd)); return fd; }
// Scan an open directory filedesc and return the next entry. // Returns a pointer to the next matching file inode's 'dirent' struct, // or NULL if the directory being scanned contains no more entries. struct dirent *readdir(DIR *dir) { #if SOL >= 4 assert(filedesc_isopen(dir)); int ino; while ((ino = dir->ofs++) < FILE_INODES) { if (!fileino_exists(ino) || files->fi[ino].dino != dir->ino) continue; return &files->fi[ino].de; // Return inode's dirent } return NULL; // End of directory #else // ! SOL >= 4 // Lab 4: insert your directory scanning code here. // Hint: a fileinode's 'dino' field indicates // what directory the file is in; // this function shouldn't return entries from other directories! warn("readdir() not implemented"); return NULL; #endif // ! SOL >= 4 }
// Seek the given file descriptor to a specificied position, // which may be relative to the file start, end, or corrent position, // depending on 'whence' (SEEK_SET, SEEK_CUR, or SEEK_END). // Returns the resulting absolute file position, // or returns -1 and sets errno appropriately on error. off_t filedesc_seek(filedesc *fd, off_t offset, int whence) { assert(filedesc_isopen(fd)); assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END); fileinode *fi = &files->fi[fd->ino]; #if SOL >= 4 off_t newofs = offset; if (whence == SEEK_CUR) newofs += fd->ofs; else if (whence == SEEK_END) newofs += fi->size; assert(newofs >= 0); fd->ofs = newofs; return newofs; #else // ! SOL >= 4 // Lab 4: insert your file descriptor seek implementation here. warn("filedesc_seek() not implemented"); errno = EINVAL; return -1; #endif // ! SOL >= 4 }
FILE * freopen(const char *path, const char *mode, FILE *fd) { assert(filedesc_isvalid(fd)); if (filedesc_isopen(fd)) fclose(fd); // Parse the open mode string int flags; switch (*mode++) { case 'r': flags = O_RDONLY; break; case 'w': flags = O_WRONLY | O_CREAT | O_TRUNC; break; case 'a': flags = O_WRONLY | O_CREAT | O_APPEND; break; default: panic("freopen: unknown file mode '%c'\n", *--mode); } if (*mode == 'b') // binary flag - compatibility only mode++; if (*mode == '+') flags |= O_RDWR; if (filedesc_open(fd, path, flags, 0666) != fd) return NULL; return fd; }
int fileno(FILE *fd) { assert(filedesc_isopen(fd)); return fd - files->fd; }
void clearerr(FILE *fd) { assert(filedesc_isopen(fd)); fd->err = 0; }
int ferror(FILE *fd) { assert(filedesc_isopen(fd)); return fd->err; }
long ftell(FILE *fd) { assert(filedesc_isopen(fd)); return fd->ofs; }
int fsync(int fn) { assert(filedesc_isopen(&files->fd[fn])); return fileino_flush(files->fd[fn].ino); }
int fstat(int fn, struct stat *statbuf) { assert(filedesc_isopen(&files->fd[fn])); return fileino_stat(files->fd[fn].ino, statbuf); }
int ftruncate(int fn, off_t newlength) { assert(filedesc_isopen(&files->fd[fn])); return fileino_truncate(files->fd[fn].ino, newlength); }