2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-2000
6 Copyright (C) Jeremy Allison 1999-200
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern BOOL case_sensitive
;
29 /****************************************************************************
30 Stat cache code used in unix_convert.
31 *****************************************************************************/
33 static int global_stat_cache_lookups
;
34 static int global_stat_cache_misses
;
35 static int global_stat_cache_hits
;
37 /****************************************************************************
38 Stat cache statistics code.
39 *****************************************************************************/
41 void print_stat_cache_statistics(void)
45 if(global_stat_cache_lookups
== 0)
48 eff
= (100.0* (double)global_stat_cache_hits
)/(double)global_stat_cache_lookups
;
50 DEBUG(0,("stat cache stats: lookups = %d, hits = %d, misses = %d, \
51 stat cache was %f%% effective.\n", global_stat_cache_lookups
,
52 global_stat_cache_hits
, global_stat_cache_misses
, eff
));
57 char names
[2]; /* This is extended via malloc... */
60 #define INIT_STAT_CACHE_SIZE 512
61 static hash_table stat_cache
;
63 /****************************************************************************
64 Add an entry into the stat cache.
65 *****************************************************************************/
67 void stat_cache_add( char *full_orig_name
, char *orig_translated_path
)
69 stat_cache_entry
*scp
;
70 stat_cache_entry
*found_scp
;
72 pstring translated_path
;
74 hash_element
*hash_elem
;
76 if (!lp_stat_cache()) return;
78 namelen
= strlen(orig_translated_path
);
81 * Don't cache trivial valid directory entries.
83 if((*full_orig_name
== '\0') || (strcmp(full_orig_name
, ".") == 0) ||
84 (strcmp(full_orig_name
, "..") == 0))
88 * If we are in case insentive mode, we need to
89 * store names that need no translation - else, it
93 if(case_sensitive
&& (strcmp(full_orig_name
, orig_translated_path
) == 0))
97 * Remove any trailing '/' characters from the
101 pstrcpy(translated_path
, orig_translated_path
);
102 if(translated_path
[namelen
-1] == '/') {
103 translated_path
[namelen
-1] = '\0';
108 * We will only replace namelen characters
110 * StrnCpy always null terminates.
113 StrnCpy(orig_name
, full_orig_name
, namelen
);
115 strupper( orig_name
);
118 * Check this name doesn't exist in the cache before we
122 if ((hash_elem
= hash_lookup(&stat_cache
, orig_name
))) {
123 found_scp
= (stat_cache_entry
*)(hash_elem
->value
);
124 if (strcmp((found_scp
->names
+found_scp
->name_len
+1), translated_path
) == 0) {
127 hash_remove(&stat_cache
, hash_elem
);
128 if((scp
= (stat_cache_entry
*)malloc(sizeof(stat_cache_entry
)+2*namelen
)) == NULL
) {
129 DEBUG(0,("stat_cache_add: Out of memory !\n"));
132 pstrcpy(scp
->names
, orig_name
);
133 pstrcpy((scp
->names
+namelen
+1), translated_path
);
134 scp
->name_len
= namelen
;
135 hash_insert(&stat_cache
, (char *)scp
, orig_name
);
144 if((scp
= (stat_cache_entry
*)malloc(sizeof(stat_cache_entry
)+2*namelen
)) == NULL
) {
145 DEBUG(0,("stat_cache_add: Out of memory !\n"));
148 pstrcpy(scp
->names
, orig_name
);
149 pstrcpy(scp
->names
+namelen
+1, translated_path
);
150 scp
->name_len
= namelen
;
151 hash_insert(&stat_cache
, (char *)scp
, orig_name
);
154 DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp
->names
, (scp
->names
+scp
->name_len
+1)));
157 /****************************************************************************
158 Look through the stat cache for an entry - promote it to the top if found.
159 Return True if we translated (and did a scuccessful stat on) the entire name.
160 *****************************************************************************/
162 BOOL
stat_cache_lookup(connection_struct
*conn
, char *name
, char *dirpath
,
163 char **start
, SMB_STRUCT_STAT
*pst
)
165 stat_cache_entry
*scp
;
169 hash_element
*hash_elem
;
172 if (!lp_stat_cache())
175 namelen
= strlen(name
);
178 global_stat_cache_lookups
++;
181 * Don't lookup trivial valid directory entries.
183 if((*name
== '\0') || (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0)) {
184 global_stat_cache_misses
++;
188 pstrcpy(chk_name
, name
);
190 strupper( chk_name
);
193 hash_elem
= hash_lookup(&stat_cache
, chk_name
);
194 if(hash_elem
== NULL
) {
196 * Didn't find it - remove last component for next try.
198 sp
= strrchr(chk_name
, '/');
203 * We reached the end of the name - no match.
205 global_stat_cache_misses
++;
208 if((*chk_name
== '\0') || (strcmp(chk_name
, ".") == 0)
209 || (strcmp(chk_name
, "..") == 0)) {
210 global_stat_cache_misses
++;
214 scp
= (stat_cache_entry
*)(hash_elem
->value
);
215 global_stat_cache_hits
++;
216 trans_name
= scp
->names
+scp
->name_len
+1;
217 if(conn
->vfs_ops
.stat(dos_to_unix(trans_name
,False
), pst
) != 0) {
218 /* Discard this entry - it doesn't exist in the filesystem. */
219 hash_remove(&stat_cache
, hash_elem
);
222 memcpy(name
, trans_name
, scp
->name_len
);
223 *start
= &name
[scp
->name_len
];
226 StrnCpy( dirpath
, trans_name
, name
- (*start
));
227 return (namelen
== scp
->name_len
);
232 /*************************************************************************** **
233 * Initializes or clears the stat cache.
238 * ************************************************************************** **
240 BOOL
reset_stat_cache( void )
242 return hash_table_init( &stat_cache
, INIT_STAT_CACHE_SIZE
, (compare_function
)(strcmp
));
243 } /* reset_stat_cache */