#include "spadfs.h"

static int SPADFS_HASH_DENTRY(struct dentry *dentry, struct qstr *qstr)
{
	unsigned i;
	unsigned long hash;
	if (__unlikely((unsigned)(qstr->len - 1) > (255 - 1)) || __unlikely(qstr->name[0] == '^')) return -EINVAL;
	hash = init_name_hash();
	for (i = 0; i < qstr->len; i++) {
		if (__unlikely(qstr->name[i] == ':')) return -EINVAL;
		hash = partial_name_hash(qstr->name[i] & 0xdf, hash);
	}
	qstr->hash = hash;
	return 0;
}

__finline__ int SPADFS_COMPARE_NAMES(SPADFS *fs, const char *n1, unsigned l1, const char *n2, unsigned l2)
{
	if (l1 != l2) return 1;
	if (__likely(fs->flags_compat_none & FLAG_COMPAT_NONE_UNIX_NAMES)) {
		return memcmp(n1, n2, l1);
	} else {
		while (l1--) {
			char c1 = *n1++;
			char c2 = *n2++;
			if (c1 >= 'a' && c1 <= 'z') c1 -= 0x20;
			if (c2 >= 'a' && c2 <= 'z') c2 -= 0x20;
			if (c1 != c2) return 1;
		}
		return 0;
	}
}

void SPADFS_SET_NAME(SPADFS *fs, char *dest, const char *src, unsigned len)
{
	strncpy(dest, src, (len + 7) & ~7);
	if (__unlikely(!(fs->flags_compat_none & FLAG_COMPAT_NONE_UNIX_NAMES))) {
		while (len--) {
			if (*dest >= 'a' && *dest <= 'z') *dest -= 0x20;
			dest++;
		}
	}
}

static int SPADFS_COMPARE_DENTRY(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
	return SPADFS_COMPARE_NAMES(spadfs(dentry->d_sb), a->name, a->len, b->name, b->len);
}

struct dentry_operations spadfs_dops = {
	.d_hash = SPADFS_HASH_DENTRY,
	.d_compare = SPADFS_COMPARE_DENTRY,
};
