- *cpath += len + size;
- *path = '\0';
- ret.m_name = path;
- ret.st_errno = 0;
- ret.st_valid = 0;
- for ( ;; ) {
- if ( len == 0 ) {
- if (movecwd( vol, dir ) < 0 ) {
- /* 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;
- }
- ret.m_name = dir->d_m_name;
- ret.u_name = dir->d_u_name;
- return &ret;
- }
-
- dir_invalidate(vol, dir);
- return NULL;
- }
- if (*path == '\0') {
- ret.u_name = ".";
- }
- return &ret;
- }
+
+ /* 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;
+}
+
+/* -------------------------------------------------- */
+/* cname
+ return
+ if it's a filename:
+ in extenddir:
+ compute unix name
+ stat the file or errno
+ return
+ filename
+ curdir: filename parent directory
+
+ if it's a dirname:
+ not in the cache
+ in extenddir
+ compute unix name
+ stat the dir or errno
+ return
+ if chdir error
+ dirname
+ curdir: dir parent directory
+ sinon
+ dirname: ""
+ curdir: dir
+ in the cache
+ return
+ if chdir error
+ dirname
+ curdir: dir parent directory
+ else
+ dirname: ""
+ curdir: dir
+
+*/
+struct path *
+cname(struct vol *vol, struct dir *dir, char **cpath)
+{
+ struct dir *cdir, *scdir=NULL;
+ static char path[ MAXPATHLEN + 1];
+ static struct path ret;
+
+ char *data, *p;
+ int extend = 0;
+ int len;
+ u_int32_t hint;
+ u_int16_t len16;
+ int size = 0;
+ char sep;
+ int toUTF8 = 0;
+
+ data = *cpath;
+ afp_errno = AFPERR_NOOBJ;
+ memset(&ret, 0, sizeof(ret));
+ switch (ret.m_type = *data) { /* path type */
+ case 2:
+ data++;
+ len = (unsigned char) *data++;
+ size = 2;
+ sep = 0;
+ if (afp_version >= 30) {
+ ret.m_type = 3;
+ toUTF8 = 1;
+ }
+ break;
+ case 3:
+ if (afp_version >= 30) {
+ data++;
+ memcpy(&hint, data, sizeof(hint));
+ hint = ntohl(hint);
+ data += sizeof(hint);
+
+ memcpy(&len16, data, sizeof(len16));
+ len = ntohs(len16);
+ data += 2;
+ size = 7;
+ sep = 0; /* '/';*/
+ break;
+ }
+ /* else it's an error */
+ default:
+ afp_errno = AFPERR_PARAM;
+ return( NULL );
+ }
+ *cpath += len + size;
+ *path = '\0';
+ ret.m_name = path;
+ for ( ;; ) {
+ if ( len == 0 ) {
+ if (movecwd( vol, dir ) < 0 ) {
+ return invalidate(vol, dir, &ret );
+ }
+ if (*path == '\0') {
+ ret.u_name = ".";
+ ret.d_dir = dir;
+ }
+ return &ret;
+ }