00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "includes.h"
00024
00025
00026
00027
00028
00029 static TDB_CONTEXT *tdb_stat_cache;
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 void stat_cache_add( const char *full_orig_name, const char *orig_translated_path, BOOL case_sensitive)
00044 {
00045 char *translated_path;
00046 size_t translated_path_length;
00047 TDB_DATA data_val;
00048 char *original_path;
00049 size_t original_path_length;
00050 size_t sc_size = lp_max_stat_cache_size();
00051
00052 if (!lp_stat_cache())
00053 return;
00054
00055 if (sc_size && (tdb_map_size(tdb_stat_cache) > sc_size*1024)) {
00056 reset_stat_cache();
00057 }
00058
00059 ZERO_STRUCT(data_val);
00060
00061
00062
00063
00064
00065 if((*full_orig_name == '\0') || (full_orig_name[0] == '.' &&
00066 ((full_orig_name[1] == '\0') ||
00067 (full_orig_name[1] == '.' && full_orig_name[2] == '\0'))))
00068 return;
00069
00070
00071
00072
00073
00074
00075
00076 if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0))
00077 return;
00078
00079
00080
00081
00082
00083
00084 translated_path = SMB_STRDUP(orig_translated_path);
00085 if (!translated_path)
00086 return;
00087
00088 translated_path_length = strlen(translated_path);
00089
00090 if(translated_path[translated_path_length-1] == '/') {
00091 translated_path[translated_path_length-1] = '\0';
00092 translated_path_length--;
00093 }
00094
00095 if(case_sensitive) {
00096 original_path = SMB_STRDUP(full_orig_name);
00097 } else {
00098 original_path = strdup_upper(full_orig_name);
00099 }
00100
00101 if (!original_path) {
00102 SAFE_FREE(translated_path);
00103 return;
00104 }
00105
00106 original_path_length = strlen(original_path);
00107
00108 if(original_path[original_path_length-1] == '/') {
00109 original_path[original_path_length-1] = '\0';
00110 original_path_length--;
00111 }
00112
00113 if (original_path_length != translated_path_length) {
00114 if (original_path_length < translated_path_length) {
00115 DEBUG(0, ("OOPS - tried to store stat cache entry for weird length paths [%s] %lu and [%s] %lu)!\n",
00116 original_path, (unsigned long)original_path_length, translated_path, (unsigned long)translated_path_length));
00117 SAFE_FREE(original_path);
00118 SAFE_FREE(translated_path);
00119 return;
00120 }
00121
00122
00123
00124
00125 original_path[translated_path_length] = '\0';
00126 original_path_length = translated_path_length;
00127 }
00128
00129
00130
00131
00132
00133 data_val.dsize = translated_path_length + 1;
00134 data_val.dptr = translated_path;
00135
00136 if (tdb_store_bystring(tdb_stat_cache, original_path, data_val, TDB_REPLACE) != 0) {
00137 DEBUG(0,("stat_cache_add: Error storing entry %s -> %s\n", original_path, translated_path));
00138 } else {
00139 DEBUG(5,("stat_cache_add: Added entry (%lx:size%x) %s -> %s\n",
00140 (unsigned long)data_val.dptr, (unsigned int)data_val.dsize, original_path, translated_path));
00141 }
00142
00143 SAFE_FREE(original_path);
00144 SAFE_FREE(translated_path);
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
00162 char **start, SMB_STRUCT_STAT *pst)
00163 {
00164 char *chk_name;
00165 size_t namelen;
00166 BOOL sizechanged = False;
00167 unsigned int num_components = 0;
00168
00169 if (!lp_stat_cache())
00170 return False;
00171
00172 namelen = strlen(name);
00173
00174 *start = name;
00175
00176 DO_PROFILE_INC(statcache_lookups);
00177
00178
00179
00180
00181 if((*name == '\0') || (name[0] == '.' &&
00182 ((name[1] == '\0') ||
00183 (name[1] == '.' && name[1] == '\0'))))
00184 return False;
00185
00186 if (conn->case_sensitive) {
00187 chk_name = SMB_STRDUP(name);
00188 if (!chk_name) {
00189 DEBUG(0, ("stat_cache_lookup: strdup failed!\n"));
00190 return False;
00191 }
00192
00193 } else {
00194 chk_name = strdup_upper(name);
00195 if (!chk_name) {
00196 DEBUG(0, ("stat_cache_lookup: strdup_upper failed!\n"));
00197 return False;
00198 }
00199
00200
00201
00202
00203
00204
00205 if (strlen(chk_name) != namelen)
00206 sizechanged = True;
00207 }
00208
00209 while (1) {
00210 TDB_DATA data_val;
00211 char *sp;
00212
00213 data_val = tdb_fetch_bystring(tdb_stat_cache, chk_name);
00214 if(data_val.dptr == NULL || data_val.dsize == 0) {
00215 DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n", chk_name ));
00216
00217
00218
00219 sp = strrchr_m(chk_name, '/');
00220 if (sp) {
00221 *sp = '\0';
00222
00223
00224
00225
00226 if (sizechanged)
00227 num_components++;
00228
00229 } else {
00230
00231
00232
00233 DO_PROFILE_INC(statcache_misses);
00234 SAFE_FREE(chk_name);
00235 return False;
00236 }
00237 if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0)
00238 || (strcmp(chk_name, "..") == 0)) {
00239 DO_PROFILE_INC(statcache_misses);
00240 SAFE_FREE(chk_name);
00241 return False;
00242 }
00243 } else {
00244 BOOL retval;
00245 char *translated_path = data_val.dptr;
00246 size_t translated_path_length = data_val.dsize - 1;
00247
00248 DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] -> [%s]\n", chk_name, translated_path ));
00249 DO_PROFILE_INC(statcache_hits);
00250 if(SMB_VFS_STAT(conn,translated_path, pst) != 0) {
00251
00252 tdb_delete_bystring(tdb_stat_cache, chk_name);
00253 SAFE_FREE(chk_name);
00254 SAFE_FREE(data_val.dptr);
00255 return False;
00256 }
00257
00258 if (!sizechanged) {
00259 memcpy(name, translated_path, MIN(sizeof(pstring)-1, translated_path_length));
00260 } else if (num_components == 0) {
00261 pstrcpy(name, translated_path);
00262 } else {
00263 sp = strnrchr_m(name, '/', num_components);
00264 if (sp) {
00265 pstring last_component;
00266 pstrcpy(last_component, sp);
00267 pstrcpy(name, translated_path);
00268 pstrcat(name, last_component);
00269 } else {
00270 pstrcpy(name, translated_path);
00271 }
00272 }
00273
00274
00275 *start = &name[translated_path_length];
00276 if(**start == '/')
00277 ++*start;
00278
00279 pstrcpy(dirpath, translated_path);
00280 retval = (namelen == translated_path_length) ? True : False;
00281 SAFE_FREE(chk_name);
00282 SAFE_FREE(data_val.dptr);
00283 return retval;
00284 }
00285 }
00286 }
00287
00288
00289
00290
00291
00292 void send_stat_cache_delete_message(const char *name)
00293 {
00294 #ifdef DEVELOPER
00295 message_send_all(conn_tdb_ctx(),
00296 MSG_SMB_STAT_CACHE_DELETE,
00297 name,
00298 strlen(name)+1,
00299 True,
00300 NULL);
00301 #endif
00302 }
00303
00304
00305
00306
00307
00308 void stat_cache_delete(const char *name)
00309 {
00310 char *lname = strdup_upper(name);
00311
00312 if (!lname) {
00313 return;
00314 }
00315 DEBUG(10,("stat_cache_delete: deleting name [%s] -> %s\n",
00316 lname, name ));
00317
00318 tdb_delete_bystring(tdb_stat_cache, lname);
00319 SAFE_FREE(lname);
00320 }
00321
00322
00323
00324
00325
00326
00327
00328 unsigned int fast_string_hash(TDB_DATA *key)
00329 {
00330 unsigned int n = 0;
00331 const char *p;
00332 for (p = key->dptr; *p != '\0'; p++) {
00333 n = ((n << 5) + n) ^ (unsigned int)(*p);
00334 }
00335 return n;
00336 }
00337
00338
00339
00340
00341
00342 BOOL reset_stat_cache( void )
00343 {
00344 if (!lp_stat_cache())
00345 return True;
00346
00347 if (tdb_stat_cache) {
00348 tdb_close(tdb_stat_cache);
00349 }
00350
00351
00352 tdb_stat_cache = tdb_open_ex("statcache", 1031, TDB_INTERNAL,
00353 (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
00354
00355 if (!tdb_stat_cache)
00356 return False;
00357 return True;
00358 }