1433d6423SLionel Sambuc /* This file contains file writing system call handlers.
2433d6423SLionel Sambuc *
3433d6423SLionel Sambuc * The entry points into this file are:
4433d6423SLionel Sambuc * do_write perform the WRITE file system call
5a99c939dSDavid van Moolenbroek * do_trunc perform the TRUNC file system call
6433d6423SLionel Sambuc *
7433d6423SLionel Sambuc * Created:
8433d6423SLionel Sambuc * April 2009 (D.C. van Moolenbroek)
9433d6423SLionel Sambuc */
10433d6423SLionel Sambuc
11433d6423SLionel Sambuc #include "inc.h"
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc /*===========================================================================*
14433d6423SLionel Sambuc * write_file *
15433d6423SLionel Sambuc *===========================================================================*/
write_file(struct inode * ino,off_t pos,size_t count,struct fsdriver_data * data)16a99c939dSDavid van Moolenbroek static ssize_t write_file(struct inode *ino, off_t pos, size_t count,
17a99c939dSDavid van Moolenbroek struct fsdriver_data *data)
18433d6423SLionel Sambuc {
19433d6423SLionel Sambuc /* Write data or zeroes to a file, depending on whether a valid pointer to
20433d6423SLionel Sambuc * a data grant was provided.
21433d6423SLionel Sambuc */
22a99c939dSDavid van Moolenbroek size_t size, off, chunk;
23433d6423SLionel Sambuc char *ptr;
24a99c939dSDavid van Moolenbroek int r;
25a99c939dSDavid van Moolenbroek
26a99c939dSDavid van Moolenbroek if (pos < 0)
27a99c939dSDavid van Moolenbroek return EINVAL;
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc assert(!IS_DIR(ino));
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc if ((r = get_handle(ino)) != OK)
32433d6423SLionel Sambuc return r;
33433d6423SLionel Sambuc
34433d6423SLionel Sambuc assert(count > 0);
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc /* Use the buffer from below to eliminate extra copying. */
37433d6423SLionel Sambuc size = sffs_table->t_writebuf(&ptr);
38433d6423SLionel Sambuc off = 0;
39433d6423SLionel Sambuc
40433d6423SLionel Sambuc while (count > 0) {
41433d6423SLionel Sambuc chunk = MIN(count, size);
42433d6423SLionel Sambuc
43a99c939dSDavid van Moolenbroek if (data != NULL) {
44a99c939dSDavid van Moolenbroek if ((r = fsdriver_copyin(data, off, ptr, chunk)) != OK)
45433d6423SLionel Sambuc break;
46433d6423SLionel Sambuc } else {
47433d6423SLionel Sambuc /* Do this every time. We don't know what happens below. */
48433d6423SLionel Sambuc memset(ptr, 0, chunk);
49433d6423SLionel Sambuc }
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc if ((r = sffs_table->t_write(ino->i_file, ptr, chunk, pos)) <= 0)
52433d6423SLionel Sambuc break;
53433d6423SLionel Sambuc
54433d6423SLionel Sambuc count -= r;
55433d6423SLionel Sambuc off += r;
56433d6423SLionel Sambuc pos += r;
57433d6423SLionel Sambuc }
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc if (r < 0)
60433d6423SLionel Sambuc return r;
61433d6423SLionel Sambuc
62a99c939dSDavid van Moolenbroek return off;
63433d6423SLionel Sambuc }
64433d6423SLionel Sambuc
65433d6423SLionel Sambuc /*===========================================================================*
66433d6423SLionel Sambuc * do_write *
67433d6423SLionel Sambuc *===========================================================================*/
do_write(ino_t ino_nr,struct fsdriver_data * data,size_t count,off_t pos,int call)68a99c939dSDavid van Moolenbroek ssize_t do_write(ino_t ino_nr, struct fsdriver_data *data, size_t count,
69a99c939dSDavid van Moolenbroek off_t pos, int call)
70433d6423SLionel Sambuc {
71433d6423SLionel Sambuc /* Write data to a file.
72433d6423SLionel Sambuc */
73433d6423SLionel Sambuc struct inode *ino;
74433d6423SLionel Sambuc
75*289b0467SDavid van Moolenbroek if (read_only)
76433d6423SLionel Sambuc return EROFS;
77433d6423SLionel Sambuc
78a99c939dSDavid van Moolenbroek if ((ino = find_inode(ino_nr)) == NULL)
79433d6423SLionel Sambuc return EINVAL;
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc if (IS_DIR(ino)) return EISDIR;
82433d6423SLionel Sambuc
83a99c939dSDavid van Moolenbroek if (count == 0) return 0;
84433d6423SLionel Sambuc
85a99c939dSDavid van Moolenbroek return write_file(ino, pos, count, data);
86433d6423SLionel Sambuc }
87433d6423SLionel Sambuc
88433d6423SLionel Sambuc /*===========================================================================*
89a99c939dSDavid van Moolenbroek * do_trunc *
90433d6423SLionel Sambuc *===========================================================================*/
do_trunc(ino_t ino_nr,off_t start,off_t end)91a99c939dSDavid van Moolenbroek int do_trunc(ino_t ino_nr, off_t start, off_t end)
92433d6423SLionel Sambuc {
93433d6423SLionel Sambuc /* Change file size or create file holes.
94433d6423SLionel Sambuc */
95433d6423SLionel Sambuc char path[PATH_MAX];
96433d6423SLionel Sambuc struct inode *ino;
97433d6423SLionel Sambuc struct sffs_attr attr;
98a99c939dSDavid van Moolenbroek uint64_t delta;
99a99c939dSDavid van Moolenbroek ssize_t r;
100433d6423SLionel Sambuc
101*289b0467SDavid van Moolenbroek if (read_only)
102433d6423SLionel Sambuc return EROFS;
103433d6423SLionel Sambuc
104a99c939dSDavid van Moolenbroek if ((ino = find_inode(ino_nr)) == NULL)
105433d6423SLionel Sambuc return EINVAL;
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc if (IS_DIR(ino)) return EISDIR;
108433d6423SLionel Sambuc
109433d6423SLionel Sambuc if (end == 0) {
110433d6423SLionel Sambuc /* Truncate or expand the file. */
111433d6423SLionel Sambuc if ((r = verify_inode(ino, path, NULL)) != OK)
112433d6423SLionel Sambuc return r;
113433d6423SLionel Sambuc
114433d6423SLionel Sambuc attr.a_mask = SFFS_ATTR_SIZE;
115433d6423SLionel Sambuc attr.a_size = start;
116433d6423SLionel Sambuc
117433d6423SLionel Sambuc r = sffs_table->t_setattr(path, &attr);
118433d6423SLionel Sambuc } else {
119433d6423SLionel Sambuc /* Write zeroes to the file. We can't create holes. */
120433d6423SLionel Sambuc if (end <= start) return EINVAL;
121433d6423SLionel Sambuc
122a99c939dSDavid van Moolenbroek delta = (uint64_t)end - (uint64_t)start;
123433d6423SLionel Sambuc
124a99c939dSDavid van Moolenbroek if (delta > SSIZE_MAX) return EINVAL;
125433d6423SLionel Sambuc
126a99c939dSDavid van Moolenbroek if ((r = write_file(ino, start, (size_t)delta, NULL)) >= 0)
127a99c939dSDavid van Moolenbroek r = OK;
128433d6423SLionel Sambuc }
129433d6423SLionel Sambuc
130433d6423SLionel Sambuc return r;
131433d6423SLionel Sambuc }
132