/*---------------------------------------------------------------------------*/ int cfs_read(int fd, void *buf, unsigned size) { struct file_header hdr; struct file_desc *fdp; struct file *file; unsigned bytes_left; int r; #if COFFEE_MICRO_LOGS struct log_param lp; #endif if(!(FD_VALID(fd) && FD_READABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; if(fdp->offset + size > file->end) { size = file->end - fdp->offset; } bytes_left = size; if(FILE_MODIFIED(file)) { read_header(&hdr, file->page); } /* * Fill the buffer by copying from the log in first hand, or the * ordinary file if the page has no log record. */ while(bytes_left) { watchdog_periodic(); r = -1; #if COFFEE_MICRO_LOGS if(FILE_MODIFIED(file)) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; r = read_log_page(&hdr, file->record_count, &lp); } #endif /* COFFEE_MICRO_LOGS */ /* Read from the original file if we cannot find the data in the log. */ if(r < 0) { r = bytes_left; COFFEE_READ(buf, r, absolute_offset(file->page, fdp->offset)); } bytes_left -= r; fdp->offset += r; buf += r; } return size; }
/*---------------------------------------------------------------------------*/ int cfs_read(int fd, void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS struct file_header hdr; struct log_param lp; unsigned bytes_left; int r; #endif if(!(FD_VALID(fd) && FD_READABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; if(fdp->offset + size > file->end) { size = file->end - fdp->offset; } /* If the file is allocated, read directly in the file. */ if(!FILE_MODIFIED(file)) { COFFEE_READ(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; return size; } #if COFFEE_MICRO_LOGS read_header(&hdr, file->page); /* * Fill the buffer by copying from the log in first hand, or the * ordinary file if the page has no log record. */ for(bytes_left = size; bytes_left > 0; bytes_left -= r) { r = -1; lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; r = read_log_page(&hdr, file->record_count, &lp); /* Read from the original file if we cannot find the data in the log. */ if(r < 0) { COFFEE_READ(buf, lp.size, absolute_offset(file->page, fdp->offset)); r = lp.size; } fdp->offset += r; buf = (char *)buf + r; } #endif /* COFFEE_MICRO_LOGS */ return size; }
/*---------------------------------------------------------------------------*/ int cfs_read(int fd, void *buf, unsigned size) { struct file_desc *fdp; struct file *file; #if COFFEE_MICRO_LOGS struct file_header hdr; struct log_param lp; unsigned bytes_left; int r; #endif if(!(FD_VALID(fd) && FD_READABLE(fd))) { return -1; } fdp = &coffee_fd_set[fd]; file = fdp->file; if(fdp->offset + size > file->end) { size = file->end - fdp->offset; } /* If the file is not modified, read directly from the file extent. */ if(!FILE_MODIFIED(file)) { COFFEE_READ(buf, size, absolute_offset(file->page, fdp->offset)); fdp->offset += size; return size; } #if COFFEE_MICRO_LOGS read_header(&hdr, file->page); /* * Copy the contents of the most recent log record. If there is * no log record for the file area to read from, we simply read * from the original file extent. */ for(bytes_left = size; bytes_left > 0; bytes_left -= r) { lp.offset = fdp->offset; lp.buf = buf; lp.size = bytes_left; r = read_log_page(&hdr, file->record_count, &lp); /* Read from the original file if we cannot find the data in the log. */ if(r < 0) { COFFEE_READ(buf, lp.size, absolute_offset(file->page, fdp->offset)); r = lp.size; } fdp->offset += r; buf = (char *)buf + r; } #endif /* COFFEE_MICRO_LOGS */ return size; }
/*---------------------------------------------------------------------------*/ 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; }