2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-2000
5 Copyright (C) Jeremy Allison 1999-2000
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 extern BOOL case_sensitive
;
28 /****************************************************************************
29 Stat cache code used in unix_convert.
30 *****************************************************************************/
34 char names
[2]; /* This is extended via malloc... */
37 #define INIT_STAT_CACHE_SIZE 512
38 static hash_table stat_cache
;
40 /****************************************************************************
41 Add an entry into the stat cache.
42 *****************************************************************************/
44 void stat_cache_add( char *full_orig_name
, char *orig_translated_path
)
46 stat_cache_entry
*scp
;
47 stat_cache_entry
*found_scp
;
49 pstring translated_path
;
51 hash_element
*hash_elem
;
53 if (!lp_stat_cache()) return;
55 namelen
= strlen(orig_translated_path
);
58 * Don't cache trivial valid directory entries.
60 if((*full_orig_name
== '\0') || (strcmp(full_orig_name
, ".") == 0) ||
61 (strcmp(full_orig_name
, "..") == 0))
65 * If we are in case insentive mode, we need to
66 * store names that need no translation - else, it
70 if(case_sensitive
&& (strcmp(full_orig_name
, orig_translated_path
) == 0))
74 * Remove any trailing '/' characters from the
78 pstrcpy(translated_path
, orig_translated_path
);
79 if(translated_path
[namelen
-1] == '/') {
80 translated_path
[namelen
-1] = '\0';
85 * We will only replace namelen characters
87 * StrnCpy always null terminates.
90 StrnCpy(orig_name
, full_orig_name
, namelen
);
92 strupper( orig_name
);
95 * Check this name doesn't exist in the cache before we
99 if ((hash_elem
= hash_lookup(&stat_cache
, orig_name
))) {
100 found_scp
= (stat_cache_entry
*)(hash_elem
->value
);
101 if (strcmp((found_scp
->names
+found_scp
->name_len
+1), translated_path
) == 0) {
104 hash_remove(&stat_cache
, hash_elem
);
105 if((scp
= (stat_cache_entry
*)malloc(sizeof(stat_cache_entry
)+2*namelen
)) == NULL
) {
106 DEBUG(0,("stat_cache_add: Out of memory !\n"));
109 pstrcpy(scp
->names
, orig_name
);
110 pstrcpy((scp
->names
+namelen
+1), translated_path
);
111 scp
->name_len
= namelen
;
112 hash_insert(&stat_cache
, (char *)scp
, orig_name
);
121 if((scp
= (stat_cache_entry
*)malloc(sizeof(stat_cache_entry
)+2*namelen
)) == NULL
) {
122 DEBUG(0,("stat_cache_add: Out of memory !\n"));
125 safe_strcpy(scp
->names
, orig_name
, namelen
);
126 safe_strcpy(scp
->names
+namelen
+1, translated_path
, namelen
);
127 scp
->name_len
= namelen
;
128 hash_insert(&stat_cache
, (char *)scp
, orig_name
);
131 DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp
->names
, (scp
->names
+scp
->name_len
+1)));
134 /****************************************************************************
135 Look through the stat cache for an entry - promote it to the top if found.
136 Return True if we translated (and did a scuccessful stat on) the entire name.
137 *****************************************************************************/
139 BOOL
stat_cache_lookup(connection_struct
*conn
, char *name
, char *dirpath
,
140 char **start
, SMB_STRUCT_STAT
*pst
)
142 stat_cache_entry
*scp
;
146 hash_element
*hash_elem
;
149 if (!lp_stat_cache())
152 namelen
= strlen(name
);
156 DO_PROFILE_INC(statcache_lookups
);
159 * Don't lookup trivial valid directory entries.
161 if((*name
== '\0') || (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0)) {
162 DO_PROFILE_INC(statcache_misses
);
166 pstrcpy(chk_name
, name
);
168 strupper( chk_name
);
171 hash_elem
= hash_lookup(&stat_cache
, chk_name
);
172 if(hash_elem
== NULL
) {
174 * Didn't find it - remove last component for next try.
176 sp
= strrchr_m(chk_name
, '/');
181 * We reached the end of the name - no match.
183 DO_PROFILE_INC(statcache_misses
);
186 if((*chk_name
== '\0') || (strcmp(chk_name
, ".") == 0)
187 || (strcmp(chk_name
, "..") == 0)) {
188 DO_PROFILE_INC(statcache_misses
);
192 scp
= (stat_cache_entry
*)(hash_elem
->value
);
193 DO_PROFILE_INC(statcache_hits
);
194 trans_name
= scp
->names
+scp
->name_len
+1;
195 if(vfs_stat(conn
,trans_name
, pst
) != 0) {
196 /* Discard this entry - it doesn't exist in the filesystem. */
197 hash_remove(&stat_cache
, hash_elem
);
200 memcpy(name
, trans_name
, scp
->name_len
);
201 *start
= &name
[scp
->name_len
];
204 StrnCpy( dirpath
, trans_name
, name
- (*start
));
205 return (namelen
== scp
->name_len
);
210 /*************************************************************************** **
211 * Initializes or clears the stat cache.
216 * ************************************************************************** **
218 BOOL
reset_stat_cache( void )
220 static BOOL initialised
;
221 if (!lp_stat_cache()) return True
;
224 hash_clear(&stat_cache
);
227 initialised
= hash_table_init( &stat_cache
, INIT_STAT_CACHE_SIZE
,
228 (compare_function
)(strcmp
));
230 } /* reset_stat_cache */