1 /* This file contains file writing system call handlers. 2 * 3 * The entry points into this file are: 4 * do_write perform the WRITE file system call 5 * do_trunc perform the TRUNC file system call 6 * 7 * Created: 8 * April 2009 (D.C. van Moolenbroek) 9 */ 10 11 #include "inc.h" 12 13 /*===========================================================================* 14 * write_file * 15 *===========================================================================*/ 16 static ssize_t write_file(struct inode *ino, off_t pos, size_t count, 17 struct fsdriver_data *data) 18 { 19 /* Write data or zeroes to a file, depending on whether a valid pointer to 20 * a data grant was provided. 21 */ 22 size_t size, off, chunk; 23 char *ptr; 24 int r; 25 26 if (pos < 0) 27 return EINVAL; 28 29 assert(!IS_DIR(ino)); 30 31 if ((r = get_handle(ino)) != OK) 32 return r; 33 34 assert(count > 0); 35 36 /* Use the buffer from below to eliminate extra copying. */ 37 size = sffs_table->t_writebuf(&ptr); 38 off = 0; 39 40 while (count > 0) { 41 chunk = MIN(count, size); 42 43 if (data != NULL) { 44 if ((r = fsdriver_copyin(data, off, ptr, chunk)) != OK) 45 break; 46 } else { 47 /* Do this every time. We don't know what happens below. */ 48 memset(ptr, 0, chunk); 49 } 50 51 if ((r = sffs_table->t_write(ino->i_file, ptr, chunk, pos)) <= 0) 52 break; 53 54 count -= r; 55 off += r; 56 pos += r; 57 } 58 59 if (r < 0) 60 return r; 61 62 return off; 63 } 64 65 /*===========================================================================* 66 * do_write * 67 *===========================================================================*/ 68 ssize_t do_write(ino_t ino_nr, struct fsdriver_data *data, size_t count, 69 off_t pos, int call) 70 { 71 /* Write data to a file. 72 */ 73 struct inode *ino; 74 75 if (read_only) 76 return EROFS; 77 78 if ((ino = find_inode(ino_nr)) == NULL) 79 return EINVAL; 80 81 if (IS_DIR(ino)) return EISDIR; 82 83 if (count == 0) return 0; 84 85 return write_file(ino, pos, count, data); 86 } 87 88 /*===========================================================================* 89 * do_trunc * 90 *===========================================================================*/ 91 int do_trunc(ino_t ino_nr, off_t start, off_t end) 92 { 93 /* Change file size or create file holes. 94 */ 95 char path[PATH_MAX]; 96 struct inode *ino; 97 struct sffs_attr attr; 98 uint64_t delta; 99 ssize_t r; 100 101 if (read_only) 102 return EROFS; 103 104 if ((ino = find_inode(ino_nr)) == NULL) 105 return EINVAL; 106 107 if (IS_DIR(ino)) return EISDIR; 108 109 if (end == 0) { 110 /* Truncate or expand the file. */ 111 if ((r = verify_inode(ino, path, NULL)) != OK) 112 return r; 113 114 attr.a_mask = SFFS_ATTR_SIZE; 115 attr.a_size = start; 116 117 r = sffs_table->t_setattr(path, &attr); 118 } else { 119 /* Write zeroes to the file. We can't create holes. */ 120 if (end <= start) return EINVAL; 121 122 delta = (uint64_t)end - (uint64_t)start; 123 124 if (delta > SSIZE_MAX) return EINVAL; 125 126 if ((r = write_file(ino, start, (size_t)delta, NULL)) >= 0) 127 r = OK; 128 } 129 130 return r; 131 } 132