Orion
Barry Adding pipes e59e4fe (2 years, 4 months ago)/* * This file handles the file operations. Most of the functions here are just * wrapper around the file operations. They generally check if the operation * exists and use it if it does. If it doesn't they may implement a generic * action, or just simply return. They also perform the necessary validation to * ensure the operation can be called on the particular file. */ #include <string.h> #include <errno.h> #include "vfs.h" #include "inode.h" #include "cache.h" #include "../mem/heap.h" #include "../mem/frame.h" #include "../screen.h" /* Get a File */ File * file_get(File *file) { file->usage++; return file; } /* Put a File */ void file_put(File *file) { ASSERT(file->usage); if (--file->usage) return; if (file->ops && file->ops->release) file->ops->release(file); if (file->inode) inode_put(file->inode); if (file->path) destroy_custody_chain(file->path); kfree(file); } /* Read a file */ size_t file_read(File *file, char *buf, size_t size) { size_t count = 0; if (!S_ISREG(file->inode->mode)) { if (!file->ops) return count; if (!file->ops->read) return count; count = file->ops->read(file, buf, size, file->pos); file->pos += count; return count; } if (file->pos > file->inode->size) return count; if (size + file->pos > file->inode->size) size = file->inode->size - file->pos; uint16_t min, offset = file->pos & 0xFFF; Page *page; page_t oldPage; acquire(&file->lock); while (size) { min = (size > 0x1000) ? 0x1000 : size; page = page_find(file->inode, file->pos + (count & ~0xFFF)); if (!page) { if (!file->ops) goto end; if (!file->ops->read) goto end; file->ops->read(file, buf + count, min, file->pos + count); } else { acquire(&quickPageLock); oldPage = quick_page(page->frame); memcpy(buf + count, QUICK_PAGE + offset, min); quick_page(oldPage); release(&quickPageLock); } offset = 0; end: size -= min; count += min; } file->pos += count; release(&file->lock); return count; } /* Write a file */ size_t file_write(File *file, char *buf, size_t size) { size_t count = 0; if (!S_ISREG(file->inode->mode)) { if (!file->ops) return count; if (!file->ops->write) return count; count = file->ops->write(file, buf, size, file->pos); file->pos += count; return count; } if (size + file->pos > file->inode->size) file->inode->size = size + file->pos; uint16_t min, offset = file->pos & 0xFFF; Page *page; page_t oldPage; acquire(&file->lock); while (size) { min = (size > 0x1000) ? 0x1000 : size; page = page_find(file->inode, file->pos + (count & ~0xFFF)); if (!page) { if (!file->ops) goto end; if (!file->ops->write) goto end; file->ops->write(file, buf + count, min, file->pos + count); } else { acquire(&quickPageLock); oldPage = quick_page(page->frame); memcpy(QUICK_PAGE + offset, buf + count, min); quick_page(oldPage); release(&quickPageLock); } offset = 0; end: size -= min; count += min; } file->pos += count; release(&file->lock); return count; } /* I/O Control */ int file_ioctl(File *file, unsigned long request, uintptr_t argp) { if (!file->ops) return -EINVAL; if (!file->ops->ioctl) return -ENOTTY; return file->ops->ioctl(file, request, argp); } /* Read a directory entry (DirEnt) from a directory */ int file_readdir(File *file, DirEnt *dent, off_t index) { if (!file->ops) return -EINVAL; if (!file->ops->readdir) return -EINVAL; return file->ops->readdir(file, dent, index); } /* Open a file */ int file_open(File *file) { if (!file->ops) return -EINVAL; if (!file->ops->open) return -EINVAL; return file->ops->open(file); } /* Map a file into memory */ void file_mmap(File *file, void *addr, size_t len, off_t offset) { if (!file->ops) return; if (file->ops->mmap) return file->ops->mmap(file, addr, len, offset); if (S_ISREG(file->mode)) file->ops->read(file, addr, len, offset); }