/*---------------------------------------------------------------------------*/ cfs_offset_t cfs_seek(int fd, cfs_offset_t offset, int whence) { struct file_desc *fdp; cfs_offset_t new_offset; if(!FD_VALID(fd)) { return -1; } fdp = &coffee_fd_set[fd]; if(whence == CFS_SEEK_SET) { new_offset = offset; } else if(whence == CFS_SEEK_END) { new_offset = fdp->file->end + offset; } else if(whence == CFS_SEEK_CUR) { new_offset = fdp->offset + offset; } else { return (cfs_offset_t)-1; } if(new_offset < 0 || new_offset > fdp->file->max_pages * COFFEE_PAGE_SIZE) { return -1; } if(fdp->file->end < new_offset) { if(FD_WRITABLE(fd)) { fdp->file->end = new_offset; } else { /* Disallow seeking past the end of the file for read only FDs */ return (cfs_offset_t)-1; } } return fdp->offset = new_offset; }
/*---------------------------------------------------------------------------*/ int cfs_write(int fd, const void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS int i; struct log_param lp; cfs_offset_t bytes_left; const char dummy[1] = { 0xff }; #endif if(!(FD_VALID(fd) && FD_WRITABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; /* Attempt to extend the file if we try to write past the end. */ #if COFFEE_IO_SEMANTICS if(!(fdp->io_flags & CFS_COFFEE_IO_FIRM_SIZE)) { #endif while(size + fdp->offset + sizeof(struct file_header) > (file->max_pages * COFFEE_PAGE_SIZE)) { if(merge_log(file->page, 1) < 0) { return -1; } file = fdp->file; PRINTF(("Extended the file at page %u\n", (unsigned)file->page)); } #if COFFEE_IO_SEMANTICS } #endif #if COFFEE_MICRO_LOGS #if COFFEE_IO_SEMANTICS if(!(fdp->io_flags & CFS_COFFEE_IO_FLASH_AWARE) && (FILE_MODIFIED(file) || fdp->offset < file->end)) { #else if(FILE_MODIFIED(file) || fdp->offset < file->end) { #endif for(bytes_left = size; bytes_left > 0;) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; i = write_log_page(file, &lp); if(i < 0) { /* Return -1 if we wrote nothing because the log write failed. */ if(size == bytes_left) { return -1; } break; } else if(i == 0) { /* The file was merged with the log. */ file = fdp->file; } else { /* A log record was written. */ bytes_left -= i; fdp->offset += i; buf = (char *)buf + i; /* Update the file end for a potential log merge that might occur while writing log records. */ if(fdp->offset > file->end) { file->end = fdp->offset; } } } if(fdp->offset > file->end) { /* Update the original file's end with a dummy write. */ COFFEE_WRITE(dummy, 1, absolute_offset(file->page, fdp->offset)); } } else { #endif /* COFFEE_MICRO_LOGS */ #if COFFEE_APPEND_ONLY if(fdp->offset < file->end) { return -1; } #endif /* COFFEE_APPEND_ONLY */ COFFEE_WRITE(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; #if COFFEE_MICRO_LOGS } #endif /* COFFEE_MICRO_LOGS */ if(fdp->offset > file->end) { file->end = fdp->offset; } return size; } /*---------------------------------------------------------------------------*/ int cfs_opendir(struct cfs_dir *dir, const char *name) { /* * Coffee is only guaranteed to support "/" and ".", but it does not * currently enforce this. */ memset(dir->dummy_space, 0, sizeof(coffee_page_t)); return 0; }
/*---------------------------------------------------------------------------*/ int cfs_write(int fd, const void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS int i; struct log_param lp; cfs_offset_t bytes_left; const char dummy[1] = { 0xff }; #endif if(!(FD_VALID(fd) && FD_WRITABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; /* Attempt to extend the file if we try to write past the end. */ while(size + fdp->offset + sizeof(struct file_header) > (file->max_pages * COFFEE_PAGE_SIZE)) { if(merge_log(file->page, 1) < 0) { return -1; } file = fdp->file; PRINTF("Extended the file at page %u\n", (unsigned)file->page); } #if COFFEE_MICRO_LOGS if(FILE_MODIFIED(file) || fdp->offset < file->end) { bytes_left = size; while(bytes_left) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; i = write_log_page(file, &lp); if(i < 0) { /* Return -1 if we wrote nothing because the log write failed. */ if(size == bytes_left) { return -1; } break; } else if(i == 0) { /* The file was merged with the log. */ file = fdp->file; } else { /* A log record was written. */ bytes_left -= i; fdp->offset += i; buf += i; } } if(fdp->offset > file->end) { /* Update the original file's end with a dummy write. */ COFFEE_WRITE(dummy, 1, absolute_offset(file->page, fdp->offset)); } } else { #endif /* COFFEE_MICRO_LOGS */ #if COFFEE_APPEND_ONLY if(fdp->offset < file->end) { return -1; } #endif /* COFFEE_APPEND_ONLY */ COFFEE_WRITE(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; #if COFFEE_MICRO_LOGS } #endif /* COFFEE_MICRO_LOGS */ if(fdp->offset > file->end) { file->end = fdp->offset; } return size; }