/* * This file implements the Files object, which is the namespace for a task's * files. It stores all the opened files for a task. It also implements many * of the file-based system calls that need to use a file descriptor. */ #include #include #include #include #include #include #include #include #include /* Structure for a Files namespace */ struct Files { Object obj; File *fd[NFILES]; }; static void files_delete(Object *); static void files_copy(Object *, Object *); /* Files object type */ ObjectType filesType = { .name = "FILES", .size = sizeof(Files), .delete = files_delete, .copy = files_copy, }; /* Destroy a Files object */ static void files_delete(Object *obj) { Files *files = (void *) obj; int fd; for (fd = 0; fd < NFILES; fd++) if (files->fd[fd]) put(files->fd[fd]); } /* Copy a Files object */ static void files_copy(Object *a, Object *b) { Files *parent = (void *) a, *child = (void *) b; File *file; int fd; for (fd = 0; fd < NFILES; fd++) { file = parent->fd[fd]; if (!file) continue; child->fd[fd] = get(file); } } /* Get the file described by fd */ File * get_file_by_fd(int fd) { if (fd < 0 || fd >= NFILES) return NULL; return current->files->fd[fd]; } /* Allocate file descriptor */ int allocate_fd(void) { int fd; for (fd = 0; fd < NFILES; fd++) if (!current->files->fd[fd]) break; if (fd == NFILES) fd = -1; return fd; } /* Install a file in a file descriptor */ void install_fd(int fd, File *file) { current->files->fd[fd] = file; } /* Close a file */ int close(int fd) { if (!get_file_by_fd(fd)) return -EBADF; put(current->files->fd[fd]); current->files->fd[fd] = NULL; return 0; } /* Read a file */ int read(int fd, void *buf, size_t count) { if (!verify_access(buf, count, PROT_WRITE)) return -EFAULT; File *file = get_file_by_fd(fd); if (!file) return -EBADF; if (file->inode && S_ISDIR(file->inode->mode)) return -EISDIR; lock(file); int sz = file_read(file, buf, count); unlock(file); return sz; } /* Write a file */ int write(int fd, void *buf, size_t count) { if (!verify_access(buf, count, PROT_READ)) return -EFAULT; File *file = get_file_by_fd(fd); if (!file) return -EBADF; if (file->inode && S_ISDIR(file->inode->mode)) return -EISDIR; lock(file); int sz = file_write(file, buf, count); unlock(file); return sz; } /* Move a file's position */ off_t lseek(int fd, off_t offset, int whence) { File *file = get_file_by_fd(fd); if (!file) return -EBADF; lock(file); switch (whence) { case SEEK_SET: file->pos = offset; break; case SEEK_CUR: file->pos += offset; break; case SEEK_END: file->pos = file->inode->size + offset; break; default: unlock(file); return -EINVAL; } unlock(file); return file->pos; }