xref: /minix3/minix/lib/libsffs/write.c (revision 289b04677a1b234d09a045a727f5e614a6c8d716)
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