xref: /minix3/minix/lib/libsffs/dentry.c (revision a99c939dee4822394c21dbd4cb89e9451b901e7d)
1*433d6423SLionel Sambuc /* This file contains directory entry management and the name lookup hashtable.
2*433d6423SLionel Sambuc  *
3*433d6423SLionel Sambuc  * The entry points into this file are:
4*433d6423SLionel Sambuc  *   init_dentry	initialize the directory entry name lookup hashtable
5*433d6423SLionel Sambuc  *   lookup_dentry	find an inode based on parent directory and name
6*433d6423SLionel Sambuc  *   add_dentry		add an inode as directory entry to a parent directory
7*433d6423SLionel Sambuc  *   del_dentry		delete an inode from its parent directory
8*433d6423SLionel Sambuc  *
9*433d6423SLionel Sambuc  * Created:
10*433d6423SLionel Sambuc  *   April 2009 (D.C. van Moolenbroek)
11*433d6423SLionel Sambuc  */
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc #include "inc.h"
14*433d6423SLionel Sambuc 
LIST_HEAD(hash_head,inode)15*433d6423SLionel Sambuc static LIST_HEAD(hash_head, inode) hash_table[NUM_HASH_SLOTS];
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc static unsigned int hash_dentry(struct inode *parent, char *name);
18*433d6423SLionel Sambuc 
19*433d6423SLionel Sambuc /*===========================================================================*
20*433d6423SLionel Sambuc  *				init_dentry				     *
21*433d6423SLionel Sambuc  *===========================================================================*/
22*433d6423SLionel Sambuc void init_dentry(void)
23*433d6423SLionel Sambuc {
24*433d6423SLionel Sambuc /* Initialize the names hashtable.
25*433d6423SLionel Sambuc  */
26*433d6423SLionel Sambuc   int i;
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc   for (i = 0; i < NUM_HASH_SLOTS; i++)
29*433d6423SLionel Sambuc 	LIST_INIT(&hash_table[i]);
30*433d6423SLionel Sambuc }
31*433d6423SLionel Sambuc 
32*433d6423SLionel Sambuc /*===========================================================================*
33*433d6423SLionel Sambuc  *				lookup_dentry				     *
34*433d6423SLionel Sambuc  *===========================================================================*/
lookup_dentry(struct inode * parent,char * name)35*433d6423SLionel Sambuc struct inode *lookup_dentry(struct inode *parent, char *name)
36*433d6423SLionel Sambuc {
37*433d6423SLionel Sambuc /* Given a directory inode and a component name, look up the inode associated
38*433d6423SLionel Sambuc  * with that directory entry. Return the inode (with increased reference
39*433d6423SLionel Sambuc  * count) if found, or NULL otherwise.
40*433d6423SLionel Sambuc  */
41*433d6423SLionel Sambuc   struct inode *ino;
42*433d6423SLionel Sambuc   unsigned int slot;
43*433d6423SLionel Sambuc 
44*433d6423SLionel Sambuc   assert(IS_DIR(parent));
45*433d6423SLionel Sambuc 
46*433d6423SLionel Sambuc   slot = hash_dentry(parent, name);
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc   LIST_FOREACH(ino, &hash_table[slot], i_hash) {
49*433d6423SLionel Sambuc 	if (compare_name(ino->i_name, name) == TRUE)
50*433d6423SLionel Sambuc 		break;
51*433d6423SLionel Sambuc   }
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc   if (ino == NULL)
54*433d6423SLionel Sambuc 	return NULL;
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc   get_inode(ino);
57*433d6423SLionel Sambuc 
58*433d6423SLionel Sambuc   return ino;
59*433d6423SLionel Sambuc }
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc /*===========================================================================*
62*433d6423SLionel Sambuc  *				add_dentry				     *
63*433d6423SLionel Sambuc  *===========================================================================*/
add_dentry(struct inode * parent,char * name,struct inode * ino)64*433d6423SLionel Sambuc void add_dentry(struct inode *parent, char *name, struct inode *ino)
65*433d6423SLionel Sambuc {
66*433d6423SLionel Sambuc /* Add an entry to a parent inode, in the form of a new inode, with the given
67*433d6423SLionel Sambuc  * name. An entry with this name must not already exist.
68*433d6423SLionel Sambuc  */
69*433d6423SLionel Sambuc   unsigned int slot;
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc   assert(IS_DIR(parent));
72*433d6423SLionel Sambuc   assert(parent->i_ref > 0);
73*433d6423SLionel Sambuc   assert(ino->i_ref > 0);
74*433d6423SLionel Sambuc   assert(name[0]);
75*433d6423SLionel Sambuc   assert(strlen(name) <= NAME_MAX);
76*433d6423SLionel Sambuc 
77*433d6423SLionel Sambuc   link_inode(parent, ino);
78*433d6423SLionel Sambuc 
79*433d6423SLionel Sambuc   strlcpy(ino->i_name, name, sizeof(ino->i_name));
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc   /* hash_add(ino); */
82*433d6423SLionel Sambuc   slot = hash_dentry(parent, ino->i_name);
83*433d6423SLionel Sambuc   LIST_INSERT_HEAD(&hash_table[slot], ino, i_hash);
84*433d6423SLionel Sambuc }
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc /*===========================================================================*
87*433d6423SLionel Sambuc  *				del_one_dentry				     *
88*433d6423SLionel Sambuc  *===========================================================================*/
del_one_dentry(struct inode * ino)89*433d6423SLionel Sambuc static void del_one_dentry(struct inode *ino)
90*433d6423SLionel Sambuc {
91*433d6423SLionel Sambuc /* This inode has become inaccessible by name. Disassociate it from its parent
92*433d6423SLionel Sambuc  * and remove it from the names hash table.
93*433d6423SLionel Sambuc  */
94*433d6423SLionel Sambuc 
95*433d6423SLionel Sambuc   /* There can and must be exactly one root inode, so don't delete it! */
96*433d6423SLionel Sambuc   if (IS_ROOT(ino))
97*433d6423SLionel Sambuc 	return;
98*433d6423SLionel Sambuc 
99*433d6423SLionel Sambuc   /* INUSE -> DELETED, CACHED -> FREE */
100*433d6423SLionel Sambuc 
101*433d6423SLionel Sambuc   /* Remove the entry from the hashtable.
102*433d6423SLionel Sambuc    * Decrease parent's refcount, possibly adding it to the free list.
103*433d6423SLionel Sambuc    * Do not touch open handles. Do not add to the free list.
104*433d6423SLionel Sambuc    */
105*433d6423SLionel Sambuc 
106*433d6423SLionel Sambuc   assert(ino->i_parent != NULL);
107*433d6423SLionel Sambuc 
108*433d6423SLionel Sambuc   /* hash_del(ino); */
109*433d6423SLionel Sambuc   LIST_REMOVE(ino, i_hash);
110*433d6423SLionel Sambuc 
111*433d6423SLionel Sambuc   ino->i_name[0] = 0;
112*433d6423SLionel Sambuc 
113*433d6423SLionel Sambuc   unlink_inode(ino);
114*433d6423SLionel Sambuc }
115*433d6423SLionel Sambuc 
116*433d6423SLionel Sambuc /*===========================================================================*
117*433d6423SLionel Sambuc  *				del_dentry				     *
118*433d6423SLionel Sambuc  *===========================================================================*/
del_dentry(struct inode * ino)119*433d6423SLionel Sambuc void del_dentry(struct inode *ino)
120*433d6423SLionel Sambuc {
121*433d6423SLionel Sambuc /* Disassociate an inode from its parent, effectively deleting it. Recursively
122*433d6423SLionel Sambuc  * delete all its children as well, fragmenting the deleted branch into single
123*433d6423SLionel Sambuc  * inodes.
124*433d6423SLionel Sambuc  */
125*433d6423SLionel Sambuc   LIST_HEAD(work_list, inode) work_list;
126*433d6423SLionel Sambuc   struct inode *child;
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc   del_one_dentry(ino);
129*433d6423SLionel Sambuc 
130*433d6423SLionel Sambuc   /* Quick way out: one directory entry that itself has no children. */
131*433d6423SLionel Sambuc   if (!HAS_CHILDREN(ino))
132*433d6423SLionel Sambuc 	return;
133*433d6423SLionel Sambuc 
134*433d6423SLionel Sambuc   /* Recursively delete all children of the inode as well.
135*433d6423SLionel Sambuc    * Iterative version: this is potentially 128 levels deep.
136*433d6423SLionel Sambuc    */
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc   LIST_INIT(&work_list);
139*433d6423SLionel Sambuc   LIST_INSERT_HEAD(&work_list, ino, i_next);
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc   do {
142*433d6423SLionel Sambuc 	ino = LIST_FIRST(&work_list);
143*433d6423SLionel Sambuc 	LIST_REMOVE(ino, i_next);
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc 	assert(IS_DIR(ino));
146*433d6423SLionel Sambuc 
147*433d6423SLionel Sambuc 	while (!LIST_EMPTY(&ino->i_child)) {
148*433d6423SLionel Sambuc 		child = LIST_FIRST(&ino->i_child);
149*433d6423SLionel Sambuc 		LIST_REMOVE(child, i_next);
150*433d6423SLionel Sambuc 
151*433d6423SLionel Sambuc 		del_one_dentry(child);
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc 		if (HAS_CHILDREN(child))
154*433d6423SLionel Sambuc 			LIST_INSERT_HEAD(&work_list, child, i_next);
155*433d6423SLionel Sambuc 	}
156*433d6423SLionel Sambuc   } while (!LIST_EMPTY(&work_list));
157*433d6423SLionel Sambuc }
158*433d6423SLionel Sambuc 
159*433d6423SLionel Sambuc /*===========================================================================*
160*433d6423SLionel Sambuc  *				hash_dentry				     *
161*433d6423SLionel Sambuc  *===========================================================================*/
hash_dentry(struct inode * parent,char * name)162*433d6423SLionel Sambuc static unsigned int hash_dentry(struct inode *parent, char *name)
163*433d6423SLionel Sambuc {
164*433d6423SLionel Sambuc /* Generate a hash value for a given name. Normalize the name first, so that
165*433d6423SLionel Sambuc  * different variations of the name will result in the same hash value.
166*433d6423SLionel Sambuc  */
167*433d6423SLionel Sambuc   unsigned int val;
168*433d6423SLionel Sambuc   char buf[NAME_MAX+1], *p;
169*433d6423SLionel Sambuc 
170*433d6423SLionel Sambuc   dprintf(("%s: hash_dentry for '%s'\n", sffs_name, name));
171*433d6423SLionel Sambuc 
172*433d6423SLionel Sambuc   normalize_name(buf, name);
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc   /* djb2 string hash algorithm, XOR variant */
175*433d6423SLionel Sambuc   val = 5381;
176*433d6423SLionel Sambuc   for (p = buf; *p; p++)
177*433d6423SLionel Sambuc 	val = ((val << 5) + val) ^ *p;
178*433d6423SLionel Sambuc 
179*433d6423SLionel Sambuc   /* Mix with inode number: typically, many file names occur in several
180*433d6423SLionel Sambuc    * different directories.
181*433d6423SLionel Sambuc    */
182*433d6423SLionel Sambuc   return (val ^ parent->i_num) % NUM_HASH_SLOTS;
183*433d6423SLionel Sambuc }
184