Fixes to allow versionless packages on cd
[minix3.git] / servers / hgfs / lookup.c
blob6ad432cbf79bd615806acf515d55d34673fa1f0e
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 FORWARD _PROTOTYPE( int get_mask, (vfs_ucred_t *ucred) );
13 FORWARD _PROTOTYPE( int access_as_dir, (struct inode *ino,
14 struct hgfs_attr *attr, int uid, int mask) );
15 FORWARD _PROTOTYPE( int next_name, (char **ptr, char **start,
16 char name[NAME_MAX+1]) );
17 FORWARD _PROTOTYPE( int go_up, (char path[PATH_MAX], struct inode *ino,
18 struct inode **res_ino, struct hgfs_attr *attr) );
19 FORWARD _PROTOTYPE( int go_down, (char path[PATH_MAX],
20 struct inode *ino, char *name,
21 struct inode **res_ino, struct hgfs_attr *attr) );
23 /*===========================================================================*
24 * get_mask *
25 *===========================================================================*/
26 PRIVATE int get_mask(ucred)
27 vfs_ucred_t *ucred; /* credentials of the caller */
29 /* Given the caller's credentials, precompute a search access mask to test
30 * against directory modes.
32 int i;
34 if (ucred->vu_uid == opt.uid) return S_IXUSR;
36 if (ucred->vu_gid == opt.gid) return S_IXGRP;
38 for (i = 0; i < ucred->vu_ngroups; i++)
39 if (ucred->vu_sgroups[i] == opt.gid) return S_IXGRP;
41 return S_IXOTH;
44 /*===========================================================================*
45 * access_as_dir *
46 *===========================================================================*/
47 PRIVATE int access_as_dir(ino, attr, uid, mask)
48 struct inode *ino; /* the inode to test */
49 struct hgfs_attr *attr; /* attributes of the inode */
50 int uid; /* UID of the caller */
51 int mask; /* search access mask of the caller */
53 /* Check whether the given inode may be accessed as directory.
54 * Return OK or an appropriate error code.
56 mode_t mode;
58 assert(attr->a_mask & HGFS_ATTR_MODE);
60 /* The inode must be a directory to begin with. */
61 if (!IS_DIR(ino)) return ENOTDIR;
63 /* The caller must have search access to the directory. Root always does. */
64 if (uid == 0) return OK;
66 mode = get_mode(ino, attr->a_mode);
68 return (mode & mask) ? OK : EACCES;
71 /*===========================================================================*
72 * next_name *
73 *===========================================================================*/
74 PRIVATE int next_name(ptr, start, name)
75 char **ptr; /* cursor pointer into path (in, out) */
76 char **start; /* place to store start of name */
77 char name[NAME_MAX+1]; /* place to store name */
79 /* Get the next path component from a path.
81 char *p;
82 int i;
84 for (p = *ptr; *p == '/'; p++);
86 *start = p;
88 if (*p) {
89 for (i = 0; *p && *p != '/' && i <= NAME_MAX; p++, i++)
90 name[i] = *p;
92 if (i > NAME_MAX)
93 return ENAMETOOLONG;
95 name[i] = 0;
96 } else {
97 strcpy(name, ".");
100 *ptr = p;
101 return OK;
104 /*===========================================================================*
105 * go_up *
106 *===========================================================================*/
107 PRIVATE int go_up(path, ino, res_ino, attr)
108 char path[PATH_MAX]; /* path to take the last part from */
109 struct inode *ino; /* inode of the current directory */
110 struct inode **res_ino; /* place to store resulting inode */
111 struct hgfs_attr *attr; /* place to store inode attributes */
113 /* Given an inode, progress into the parent directory.
115 struct inode *parent;
116 int r;
118 pop_path(path);
120 parent = ino->i_parent;
121 assert(parent != NULL);
123 if ((r = verify_path(path, parent, attr, NULL)) != OK)
124 return r;
126 get_inode(parent);
128 *res_ino = parent;
130 return r;
133 /*===========================================================================*
134 * go_down *
135 *===========================================================================*/
136 PRIVATE int go_down(path, parent, name, res_ino, attr)
137 char path[PATH_MAX]; /* path to add the name to */
138 struct inode *parent; /* inode of the current directory */
139 char *name; /* name of the directory entry */
140 struct inode **res_ino; /* place to store resulting inode */
141 struct hgfs_attr *attr; /* place to store inode attributes */
143 /* Given a directory inode and a name, progress into a directory entry.
145 struct inode *ino;
146 int r, stale = 0;
148 if ((r = push_path(path, name)) != OK)
149 return r;
151 dprintf(("HGFS: go_down: name '%s', path now '%s'\n", name, path));
153 ino = lookup_dentry(parent, name);
155 dprintf(("HGFS: lookup_dentry('%s') returned %p\n", name, ino));
157 if (ino != NULL)
158 r = verify_path(path, ino, attr, &stale);
159 else
160 r = hgfs_getattr(path, attr);
162 dprintf(("HGFS: path query returned %d\n", r));
164 if (r != OK) {
165 if (ino != NULL) {
166 put_inode(ino);
168 ino = NULL;
171 if (!stale)
172 return r;
175 dprintf(("HGFS: name '%s'\n", name));
177 if (ino == NULL) {
178 if ((ino = get_free_inode()) == NULL)
179 return ENFILE;
181 dprintf(("HGFS: inode %p ref %d\n", ino, ino->i_ref));
183 ino->i_flags = MODE_TO_DIRFLAG(attr->a_mode);
185 add_dentry(parent, name, ino);
188 *res_ino = ino;
189 return OK;
192 /*===========================================================================*
193 * do_lookup *
194 *===========================================================================*/
195 PUBLIC int do_lookup()
197 /* Resolve a path string to an inode.
199 ino_t dir_ino_nr, root_ino_nr;
200 struct inode *cur_ino, *root_ino;
201 struct inode *next_ino = NULL;
202 struct hgfs_attr attr;
203 char buf[PATH_MAX], path[PATH_MAX];
204 char name[NAME_MAX+1];
205 char *ptr, *last;
206 vfs_ucred_t ucred;
207 mode_t mask;
208 size_t len;
209 int r;
211 dir_ino_nr = m_in.REQ_DIR_INO;
212 root_ino_nr = m_in.REQ_ROOT_INO;
213 len = m_in.REQ_PATH_LEN;
215 /* Fetch the path name. */
216 if (len < 1 || len > PATH_MAX)
217 return EINVAL;
219 r = sys_safecopyfrom(m_in.m_source, m_in.REQ_GRANT, 0,
220 (vir_bytes) buf, len, D);
222 if (r != OK)
223 return r;
225 if (buf[len-1] != 0) {
226 printf("HGFS: VFS did not zero-terminate path!\n");
228 return EINVAL;
231 /* Fetch the credentials, and generate a search access mask to test against
232 * directory modes.
234 if (m_in.REQ_FLAGS & PATH_GET_UCRED) {
235 if (m_in.REQ_UCRED_SIZE != sizeof(ucred)) {
236 printf("HGFS: bad credential structure size\n");
238 return EINVAL;
241 r = sys_safecopyfrom(m_in.m_source, m_in.REQ_GRANT2, 0,
242 (vir_bytes) &ucred, m_in.REQ_UCRED_SIZE, D);
244 if (r != OK)
245 return r;
247 else {
248 ucred.vu_uid = m_in.REQ_UID;
249 ucred.vu_gid = m_in.REQ_GID;
250 ucred.vu_ngroups = 0;
253 mask = get_mask(&ucred);
255 /* Start the actual lookup. */
256 dprintf(("HGFS: lookup: got query '%s'\n", buf));
258 if ((cur_ino = find_inode(dir_ino_nr)) == NULL)
259 return EINVAL;
261 attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE;
263 if ((r = verify_inode(cur_ino, path, &attr)) != OK)
264 return r;
266 get_inode(cur_ino);
268 if (root_ino_nr > 0)
269 root_ino = find_inode(root_ino_nr);
270 else
271 root_ino = NULL;
273 /* One possible optimization would be to check a path only right before the
274 * first ".." in a row, and at the very end (if still necessary). This would
275 * have consequences for inode validation, though.
277 for (ptr = last = buf; *ptr != 0; ) {
278 if ((r = access_as_dir(cur_ino, &attr, ucred.vu_uid, mask)) != OK)
279 break;
281 if ((r = next_name(&ptr, &last, name)) != OK)
282 break;
284 dprintf(("HGFS: lookup: next name '%s'\n", name));
286 if (!strcmp(name, ".") ||
287 (cur_ino == root_ino && !strcmp(name, "..")))
288 continue;
290 if (!strcmp(name, "..")) {
291 if (IS_ROOT(cur_ino))
292 r = ELEAVEMOUNT;
293 else
294 r = go_up(path, cur_ino, &next_ino, &attr);
295 } else {
296 r = go_down(path, cur_ino, name, &next_ino, &attr);
299 if (r != OK)
300 break;
302 assert(next_ino != NULL);
304 put_inode(cur_ino);
306 cur_ino = next_ino;
309 dprintf(("HGFS: lookup: result %d\n", r));
311 if (r != OK) {
312 put_inode(cur_ino);
314 /* We'd need support for these here. We don't have such support. */
315 assert(r != EENTERMOUNT && r != ESYMLINK);
317 if (r == ELEAVEMOUNT) {
318 m_out.RES_OFFSET = (int) (last - buf);
319 m_out.RES_SYMLOOP = 0;
322 return r;
325 m_out.RES_INODE_NR = INODE_NR(cur_ino);
326 m_out.RES_MODE = get_mode(cur_ino, attr.a_mode);
327 m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
328 m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
329 m_out.RES_UID = opt.uid;
330 m_out.RES_GID = opt.gid;
331 m_out.RES_DEV = NO_DEV;
333 return OK;