sprofalyze fixes
[minix.git] / lib / libsffs / lookup.c
blobb94b6a0fd837b1f86b84ba181e78775fa257e670
1 /* This file provides path-to-inode lookup functionality.
3 * The entry points into this file are:
4 * do_lookup perform the LOOKUP file system call
6 * Created:
7 * April 2009 (D.C. van Moolenbroek)
8 */
10 #include "inc.h"
12 static int get_mask(vfs_ucred_t *ucred);
13 static int access_as_dir(struct inode *ino, struct sffs_attr *attr, int
14 uid, int mask);
15 static int next_name(char **ptr, char **start, char name[NAME_MAX+1]);
16 static int go_up(char path[PATH_MAX], struct inode *ino, struct inode
17 **res_ino, struct sffs_attr *attr);
18 static int go_down(char path[PATH_MAX], struct inode *ino, char *name,
19 struct inode **res_ino, struct sffs_attr *attr);
21 /*===========================================================================*
22 * get_mask *
23 *===========================================================================*/
24 static int get_mask(ucred)
25 vfs_ucred_t *ucred; /* credentials of the caller */
27 /* Given the caller's credentials, precompute a search access mask to test
28 * against directory modes.
30 int i;
32 if (ucred->vu_uid == sffs_params->p_uid) return S_IXUSR;
34 if (ucred->vu_gid == sffs_params->p_gid) return S_IXGRP;
36 for (i = 0; i < ucred->vu_ngroups; i++)
37 if (ucred->vu_sgroups[i] == sffs_params->p_gid) return S_IXGRP;
39 return S_IXOTH;
42 /*===========================================================================*
43 * access_as_dir *
44 *===========================================================================*/
45 static int access_as_dir(ino, attr, uid, mask)
46 struct inode *ino; /* the inode to test */
47 struct sffs_attr *attr; /* attributes of the inode */
48 int uid; /* UID of the caller */
49 int mask; /* search access mask of the caller */
51 /* Check whether the given inode may be accessed as directory.
52 * Return OK or an appropriate error code.
54 mode_t mode;
56 assert(attr->a_mask & SFFS_ATTR_MODE);
58 /* The inode must be a directory to begin with. */
59 if (!IS_DIR(ino)) return ENOTDIR;
61 /* The caller must have search access to the directory. Root always does. */
62 if (uid == 0) return OK;
64 mode = get_mode(ino, attr->a_mode);
66 return (mode & mask) ? OK : EACCES;
69 /*===========================================================================*
70 * next_name *
71 *===========================================================================*/
72 static int next_name(ptr, start, name)
73 char **ptr; /* cursor pointer into path (in, out) */
74 char **start; /* place to store start of name */
75 char name[NAME_MAX+1]; /* place to store name */
77 /* Get the next path component from a path.
79 char *p;
80 int i;
82 for (p = *ptr; *p == '/'; p++);
84 *start = p;
86 if (*p) {
87 for (i = 0; *p && *p != '/' && i <= NAME_MAX; p++, i++)
88 name[i] = *p;
90 if (i > NAME_MAX)
91 return ENAMETOOLONG;
93 name[i] = 0;
94 } else {
95 strcpy(name, ".");
98 *ptr = p;
99 return OK;
102 /*===========================================================================*
103 * go_up *
104 *===========================================================================*/
105 static int go_up(path, ino, res_ino, attr)
106 char path[PATH_MAX]; /* path to take the last part from */
107 struct inode *ino; /* inode of the current directory */
108 struct inode **res_ino; /* place to store resulting inode */
109 struct sffs_attr *attr; /* place to store inode attributes */
111 /* Given an inode, progress into the parent directory.
113 struct inode *parent;
114 int r;
116 pop_path(path);
118 parent = ino->i_parent;
119 assert(parent != NULL);
121 if ((r = verify_path(path, parent, attr, NULL)) != OK)
122 return r;
124 get_inode(parent);
126 *res_ino = parent;
128 return r;
131 /*===========================================================================*
132 * go_down *
133 *===========================================================================*/
134 static int go_down(path, parent, name, res_ino, attr)
135 char path[PATH_MAX]; /* path to add the name to */
136 struct inode *parent; /* inode of the current directory */
137 char *name; /* name of the directory entry */
138 struct inode **res_ino; /* place to store resulting inode */
139 struct sffs_attr *attr; /* place to store inode attributes */
141 /* Given a directory inode and a name, progress into a directory entry.
143 struct inode *ino;
144 int r, stale = 0;
146 if ((r = push_path(path, name)) != OK)
147 return r;
149 dprintf(("%s: go_down: name '%s', path now '%s'\n", sffs_name, name, path));
151 ino = lookup_dentry(parent, name);
153 dprintf(("%s: lookup_dentry('%s') returned %p\n", sffs_name, name, ino));
155 if (ino != NULL)
156 r = verify_path(path, ino, attr, &stale);
157 else
158 r = sffs_table->t_getattr(path, attr);
160 dprintf(("%s: path query returned %d\n", sffs_name, r));
162 if (r != OK) {
163 if (ino != NULL) {
164 put_inode(ino);
166 ino = NULL;
169 if (!stale)
170 return r;
173 dprintf(("%s: name '%s'\n", sffs_name, name));
175 if (ino == NULL) {
176 if ((ino = get_free_inode()) == NULL)
177 return ENFILE;
179 dprintf(("%s: inode %p ref %d\n", sffs_name, ino, ino->i_ref));
181 ino->i_flags = MODE_TO_DIRFLAG(attr->a_mode);
183 add_dentry(parent, name, ino);
186 *res_ino = ino;
187 return OK;
190 /*===========================================================================*
191 * do_lookup *
192 *===========================================================================*/
193 int do_lookup()
195 /* Resolve a path string to an inode.
197 ino_t dir_ino_nr, root_ino_nr;
198 struct inode *cur_ino, *root_ino;
199 struct inode *next_ino = NULL;
200 struct sffs_attr attr;
201 char buf[PATH_MAX], path[PATH_MAX];
202 char name[NAME_MAX+1];
203 char *ptr, *last;
204 vfs_ucred_t ucred;
205 mode_t mask;
206 size_t len;
207 int r;
209 dir_ino_nr = m_in.REQ_DIR_INO;
210 root_ino_nr = m_in.REQ_ROOT_INO;
211 len = m_in.REQ_PATH_LEN;
213 /* Fetch the path name. */
214 if (len < 1 || len > PATH_MAX)
215 return EINVAL;
217 r = sys_safecopyfrom(m_in.m_source, m_in.REQ_GRANT, 0,
218 (vir_bytes) buf, len);
220 if (r != OK)
221 return r;
223 if (buf[len-1] != 0) {
224 printf("%s: VFS did not zero-terminate path!\n", sffs_name);
226 return EINVAL;
229 /* Fetch the credentials, and generate a search access mask to test against
230 * directory modes.
232 if (m_in.REQ_FLAGS & PATH_GET_UCRED) {
233 if (m_in.REQ_UCRED_SIZE != sizeof(ucred)) {
234 printf("%s: bad credential structure size\n", sffs_name);
236 return EINVAL;
239 r = sys_safecopyfrom(m_in.m_source, m_in.REQ_GRANT2, 0,
240 (vir_bytes) &ucred, m_in.REQ_UCRED_SIZE);
242 if (r != OK)
243 return r;
245 else {
246 ucred.vu_uid = m_in.REQ_UID;
247 ucred.vu_gid = m_in.REQ_GID;
248 ucred.vu_ngroups = 0;
251 mask = get_mask(&ucred);
253 /* Start the actual lookup. */
254 dprintf(("%s: lookup: got query '%s'\n", sffs_name, buf));
256 if ((cur_ino = find_inode(dir_ino_nr)) == NULL)
257 return EINVAL;
259 attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
261 if ((r = verify_inode(cur_ino, path, &attr)) != OK)
262 return r;
264 get_inode(cur_ino);
266 if (root_ino_nr > 0)
267 root_ino = find_inode(root_ino_nr);
268 else
269 root_ino = NULL;
271 /* One possible optimization would be to check a path only right before the
272 * first ".." in a row, and at the very end (if still necessary). This would
273 * have consequences for inode validation, though.
275 for (ptr = last = buf; *ptr != 0; ) {
276 if ((r = access_as_dir(cur_ino, &attr, ucred.vu_uid, mask)) != OK)
277 break;
279 if ((r = next_name(&ptr, &last, name)) != OK)
280 break;
282 dprintf(("%s: lookup: next name '%s'\n", sffs_name, name));
284 if (!strcmp(name, ".") ||
285 (cur_ino == root_ino && !strcmp(name, "..")))
286 continue;
288 if (!strcmp(name, "..")) {
289 if (IS_ROOT(cur_ino))
290 r = ELEAVEMOUNT;
291 else
292 r = go_up(path, cur_ino, &next_ino, &attr);
293 } else {
294 r = go_down(path, cur_ino, name, &next_ino, &attr);
297 if (r != OK)
298 break;
300 assert(next_ino != NULL);
302 put_inode(cur_ino);
304 cur_ino = next_ino;
307 dprintf(("%s: lookup: result %d\n", sffs_name, r));
309 if (r != OK) {
310 put_inode(cur_ino);
312 /* We'd need support for these here. We don't have such support. */
313 assert(r != EENTERMOUNT && r != ESYMLINK);
315 if (r == ELEAVEMOUNT) {
316 m_out.RES_OFFSET = (int) (last - buf);
317 m_out.RES_SYMLOOP = 0;
320 return r;
323 m_out.RES_INODE_NR = INODE_NR(cur_ino);
324 m_out.RES_MODE = get_mode(cur_ino, attr.a_mode);
325 m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
326 m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
327 m_out.RES_UID = sffs_params->p_uid;
328 m_out.RES_GID = sffs_params->p_gid;
329 m_out.RES_DEV = NO_DEV;
331 return OK;