add swifi to the build/install.
[minix.git] / servers / vfs / path.c
blob3c36ad1e89761b330857f4d4d71509faa52c8df7
1 /* lookup() is the main routine that controls the path name lookup. It
2 * handles mountpoints and symbolic links. The actual lookup requests
3 * are sent through the req_lookup wrapper function.
4 */
6 #include "fs.h"
7 #include <string.h>
8 #include <minix/callnr.h>
9 #include <minix/com.h>
10 #include <minix/keymap.h>
11 #include <minix/const.h>
12 #include <minix/endpoint.h>
13 #include <unistd.h>
14 #include <minix/vfsif.h>
15 #include "fproc.h"
16 #include "vmnt.h"
17 #include "vnode.h"
18 #include "param.h"
20 /* Set to following define to 1 if you really want to use the POSIX definition
21 * (IEEE Std 1003.1, 2004) of pathname resolution. POSIX requires pathnames
22 * with a traling slash (and that do not entirely consist of slash characters)
23 * to be treated as if a single dot is appended. This means that for example
24 * mkdir("dir/", ...) and rmdir("dir/") will fail because the call tries to
25 * create or remove the directory '.'. Historically, Unix systems just ignore
26 * trailing slashes.
28 #define DO_POSIX_PATHNAME_RES 0
30 FORWARD _PROTOTYPE( int lookup, (struct vnode *dirp, int flags,
31 node_details_t *node) );
33 /*===========================================================================*
34 * advance *
35 *===========================================================================*/
36 PUBLIC struct vnode *advance(dirp, flags)
37 struct vnode *dirp;
38 int flags;
40 /* Resolve a pathname (in user_fullpath) starting at dirp to a vnode. */
41 int r;
42 struct vnode *new_vp, *vp;
43 struct vmnt *vmp;
44 struct node_details res;
46 /* Get a free vnode */
47 if((new_vp = get_free_vnode()) == NIL_VNODE) return(NIL_VNODE);
49 /* Lookup vnode belonging to the file. */
50 if ((r = lookup(dirp, flags, &res)) != OK) {
51 err_code = r;
52 return(NIL_VNODE);
55 /* Check whether vnode is already in use or not */
56 if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) {
57 dup_vnode(vp);
58 vp->v_fs_count++; /* We got a reference from the FS */
59 return(vp);
62 /* Fill in the free vnode's fields */
63 new_vp->v_fs_e = res.fs_e;
64 new_vp->v_inode_nr = res.inode_nr;
65 new_vp->v_mode = res.fmode;
66 new_vp->v_size = res.fsize;
67 new_vp->v_uid = res.uid;
68 new_vp->v_gid = res.gid;
69 new_vp->v_sdev = res.dev;
71 if( (vmp = find_vmnt(new_vp->v_fs_e)) == NIL_VMNT)
72 panic(__FILE__, "VFS advance: vmnt not found", NO_NUM);
74 new_vp->v_vmnt = vmp;
75 new_vp->v_dev = vmp->m_dev;
76 new_vp->v_fs_count = 1;
77 new_vp->v_ref_count = 1;
79 return(new_vp);
83 /*===========================================================================*
84 * eat_path *
85 *===========================================================================*/
86 PUBLIC struct vnode *eat_path(flags)
87 int flags;
89 /* Resolve 'user_fullpath' to a vnode. advance does the actual work. */
90 struct vnode *vp;
92 vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd);
93 return advance(vp, flags);
97 /*===========================================================================*
98 * last_dir *
99 *===========================================================================*/
100 PUBLIC struct vnode *last_dir(void)
102 /* Parse a path, 'user_fullpath', as far as the last directory, fetch the vnode
103 * for the last directory into the vnode table, and return a pointer to the
104 * vnode. In addition, return the final component of the path in 'string'. If
105 * the last directory can't be opened, return NIL_VNODE and the reason for
106 * failure in 'err_code'. We can't parse component by component as that would
107 * be too expensive. Alternatively, we cut off the last component of the path,
108 * and parse the path up to the penultimate component.
111 int r;
112 size_t len;
113 char *cp;
114 char dir_entry[PATH_MAX+1];
115 struct vnode *vp, *res;
117 /* Is the path absolute or relative? Initialize 'vp' accordingly. */
118 vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd);
120 len = strlen(user_fullpath);
122 /* If path is empty, return ENOENT. */
123 if (len == 0) {
124 err_code = ENOENT;
125 return(NIL_VNODE);
128 #if !DO_POSIX_PATHNAME_RES
129 /* Remove trailing slashes */
130 while (len > 1 && user_fullpath[len-1] == '/') {
131 len--;
132 user_fullpath[len]= '\0';
134 #endif
136 cp = strrchr(user_fullpath, '/');
137 if (cp == NULL) {
138 /* Just one entry in the current working directory */
139 dup_vnode(vp);
140 return(vp);
141 } else if (cp[1] == '\0') {
142 /* Path ends in a slash. The directory entry is '.' */
143 strcpy(dir_entry, ".");
144 } else {
145 /* A path name for the directory and a directory entry */
146 strcpy(dir_entry, cp+1);
147 cp[1]= '\0';
150 /* Remove trailing slashes */
151 while(cp > user_fullpath && cp[0] == '/') {
152 cp[0]= '\0';
153 cp--;
156 res = advance(vp, PATH_NOFLAGS);
157 if (res == NIL_VNODE) return(NIL_VNODE);
159 /* Copy the directory entry back to user_fullpath */
160 strcpy(user_fullpath, dir_entry);
162 return(res);
166 /*===========================================================================*
167 * lookup *
168 *===========================================================================*/
169 PRIVATE int lookup(start_node, flags, node)
170 struct vnode *start_node;
171 int flags;
172 node_details_t *node;
174 /* Resolve a pathname (in user_fullpath) relative to start_node. */
176 int r, symloop;
177 endpoint_t fs_e;
178 size_t path_off, path_left_len;
179 ino_t dir_ino, root_ino;
180 uid_t uid;
181 gid_t gid;
182 struct vnode *dir_vp;
183 struct vmnt *vmp;
184 struct lookup_res res;
186 /* Empty (start) path? */
187 if (user_fullpath[0] == '\0') {
188 node->inode_nr = 0;
189 return(ENOENT);
192 if(!fp->fp_rd || !fp->fp_wd) {
193 printf("VFS: lookup_rel %d: no rd/wd\n", fp->fp_endpoint);
194 return(ENOENT);
197 fs_e = start_node->v_fs_e;
198 dir_ino = start_node->v_inode_nr;
200 /* Is the process' root directory on the same partition?,
201 * if so, set the chroot directory too. */
202 if (fp->fp_rd->v_dev == fp->fp_wd->v_dev)
203 root_ino = fp->fp_rd->v_inode_nr;
204 else
205 root_ino = 0;
207 /* Set user and group ids according to the system call */
208 uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
209 gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
211 symloop = 0; /* Number of symlinks seen so far */
213 /* Issue the request */
214 r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res);
216 if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK)
217 return(r); /* i.e., an error occured */
219 /* While the response is related to mount control set the
220 * new requests respectively */
221 while(r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) {
222 /* Update user_fullpath to reflect what's left to be parsed. */
223 path_off = res.char_processed;
224 path_left_len = strlen(&user_fullpath[path_off]);
225 memmove(user_fullpath, &user_fullpath[path_off], path_left_len);
226 user_fullpath[path_left_len] = '\0'; /* terminate string */
228 /* Update the current value of the symloop counter */
229 symloop += res.symloop;
230 if (symloop > SYMLOOP_MAX)
231 return(ELOOP);
233 /* Symlink encountered with absolute path */
234 if (r == ESYMLINK) {
235 dir_vp = fp->fp_rd;
236 } else if (r == EENTERMOUNT) {
237 /* Entering a new partition */
238 dir_vp = 0;
239 /* Start node is now the mounted partition's root node */
240 for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) {
241 if (vmp->m_dev != NO_DEV) {
242 if (vmp->m_mounted_on->v_inode_nr == res.inode_nr &&
243 vmp->m_mounted_on->v_fs_e == res.fs_e) {
244 dir_vp = vmp->m_root_node;
245 break;
250 if (!dir_vp) {
251 panic(__FILE__,
252 "VFS lookup: can't find mounted partition",
253 NO_NUM);
255 } else {
256 /* Climbing up mount */
257 /* Find the vmnt that represents the partition on
258 * which we "climb up". */
259 if ((vmp = find_vmnt(res.fs_e)) == NIL_VMNT) {
260 panic(__FILE__,
261 "VFS lookup: can't find parent vmnt",NO_NUM);
264 /* Make sure that the child FS does not feed a bogus path
265 * to the parent FS. That is, when we climb up the tree, we
266 * must've encountered ".." in the path, and that is exactly
267 * what we're going to feed to the parent */
268 if(strncmp(user_fullpath, "..", 2) != 0) {
269 printf("VFS: bogus path: %s\n", user_fullpath);
270 return(ENOENT);
273 /* Start node is the vnode on which the partition is
274 * mounted */
275 dir_vp = vmp->m_mounted_on;
278 /* Set the starting directories inode number and FS endpoint */
279 fs_e = dir_vp->v_fs_e;
280 dir_ino = dir_vp->v_inode_nr;
282 /* Is the process' root directory on the same partition?,
283 * if so, set the chroot directory too. */
284 if(dir_vp->v_dev == fp->fp_rd->v_dev)
285 root_ino = fp->fp_rd->v_inode_nr;
286 else
287 root_ino = 0;
289 r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res);
291 if(r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK)
292 return(r);
295 /* Fill in response fields */
296 node->inode_nr = res.inode_nr;
297 node->fmode = res.fmode;
298 node->fsize = res.fsize;
299 node->dev = res.dev;
300 node->fs_e = res.fs_e;
301 node->uid = res.uid;
302 node->gid = res.gid;
304 return(r);