Remove building with NOCRYPTO option
[minix3.git] / minix / lib / libvtreefs / file.c
blobecdbd7879f1e4cac515e6eadb8ebb9dca21be79e
1 /* VTreeFS - file.c - file and directory I/O */
3 #include "inc.h"
4 #include <dirent.h>
6 #define GETDENTS_BUFSIZ 4096
8 static char *buf = NULL;
9 static size_t bufsize = 0;
12 * Initialize the main buffer used for I/O. Return OK or an error code.
14 int
15 init_buf(size_t size)
18 /* A default buffer size, for at least getdents. */
19 if (size < GETDENTS_BUFSIZ)
20 size = GETDENTS_BUFSIZ;
22 if ((buf = malloc(size)) == NULL)
23 return ENOMEM;
25 bufsize = size;
26 return OK;
30 * Free up the I/O buffer.
32 void
33 cleanup_buf(void)
36 free(buf);
38 buf = NULL;
39 bufsize = 0;
43 * Read from a file.
45 ssize_t
46 fs_read(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
47 off_t pos, int __unused call)
49 struct inode *node;
50 size_t off, chunk;
51 ssize_t r, len;
53 /* Try to get inode by its inode number. */
54 if ((node = find_inode(ino_nr)) == NULL)
55 return EINVAL;
57 /* Check whether the node is a regular file. */
58 if (!S_ISREG(node->i_stat.mode))
59 return EINVAL;
61 /* For deleted files or with no read hook, feign an empty file. */
62 if (is_inode_deleted(node) || vtreefs_hooks->read_hook == NULL)
63 return 0; /* EOF */
65 assert(buf != NULL);
66 assert(bufsize > 0);
69 * Call the read hook to fill the result buffer, repeatedly for as long
70 * as 1) the request is not yet fully completed, and 2) the read hook
71 * fills the entire buffer.
73 for (off = 0; off < bytes; ) {
74 /* Get the next result chunk by calling the read hook. */
75 chunk = bytes - off;
76 if (chunk > bufsize)
77 chunk = bufsize;
79 len = vtreefs_hooks->read_hook(node, buf, chunk, pos,
80 get_inode_cbdata(node));
82 /* Copy any resulting data to user space. */
83 if (len > 0)
84 r = fsdriver_copyout(data, off, buf, len);
85 else
86 r = len; /* EOF or error */
89 * If an error occurred, but we already produced some output,
90 * return a partial result. Otherwise return the error.
92 if (r < 0)
93 return (off > 0) ? (ssize_t)off : r;
95 off += len;
96 pos += len;
98 if ((size_t)len < bufsize)
99 break;
102 return off;
106 * Write to a file.
108 ssize_t
109 fs_write(ino_t ino_nr, struct fsdriver_data * data, size_t bytes, off_t pos,
110 int __unused call)
112 struct inode *node;
113 size_t off, chunk;
114 ssize_t r;
116 if ((node = find_inode(ino_nr)) == NULL)
117 return EINVAL;
119 if (!S_ISREG(node->i_stat.mode))
120 return EINVAL;
122 if (is_inode_deleted(node) || vtreefs_hooks->write_hook == NULL)
123 return EACCES;
125 if (bytes == 0)
126 return 0;
128 assert(buf != NULL);
129 assert(bufsize > 0);
132 * Call the write hook to process the incoming data, repeatedly for as
133 * long as 1) the request is not yet fully completed, and 2) the write
134 * hook processes at least some of the given data.
136 for (off = 0; off < bytes; ) {
137 chunk = bytes - off;
138 if (chunk > bufsize)
139 chunk = bufsize;
141 /* Copy the data from user space. */
142 r = fsdriver_copyin(data, off, buf, chunk);
144 /* Call the write hook for the chunk. */
145 if (r == OK)
146 r = vtreefs_hooks->write_hook(node, buf, chunk, pos,
147 get_inode_cbdata(node));
150 * If an error occurred, but we already processed some input,
151 * return a partial result. Otherwise return the error.
153 if (r < 0)
154 return (off > 0) ? (ssize_t)off : r;
156 off += r;
157 pos += r;
159 if ((size_t)r == 0)
160 break;
163 return off;
167 * Truncate a file.
170 fs_trunc(ino_t ino_nr, off_t start_pos, off_t end_pos)
172 struct inode *node;
174 if ((node = find_inode(ino_nr)) == NULL)
175 return EINVAL;
177 if (!S_ISREG(node->i_stat.mode))
178 return EINVAL;
180 if (is_inode_deleted(node) || vtreefs_hooks->trunc_hook == NULL)
181 return EACCES;
183 /* TODO: translate this case into all-zeroes write callbacks. */
184 if (end_pos != 0)
185 return EINVAL;
187 return vtreefs_hooks->trunc_hook(node, start_pos,
188 get_inode_cbdata(node));
192 * Retrieve directory entries.
194 ssize_t
195 fs_getdents(ino_t ino_nr, struct fsdriver_data * data, size_t bytes,
196 off_t * posp)
198 struct fsdriver_dentry fsdentry;
199 struct inode *node, *child;
200 const char *name;
201 off_t pos;
202 int r, skip, get_next, indexed;
204 if (*posp >= ULONG_MAX)
205 return EIO;
207 if ((node = find_inode(ino_nr)) == NULL)
208 return EINVAL;
210 indexed = node->i_indexed;
211 get_next = FALSE;
212 child = NULL;
214 /* Call the getdents hook, if any, to "refresh" the directory. */
215 if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) {
216 r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node));
217 if (r != OK)
218 return r;
221 assert(buf != NULL);
222 assert(bufsize > 0);
224 fsdriver_dentry_init(&fsdentry, data, bytes, buf, bufsize);
226 for (;;) {
227 /* Determine which inode and name to use for this entry. */
228 pos = (*posp)++;
230 if (pos == 0) {
231 /* The "." entry. */
232 child = node;
233 name = ".";
234 } else if (pos == 1) {
235 /* The ".." entry. */
236 child = get_parent_inode(node);
237 if (child == NULL)
238 child = node;
239 name = "..";
240 } else if (pos - 2 < indexed) {
241 /* All indexed entries. */
242 child = get_inode_by_index(node, pos - 2);
245 * If there is no inode with this particular index,
246 * continue with the next index number.
248 if (child == NULL) continue;
250 name = child->i_name;
251 } else {
252 /* All non-indexed entries. */
254 * If this is the first loop iteration, first get to
255 * the non-indexed child identified by the current
256 * position.
258 if (get_next == FALSE) {
259 skip = pos - indexed - 2;
260 child = get_first_inode(node);
262 /* Skip indexed children. */
263 while (child != NULL &&
264 child->i_index != NO_INDEX)
265 child = get_next_inode(child);
267 /* Skip to the right position. */
268 while (child != NULL && skip-- > 0)
269 child = get_next_inode(child);
271 get_next = TRUE;
272 } else
273 child = get_next_inode(child);
275 /* No more children? Then stop. */
276 if (child == NULL)
277 break;
279 assert(!is_inode_deleted(child));
281 name = child->i_name;
284 /* Add the directory entry to the output. */
285 r = fsdriver_dentry_add(&fsdentry,
286 (ino_t)get_inode_number(child), name, strlen(name),
287 IFTODT(child->i_stat.mode));
288 if (r < 0)
289 return r;
290 if (r == 0)
291 break;
294 return fsdriver_dentry_finish(&fsdentry);