1433d6423SLionel Sambuc /* This file contains file and directory reading file system call handlers.
2433d6423SLionel Sambuc *
3433d6423SLionel Sambuc * The entry points into this file are:
4433d6423SLionel Sambuc * do_read perform the READ file system call
5433d6423SLionel Sambuc * do_getdents perform the GETDENTS 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 #include <dirent.h>
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc /*===========================================================================*
16433d6423SLionel Sambuc * do_read *
17433d6423SLionel Sambuc *===========================================================================*/
do_read(ino_t ino_nr,struct fsdriver_data * data,size_t count,off_t pos,int call)18a99c939dSDavid van Moolenbroek ssize_t do_read(ino_t ino_nr, struct fsdriver_data *data, size_t count,
19a99c939dSDavid van Moolenbroek off_t pos, int call)
20433d6423SLionel Sambuc {
21433d6423SLionel Sambuc /* Read data from a file.
22433d6423SLionel Sambuc */
23433d6423SLionel Sambuc struct inode *ino;
24a99c939dSDavid van Moolenbroek size_t size, off;
25433d6423SLionel Sambuc char *ptr;
26433d6423SLionel Sambuc int r, chunk;
27433d6423SLionel Sambuc
28a99c939dSDavid van Moolenbroek if ((ino = find_inode(ino_nr)) == NULL)
29433d6423SLionel Sambuc return EINVAL;
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc if (IS_DIR(ino)) return EISDIR;
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc if ((r = get_handle(ino)) != OK)
34433d6423SLionel Sambuc return r;
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc assert(count > 0);
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc /* Use the buffer from below to eliminate extra copying. */
39433d6423SLionel Sambuc size = sffs_table->t_readbuf(&ptr);
40433d6423SLionel Sambuc off = 0;
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc while (count > 0) {
43433d6423SLionel Sambuc chunk = MIN(count, size);
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc if ((r = sffs_table->t_read(ino->i_file, ptr, chunk, pos)) <= 0)
46433d6423SLionel Sambuc break;
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc chunk = r;
49433d6423SLionel Sambuc
50a99c939dSDavid van Moolenbroek if ((r = fsdriver_copyout(data, off, ptr, chunk)) != OK)
51433d6423SLionel Sambuc break;
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc count -= chunk;
54433d6423SLionel Sambuc off += chunk;
55433d6423SLionel Sambuc pos += chunk;
56433d6423SLionel Sambuc }
57433d6423SLionel Sambuc
58433d6423SLionel Sambuc if (r < 0)
59433d6423SLionel Sambuc return r;
60433d6423SLionel Sambuc
61a99c939dSDavid van Moolenbroek return off;
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc
64433d6423SLionel Sambuc /*===========================================================================*
65433d6423SLionel Sambuc * do_getdents *
66433d6423SLionel Sambuc *===========================================================================*/
do_getdents(ino_t ino_nr,struct fsdriver_data * data,size_t bytes,off_t * posp)67a99c939dSDavid van Moolenbroek ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
68a99c939dSDavid van Moolenbroek off_t *posp)
69433d6423SLionel Sambuc {
70433d6423SLionel Sambuc /* Retrieve directory entries.
71433d6423SLionel Sambuc */
72a99c939dSDavid van Moolenbroek struct fsdriver_dentry fsdentry;
73433d6423SLionel Sambuc char name[NAME_MAX+1];
74433d6423SLionel Sambuc struct inode *ino, *child;
75433d6423SLionel Sambuc struct sffs_attr attr;
76433d6423SLionel Sambuc off_t pos;
77a99c939dSDavid van Moolenbroek int r;
78433d6423SLionel Sambuc /* must be at least sizeof(struct dirent) + NAME_MAX */
79433d6423SLionel Sambuc static char buf[BLOCK_SIZE];
80433d6423SLionel Sambuc
81a99c939dSDavid van Moolenbroek if ((ino = find_inode(ino_nr)) == NULL)
82433d6423SLionel Sambuc return EINVAL;
83433d6423SLionel Sambuc
84433d6423SLionel Sambuc if (!IS_DIR(ino)) return ENOTDIR;
85433d6423SLionel Sambuc
86a99c939dSDavid van Moolenbroek if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL;
87a99c939dSDavid van Moolenbroek
88433d6423SLionel Sambuc /* We are going to need at least one free inode to store children in. */
89433d6423SLionel Sambuc if (!have_free_inode()) return ENFILE;
90433d6423SLionel Sambuc
91433d6423SLionel Sambuc /* If we don't have a directory handle yet, get one now. */
92433d6423SLionel Sambuc if ((r = get_handle(ino)) != OK)
93433d6423SLionel Sambuc return r;
94433d6423SLionel Sambuc
95a99c939dSDavid van Moolenbroek fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf));
96433d6423SLionel Sambuc
97433d6423SLionel Sambuc /* We use the seek position as file index number. The first position is for
98433d6423SLionel Sambuc * the "." entry, the second position is for the ".." entry, and the next
99433d6423SLionel Sambuc * position numbers each represent a file in the directory.
100433d6423SLionel Sambuc */
101*f912036bSDavid van Moolenbroek for (;;) {
102433d6423SLionel Sambuc /* Determine which inode and name to use for this entry.
103433d6423SLionel Sambuc * We have no idea whether the host will give us "." and/or "..",
104433d6423SLionel Sambuc * so generate our own and skip those from the host.
105433d6423SLionel Sambuc */
106a99c939dSDavid van Moolenbroek pos = (*posp)++;
107a99c939dSDavid van Moolenbroek
108433d6423SLionel Sambuc if (pos == 0) {
109433d6423SLionel Sambuc /* Entry for ".". */
110433d6423SLionel Sambuc child = ino;
111433d6423SLionel Sambuc
112433d6423SLionel Sambuc strcpy(name, ".");
113433d6423SLionel Sambuc
114433d6423SLionel Sambuc get_inode(child);
115433d6423SLionel Sambuc }
116433d6423SLionel Sambuc else if (pos == 1) {
117433d6423SLionel Sambuc /* Entry for "..", but only when there is a parent. */
118433d6423SLionel Sambuc if (ino->i_parent == NULL)
119433d6423SLionel Sambuc continue;
120433d6423SLionel Sambuc
121433d6423SLionel Sambuc child = ino->i_parent;
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc strcpy(name, "..");
124433d6423SLionel Sambuc
125433d6423SLionel Sambuc get_inode(child);
126433d6423SLionel Sambuc }
127433d6423SLionel Sambuc else {
128433d6423SLionel Sambuc /* Any other entry, not being "." or "..". */
129a99c939dSDavid van Moolenbroek attr.a_mask = SFFS_ATTR_MODE;
130a99c939dSDavid van Moolenbroek
131433d6423SLionel Sambuc r = sffs_table->t_readdir(ino->i_dir, pos - 2, name,
132433d6423SLionel Sambuc sizeof(name), &attr);
133433d6423SLionel Sambuc
134433d6423SLionel Sambuc if (r != OK) {
135433d6423SLionel Sambuc /* No more entries? Then close the handle and stop. */
136433d6423SLionel Sambuc if (r == ENOENT) {
137433d6423SLionel Sambuc put_handle(ino);
138433d6423SLionel Sambuc
139433d6423SLionel Sambuc break;
140433d6423SLionel Sambuc }
141433d6423SLionel Sambuc
142433d6423SLionel Sambuc /* FIXME: what if the error is ENAMETOOLONG? */
143433d6423SLionel Sambuc return r;
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc
146433d6423SLionel Sambuc if (!strcmp(name, ".") || !strcmp(name, ".."))
147433d6423SLionel Sambuc continue;
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc if ((child = lookup_dentry(ino, name)) == NULL) {
150433d6423SLionel Sambuc child = get_free_inode();
151433d6423SLionel Sambuc
152433d6423SLionel Sambuc /* We were promised a free inode! */
153433d6423SLionel Sambuc assert(child != NULL);
154433d6423SLionel Sambuc
155433d6423SLionel Sambuc child->i_flags = MODE_TO_DIRFLAG(attr.a_mode);
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc add_dentry(ino, name, child);
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc }
160433d6423SLionel Sambuc
161a99c939dSDavid van Moolenbroek r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name),
162a99c939dSDavid van Moolenbroek IS_DIR(child) ? DT_DIR : DT_REG);
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc put_inode(child);
165433d6423SLionel Sambuc
166a99c939dSDavid van Moolenbroek if (r < 0)
167433d6423SLionel Sambuc return r;
168*f912036bSDavid van Moolenbroek if (r == 0)
169*f912036bSDavid van Moolenbroek break;
170*f912036bSDavid van Moolenbroek }
171433d6423SLionel Sambuc
172a99c939dSDavid van Moolenbroek return fsdriver_dentry_finish(&fsdentry);
173433d6423SLionel Sambuc }
174