151 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* This file provides path-to-inode lookup functionality.
 | 
						|
 *
 | 
						|
 * The entry points into this file are:
 | 
						|
 *   do_lookup		perform the LOOKUP file system call
 | 
						|
 *
 | 
						|
 * Created:
 | 
						|
 *   April 2009 (D.C. van Moolenbroek)
 | 
						|
 */
 | 
						|
 | 
						|
#include "inc.h"
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				go_up					     *
 | 
						|
 *===========================================================================*/
 | 
						|
static int go_up(
 | 
						|
	char path[PATH_MAX],    /* path to take the last part from */
 | 
						|
	struct inode *ino,      /* inode of the current directory */
 | 
						|
	struct inode **res_ino, /* place to store resulting inode */
 | 
						|
	struct sffs_attr *attr  /* place to store inode attributes */
 | 
						|
)
 | 
						|
{
 | 
						|
/* Given an inode, progress into the parent directory.
 | 
						|
 */
 | 
						|
  struct inode *parent;
 | 
						|
  int r;
 | 
						|
 | 
						|
  pop_path(path);
 | 
						|
 | 
						|
  parent = ino->i_parent;
 | 
						|
  assert(parent != NULL);
 | 
						|
 | 
						|
  if ((r = verify_path(path, parent, attr, NULL)) != OK)
 | 
						|
	return r;
 | 
						|
 | 
						|
  get_inode(parent);
 | 
						|
 | 
						|
  *res_ino = parent;
 | 
						|
 | 
						|
  return r;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				go_down					     *
 | 
						|
 *===========================================================================*/
 | 
						|
static int go_down(
 | 
						|
	char path[PATH_MAX],    /* path to add the name to */
 | 
						|
	struct inode *parent,   /* inode of the current directory */
 | 
						|
	char *name,             /* name of the directory entry */
 | 
						|
	struct inode **res_ino, /* place to store resulting inode */
 | 
						|
	struct sffs_attr *attr  /* place to store inode attributes */
 | 
						|
)
 | 
						|
{
 | 
						|
/* Given a directory inode and a name, progress into a directory entry.
 | 
						|
 */
 | 
						|
  struct inode *ino;
 | 
						|
  int r, stale = 0;
 | 
						|
 | 
						|
  if ((r = push_path(path, name)) != OK)
 | 
						|
	return r;
 | 
						|
 | 
						|
  dprintf(("%s: go_down: name '%s', path now '%s'\n", sffs_name, name, path));
 | 
						|
 | 
						|
  ino = lookup_dentry(parent, name);
 | 
						|
 | 
						|
  dprintf(("%s: lookup_dentry('%s') returned %p\n", sffs_name, name, ino));
 | 
						|
 | 
						|
  if (ino != NULL)
 | 
						|
	r = verify_path(path, ino, attr, &stale);
 | 
						|
  else
 | 
						|
	r = sffs_table->t_getattr(path, attr);
 | 
						|
 | 
						|
  dprintf(("%s: path query returned %d\n", sffs_name, r));
 | 
						|
 | 
						|
  if (r != OK) {
 | 
						|
	if (ino != NULL) {
 | 
						|
		put_inode(ino);
 | 
						|
 | 
						|
		ino = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!stale)
 | 
						|
		return r;
 | 
						|
  }
 | 
						|
 | 
						|
  dprintf(("%s: name '%s'\n", sffs_name, name));
 | 
						|
 | 
						|
  if (ino == NULL) {
 | 
						|
	if ((ino = get_free_inode()) == NULL)
 | 
						|
		return ENFILE;
 | 
						|
 | 
						|
	dprintf(("%s: inode %p ref %d\n", sffs_name, ino, ino->i_ref));
 | 
						|
 | 
						|
	ino->i_flags = MODE_TO_DIRFLAG(attr->a_mode);
 | 
						|
 | 
						|
	add_dentry(parent, name, ino);
 | 
						|
  }
 | 
						|
 | 
						|
  *res_ino = ino;
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_lookup				     *
 | 
						|
 *===========================================================================*/
 | 
						|
int do_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
 | 
						|
	int *is_mountpt)
 | 
						|
{
 | 
						|
/* Resolve a path string to an inode.
 | 
						|
 */
 | 
						|
  struct inode *dir_ino, *ino;
 | 
						|
  struct sffs_attr attr;
 | 
						|
  char path[PATH_MAX];
 | 
						|
  int r;
 | 
						|
 | 
						|
  dprintf(("%s: lookup: got query for %"PRIu64", '%s'\n",
 | 
						|
	sffs_name, dir_nr, name));
 | 
						|
 | 
						|
  if ((dir_ino = find_inode(dir_nr)) == NULL)
 | 
						|
	return EINVAL;
 | 
						|
 | 
						|
  attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
 | 
						|
 | 
						|
  if ((r = verify_inode(dir_ino, path, &attr)) != OK)
 | 
						|
	return r;
 | 
						|
 | 
						|
  if (!IS_DIR(dir_ino))
 | 
						|
	return ENOTDIR;
 | 
						|
 | 
						|
  r = OK;
 | 
						|
  if (!strcmp(name, "."))
 | 
						|
	get_inode(ino = dir_ino);
 | 
						|
  else if (!strcmp(name, ".."))
 | 
						|
	r = go_up(path, dir_ino, &ino, &attr);
 | 
						|
  else
 | 
						|
	r = go_down(path, dir_ino, name, &ino, &attr);
 | 
						|
 | 
						|
  if (r != OK)
 | 
						|
	return r;
 | 
						|
 | 
						|
  node->fn_ino_nr = INODE_NR(ino);
 | 
						|
  node->fn_mode = get_mode(ino, attr.a_mode);
 | 
						|
  node->fn_size = attr.a_size;
 | 
						|
  node->fn_uid = sffs_params->p_uid;
 | 
						|
  node->fn_gid = sffs_params->p_gid;
 | 
						|
  node->fn_dev = NO_DEV;
 | 
						|
 | 
						|
  *is_mountpt = FALSE;
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 |