+/* ------------------ */
+static hash_val_t hash_fun_dir(const void *key)
+{
+ const struct dir *k = key;
+
+ static unsigned long randbox[] = {
+ 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
+ 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
+ 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
+ 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
+ };
+
+ const unsigned char *str = (unsigned char *)(k->d_u_name);
+ hash_val_t acc = k->d_parent->d_did;
+
+ while (*str) {
+ acc ^= randbox[(*str + acc) & 0xf];
+ acc = (acc << 1) | (acc >> 31);
+ acc &= 0xffffffffU;
+ acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
+ acc = (acc << 2) | (acc >> 30);
+ acc &= 0xffffffffU;
+ }
+ return acc;
+}
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+static hash_val_t hash_fun2_dir(const void *key)
+{
+ const struct dir *k = key;
+ const char *data = k->d_u_name;
+ int len = strlen(k->d_u_name);
+ hash_val_t hash = k->d_parent->d_did, tmp;
+
+ int rem = len & 3;
+ len >>= 2;
+
+ /* Main loop */
+ for (;len > 0; len--) {
+ hash += get16bits (data);
+ tmp = (get16bits (data+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2*sizeof (uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem) {
+ case 3: hash += get16bits (data);
+ hash ^= hash << 16;
+ hash ^= data[sizeof (uint16_t)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (data);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += *data;
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
+
+/* ---------------- */
+static int hash_comp_dir(const void *key1, const void *key2)
+{
+ const struct dir *k1 = key1;
+ const struct dir *k2 = key2;
+
+ return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
+}
+
+/* ---------------- */
+hash_t *
+dirhash(void)
+{
+ return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
+}
+
+/* ------------------ */
+static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
+{
+ /* it's tricky:
+ movecwd failed some of dir path are not there anymore.
+ FIXME Is it true with other errors?
+ so we remove dir from the cache
+ */
+ if (dir->d_did == DIRDID_ROOT_PARENT)
+ return NULL;
+ if (afp_errno == AFPERR_ACCESS) {
+ if ( movecwd( vol, dir->d_parent ) < 0 ) {
+ return NULL;
+ }
+ /* FIXME should we set these?, don't need to call stat() after:
+ ret->st_valid = 1;
+ ret->st_errno = EACCES;
+ */
+ ret->m_name = dir->d_m_name;
+ ret->u_name = dir->d_u_name;
+ ret->d_dir = dir;
+ return ret;
+ } else if (afp_errno == AFPERR_NOOBJ) {
+ if ( movecwd( vol, dir->d_parent ) < 0 ) {
+ return NULL;
+ }
+ strcpy(ret->m_name, dir->d_m_name);
+ if (dir->d_m_name == dir->d_u_name) {
+ ret->u_name = ret->m_name;
+ }
+ else {
+ size_t tp = strlen(ret->m_name)+1;
+
+ ret->u_name = ret->m_name +tp;
+ strcpy(ret->u_name, dir->d_u_name);
+ }
+ /* FIXME should we set :
+ ret->st_valid = 1;
+ ret->st_errno = ENOENT;
+ */
+ dir_invalidate(vol, dir);
+ return ret;
+ }
+ dir_invalidate(vol, dir);
+ return NULL;
+}
+