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