1 /*
2 * This file contains the procedures that look up path names in the directory
3 * system and determine the pnode number that goes with a given path name.
4 *
5 * Created (based on MFS):
6 * June 2011 (Evgeniy Ivanov)
7 */
8
9 #include "fs.h"
10
11 #include <sys/cdefs.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14
15 /*===========================================================================*
16 * fs_lookup *
17 *===========================================================================*/
fs_lookup(ino_t dir_nr,char * name,struct fsdriver_node * node,int * is_mountpt)18 int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
19 int *is_mountpt)
20 {
21 struct puffs_node *pn, *pn_dir;
22
23 /* Find the pnode of the directory node. */
24 if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL) {
25 lpuffs_debug("nodewalk failed\n");
26 return(EINVAL);
27 }
28
29 if (!S_ISDIR(pn_dir->pn_va.va_mode))
30 return ENOTDIR;
31
32 if ((pn = advance(pn_dir, name)) == NULL)
33 return err_code;
34
35 pn->pn_count++; /* open pnode */
36
37 node->fn_ino_nr = pn->pn_va.va_fileid;
38 node->fn_mode = pn->pn_va.va_mode;
39 node->fn_size = pn->pn_va.va_size;
40 node->fn_uid = pn->pn_va.va_uid;
41 node->fn_gid = pn->pn_va.va_gid;
42 node->fn_dev = pn->pn_va.va_rdev;
43
44 *is_mountpt = pn->pn_mountpoint;
45
46 return OK;
47 }
48
49
50 /*===========================================================================*
51 * advance *
52 *===========================================================================*/
advance(struct puffs_node * pn_dir,char string[NAME_MAX+1])53 struct puffs_node *advance(
54 struct puffs_node *pn_dir, /* pnode for directory to be searched */
55 char string[NAME_MAX + 1] /* component name to look for */
56 )
57 {
58 /* Given a directory and a component of a path, look up the component in
59 * the directory, find the pnode, open it, and return a pointer to its pnode
60 * slot.
61 * TODO: instead of string, should get pcn.
62 */
63 struct puffs_node *pn;
64
65 struct puffs_newinfo pni;
66
67 struct puffs_kcn pkcnp;
68 PUFFS_MAKECRED(pcr, &global_kcred);
69 struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
70
71 enum vtype node_vtype;
72 voff_t size;
73 dev_t rdev;
74 int error;
75
76 assert(pn_dir != NULL);
77
78 err_code = OK;
79
80 /* If 'string' is empty, return an error. */
81 if (string[0] == '\0') {
82 err_code = ENOENT;
83 return(NULL);
84 }
85
86 /* If dir has been removed return ENOENT. */
87 if (pn_dir->pn_va.va_nlink == NO_LINK) {
88 err_code = ENOENT;
89 return(NULL);
90 }
91
92 if (strcmp(string, ".") == 0) {
93 /* Otherwise we will fall into trouble: path for pnode to be looked up
94 * will be parent path (same pnode as the one to be looked up) +
95 * requested path. E.g. after several lookups we might get advance
96 * for "." with parent path "/././././././././.".
97 * FIXME: how is ".." handled then?
98 *
99 * Another problem is that after lookup pnode will be added
100 * to the pu_pnodelst, which already contains pnode instance for this
101 * pnode. It will cause lot of troubles.
102 * FIXME: check if this is actually correct, because if it is, we are
103 * in lots of trouble; there are many ways to reach already-open pnodes
104 */
105 return pn_dir;
106 }
107
108 pni.pni_cookie = (void** )&pn;
109 pni.pni_vtype = &node_vtype;
110 pni.pni_size = &size;
111 pni.pni_rdev = &rdev;
112
113 pcn.pcn_namelen = strlen(string);
114 assert(pcn.pcn_namelen <= MAXPATHLEN);
115 strcpy(pcn.pcn_name, string);
116
117 if (buildpath) {
118 if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0) {
119 lpuffs_debug("pathbuild error\n");
120 err_code = ENOENT;
121 return(NULL);
122 }
123 }
124
125 /* lookup *must* be present */
126 error = global_pu->pu_ops.puffs_node_lookup(global_pu, pn_dir, &pni, &pcn);
127
128 if (buildpath) {
129 if (error) {
130 global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
131 err_code = ENOENT;
132 return(NULL);
133 } else {
134 struct puffs_node *_pn;
135
136 /*
137 * did we get a new node or a
138 * recycled node?
139 */
140 _pn = PU_CMAP(global_pu, pn);
141 if (_pn->pn_po.po_path == NULL)
142 _pn->pn_po = pcn.pcn_po_full;
143 else
144 global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
145 }
146 }
147
148 if (error) {
149 err_code = error < 0 ? error : -error;
150 return(NULL);
151 }
152
153 err_code = OK;
154
155 assert(pn != NULL);
156
157 return(pn);
158 }
159