Remove building with NOCRYPTO option
[minix3.git] / minix / lib / libsffs / read.c
blobbb922f9a12f0333bc6c0f1df046df17032d34ff8
1 /* This file contains file and directory reading file system call handlers.
3 * The entry points into this file are:
4 * do_read perform the READ file system call
5 * do_getdents perform the GETDENTS file system call
7 * Created:
8 * April 2009 (D.C. van Moolenbroek)
9 */
11 #include "inc.h"
13 #include <dirent.h>
15 /*===========================================================================*
16 * do_read *
17 *===========================================================================*/
18 ssize_t do_read(ino_t ino_nr, struct fsdriver_data *data, size_t count,
19 off_t pos, int call)
21 /* Read data from a file.
23 struct inode *ino;
24 size_t size, off;
25 char *ptr;
26 int r, chunk;
28 if ((ino = find_inode(ino_nr)) == NULL)
29 return EINVAL;
31 if (IS_DIR(ino)) return EISDIR;
33 if ((r = get_handle(ino)) != OK)
34 return r;
36 assert(count > 0);
38 /* Use the buffer from below to eliminate extra copying. */
39 size = sffs_table->t_readbuf(&ptr);
40 off = 0;
42 while (count > 0) {
43 chunk = MIN(count, size);
45 if ((r = sffs_table->t_read(ino->i_file, ptr, chunk, pos)) <= 0)
46 break;
48 chunk = r;
50 if ((r = fsdriver_copyout(data, off, ptr, chunk)) != OK)
51 break;
53 count -= chunk;
54 off += chunk;
55 pos += chunk;
58 if (r < 0)
59 return r;
61 return off;
64 /*===========================================================================*
65 * do_getdents *
66 *===========================================================================*/
67 ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
68 off_t *posp)
70 /* Retrieve directory entries.
72 struct fsdriver_dentry fsdentry;
73 char name[NAME_MAX+1];
74 struct inode *ino, *child;
75 struct sffs_attr attr;
76 off_t pos;
77 int r;
78 /* must be at least sizeof(struct dirent) + NAME_MAX */
79 static char buf[BLOCK_SIZE];
81 if ((ino = find_inode(ino_nr)) == NULL)
82 return EINVAL;
84 if (!IS_DIR(ino)) return ENOTDIR;
86 if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL;
88 /* We are going to need at least one free inode to store children in. */
89 if (!have_free_inode()) return ENFILE;
91 /* If we don't have a directory handle yet, get one now. */
92 if ((r = get_handle(ino)) != OK)
93 return r;
95 fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf));
97 /* We use the seek position as file index number. The first position is for
98 * the "." entry, the second position is for the ".." entry, and the next
99 * position numbers each represent a file in the directory.
101 for (;;) {
102 /* Determine which inode and name to use for this entry.
103 * We have no idea whether the host will give us "." and/or "..",
104 * so generate our own and skip those from the host.
106 pos = (*posp)++;
108 if (pos == 0) {
109 /* Entry for ".". */
110 child = ino;
112 strcpy(name, ".");
114 get_inode(child);
116 else if (pos == 1) {
117 /* Entry for "..", but only when there is a parent. */
118 if (ino->i_parent == NULL)
119 continue;
121 child = ino->i_parent;
123 strcpy(name, "..");
125 get_inode(child);
127 else {
128 /* Any other entry, not being "." or "..". */
129 attr.a_mask = SFFS_ATTR_MODE;
131 r = sffs_table->t_readdir(ino->i_dir, pos - 2, name,
132 sizeof(name), &attr);
134 if (r != OK) {
135 /* No more entries? Then close the handle and stop. */
136 if (r == ENOENT) {
137 put_handle(ino);
139 break;
142 /* FIXME: what if the error is ENAMETOOLONG? */
143 return r;
146 if (!strcmp(name, ".") || !strcmp(name, ".."))
147 continue;
149 if ((child = lookup_dentry(ino, name)) == NULL) {
150 child = get_free_inode();
152 /* We were promised a free inode! */
153 assert(child != NULL);
155 child->i_flags = MODE_TO_DIRFLAG(attr.a_mode);
157 add_dentry(ino, name, child);
161 r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name),
162 IS_DIR(child) ? DT_DIR : DT_REG);
164 put_inode(child);
166 if (r < 0)
167 return r;
168 if (r == 0)
169 break;
172 return fsdriver_dentry_finish(&fsdentry);