diff options
-rw-r--r-- | source4/ntvfs/posix/pvfs_resolve.c | 16 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_shortname.c | 46 |
2 files changed, 58 insertions, 4 deletions
diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c index e846b7be77e..5d6f270a424 100644 --- a/source4/ntvfs/posix/pvfs_resolve.c +++ b/source4/ntvfs/posix/pvfs_resolve.c @@ -33,9 +33,19 @@ /* compare two filename components. This is where the name mangling hook will go */ -static int component_compare(const char *c1, const char *c2) +static int component_compare(struct pvfs_state *pvfs, const char *comp, const char *name) { - return StrCaseCmp(c1, c2); + char *shortname; + int ret; + + if (StrCaseCmp(comp, name) == 0) return 0; + + shortname = pvfs_short_name_component(pvfs, name); + + ret = StrCaseCmp(comp, shortname); + + talloc_free(shortname); + return ret; } /* @@ -110,7 +120,7 @@ static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename * } while ((de = readdir(dir))) { - if (component_compare(components[i], de->d_name) == 0) { + if (component_compare(pvfs, components[i], de->d_name) == 0) { break; } } diff --git a/source4/ntvfs/posix/pvfs_shortname.c b/source4/ntvfs/posix/pvfs_shortname.c index 21c0ca6ea0d..ae911ad8858 100644 --- a/source4/ntvfs/posix/pvfs_shortname.c +++ b/source4/ntvfs/posix/pvfs_shortname.c @@ -23,6 +23,34 @@ #include "include/includes.h" #include "vfs_posix.h" +#define FNV1_PRIME 0x01000193 +/*the following number is a fnv1 of the string: idra@samba.org 2002 */ +#define FNV1_INIT 0xa6b93095 + +/* + hash a string of the specified length. The string does not need to be + null terminated + + this hash needs to be fast with a low collision rate (what hash doesn't?) +*/ +static uint32_t mangle_hash(const char *key) +{ + uint32_t value; + codepoint_t c; + size_t c_size; + + for (value = FNV1_INIT; + (c=next_codepoint(key, &c_size)); + key += c_size) { + c = toupper_w(c); + value *= (uint32_t)FNV1_PRIME; + value ^= (uint32_t)c; + } + + /* note that we force it to a 31 bit hash, to keep within the limits + of the 36^6 mangle space */ + return value & ~0x80000000; +} /* return the short name for a component of a full name @@ -30,7 +58,23 @@ */ char *pvfs_short_name_component(struct pvfs_state *pvfs, const char *name) { - return talloc_strndup(pvfs, name, 12); + const char *basechars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t hash; + char c1, c2; + const char *ext; + + if (strlen(name) < 12) { + return talloc_strdup(pvfs, name); + } + + hash = mangle_hash(name); + ext = strrchr(name, '.'); + + c1 = basechars[(hash/36)%36]; + c2 = basechars[hash%36]; + + return talloc_asprintf(pvfs, "%.5s~%c%c%.4s", name, c1, c2, ext?ext:""); + } |