/* lookup() is the main routine that controls the path name lookup. It * handles mountpoints and symbolic links. The actual lookup requests * are sent through the req_lookup wrapper function. * * Jul 2006 (Balazs Gerofi) */ #include "fs.h" #include #include #include #include #include #include #include #include #include "fproc.h" #include "vmnt.h" #include "vnode.h" #include "param.h" FORWARD _PROTOTYPE( int Xlookup, (lookup_req_t *lookup_req, node_details_t *node, char **pathrem) ); /*===========================================================================* * lookup * *===========================================================================*/ PUBLIC int lookup(lookup_req, node) lookup_req_t *lookup_req; node_details_t *node; { struct vmnt *vmp; struct vnode *start_node; struct lookup_res res; int r, symloop = 0; int cum_path_processed = 0; /* Make a copy of the request so that the original values will be kept */ struct lookup_req req = *lookup_req; char *fullpath = lookup_req->path; /* Empty (start) path? */ if (fullpath[0] == '\0') { node->inode_nr = 0; return ENOENT; } /* Set user and group ids according to the system call */ req.uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid); req.gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid); /* Set the starting directories inode number and FS endpoint */ start_node = (fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); req.start_dir = start_node->v_inode_nr; req.fs_e = start_node->v_fs_e; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ if (fp->fp_rd->v_dev == fp->fp_wd->v_dev) req.root_dir = fp->fp_rd->v_inode_nr; else req.root_dir = 0; req.symloop = symloop; /* Issue the request */ r = req_lookup(&req, &res); /* While the response is related to mount control set the * new requests respectively */ while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) { /* If a symlink was encountered during the lookup the * new path has been copied back and the number of characters * processed has been started over. */ if (r == ESYMLINK || res.symloop > symloop) { /* The link's content is copied back to the user_fullpath * array. Use it as the path argument from now on... */ fullpath = user_fullpath; cum_path_processed = res.char_processed; } else { /* Otherwise, cumulate the characters already processsed from * the path */ cum_path_processed += res.char_processed; } /* Remember the current value of the symloop counter */ symloop = res.symloop; /* Symlink encountered with absolute path */ if (r == ESYMLINK) { start_node = fp->fp_rd; } /* Entering a new partition */ else if (r == EENTERMOUNT) { start_node = 0; /* Start node is now the mounted partition's root node */ for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) { if (vmp->m_mounted_on->v_inode_nr == res.inode_nr && vmp->m_mounted_on->v_fs_e == res.fs_e) { start_node = vmp->m_root_node; break; } } if (!start_node) { printf("VFSlookup: mounted partition couldn't be found\n"); printf("VFSlookup: res.inode_nr = %d, res.fs_e = %d\n", res.inode_nr, res.fs_e); return ENOENT; } } /* Climbing up mount */ else { /* Find the vmnt that represents the partition on * which we "climb up". */ if ((vmp = find_vmnt(res.fs_e)) == NIL_VMNT) { printf("VFS: couldn't find vmnt during the climbup!\n"); return ENOENT; } /* Start node is the vnode on which the partition is * mounted */ start_node = vmp->m_mounted_on; } /* Fill in the request fields */ req.start_dir = start_node->v_inode_nr; req.fs_e = start_node->v_fs_e; /* Is the process' root directory on the same partition?*/ if (start_node->v_dev == fp->fp_rd->v_dev) req.root_dir = fp->fp_rd->v_inode_nr; else req.root_dir = 0; /* Fill in the current path name */ req.path = &fullpath[cum_path_processed]; req.symloop = symloop; /* Issue the request */ r = req_lookup(&req, &res); } /* Fill in response fields */ node->inode_nr = res.inode_nr; node->fmode = res.fmode; node->fsize = res.fsize; node->dev = res.dev; node->fs_e = res.fs_e; node->uid = res.uid; node->gid = res.gid; return r; } /*===========================================================================* * Xlookup * *===========================================================================*/ PRIVATE int Xlookup(lookup_req, node, pathrem) lookup_req_t *lookup_req; node_details_t *node; char **pathrem; { struct vmnt *vmp; struct vnode *start_node; struct lookup_res res; int r, symloop = 0; int cum_path_processed = 0; /* Make a copy of the request so that the original values will be kept */ struct lookup_req req = *lookup_req; char *fullpath = lookup_req->path; /* Clear pathrem */ *pathrem= NULL; /* Empty (start) path? */ if (fullpath[0] == '\0') { node->inode_nr = 0; *pathrem = fullpath; return ENOENT; } /* Set user and group ids according to the system call */ req.uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid); req.gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid); /* Set the starting directories inode number and FS endpoint */ start_node = (fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); req.start_dir = start_node->v_inode_nr; req.fs_e = start_node->v_fs_e; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ if (fp->fp_rd->v_dev == fp->fp_wd->v_dev) req.root_dir = fp->fp_rd->v_inode_nr; else req.root_dir = 0; req.symloop = symloop; /* Issue the request */ r = req_lookup(&req, &res); /* While the response is related to mount control set the * new requests respectively */ while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) { /* If a symlink was encountered during the lookup the * new path has been copied back and the number of characters * processed has been started over. */ if (r == ESYMLINK || res.symloop > symloop) { /* The link's content is copied back to the user_fullpath * array. Use it as the path argument from now on... */ fullpath = user_fullpath; cum_path_processed = res.char_processed; } else { /* Otherwise, cumulate the characters already processsed from * the path */ cum_path_processed += res.char_processed; } /* Remember the current value of the symloop counter */ symloop = res.symloop; /* Symlink encountered with absolute path */ if (r == ESYMLINK) { start_node = fp->fp_rd; } /* Entering a new partition */ else if (r == EENTERMOUNT) { start_node = 0; /* Start node is now the mounted partition's root node */ for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) { if (vmp->m_mounted_on->v_inode_nr == res.inode_nr && vmp->m_mounted_on->v_fs_e == res.fs_e) { start_node = vmp->m_root_node; break; } } if (!start_node) { printf("VFSlookup: mounted partition couldn't be found\n"); printf("VFSlookup: res.inode_nr = %d, res.fs_e = %d\n", res.inode_nr, res.fs_e); return ENOENT; } } /* Climbing up mount */ else { /* Find the vmnt that represents the partition on * which we "climb up". */ if ((vmp = find_vmnt(res.fs_e)) == NIL_VMNT) { printf("VFS: couldn't find vmnt during the climbup!\n"); return ENOENT; } /* Start node is the vnode on which the partition is * mounted */ start_node = vmp->m_mounted_on; } /* Fill in the request fields */ req.start_dir = start_node->v_inode_nr; req.fs_e = start_node->v_fs_e; /* Is the process' root directory on the same partition?*/ if (start_node->v_dev == fp->fp_rd->v_dev) req.root_dir = fp->fp_rd->v_inode_nr; else req.root_dir = 0; /* Fill in the current path name */ req.path = &fullpath[cum_path_processed]; req.symloop = symloop; /* Issue the request */ r = req_lookup(&req, &res); } if (r == ENOENT) { cum_path_processed += res.char_processed; *pathrem= &fullpath[cum_path_processed]; } /* Fill in response fields */ node->inode_nr = res.inode_nr; node->fmode = res.fmode; node->fsize = res.fsize; node->dev = res.dev; node->fs_e = res.fs_e; node->uid = res.uid; node->gid = res.gid; return r; } /*===========================================================================* * lookup_vp * *===========================================================================*/ PUBLIC int lookup_vp(lookup_req, vpp) lookup_req_t *lookup_req; struct vnode **vpp; { int r, lookup_res; struct vnode *vp; struct vmnt *vmp; node_req_t node_req; struct node_details res; lookup_res = lookup(lookup_req, &res); if (res.inode_nr == 0) { #if 0 printf("lookup_vp: lookup returned no inode\n"); printf("lookup_res = %d, last = '%s'\n\n", lookup_res, lookup_req->lastc); #endif *vpp= NULL; return lookup_res; } /* Check whether vnode is already in use or not */ if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) { vp->v_ref_count++; *vpp= vp; return lookup_res; } /* See if free vnode is available */ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) { printf("VFS lookup_vp: no free vnode available\n"); *vpp= NULL; return EINVAL; } /* Fill in request message fields.*/ node_req.fs_e = res.fs_e; node_req.inode_nr = res.inode_nr; /* Issue request */ if ((r = req_getnode(&node_req, &res)) != OK) { printf("lookup_vp: req_getnode failed: %d\n", r); *vpp= NULL; return r; } /* Fill in the free vnode's fields */ vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_size = res.fsize; vp->v_uid = res.uid; vp->v_gid = res.gid; vp->v_sdev = res.dev; if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) panic(__FILE__, "lookup_vp: vmnt not found", NO_NUM); vp->v_vmnt = vmp; vp->v_dev = vmp->m_dev; vp->v_fs_count = 1; vp->v_ref_count = 1; *vpp= vp; return lookup_res; } /*===========================================================================* * Xlookup_vp * *===========================================================================*/ PUBLIC int Xlookup_vp(lookup_req, vpp, pathrem) lookup_req_t *lookup_req; struct vnode **vpp; char **pathrem; { int r, lookup_res; struct vnode *vp; struct vmnt *vmp; node_req_t node_req; struct node_details res; lookup_res = Xlookup(lookup_req, &res, pathrem); if (res.inode_nr == 0) { #if 0 printf("Xlookup_vp: lookup returned no inode\n"); printf("lookup_res = %d, last = '%s'\n\n", lookup_res, lookup_req->lastc); #endif *vpp= NULL; return lookup_res; } /* Check whether vnode is already in use or not */ if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NIL_VNODE) { vp->v_ref_count++; *vpp= vp; return lookup_res; } /* See if free vnode is available */ if ((vp = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) { printf("VFS Xlookup_vp: no free vnode available\n"); *vpp= NULL; return EINVAL; } /* Fill in request message fields.*/ node_req.fs_e = res.fs_e; node_req.inode_nr = res.inode_nr; /* Issue request */ if ((r = req_getnode(&node_req, &res)) != OK) { printf("Xlookup_vp: req_getnode failed: %d\n", r); *vpp= NULL; return r; } /* Fill in the free vnode's fields */ vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_size = res.fsize; vp->v_uid = res.uid; vp->v_gid = res.gid; vp->v_sdev = res.dev; if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT) panic(__FILE__, "Xlookup_vp: vmnt not found", NO_NUM); vp->v_vmnt = vmp; vp->v_dev = vmp->m_dev; vp->v_fs_count = 1; vp->v_ref_count = 1; *vpp= vp; return lookup_res; }