xref: /minix/minix/lib/libpuffs/path.c (revision 9f988b79)
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  *===========================================================================*/
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  *===========================================================================*/
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