/* This file contains file writing system call handlers. * * The entry points into this file are: * do_write perform the WRITE file system call * do_trunc perform the TRUNC file system call * * Created: * April 2009 (D.C. van Moolenbroek) */ #include "inc.h" /*===========================================================================* * write_file * *===========================================================================*/ static ssize_t write_file(struct inode *ino, off_t pos, size_t count, struct fsdriver_data *data) { /* Write data or zeroes to a file, depending on whether a valid pointer to * a data grant was provided. */ size_t size, off, chunk; char *ptr; int r; if (pos < 0) return EINVAL; assert(!IS_DIR(ino)); if ((r = get_handle(ino)) != OK) return r; assert(count > 0); /* Use the buffer from below to eliminate extra copying. */ size = sffs_table->t_writebuf(&ptr); off = 0; while (count > 0) { chunk = MIN(count, size); if (data != NULL) { if ((r = fsdriver_copyin(data, off, ptr, chunk)) != OK) break; } else { /* Do this every time. We don't know what happens below. */ memset(ptr, 0, chunk); } if ((r = sffs_table->t_write(ino->i_file, ptr, chunk, pos)) <= 0) break; count -= r; off += r; pos += r; } if (r < 0) return r; return off; } /*===========================================================================* * do_write * *===========================================================================*/ ssize_t do_write(ino_t ino_nr, struct fsdriver_data *data, size_t count, off_t pos, int call) { /* Write data to a file. */ struct inode *ino; if (read_only) return EROFS; if ((ino = find_inode(ino_nr)) == NULL) return EINVAL; if (IS_DIR(ino)) return EISDIR; if (count == 0) return 0; return write_file(ino, pos, count, data); } /*===========================================================================* * do_trunc * *===========================================================================*/ int do_trunc(ino_t ino_nr, off_t start, off_t end) { /* Change file size or create file holes. */ char path[PATH_MAX]; struct inode *ino; struct sffs_attr attr; uint64_t delta; ssize_t r; if (read_only) return EROFS; if ((ino = find_inode(ino_nr)) == NULL) return EINVAL; if (IS_DIR(ino)) return EISDIR; if (end == 0) { /* Truncate or expand the file. */ if ((r = verify_inode(ino, path, NULL)) != OK) return r; attr.a_mask = SFFS_ATTR_SIZE; attr.a_size = start; r = sffs_table->t_setattr(path, &attr); } else { /* Write zeroes to the file. We can't create holes. */ if (end <= start) return EINVAL; delta = (uint64_t)end - (uint64_t)start; if (delta > SSIZE_MAX) return EINVAL; if ((r = write_file(ino, start, (size_t)delta, NULL)) >= 0) r = OK; } return r; }