summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c16
-rw-r--r--source4/ntvfs/posix/pvfs_shortname.c46
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:"");
+
}