diff options
-rw-r--r-- | source3/lib/util_str.c | 20 | ||||
-rw-r--r-- | source3/lib/util_unistr.c | 31 | ||||
-rw-r--r-- | source3/smbd/statcache.c | 35 |
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]; |