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 static int get_mask(vfs_ucred_t
*ucred
);
13 static int access_as_dir(struct inode
*ino
, struct sffs_attr
*attr
, int
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 /*===========================================================================*
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.
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
;
42 /*===========================================================================*
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.
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 /*===========================================================================*
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.
82 for (p
= *ptr
; *p
== '/'; p
++);
87 for (i
= 0; *p
&& *p
!= '/' && i
<= NAME_MAX
; p
++, i
++)
102 /*===========================================================================*
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
;
118 parent
= ino
->i_parent
;
119 assert(parent
!= NULL
);
121 if ((r
= verify_path(path
, parent
, attr
, NULL
)) != OK
)
131 /*===========================================================================*
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.
146 if ((r
= push_path(path
, name
)) != OK
)
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
));
156 r
= verify_path(path
, ino
, attr
, &stale
);
158 r
= sffs_table
->t_getattr(path
, attr
);
160 dprintf(("%s: path query returned %d\n", sffs_name
, r
));
173 dprintf(("%s: name '%s'\n", sffs_name
, name
));
176 if ((ino
= get_free_inode()) == NULL
)
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
);
190 /*===========================================================================*
192 *===========================================================================*/
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];
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
)
217 r
= sys_safecopyfrom(m_in
.m_source
, m_in
.REQ_GRANT
, 0,
218 (vir_bytes
) buf
, len
);
223 if (buf
[len
-1] != 0) {
224 printf("%s: VFS did not zero-terminate path!\n", sffs_name
);
229 /* Fetch the credentials, and generate a search access mask to test against
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
);
239 r
= sys_safecopyfrom(m_in
.m_source
, m_in
.REQ_GRANT2
, 0,
240 (vir_bytes
) &ucred
, m_in
.REQ_UCRED_SIZE
);
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
)
259 attr
.a_mask
= SFFS_ATTR_MODE
| SFFS_ATTR_SIZE
;
261 if ((r
= verify_inode(cur_ino
, path
, &attr
)) != OK
)
267 root_ino
= find_inode(root_ino_nr
);
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
)
279 if ((r
= next_name(&ptr
, &last
, name
)) != OK
)
282 dprintf(("%s: lookup: next name '%s'\n", sffs_name
, name
));
284 if (!strcmp(name
, ".") ||
285 (cur_ino
== root_ino
&& !strcmp(name
, "..")))
288 if (!strcmp(name
, "..")) {
289 if (IS_ROOT(cur_ino
))
292 r
= go_up(path
, cur_ino
, &next_ino
, &attr
);
294 r
= go_down(path
, cur_ino
, name
, &next_ino
, &attr
);
300 assert(next_ino
!= NULL
);
307 dprintf(("%s: lookup: result %d\n", sffs_name
, r
));
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;
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
;