# Interface ```c++ spinlock open_files_lock; file open_files[32]; struct file_descriptor { int fd; file* f; } struct file { enum {F_FILE, F_PIPE, F_KB_C} f_type; unsigned int f_perms; // PERM_READ/PERM_WRITE/PERM_EXEC unsigned int f_offset; v_node* f_vnode; unsigned int f_refcount; } struct v_node { virtual ssize_t read(char* buf, int index, size_t sz); virtual ssize_t write(char* buf, int index, size_t sz); virtual int open(struct inode*); virtual int close(); } int syscall_dup2(regstate* regs); int syscall_close(regstate* regs); ``` We expect `v_node` to be subclassed with specific kinds of `v_nodes`, and different `read()`, `write()`, `open()`, and `close()` methods. # Functionality **Per process file descriptor table:** Every process will have an eight member long array of struct file descriptors. A member will be present if a file is open. The struct `file_descriptor` contains its own index, and a `file*` that corresponds to its open file the system-wide `open_files` array. **System-Wide `open_files` Array:** There will be one system wide file array with 32 members of struct files. A `file` contains 1. an enum corresponding to the type of file 2. an int for permissions, an int for offset, 3. a pointer to a `v_node` 4. a reference count. **Struct `file` Content** 1. File types: There are three types of files, keyboard console, disk file, and pipe. 2. Permissions: A file can have user-level read (`R_PERM`), write (`W_PERM`), and/or executable (`X_PERM`) permissions. 3. Offset: A file has a corresponding offset, utilized in during reading and writing. 4. `v_node*`: Every file descriptor has a corresponding `v_node` pointer. Depending on the file type, it would point to different v_nodes (i.e. keyboard console v_node, pipe v_node, ...). The `v_node` pointer acts as an interface for a file's interaction based function calls (open, read, etc.). 5. Refcount: Corresponding to the number of processes with a file descriptor entry (in the per-process file descriptor array) with a `file*` pointing to this file. When `refcount` becomes 0, we should clear out this `file` **Struct `v_node` Content** Each vnode will have an inode pointer, a lock, and function pointers pointing to the correct implementations dependent upon type of file. These function pointers will be set upon initialization. **`v_node` Functions** {`open(), read(), write(), close()`} When a process calls one of these functions from a `v_node`, a file descriptor (from per process file descriptor array) and corresponding file (from system wide file array) must be valid. Each of these functions have to be separately implemented for each `v_node` subclass. # Synchronization and Blocking - The global `open_files_lock` protects the global `open_files` array that stores the `file` open file descriptor objects. - When processes create new file descriptors that point to `file`s in the `open_files` array, it will grab this lock and increment refcount - When processes close file decriptors, it will grab this lock and decrement refcount; if 0, then free it - `read()` and `write()` should block, all other functions should not block --- 1. each process will have its own fd table of pointers 2. create struct file 1. start off with what is included in powerpoint: 1. perms; offset; vnode; refcount 2. (come back to vnode) 3. create system wide fd table (array type file) with max 32 files (he said thats okay). this is a small size, so free to initially initialize (deal with synchronization later: ideally, would love to allow multiple reads and one write, but start with one write) 1. create subclasses vnode_data_file/data_file 1. functions vfs_write(); _read(); open(); close() 2. create subclasses vnode_pipe_file / pipe_file 1. functions vfs_write(); _read(); open(); close() 3. create class vnode 1. vnode has functions vfs_write(); _read(); open(); close() 2. when kernel calls vfs_EX, it should pass in the index of the system wide table. with that, get file. file's v_node is pointed to struct of that type of file. call that struct's appropriate function.