xref: /minix/minix/lib/libsffs/write.c (revision 83133719)
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 (state.s_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 (state.s_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