- char *data, *p;
- char *u;
- int extend = 0;
- int len;
- int olen = 0;
- u_int32_t hint;
- u_int16_t len16;
- int size = 0;
- char sep;
-
- data = *cpath;
- switch (*data) { /* path type */
- case 2:
- data++;
- len = (unsigned char) *data++;
- size = 2;
- sep = 0;
- 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:
- return( NULL );
-
- }
- *cpath += len + size;
- *path = '\0';
- u = NULL;
- ret.m_name = path;
- ret.st_errno = 0;
- ret.st_valid = 0;
- for ( ;; ) {
- if ( len == 0 ) {
- if ( !extend && movecwd( vol, dir ) < 0 ) {
- /* it's tricky:
- movecwd failed some of dir path is not there anymore.
- FIXME Is it true with other errors?
- if path == '\0' ==> the cpath parameter is that dir,
- and maybe we are trying to recreate it! So we can't
- fail here.
-
- */
- if (dir->d_did == DIRDID_ROOT_PARENT)
- return NULL;
- if (errno != ENOENT && errno != ENOTDIR)
- return NULL;
-
- cdir = dir->d_parent;
- dir_invalidate(vol, dir);
- if (*path != '\0' || u == NULL) {
- /* FIXME: if path != '\0' then extend != 0 ?
- * u == NUL ==> cpath is something like:
- * toto\0\0\0
- */
- return NULL;
- }
- if (movecwd(vol, cdir) < 0) {
- printf("can't change to parent\n");
- return NULL; /* give up the whole tree is out of synch*/
- }
- /* restore the previous token */
- strncpy(path, u, olen);
- path[olen] = '\0';
- }
- if (!ret.st_valid || *path == '\0') {
- ret.u_name = ".";
- }
- return &ret;
- }
+#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 = k->d_u_name_len;
+ 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;
+}
+
+/* -------------------------------------------------- */
+/* 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;
+ }