summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix/pvfs_shortname.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs/posix/pvfs_shortname.c')
-rw-r--r--source4/ntvfs/posix/pvfs_shortname.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/source4/ntvfs/posix/pvfs_shortname.c b/source4/ntvfs/posix/pvfs_shortname.c
index 21c0ca6ea0..ae911ad885 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:"");
+
}