summaryrefslogtreecommitdiff
path: root/minix/lib/libsffs/lookup.c
blob: fbc786b080be2c9dad1eebc0fad601c9136731b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* 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 = NULL;
  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;
}