summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2003-07-02 20:01:51 +0000
committerJeremy Allison <jra@samba.org>2003-07-02 20:01:51 +0000
commitaf4d65889420eb3bb71be67d619dbc0c62e21101 (patch)
tree25dc0166e23606c72c4426d18aaa82744ef0b0f9
parent93e995159f843e7f6acdbc33d1f329844e1a9973 (diff)
downloadsamba-af4d65889420eb3bb71be67d619dbc0c62e21101.tar.gz
samba-af4d65889420eb3bb71be67d619dbc0c62e21101.tar.bz2
samba-af4d65889420eb3bb71be67d619dbc0c62e21101.zip
Added fix for Japanese case names in statcache - these can change
size on upper casing. Based on patch from monyo@home.monyo.com. Jeremy. (This used to be commit 72e382e99b92666acdaf50a040b14aa16d48b80d)
-rw-r--r--source3/lib/util_str.c20
-rw-r--r--source3/lib/util_unistr.c31
-rw-r--r--source3/smbd/statcache.c35
3 files changed, 82 insertions, 4 deletions
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index af8d6aa04c..ac8fccfa5a 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -1111,6 +1111,26 @@ char *strrchr_m(const char *s, char c)
return (char *)(s+strlen(s2));
}
+/***********************************************************************
+ Return the equivalent of doing strrchr 'n' times - always going
+ backwards.
+***********************************************************************/
+
+char *strnrchr_m(const char *s, char c, unsigned int n)
+{
+ wpstring ws;
+ pstring s2;
+ smb_ucs2_t *p;
+
+ push_ucs2(NULL, ws, s, sizeof(ws), STR_TERMINATE);
+ p = strnrchr_w(ws, UCS2_CHAR(c), n);
+ if (!p)
+ return NULL;
+ *p = 0;
+ pull_ucs2_pstring(s2, ws);
+ return (char *)(s+strlen(s2));
+}
+
/**
Convert a string to lower case.
**/
diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c
index 5df0828295..ae000fba02 100644
--- a/source3/lib/util_unistr.c
+++ b/source3/lib/util_unistr.c
@@ -391,8 +391,9 @@ size_t strnlen_w(const smb_ucs2_t *src, size_t max)
}
/*******************************************************************
-wide strchr()
+ Wide strchr().
********************************************************************/
+
smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
{
while (*s != 0) {
@@ -409,6 +410,10 @@ smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
return strchr_w(s, UCS2_CHAR(c));
}
+/*******************************************************************
+ Wide strrchr().
+********************************************************************/
+
smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
{
const smb_ucs2_t *p = s;
@@ -422,8 +427,30 @@ smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
}
/*******************************************************************
-wide strstr()
+ Wide version of strrchr that returns after doing strrchr 'n' times.
********************************************************************/
+
+smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n)
+{
+ const smb_ucs2_t *p = s;
+ int len = strlen_w(s);
+ if (len == 0 || !n)
+ return NULL;
+ p += (len - 1);
+ do {
+ if (c == *p)
+ n--;
+
+ if (!n)
+ return (smb_ucs2_t *)p;
+ } while (p-- != s);
+ return NULL;
+}
+
+/*******************************************************************
+ Wide strstr().
+********************************************************************/
+
smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
{
smb_ucs2_t *r;
diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
index 0d55c22f7a..593df745cc 100644
--- a/source3/smbd/statcache.c
+++ b/source3/smbd/statcache.c
@@ -198,6 +198,8 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
size_t namelen;
hash_element *hash_elem;
char *sp;
+ BOOL sizechanged = False;
+ unsigned int num_components = 0;
if (!lp_stat_cache())
return False;
@@ -217,8 +219,17 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
}
pstrcpy(chk_name, name);
- if(!case_sensitive)
+
+ if(!case_sensitive) {
strupper( chk_name );
+ /*
+ * In some language encodings the length changes
+ * if we uppercase. We need to treat this differently
+ * below.
+ */
+ if (strlen(chk_name) != namelen)
+ sizechanged = True;
+ }
while (1) {
hash_elem = hash_lookup(&stat_cache, chk_name);
@@ -229,6 +240,13 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
sp = strrchr_m(chk_name, '/');
if (sp) {
*sp = '\0';
+ /*
+ * Count the number of times we have done this,
+ * we'll need it when reconstructing the string.
+ */
+ if (sizechanged)
+ num_components++;
+
} else {
/*
* We reached the end of the name - no match.
@@ -249,7 +267,20 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
hash_remove(&stat_cache, hash_elem);
return False;
}
- memcpy(name, scp->translated_path, MIN(sizeof(pstring)-1, scp->translated_path_length));
+
+ if (!sizechanged) {
+ memcpy(name, scp->translated_path, MIN(sizeof(pstring)-1, scp->translated_path_length));
+ } else {
+ pstring last_component;
+ sp = strnrchr_m(name, '/', num_components);
+ if (!sp) {
+ /* Logic error. */
+ smb_panic("logic error in stat_cache_lookup\n");
+ }
+ pstrcpy(last_component, sp);
+ pstrcpy(name, scp->translated_path);
+ pstrcat(name, last_component);
+ }
/* set pointer for 'where to start' on fixing the rest of the name */
*start = &name[scp->translated_path_length];