Ejemplo n.º 1
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. */
#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;
}