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.
8 #include <minix/callnr.h>
10 #include <minix/keymap.h>
11 #include <minix/const.h>
12 #include <minix/endpoint.h>
14 #include <minix/vfsif.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
28 #define DO_POSIX_PATHNAME_RES 0
30 FORWARD
_PROTOTYPE( int lookup
, (struct vnode
*dirp
, int flags
,
31 node_details_t
*node
) );
33 /*===========================================================================*
35 *===========================================================================*/
36 PUBLIC
struct vnode
*advance(dirp
, flags
)
40 /* Resolve a pathname (in user_fullpath) starting at dirp to a vnode. */
42 struct vnode
*new_vp
, *vp
;
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
) {
55 /* Check whether vnode is already in use or not */
56 if ((vp
= find_vnode(res
.fs_e
, res
.inode_nr
)) != NIL_VNODE
) {
58 vp
->v_fs_count
++; /* We got a reference from the FS */
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
);
75 new_vp
->v_dev
= vmp
->m_dev
;
76 new_vp
->v_fs_count
= 1;
77 new_vp
->v_ref_count
= 1;
83 /*===========================================================================*
85 *===========================================================================*/
86 PUBLIC
struct vnode
*eat_path(flags
)
89 /* Resolve 'user_fullpath' to a vnode. advance does the actual work. */
92 vp
= (user_fullpath
[0] == '/' ? fp
->fp_rd
: fp
->fp_wd
);
93 return advance(vp
, flags
);
97 /*===========================================================================*
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.
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. */
128 #if !DO_POSIX_PATHNAME_RES
129 /* Remove trailing slashes */
130 while (len
> 1 && user_fullpath
[len
-1] == '/') {
132 user_fullpath
[len
]= '\0';
136 cp
= strrchr(user_fullpath
, '/');
138 /* Just one entry in the current working directory */
141 } else if (cp
[1] == '\0') {
142 /* Path ends in a slash. The directory entry is '.' */
143 strcpy(dir_entry
, ".");
145 /* A path name for the directory and a directory entry */
146 strcpy(dir_entry
, cp
+1);
150 /* Remove trailing slashes */
151 while(cp
> user_fullpath
&& cp
[0] == '/') {
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
);
166 /*===========================================================================*
168 *===========================================================================*/
169 PRIVATE
int lookup(start_node
, flags
, node
)
170 struct vnode
*start_node
;
172 node_details_t
*node
;
174 /* Resolve a pathname (in user_fullpath) relative to start_node. */
178 size_t path_off
, path_left_len
;
179 ino_t dir_ino
, root_ino
;
182 struct vnode
*dir_vp
;
184 struct lookup_res res
;
186 /* Empty (start) path? */
187 if (user_fullpath
[0] == '\0') {
192 if(!fp
->fp_rd
|| !fp
->fp_wd
) {
193 printf("VFS: lookup_rel %d: no rd/wd\n", fp
->fp_endpoint
);
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
;
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
)
233 /* Symlink encountered with absolute path */
236 } else if (r
== EENTERMOUNT
) {
237 /* Entering a new partition */
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
;
252 "VFS lookup: can't find mounted partition",
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
) {
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
);
273 /* Start node is the vnode on which the partition is
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
;
289 r
= req_lookup(fs_e
, dir_ino
, root_ino
, uid
, gid
, flags
, &res
);
291 if(r
!= OK
&& r
!= EENTERMOUNT
&& r
!= ELEAVEMOUNT
&& r
!= ESYMLINK
)
295 /* Fill in response fields */
296 node
->inode_nr
= res
.inode_nr
;
297 node
->fmode
= res
.fmode
;
298 node
->fsize
= res
.fsize
;
300 node
->fs_e
= res
.fs_e
;