make vfs & filesystems use failable copying
[minix3.git] / lib / libsffs / write.c
blob4d852ea997e6f5f0a89721248c9b0edf5e7ad6ec
1 /* This file contains file writing system call handlers.
3 * The entry points into this file are:
4 * do_write perform the WRITE file system call
5 * do_ftrunc perform the FTRUNC file system call
7 * Created:
8 * April 2009 (D.C. van Moolenbroek)
9 */
11 #include "inc.h"
13 static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
14 cp_grant_id_t *grantp);
16 /*===========================================================================*
17 * write_file *
18 *===========================================================================*/
19 static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
20 cp_grant_id_t *grantp)
22 /* Write data or zeroes to a file, depending on whether a valid pointer to
23 * a data grant was provided.
25 u64_t pos;
26 size_t count, size;
27 vir_bytes off;
28 char *ptr;
29 int r, chunk;
31 assert(!IS_DIR(ino));
33 if ((r = get_handle(ino)) != OK)
34 return r;
36 pos = *posp;
37 count = *countp;
39 assert(count > 0);
41 /* Use the buffer from below to eliminate extra copying. */
42 size = sffs_table->t_writebuf(&ptr);
43 off = 0;
45 while (count > 0) {
46 chunk = MIN(count, size);
48 if (grantp != NULL) {
49 r = sys_safecopyfrom(m_in.m_source, *grantp,
50 off, (vir_bytes) ptr, chunk);
52 if (r != OK)
53 break;
54 } else {
55 /* Do this every time. We don't know what happens below. */
56 memset(ptr, 0, chunk);
59 if ((r = sffs_table->t_write(ino->i_file, ptr, chunk, pos)) <= 0)
60 break;
62 count -= r;
63 off += r;
64 pos += r;
67 if (r < 0)
68 return r;
70 *posp = pos;
71 *countp = off;
73 return OK;
76 /*===========================================================================*
77 * do_write *
78 *===========================================================================*/
79 int do_write(void)
81 /* Write data to a file.
83 struct inode *ino;
84 u64_t pos;
85 size_t count;
86 cp_grant_id_t grant;
87 int r;
89 if (state.s_read_only)
90 return EROFS;
92 if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
93 return EINVAL;
95 if (IS_DIR(ino)) return EISDIR;
97 pos = m_in.REQ_SEEK_POS;
98 count = m_in.REQ_NBYTES;
99 grant = m_in.REQ_GRANT;
101 if (count == 0) return EINVAL;
103 if ((r = write_file(ino, &pos, &count, &grant)) != OK)
104 return r;
106 m_out.RES_SEEK_POS = pos;
107 m_out.RES_NBYTES = count;
109 return OK;
112 /*===========================================================================*
113 * do_ftrunc *
114 *===========================================================================*/
115 int do_ftrunc(void)
117 /* Change file size or create file holes.
119 char path[PATH_MAX];
120 struct inode *ino;
121 struct sffs_attr attr;
122 u64_t start, end, delta;
123 size_t count;
124 int r;
126 if (state.s_read_only)
127 return EROFS;
129 if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
130 return EINVAL;
132 if (IS_DIR(ino)) return EISDIR;
134 start = m_in.REQ_TRC_START;
135 end = m_in.REQ_TRC_END;
137 if (end == 0) {
138 /* Truncate or expand the file. */
139 if ((r = verify_inode(ino, path, NULL)) != OK)
140 return r;
142 attr.a_mask = SFFS_ATTR_SIZE;
143 attr.a_size = start;
145 r = sffs_table->t_setattr(path, &attr);
146 } else {
147 /* Write zeroes to the file. We can't create holes. */
148 if (end <= start) return EINVAL;
150 delta = end - start;
152 if (ex64hi(delta) != 0) return EINVAL;
154 count = ex64lo(delta);
156 r = write_file(ino, &start, &count, NULL);
159 return r;