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