449 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /* 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 <string.h>
 | |
| #include <minix/callnr.h>
 | |
| #include <minix/com.h>
 | |
| #include <minix/keymap.h>
 | |
| #include <minix/const.h>
 | |
| #include <minix/endpoint.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <minix/vfsif.h>
 | |
| #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;
 | |
| }
 | |
| 
 | 
