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 *****************************************************************************/
35 char names
[2]; /* This is extended via malloc... */
38 #define INIT_STAT_CACHE_SIZE 512
39 static hash_table stat_cache
;
41 /****************************************************************************
42 Add an entry into the stat cache.
43 *****************************************************************************/
45 void stat_cache_add( char *full_orig_name
, char *orig_translated_path
)
47 stat_cache_entry
*scp
;
48 stat_cache_entry
*found_scp
;
50 pstring translated_path
;
52 hash_element
*hash_elem
;
54 if (!lp_stat_cache()) return;
56 namelen
= strlen(orig_translated_path
);
59 * Don't cache trivial valid directory entries.
61 if((*full_orig_name
== '\0') || (strcmp(full_orig_name
, ".") == 0) ||
62 (strcmp(full_orig_name
, "..") == 0))
66 * If we are in case insentive mode, we need to
67 * store names that need no translation - else, it
71 if(case_sensitive
&& (strcmp(full_orig_name
, orig_translated_path
) == 0))
75 * Remove any trailing '/' characters from the
79 pstrcpy(translated_path
, orig_translated_path
);
80 if(translated_path
[namelen
-1] == '/') {
81 translated_path
[namelen
-1] = '\0';
86 * We will only replace namelen characters
88 * StrnCpy always null terminates.
91 StrnCpy(orig_name
, full_orig_name
, namelen
);
93 strupper( orig_name
);
96 * Check this name doesn't exist in the cache before we
100 if ((hash_elem
= hash_lookup(&stat_cache
, orig_name
))) {
101 found_scp
= (stat_cache_entry
*)(hash_elem
->value
);
102 if (strcmp((found_scp
->names
+found_scp
->name_len
+1), translated_path
) == 0) {
105 hash_remove(&stat_cache
, hash_elem
);
106 if((scp
= (stat_cache_entry
*)malloc(sizeof(stat_cache_entry
)+2*namelen
)) == NULL
) {
107 DEBUG(0,("stat_cache_add: Out of memory !\n"));
110 pstrcpy(scp
->names
, orig_name
);
111 pstrcpy((scp
->names
+namelen
+1), translated_path
);
112 scp
->name_len
= namelen
;
113 hash_insert(&stat_cache
, (char *)scp
, orig_name
);
122 if((scp
= (stat_cache_entry
*)malloc(sizeof(stat_cache_entry
)+2*namelen
)) == NULL
) {
123 DEBUG(0,("stat_cache_add: Out of memory !\n"));
126 pstrcpy(scp
->names
, orig_name
);
127 pstrcpy(scp
->names
+namelen
+1, translated_path
);
128 scp
->name_len
= namelen
;
129 hash_insert(&stat_cache
, (char *)scp
, orig_name
);
132 DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp
->names
, (scp
->names
+scp
->name_len
+1)));
135 /****************************************************************************
136 Look through the stat cache for an entry - promote it to the top if found.
137 Return True if we translated (and did a scuccessful stat on) the entire name.
138 *****************************************************************************/
140 BOOL
stat_cache_lookup(connection_struct
*conn
, char *name
, char *dirpath
,
141 char **start
, SMB_STRUCT_STAT
*pst
)
143 stat_cache_entry
*scp
;
147 hash_element
*hash_elem
;
150 if (!lp_stat_cache())
153 namelen
= strlen(name
);
157 DO_PROFILE_INC(statcache_lookups
);
160 * Don't lookup trivial valid directory entries.
162 if((*name
== '\0') || (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0)) {
163 DO_PROFILE_INC(statcache_misses
);
167 pstrcpy(chk_name
, name
);
169 strupper( chk_name
);
172 hash_elem
= hash_lookup(&stat_cache
, chk_name
);
173 if(hash_elem
== NULL
) {
175 * Didn't find it - remove last component for next try.
177 sp
= strrchr(chk_name
, '/');
182 * We reached the end of the name - no match.
184 DO_PROFILE_INC(statcache_misses
);
187 if((*chk_name
== '\0') || (strcmp(chk_name
, ".") == 0)
188 || (strcmp(chk_name
, "..") == 0)) {
189 DO_PROFILE_INC(statcache_misses
);
193 scp
= (stat_cache_entry
*)(hash_elem
->value
);
194 DO_PROFILE_INC(statcache_hits
);
195 trans_name
= scp
->names
+scp
->name_len
+1;
196 if(vfs_stat(conn
,trans_name
, pst
) != 0) {
197 /* Discard this entry - it doesn't exist in the filesystem. */
198 hash_remove(&stat_cache
, hash_elem
);
201 memcpy(name
, trans_name
, scp
->name_len
);
202 *start
= &name
[scp
->name_len
];
205 StrnCpy( dirpath
, trans_name
, name
- (*start
));
206 return (namelen
== scp
->name_len
);
211 /*************************************************************************** **
212 * Initializes or clears the stat cache.
217 * ************************************************************************** **
219 BOOL
reset_stat_cache( void )
221 static BOOL initialised
;
222 if (!lp_stat_cache()) return True
;
225 hash_clear(&stat_cache
);
228 initialised
= hash_table_init( &stat_cache
, INIT_STAT_CACHE_SIZE
,
229 (compare_function
)(strcmp
));
231 } /* reset_stat_cache */