mirror of
https://github.com/samba-team/samba.git
synced 2025-07-30 19:42:05 +03:00
Added hash-based stat cache code from Ying Chen.
Jeremy.
This commit is contained in:
@ -99,7 +99,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \
|
||||
lib/util_array.o lib/util_str.o lib/util_sid.o \
|
||||
lib/util_unistr.o lib/util_file.o \
|
||||
lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o lib/fnmatch.o \
|
||||
tdb/tdb.o lib/talloc.o
|
||||
tdb/tdb.o lib/talloc.o lib/hash.o
|
||||
|
||||
UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
|
||||
ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o ubiqx/debugparse.o
|
||||
|
75
source/include/hash.h
Normal file
75
source/include/hash.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Copyright (C) Ying Chen 2000.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _HASH_H_
|
||||
#define _HASH_H_
|
||||
|
||||
#define MAX_HASH_TABLE_SIZE 32768
|
||||
#define HASH_TABLE_INCREMENT 2
|
||||
|
||||
typedef int (*compare_function)(char *, char *);
|
||||
typedef int (*hash_function)(int, char *);
|
||||
|
||||
/*
|
||||
* lru_link: links the node to the LRU list.
|
||||
* hash_elem: the pointer to the element that is tied onto the link.
|
||||
*/
|
||||
typedef struct lru_node {
|
||||
ubi_dlNode lru_link;
|
||||
void *hash_elem;
|
||||
} lru_node;
|
||||
|
||||
/*
|
||||
* bucket_link: link the hash element to the bucket chain that it belongs to.
|
||||
* lru_link: this element ties the hash element to the lru list.
|
||||
* bucket: a pointer to the hash bucket that this element belongs to.
|
||||
* value: a pointer to the hash element content. It can be anything.
|
||||
* key: stores the string key. The hash_element is always allocated with
|
||||
* more memory space than the structure shown below to accomodate the space
|
||||
* used for the whole string. But the memory is always appended at the
|
||||
* end of the structure, so keep "key" at the end of the structure.
|
||||
* Don't move it.
|
||||
*/
|
||||
typedef struct hash_element {
|
||||
ubi_dlNode bucket_link;
|
||||
lru_node lru_link;
|
||||
ubi_dlList *bucket;
|
||||
void *value;
|
||||
char key[1];
|
||||
} hash_element;
|
||||
|
||||
/*
|
||||
* buckets: a list of buckets, implemented as a dLinkList.
|
||||
* lru_chain: the lru list of all the hash elements.
|
||||
* num_elements: the # of elements in the hash table.
|
||||
* size: the hash table size.
|
||||
* comp_func: the compare function used during hash key comparisons.
|
||||
*/
|
||||
|
||||
typedef struct hash_table {
|
||||
ubi_dlList *buckets;
|
||||
ubi_dlList lru_chain;
|
||||
int num_elements;
|
||||
int size;
|
||||
compare_function comp_func;
|
||||
} hash_table;
|
||||
|
||||
#endif /* _HASH_H_ */
|
@ -619,6 +619,7 @@ extern int errno;
|
||||
#include "../tdb/tdb.h"
|
||||
#include "talloc.h"
|
||||
#include "interfaces.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifdef HAVE_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
|
@ -97,6 +97,15 @@ void generate_random_buffer( unsigned char *out, int len, BOOL re_seed);
|
||||
|
||||
char *getsmbpass(char *prompt) ;
|
||||
|
||||
/*The following definitions come from lib/hash.c */
|
||||
|
||||
BOOL hash_table_init(hash_table *table, int num_buckets, compare_function compare_func);
|
||||
int string_hash(int hash_size, const char *key);
|
||||
hash_element *hash_lookup(hash_table *table, char *key);
|
||||
hash_element *hash_insert(hash_table *table, char *value, char *key);
|
||||
void hash_remove(hash_table *table, hash_element *hash_elem);
|
||||
void hash_clear(hash_table *table);
|
||||
|
||||
/*The following definitions come from lib/interface.c */
|
||||
|
||||
void load_interfaces(void);
|
||||
@ -2636,6 +2645,7 @@ void print_stat_cache_statistics(void);
|
||||
BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
|
||||
BOOL *bad_path, SMB_STRUCT_STAT *pst);
|
||||
BOOL check_name(char *name,connection_struct *conn);
|
||||
BOOL reset_stat_cache( void );
|
||||
|
||||
/*The following definitions come from smbd/files.c */
|
||||
|
||||
|
320
source/lib/hash.c
Normal file
320
source/lib/hash.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2.0
|
||||
|
||||
Copyright (C) Ying Chen 2000.
|
||||
Copyright (C) Jeremy Allison 2000.
|
||||
- added some defensive programming.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NB. We may end up replacing this functionality in a future 2.x
|
||||
* release to reduce the number of hashing/lookup methods we support. JRA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
|
||||
#define NUM_PRIMES 11
|
||||
|
||||
static BOOL enlarge_hash_table(hash_table *table);
|
||||
static int primes[NUM_PRIMES] =
|
||||
{17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411};
|
||||
|
||||
/****************************************************************************
|
||||
* This function initializes the hash table.
|
||||
* This hash function hashes on string keys.
|
||||
* This number of hash buckets is always rounded up to a power of
|
||||
* 2 first, then to a prime number that is large than the power of two.
|
||||
* Input:
|
||||
* table -- the hash table pointer.
|
||||
* num_buckets -- the number of buckets to be allocated. This
|
||||
* hash function can dynamically increase its size when the
|
||||
* the hash table size becomes small. There is a MAX hash table
|
||||
* size defined in hash.h.
|
||||
* compare_func -- the function pointer to a comparison function
|
||||
* used by the hash key comparison.
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
BOOL hash_table_init(hash_table *table, int num_buckets, compare_function compare_func)
|
||||
{
|
||||
int i;
|
||||
ubi_dlList *bucket;
|
||||
|
||||
table->num_elements = 0;
|
||||
table->size = 2;
|
||||
table->comp_func = compare_func;
|
||||
while (table->size < num_buckets)
|
||||
table->size <<= 1;
|
||||
for (i = 0; i < NUM_PRIMES; i++) {
|
||||
if (primes[i] > table->size) {
|
||||
table->size = primes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(5, ("Hash size = %d.\n", table->size));
|
||||
|
||||
if(!(table->buckets = (ubi_dlList *) malloc(sizeof(ubi_dlList) * table->size))) {
|
||||
DEBUG(0,("hash_table_init: malloc fail !\n"));
|
||||
return False;
|
||||
}
|
||||
ubi_dlInitList(&(table->lru_chain));
|
||||
for (i=0, bucket = table->buckets; i < table->size; i++, bucket++)
|
||||
ubi_dlInitList(bucket);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
**************************************************************
|
||||
* Compute a hash value based on a string key value.
|
||||
* Make the string key into an array of int's if possible.
|
||||
* For the last few chars that cannot be int'ed, use char instead.
|
||||
* The function returns the bucket index number for the hashed
|
||||
* key.
|
||||
**************************************************************
|
||||
*/
|
||||
|
||||
int string_hash(int hash_size, const char *key)
|
||||
{
|
||||
int j=0;
|
||||
while (*key)
|
||||
j = j*10 + *key++;
|
||||
return(((j>=0)?j:(-j)) % hash_size);
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
* Search the hash table for the entry in the hash chain.
|
||||
* The function returns the pointer to the
|
||||
* element found in the chain or NULL if none is found.
|
||||
* If the element is found, the element is also moved to
|
||||
* the head of the LRU list.
|
||||
*
|
||||
* Input:
|
||||
* table -- The hash table where the element is stored in.
|
||||
* hash_chain -- The pointer to the bucket that stores the
|
||||
* element to be found.
|
||||
* key -- The hash key to be found.
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
static hash_element *hash_chain_find(hash_table *table, ubi_dlList *hash_chain, char *key)
|
||||
{
|
||||
hash_element *hash_elem;
|
||||
ubi_dlNodePtr lru_item;
|
||||
int i = 0;
|
||||
|
||||
for (hash_elem = (hash_element *)(ubi_dlFirst(hash_chain)); i < hash_chain->count;
|
||||
i++, hash_elem = (hash_element *)(ubi_dlNext(hash_elem))) {
|
||||
if ((table->comp_func)(hash_elem->key, key) == 0) {
|
||||
/* Move to the head of the lru List. */
|
||||
lru_item = ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
|
||||
ubi_dlAddHead(&(table->lru_chain), lru_item);
|
||||
return(hash_elem);
|
||||
}
|
||||
}
|
||||
return ((hash_element *) NULL);
|
||||
}
|
||||
|
||||
/* ***************************************************************************
|
||||
*
|
||||
* Lookup a hash table for an element with key.
|
||||
* The function returns a pointer to the hash element.
|
||||
* If no element is found, the function returns NULL.
|
||||
*
|
||||
* Input:
|
||||
* table -- The hash table to be searched on.
|
||||
* key -- The key to be found.
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
hash_element *hash_lookup(hash_table *table, char *key)
|
||||
{
|
||||
return (hash_chain_find(table, &(table->buckets[string_hash(table->size, key)]), key));
|
||||
}
|
||||
|
||||
/* ***************************************************************
|
||||
*
|
||||
* This function first checks if an element with key "key"
|
||||
* exists in the hash table. If so, the function moves the
|
||||
* element to the front of the LRU list. Otherwise, a new
|
||||
* hash element corresponding to "value" and "key" is allocated
|
||||
* and inserted into the hash table. The new elements are
|
||||
* always inserted in the LRU order to the LRU list as well.
|
||||
*
|
||||
* Input:
|
||||
* table -- The hash table to be inserted in.
|
||||
* value -- The content of the element to be inserted.
|
||||
* key -- The key of the new element to be inserted.
|
||||
*
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
hash_element *hash_insert(hash_table *table, char *value, char *key)
|
||||
{
|
||||
hash_element *hash_elem;
|
||||
ubi_dlNodePtr lru_item;
|
||||
ubi_dlList *bucket;
|
||||
|
||||
/*
|
||||
* If the hash table size has not reached the MAX_HASH_TABLE_SIZE,
|
||||
* the hash table may be enlarged if the current hash table is full.
|
||||
* If the hash table size has reached the MAX_HASH_TABLE_SIZE,
|
||||
* use LRU to remove the oldest element from the hash table.
|
||||
*/
|
||||
|
||||
if ((table->num_elements >= table->size) &&
|
||||
(table->num_elements < MAX_HASH_TABLE_SIZE)) {
|
||||
if(!enlarge_hash_table(table))
|
||||
return (hash_element *)NULL;
|
||||
table->num_elements += 1;
|
||||
} else if (table->num_elements >= MAX_HASH_TABLE_SIZE) {
|
||||
/* Do an LRU replacement. */
|
||||
lru_item = ubi_dlLast(&(table->lru_chain));
|
||||
hash_elem = (hash_element *)(((lru_node *)lru_item)->hash_elem);
|
||||
bucket = hash_elem->bucket;
|
||||
ubi_dlRemThis(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
|
||||
ubi_dlRemThis(bucket, (ubi_dlNodePtr)hash_elem);
|
||||
free((char*)(hash_elem->value));
|
||||
free(hash_elem);
|
||||
} else {
|
||||
table->num_elements += 1;
|
||||
}
|
||||
|
||||
bucket = &(table->buckets[string_hash(table->size, key)]);
|
||||
|
||||
/* Since we only have 1-byte for the key string, we need to
|
||||
* allocate extra space in the hash_element to store the entire key
|
||||
* string.
|
||||
*/
|
||||
|
||||
if(!(hash_elem = (hash_element *) malloc(sizeof(hash_element) + strlen(key)))) {
|
||||
DEBUG(0,("hash_insert: malloc fail !\n"));
|
||||
return (hash_element *)NULL;
|
||||
}
|
||||
|
||||
safe_strcpy((char *) hash_elem->key, key, strlen(key)+1);
|
||||
|
||||
hash_elem->value = (char *)value;
|
||||
hash_elem->bucket = bucket;
|
||||
/* Insert in front of the lru list and the bucket list. */
|
||||
ubi_dlAddHead(bucket, hash_elem);
|
||||
hash_elem->lru_link.hash_elem = hash_elem;
|
||||
ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
|
||||
|
||||
return(hash_elem);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
*
|
||||
* Remove a hash element from the hash table. The hash element is
|
||||
* removed from both the LRU list and the hash bucket chain.
|
||||
*
|
||||
* Input:
|
||||
* table -- the hash table to be manipulated on.
|
||||
* hash_elem -- the element to be removed.
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
void hash_remove(hash_table *table, hash_element *hash_elem)
|
||||
{
|
||||
if (hash_elem) {
|
||||
ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
|
||||
ubi_dlRemove(hash_elem->bucket, (ubi_dlNodePtr) hash_elem);
|
||||
if(hash_elem->value)
|
||||
free((char *)(hash_elem->value));
|
||||
if(hash_elem)
|
||||
free((char *) hash_elem);
|
||||
table->num_elements--;
|
||||
}
|
||||
}
|
||||
|
||||
/* ******************************************************************
|
||||
* Increase the hash table size if it is too small.
|
||||
* The hash table size is increased by the HASH_TABLE_INCREMENT
|
||||
* ratio.
|
||||
* Input:
|
||||
* table -- the hash table to be enlarged.
|
||||
******************************************************************
|
||||
*/
|
||||
|
||||
static BOOL enlarge_hash_table(hash_table *table)
|
||||
{
|
||||
hash_element *hash_elem;
|
||||
int size, hash_value;
|
||||
ubi_dlList *buckets;
|
||||
ubi_dlList *old_bucket;
|
||||
ubi_dlList *bucket;
|
||||
ubi_dlList lru_chain;
|
||||
|
||||
buckets = table->buckets;
|
||||
lru_chain = table->lru_chain;
|
||||
size = table->size;
|
||||
|
||||
/* Reinitialize the hash table. */
|
||||
if(!hash_table_init(table, table->size * HASH_TABLE_INCREMENT, table->comp_func))
|
||||
return False;
|
||||
|
||||
for (old_bucket = buckets; size > 0; size--, old_bucket++) {
|
||||
while (old_bucket->count != 0) {
|
||||
hash_elem = (hash_element *) ubi_dlRemHead(old_bucket);
|
||||
ubi_dlRemove(&lru_chain, &(hash_elem->lru_link.lru_link));
|
||||
hash_value = string_hash(table->size, (char *) hash_elem->key);
|
||||
bucket = &(table->buckets[hash_value]);
|
||||
ubi_dlAddHead(bucket, hash_elem);
|
||||
ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link));
|
||||
hash_elem->bucket = bucket;
|
||||
hash_elem->lru_link.hash_elem = hash_elem;
|
||||
table->num_elements++;
|
||||
}
|
||||
}
|
||||
if(buckets)
|
||||
free((char *) buckets);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* **********************************************************************
|
||||
*
|
||||
* Remove everything from a hash table and free up the memory it
|
||||
* occupies.
|
||||
* Input:
|
||||
* table -- the hash table to be cleared.
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
void hash_clear(hash_table *table)
|
||||
{
|
||||
int i;
|
||||
ubi_dlList *bucket = table->buckets;
|
||||
hash_element *hash_elem;
|
||||
for (i = 0; i < table->size; bucket++, i++) {
|
||||
while (bucket->count != 0) {
|
||||
hash_elem = (hash_element *) ubi_dlRemHead(bucket);
|
||||
if(hash_elem->value)
|
||||
free((char *)(hash_elem->value));
|
||||
if(hash_elem)
|
||||
free((char *)hash_elem);
|
||||
}
|
||||
}
|
||||
if(table->buckets)
|
||||
free((char *) table->buckets);
|
||||
}
|
@ -98,7 +98,7 @@ END {
|
||||
gotstart = 1;
|
||||
}
|
||||
|
||||
if( $0 ~ /^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX/ ) {
|
||||
if( $0 ~ /^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element/ ) {
|
||||
gotstart = 1;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
Version 1.9.
|
||||
filename handling routines
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
Copyright (C) Jeremy Allison 1999-200
|
||||
Copyright (C) Ying Chen 2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -19,6 +21,10 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* New hash table stat cache code added by Ying Chen.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
@ -109,15 +115,12 @@ stat cache was %f%% effective.\n", global_stat_cache_lookups,
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ubi_dlNode link;
|
||||
int name_len;
|
||||
pstring orig_name;
|
||||
pstring translated_name;
|
||||
char names[2]; /* This is extended via malloc... */
|
||||
} stat_cache_entry;
|
||||
|
||||
#define MAX_STAT_CACHE_SIZE 50
|
||||
|
||||
static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
|
||||
#define INIT_STAT_CACHE_SIZE 512
|
||||
static hash_table stat_cache;
|
||||
|
||||
/****************************************************************************
|
||||
Compare a pathname to a name in the stat cache - of a given length.
|
||||
@ -144,9 +147,11 @@ static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
|
||||
static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
|
||||
{
|
||||
stat_cache_entry *scp;
|
||||
stat_cache_entry *found_scp;
|
||||
pstring orig_name;
|
||||
pstring translated_path;
|
||||
int namelen;
|
||||
hash_element *hash_elem;
|
||||
|
||||
if (!lp_stat_cache()) return;
|
||||
|
||||
@ -194,39 +199,39 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
|
||||
* add it.
|
||||
*/
|
||||
|
||||
for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
|
||||
scp = (stat_cache_entry *)ubi_dlNext( scp )) {
|
||||
if((strcmp( scp->orig_name, orig_name) == 0) &&
|
||||
(strcmp( scp->translated_name, translated_path) == 0)) {
|
||||
/*
|
||||
* Name does exist - promote it.
|
||||
*/
|
||||
if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != scp ) {
|
||||
ubi_dlRemThis( &stat_cache, scp);
|
||||
ubi_dlAddHead( &stat_cache, scp);
|
||||
if (hash_elem = hash_lookup(&stat_cache, orig_name)) {
|
||||
found_scp = (stat_cache_entry *)(hash_elem->value);
|
||||
if (strcmp((found_scp->names+found_scp->name_len+1), translated_path) == 0) {
|
||||
return;
|
||||
} else {
|
||||
hash_remove(&stat_cache, hash_elem);
|
||||
if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
|
||||
DEBUG(0,("stat_cache_add: Out of memory !\n"));
|
||||
return;
|
||||
}
|
||||
pstrcpy(scp->names, orig_name);
|
||||
pstrcpy((scp->names+namelen+1), translated_path);
|
||||
scp->name_len = namelen;
|
||||
hash_insert(&stat_cache, (char *)scp, orig_name);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* New entry.
|
||||
*/
|
||||
|
||||
if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) {
|
||||
DEBUG(0,("stat_cache_add: Out of memory !\n"));
|
||||
return;
|
||||
}
|
||||
pstrcpy(scp->names, orig_name);
|
||||
pstrcpy(scp->names+namelen+1, translated_path);
|
||||
scp->name_len = namelen;
|
||||
hash_insert(&stat_cache, (char *)scp, orig_name);
|
||||
}
|
||||
|
||||
if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry))) == NULL) {
|
||||
DEBUG(0,("stat_cache_add: Out of memory !\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
pstrcpy(scp->orig_name, orig_name);
|
||||
pstrcpy(scp->translated_name, translated_path);
|
||||
scp->name_len = namelen;
|
||||
|
||||
ubi_dlAddHead( &stat_cache, scp);
|
||||
|
||||
DEBUG(10,("stat_cache_add: Added entry %s -> %s\n", scp->orig_name, scp->translated_name ));
|
||||
|
||||
if(ubi_dlCount(&stat_cache) > lp_stat_cache_size()) {
|
||||
scp = (stat_cache_entry *)ubi_dlRemTail( &stat_cache );
|
||||
free((char *)scp);
|
||||
return;
|
||||
}
|
||||
DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->names, (scp->names+scp->name_len+1)));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -238,10 +243,14 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRU
|
||||
{
|
||||
stat_cache_entry *scp;
|
||||
stat_cache_entry *longest_hit = NULL;
|
||||
char *trans_name;
|
||||
pstring chk_name;
|
||||
int namelen;
|
||||
hash_element *hash_elem;
|
||||
char *sp;
|
||||
|
||||
if (!lp_stat_cache()) return False;
|
||||
if (!lp_stat_cache())
|
||||
return False;
|
||||
|
||||
namelen = strlen(name);
|
||||
|
||||
@ -260,55 +269,44 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRU
|
||||
if(!case_sensitive)
|
||||
strupper( chk_name );
|
||||
|
||||
for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
|
||||
scp = (stat_cache_entry *)ubi_dlNext( scp )) {
|
||||
if(scp->name_len <= namelen) {
|
||||
if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) {
|
||||
if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len))
|
||||
longest_hit = scp;
|
||||
while (1) {
|
||||
hash_elem = hash_lookup(&stat_cache, chk_name);
|
||||
if(hash_elem == NULL) {
|
||||
/*
|
||||
* Didn't find it - remove last component for next try.
|
||||
*/
|
||||
sp = strrchr(chk_name, '/');
|
||||
if (sp) {
|
||||
*sp = '\0';
|
||||
} else {
|
||||
/*
|
||||
* We reached the end of the name - no match.
|
||||
*/
|
||||
global_stat_cache_misses++;
|
||||
return False;
|
||||
}
|
||||
if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0)
|
||||
|| (strcmp(chk_name, "..") == 0)) {
|
||||
global_stat_cache_misses++;
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
scp = (stat_cache_entry *)(hash_elem->value);
|
||||
global_stat_cache_hits++;
|
||||
trans_name = scp->names+scp->name_len+1;
|
||||
if(dos_stat( trans_name, pst) != 0) {
|
||||
/* Discard this entry - it doesn't exist in the filesystem. */
|
||||
hash_remove(&stat_cache, hash_elem);
|
||||
return False;
|
||||
}
|
||||
memcpy(name, trans_name, scp->name_len);
|
||||
*start = &name[scp->name_len];
|
||||
if(**start == '/')
|
||||
++*start;
|
||||
StrnCpy( dirpath, trans_name, name - (*start));
|
||||
return (namelen == scp->name_len);
|
||||
}
|
||||
}
|
||||
|
||||
if(longest_hit == NULL) {
|
||||
DEBUG(10,("stat_cache_lookup: cache miss on %s\n", name));
|
||||
global_stat_cache_misses++;
|
||||
return False;
|
||||
}
|
||||
|
||||
global_stat_cache_hits++;
|
||||
|
||||
DEBUG(10,("stat_cache_lookup: cache hit for name %s. %s -> %s\n",
|
||||
name, longest_hit->orig_name, longest_hit->translated_name ));
|
||||
|
||||
/*
|
||||
* longest_hit is the longest match we got in the list.
|
||||
* Check it exists - if so, overwrite the original name
|
||||
* and then promote it to the top.
|
||||
*/
|
||||
|
||||
if(dos_stat( longest_hit->translated_name, pst) != 0) {
|
||||
/*
|
||||
* Discard this entry.
|
||||
*/
|
||||
ubi_dlRemThis( &stat_cache, longest_hit);
|
||||
free((char *)longest_hit);
|
||||
return False;
|
||||
}
|
||||
|
||||
memcpy(name, longest_hit->translated_name, longest_hit->name_len);
|
||||
if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != longest_hit ) {
|
||||
ubi_dlRemThis( &stat_cache, longest_hit);
|
||||
ubi_dlAddHead( &stat_cache, longest_hit);
|
||||
}
|
||||
|
||||
*start = &name[longest_hit->name_len];
|
||||
if(**start == '/')
|
||||
++*start;
|
||||
|
||||
StrnCpy( dirpath, longest_hit->translated_name, name - (*start));
|
||||
|
||||
return (namelen == longest_hit->name_len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -352,7 +350,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
|
||||
*dirpath = 0;
|
||||
*bad_path = False;
|
||||
if(pst) {
|
||||
ZERO_STRUCTP(pst);
|
||||
ZERO_STRUCTP(pst);
|
||||
}
|
||||
|
||||
if(saved_last_component)
|
||||
@ -744,3 +742,16 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d
|
||||
CloseDir(cur_dir);
|
||||
return(False);
|
||||
}
|
||||
|
||||
/*************************************************************************** **
|
||||
* Initializes or clears the stat cache.
|
||||
*
|
||||
* Input: none.
|
||||
* Output: none.
|
||||
*
|
||||
* ************************************************************************** **
|
||||
*/
|
||||
BOOL reset_stat_cache( void )
|
||||
{
|
||||
return hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, (compare_function)(strcmp));
|
||||
} /* reset_stat_cache */
|
||||
|
@ -320,6 +320,7 @@ BOOL reload_services(BOOL test)
|
||||
}
|
||||
|
||||
reset_mangled_cache();
|
||||
reset_stat_cache();
|
||||
|
||||
/* this forces service parameters to be flushed */
|
||||
become_service(NULL,True);
|
||||
|
@ -40,6 +40,7 @@
|
||||
*/
|
||||
#define _PROTO_H_
|
||||
#define _NAMESERV_H_
|
||||
#define _HASH_H_
|
||||
|
||||
/* The main Samba system-adaptive header file.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user