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
7 * April 2009 (D.C. van Moolenbroek)
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 /*===========================================================================*
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.
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
;
44 /*===========================================================================*
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.
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 /*===========================================================================*
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.
84 for (p
= *ptr
; *p
== '/'; p
++);
89 for (i
= 0; *p
&& *p
!= '/' && i
<= NAME_MAX
; p
++, i
++)
104 /*===========================================================================*
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
;
120 parent
= ino
->i_parent
;
121 assert(parent
!= NULL
);
123 if ((r
= verify_path(path
, parent
, attr
, NULL
)) != OK
)
133 /*===========================================================================*
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.
148 if ((r
= push_path(path
, name
)) != OK
)
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
));
158 r
= verify_path(path
, ino
, attr
, &stale
);
160 r
= hgfs_getattr(path
, attr
);
162 dprintf(("HGFS: path query returned %d\n", r
));
175 dprintf(("HGFS: name '%s'\n", name
));
178 if ((ino
= get_free_inode()) == NULL
)
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
);
192 /*===========================================================================*
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];
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
)
219 r
= sys_safecopyfrom(m_in
.m_source
, m_in
.REQ_GRANT
, 0,
220 (vir_bytes
) buf
, len
, D
);
225 if (buf
[len
-1] != 0) {
226 printf("HGFS: VFS did not zero-terminate path!\n");
231 /* Fetch the credentials, and generate a search access mask to test against
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");
241 r
= sys_safecopyfrom(m_in
.m_source
, m_in
.REQ_GRANT2
, 0,
242 (vir_bytes
) &ucred
, m_in
.REQ_UCRED_SIZE
, D
);
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
)
261 attr
.a_mask
= HGFS_ATTR_MODE
| HGFS_ATTR_SIZE
;
263 if ((r
= verify_inode(cur_ino
, path
, &attr
)) != OK
)
269 root_ino
= find_inode(root_ino_nr
);
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
)
281 if ((r
= next_name(&ptr
, &last
, name
)) != OK
)
284 dprintf(("HGFS: lookup: next name '%s'\n", name
));
286 if (!strcmp(name
, ".") ||
287 (cur_ino
== root_ino
&& !strcmp(name
, "..")))
290 if (!strcmp(name
, "..")) {
291 if (IS_ROOT(cur_ino
))
294 r
= go_up(path
, cur_ino
, &next_ino
, &attr
);
296 r
= go_down(path
, cur_ino
, name
, &next_ino
, &attr
);
302 assert(next_ino
!= NULL
);
309 dprintf(("HGFS: lookup: result %d\n", r
));
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;
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
;