| 1 | #include <stdio.h> | 
|---|
| 2 | #include <stdlib.h> | 
|---|
| 3 | #include <stdarg.h> | 
|---|
| 4 | #include <string.h> | 
|---|
| 5 | #include <time.h> | 
|---|
| 6 |  | 
|---|
| 7 | #define NDPL_LARGEFILES | 
|---|
| 8 | #define INCL_LONGLONG | 
|---|
| 9 | #include <ndextpl2.h> | 
|---|
| 10 |  | 
|---|
| 11 | #include "smbwrp.h" | 
|---|
| 12 |  | 
|---|
| 13 | extern PLUGINHELPERTABLE2L *ph; | 
|---|
| 14 |  | 
|---|
| 15 | /* | 
|---|
| 16 | * Static helpers. | 
|---|
| 17 | */ | 
|---|
| 18 | static int lockCreate (NDMUTEX *pMutex) | 
|---|
| 19 | { | 
|---|
| 20 | return ph->fsphCreateMutex (pMutex); | 
|---|
| 21 | } | 
|---|
| 22 |  | 
|---|
| 23 | static void lockDelete (NDMUTEX mutex) | 
|---|
| 24 | { | 
|---|
| 25 | ph->fsphCloseMutex (mutex); | 
|---|
| 26 | } | 
|---|
| 27 |  | 
|---|
| 28 | static int lockRequest (NDMUTEX mutex) | 
|---|
| 29 | { | 
|---|
| 30 | return ph->fsphRequestMutex (mutex, 10000); | 
|---|
| 31 | } | 
|---|
| 32 |  | 
|---|
| 33 | void lockRelease (NDMUTEX mutex) | 
|---|
| 34 | { | 
|---|
| 35 | ph->fsphReleaseMutex (mutex); | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | static ULONG Hash (const char *pData, ULONG ulLen) | 
|---|
| 39 | { | 
|---|
| 40 | ULONG hash = 0ul, g; | 
|---|
| 41 | static ULONG ulHashModule = 30031ul; | 
|---|
| 42 |  | 
|---|
| 43 | const char *p; | 
|---|
| 44 | int i; | 
|---|
| 45 | for( p = pData, i = 0; i < ulLen; i++, p++ ) | 
|---|
| 46 | { | 
|---|
| 47 | hash = ( hash << 4 ) + (*p); | 
|---|
| 48 | g = hash & 0xf0000000ul; | 
|---|
| 49 | if ( g ) | 
|---|
| 50 | { | 
|---|
| 51 | hash ^= ( g >> 24 ); | 
|---|
| 52 | hash ^= g; | 
|---|
| 53 | } | 
|---|
| 54 | } | 
|---|
| 55 | return ( hash % ulHashModule ); | 
|---|
| 56 | } | 
|---|
| 57 |  | 
|---|
| 58 | static unsigned long timesec (void) | 
|---|
| 59 | { | 
|---|
| 60 | ULONG ul = 0; | 
|---|
| 61 | DosQuerySysInfo (QSV_TIME_LOW, QSV_TIME_LOW, &ul, sizeof (ul)); | 
|---|
| 62 | return ul; | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | static unsigned long computehash (const char *s) | 
|---|
| 66 | { | 
|---|
| 67 | return s? Hash ((char *)s, strlen (s)): 0; | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 |  | 
|---|
| 71 |  | 
|---|
| 72 | /* | 
|---|
| 73 | * An entry in the directory cache contains one directory listing. | 
|---|
| 74 | */ | 
|---|
| 75 | typedef struct DirectoryCacheEntry | 
|---|
| 76 | { | 
|---|
| 77 | struct DirectoryCacheEntry *pNext; | 
|---|
| 78 | struct DirectoryCacheEntry *pPrev; | 
|---|
| 79 |  | 
|---|
| 80 | struct DirectoryCache *pdc; | 
|---|
| 81 |  | 
|---|
| 82 | smbwrp_fileinfo *aInfos; | 
|---|
| 83 | int cInfos; | 
|---|
| 84 | int cInfosAllocated; | 
|---|
| 85 |  | 
|---|
| 86 | char *pszPath; | 
|---|
| 87 | ULONG ulHash; | 
|---|
| 88 | ULONG ulLastUpdateTime; | 
|---|
| 89 | int fInvalid; | 
|---|
| 90 | } DirectoryCacheEntry; | 
|---|
| 91 |  | 
|---|
| 92 | typedef struct DirectoryCache | 
|---|
| 93 | { | 
|---|
| 94 | NDMUTEX mutex; | 
|---|
| 95 |  | 
|---|
| 96 | DirectoryCacheEntry *pEntriesHead; | 
|---|
| 97 | DirectoryCacheEntry *pEntriesTail; | 
|---|
| 98 | int cEntries; | 
|---|
| 99 |  | 
|---|
| 100 | int fEnabled; | 
|---|
| 101 | unsigned long ulExpirationTime; | 
|---|
| 102 | int cMaxEntries; | 
|---|
| 103 | } DirectoryCache; | 
|---|
| 104 |  | 
|---|
| 105 | enum { | 
|---|
| 106 | CacheFault = 0, | 
|---|
| 107 | CacheOk = 1 | 
|---|
| 108 | }; | 
|---|
| 109 |  | 
|---|
| 110 |  | 
|---|
| 111 | static int dceCreate (DirectoryCacheEntry **ppdce, DirectoryCache *pdc, const char *path, int cFiles) | 
|---|
| 112 | { | 
|---|
| 113 | DirectoryCacheEntry *pdce = (DirectoryCacheEntry *)malloc(sizeof(DirectoryCacheEntry)); | 
|---|
| 114 |  | 
|---|
| 115 | if (!pdce) | 
|---|
| 116 | { | 
|---|
| 117 | return ERROR_NOT_ENOUGH_MEMORY; | 
|---|
| 118 | } | 
|---|
| 119 |  | 
|---|
| 120 | pdce->aInfos = (smbwrp_fileinfo *)malloc(cFiles * sizeof (smbwrp_fileinfo)); | 
|---|
| 121 | if (!pdce->aInfos) | 
|---|
| 122 | { | 
|---|
| 123 | free (pdce); | 
|---|
| 124 | return ERROR_NOT_ENOUGH_MEMORY; | 
|---|
| 125 | } | 
|---|
| 126 | pdce->cInfos = 0; | 
|---|
| 127 | pdce->cInfosAllocated = cFiles; | 
|---|
| 128 | pdce->ulHash = computehash (path); | 
|---|
| 129 | pdce->ulLastUpdateTime = 0; | 
|---|
| 130 | pdce->pdc = pdc; | 
|---|
| 131 | pdce->fInvalid = 0; | 
|---|
| 132 |  | 
|---|
| 133 | int l = strlen (path); | 
|---|
| 134 | pdce->pszPath = (char *)malloc (l + 1); | 
|---|
| 135 | memcpy (pdce->pszPath, path, l + 1); | 
|---|
| 136 |  | 
|---|
| 137 | pdce->pNext = NULL; | 
|---|
| 138 | pdce->pPrev = NULL; | 
|---|
| 139 |  | 
|---|
| 140 | *ppdce = pdce; | 
|---|
| 141 |  | 
|---|
| 142 | return NO_ERROR; | 
|---|
| 143 | } | 
|---|
| 144 |  | 
|---|
| 145 | static void dceDelete (DirectoryCacheEntry *pdce) | 
|---|
| 146 | { | 
|---|
| 147 | free(pdce->aInfos); | 
|---|
| 148 | free(pdce->pszPath); | 
|---|
| 149 | free(pdce); | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | static void dceClear (DirectoryCacheEntry *pdce) | 
|---|
| 153 | { | 
|---|
| 154 | pdce->cInfos = 0; | 
|---|
| 155 | } | 
|---|
| 156 |  | 
|---|
| 157 | static void dceWriteEntry (DirectoryCacheEntry *pdce, const smbwrp_fileinfo *finfo) | 
|---|
| 158 | { | 
|---|
| 159 | if (pdce->cInfos >= pdce->cInfosAllocated) | 
|---|
| 160 | { | 
|---|
| 161 | /* 50% increase of the buffer, but at least 1 more. */ | 
|---|
| 162 | int cNewAllocated = pdce->cInfosAllocated + pdce->cInfosAllocated / 2 + 1; | 
|---|
| 163 |  | 
|---|
| 164 | smbwrp_fileinfo *pNewInfos = (smbwrp_fileinfo *)realloc(pdce->aInfos, | 
|---|
| 165 | cNewAllocated * sizeof (smbwrp_fileinfo)); | 
|---|
| 166 |  | 
|---|
| 167 | debuglocal(9, "dceWriteEntry: [%s] realloc %d -> %d\n", pdce->pszPath, pdce->cInfosAllocated, cNewAllocated); | 
|---|
| 168 | if (pNewInfos) | 
|---|
| 169 | { | 
|---|
| 170 | pdce->cInfosAllocated = cNewAllocated; | 
|---|
| 171 | pdce->aInfos = pNewInfos; | 
|---|
| 172 | } | 
|---|
| 173 | else | 
|---|
| 174 | { | 
|---|
| 175 | /* Mark the entry as invalid. The entry will be deleted in dircache_write_end */ | 
|---|
| 176 | pdce->fInvalid = 1; | 
|---|
| 177 | return; | 
|---|
| 178 | } | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 | pdce->aInfos[pdce->cInfos] = *finfo; | 
|---|
| 182 | pdce->cInfos++; | 
|---|
| 183 | } | 
|---|
| 184 |  | 
|---|
| 185 | static void dceAdjust (DirectoryCacheEntry *pdce) | 
|---|
| 186 | { | 
|---|
| 187 | /* If the entry has too many preallocated info structures, adjust the memory allocation */ | 
|---|
| 188 | int cFree = pdce->cInfosAllocated - pdce->cInfos; | 
|---|
| 189 |  | 
|---|
| 190 | if (cFree > pdce->cInfos / 2) | 
|---|
| 191 | { | 
|---|
| 192 | /* More than 50% is free. Make the free space 2 times smaller. */ | 
|---|
| 193 | int cNewAllocated = pdce->cInfos + cFree / 2; | 
|---|
| 194 |  | 
|---|
| 195 | smbwrp_fileinfo *pNewInfos = (smbwrp_fileinfo *)realloc(pdce->aInfos, | 
|---|
| 196 | cNewAllocated * sizeof (smbwrp_fileinfo)); | 
|---|
| 197 |  | 
|---|
| 198 | debuglocal(9, "dceAdjust: [%s] realloc %d -> %d\n", pdce->pszPath, pdce->cInfosAllocated, cNewAllocated); | 
|---|
| 199 | if (pNewInfos) | 
|---|
| 200 | { | 
|---|
| 201 | pdce->cInfosAllocated = cNewAllocated; | 
|---|
| 202 | pdce->aInfos = pNewInfos; | 
|---|
| 203 | } | 
|---|
| 204 | else | 
|---|
| 205 | { | 
|---|
| 206 | /* Ignore. The old buffer remains. */ | 
|---|
| 207 | } | 
|---|
| 208 | } | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | static int dcePathEqualsTo (DirectoryCacheEntry *pdce, const char *path) | 
|---|
| 212 | { | 
|---|
| 213 | debuglocal(9, "dcePathEqualTo: [%s] [%s]\n", path, pdce->pszPath); | 
|---|
| 214 | return ph->fsphStrICmp (path, pdce->pszPath) == 0; | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | static int dcePathPrefixedWith (DirectoryCacheEntry *pdce, const char *path) | 
|---|
| 218 | { | 
|---|
| 219 | return ph->fsphStrNICmp (path, pdce->pszPath, strlen (path)) == 0; | 
|---|
| 220 | } | 
|---|
| 221 |  | 
|---|
| 222 | static int dceExpired (DirectoryCacheEntry *pdce, unsigned long ulExpirationTime) | 
|---|
| 223 | { | 
|---|
| 224 | return (timesec () - pdce->ulLastUpdateTime >= ulExpirationTime); | 
|---|
| 225 | } | 
|---|
| 226 |  | 
|---|
| 227 | static struct DirectoryCacheEntry *dcFindDirCache (struct DirectoryCache *pdc, const char *path, int fPrefix) | 
|---|
| 228 | { | 
|---|
| 229 | unsigned long hash = computehash (path); | 
|---|
| 230 |  | 
|---|
| 231 | DirectoryCacheEntry *iter = pdc->pEntriesHead; | 
|---|
| 232 |  | 
|---|
| 233 | debuglocal(9, "findDirCache: [%s]\n", path); | 
|---|
| 234 |  | 
|---|
| 235 | while (iter != NULL) | 
|---|
| 236 | { | 
|---|
| 237 | debuglocal(9, "findDirCache: entry [%s]\n", iter->pszPath); | 
|---|
| 238 | if (fPrefix) | 
|---|
| 239 | { | 
|---|
| 240 | if (dcePathPrefixedWith (iter, path)) | 
|---|
| 241 | { | 
|---|
| 242 | break; | 
|---|
| 243 | } | 
|---|
| 244 | } | 
|---|
| 245 | else | 
|---|
| 246 | { | 
|---|
| 247 | if (    iter->ulHash == hash | 
|---|
| 248 | && dcePathEqualsTo (iter, path) | 
|---|
| 249 | ) | 
|---|
| 250 | { | 
|---|
| 251 | break; | 
|---|
| 252 | } | 
|---|
| 253 | } | 
|---|
| 254 | iter = iter->pNext; | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | debuglocal(9, "findDirCache: %p\n", iter); | 
|---|
| 258 |  | 
|---|
| 259 | return iter; | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 | static int dcCreate (struct DirectoryCache **ppdc) | 
|---|
| 263 | { | 
|---|
| 264 | int rc; | 
|---|
| 265 |  | 
|---|
| 266 | DirectoryCache *pdc = (DirectoryCache *)malloc(sizeof (DirectoryCache)); | 
|---|
| 267 |  | 
|---|
| 268 | if (!pdc) | 
|---|
| 269 | { | 
|---|
| 270 | return ERROR_NOT_ENOUGH_MEMORY; | 
|---|
| 271 | } | 
|---|
| 272 |  | 
|---|
| 273 | rc = lockCreate (&pdc->mutex); | 
|---|
| 274 |  | 
|---|
| 275 | if (rc != NO_ERROR) | 
|---|
| 276 | { | 
|---|
| 277 | free(pdc); | 
|---|
| 278 | return rc; | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | pdc->pEntriesHead = NULL; | 
|---|
| 282 | pdc->pEntriesTail = NULL; | 
|---|
| 283 | pdc->cEntries = 0; | 
|---|
| 284 |  | 
|---|
| 285 | pdc->fEnabled = 0; | 
|---|
| 286 | pdc->ulExpirationTime = -1; | 
|---|
| 287 |  | 
|---|
| 288 | *ppdc = pdc; | 
|---|
| 289 |  | 
|---|
| 290 | return NO_ERROR; | 
|---|
| 291 | } | 
|---|
| 292 |  | 
|---|
| 293 | static void dcDelete (struct DirectoryCache *pdc) | 
|---|
| 294 | { | 
|---|
| 295 | DirectoryCacheEntry *iter = pdc->pEntriesHead; | 
|---|
| 296 |  | 
|---|
| 297 | while (iter != NULL) | 
|---|
| 298 | { | 
|---|
| 299 | DirectoryCacheEntry *next = iter->pNext; | 
|---|
| 300 |  | 
|---|
| 301 | dceDelete (iter); | 
|---|
| 302 |  | 
|---|
| 303 | iter = next; | 
|---|
| 304 | } | 
|---|
| 305 |  | 
|---|
| 306 | lockDelete (pdc->mutex); | 
|---|
| 307 | free (pdc); | 
|---|
| 308 | } | 
|---|
| 309 |  | 
|---|
| 310 | static void dcRemoveEntry (DirectoryCacheEntry *pdce) | 
|---|
| 311 | { | 
|---|
| 312 | DirectoryCache *pdc = pdce->pdc; | 
|---|
| 313 |  | 
|---|
| 314 | if (pdce->pNext) | 
|---|
| 315 | { | 
|---|
| 316 | pdce->pNext->pPrev = pdce->pPrev; | 
|---|
| 317 | } | 
|---|
| 318 | else | 
|---|
| 319 | { | 
|---|
| 320 | pdc->pEntriesTail = pdce->pPrev; | 
|---|
| 321 | } | 
|---|
| 322 |  | 
|---|
| 323 | if (pdce->pPrev) | 
|---|
| 324 | { | 
|---|
| 325 | pdce->pPrev->pNext = pdce->pNext; | 
|---|
| 326 | } | 
|---|
| 327 | else | 
|---|
| 328 | { | 
|---|
| 329 | pdc->pEntriesHead = pdce->pNext; | 
|---|
| 330 | } | 
|---|
| 331 |  | 
|---|
| 332 | pdc->cEntries--; | 
|---|
| 333 | } | 
|---|
| 334 |  | 
|---|
| 335 | static void dcInsertEntry (DirectoryCacheEntry *pdce) | 
|---|
| 336 | { | 
|---|
| 337 | DirectoryCache *pdc = pdce->pdc; | 
|---|
| 338 |  | 
|---|
| 339 | pdce->pNext = pdc->pEntriesHead; | 
|---|
| 340 |  | 
|---|
| 341 | if (pdc->pEntriesHead) | 
|---|
| 342 | { | 
|---|
| 343 | pdc->pEntriesHead->pPrev = pdce; | 
|---|
| 344 | } | 
|---|
| 345 | else | 
|---|
| 346 | { | 
|---|
| 347 | pdc->pEntriesTail = pdce; | 
|---|
| 348 | } | 
|---|
| 349 |  | 
|---|
| 350 | pdc->pEntriesHead = pdce; | 
|---|
| 351 | pdc->cEntries++; | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 |  | 
|---|
| 355 | static void dcEnable (DirectoryCache *pdc, int fEnable, unsigned long ulExpirationTime, int cMaxEntries) | 
|---|
| 356 | { | 
|---|
| 357 | pdc->fEnabled = fEnable; | 
|---|
| 358 | pdc->ulExpirationTime = ulExpirationTime; | 
|---|
| 359 | pdc->cMaxEntries = cMaxEntries; | 
|---|
| 360 | }; | 
|---|
| 361 |  | 
|---|
| 362 | static int dcExistsInCache (DirectoryCache *pdc, const char *path) | 
|---|
| 363 | { | 
|---|
| 364 | int rc = CacheFault; | 
|---|
| 365 |  | 
|---|
| 366 | if (pdc->fEnabled) | 
|---|
| 367 | { | 
|---|
| 368 | if (dcFindDirCache (pdc, path, 0) != NULL) | 
|---|
| 369 | { | 
|---|
| 370 | rc = CacheOk; | 
|---|
| 371 | } | 
|---|
| 372 |  | 
|---|
| 373 | debuglocal(9, "ExistsInCache: [%s], %d\n", path, rc); | 
|---|
| 374 | } | 
|---|
| 375 |  | 
|---|
| 376 | return rc; | 
|---|
| 377 | } | 
|---|
| 378 |  | 
|---|
| 379 | static int dcRead (DirectoryCache *pdc, const char *path, | 
|---|
| 380 | PFNADDDIRENTRY fn, | 
|---|
| 381 | filelist_state *state, | 
|---|
| 382 | int *ptotal_received, int fForceCache) | 
|---|
| 383 | { | 
|---|
| 384 | int i; | 
|---|
| 385 |  | 
|---|
| 386 | int rc = CacheFault; | 
|---|
| 387 |  | 
|---|
| 388 | if (pdc->fEnabled) | 
|---|
| 389 | { | 
|---|
| 390 | DirectoryCacheEntry *pdce; | 
|---|
| 391 |  | 
|---|
| 392 | pdce = dcFindDirCache (pdc, path, 0); | 
|---|
| 393 |  | 
|---|
| 394 | if (pdce) | 
|---|
| 395 | { | 
|---|
| 396 | debuglocal(9, "CacheRead: entry %p found for [%s]\n", pdce, path); | 
|---|
| 397 |  | 
|---|
| 398 | if (fForceCache) | 
|---|
| 399 | { | 
|---|
| 400 | for (i = 0; i < pdce->cInfos; i++) | 
|---|
| 401 | { | 
|---|
| 402 | fn ("", &pdce->aInfos[i], path, state); | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 | rc = CacheOk; | 
|---|
| 406 | } | 
|---|
| 407 | else | 
|---|
| 408 | { | 
|---|
| 409 | if (dceExpired (pdce, pdc->ulExpirationTime)) | 
|---|
| 410 | { | 
|---|
| 411 | debuglocal(9, "CacheRead: expired\n"); | 
|---|
| 412 | dcRemoveEntry (pdce); | 
|---|
| 413 | dceDelete (pdce); | 
|---|
| 414 | } | 
|---|
| 415 | else | 
|---|
| 416 | { | 
|---|
| 417 | for (i = 0; i < pdce->cInfos; i++) | 
|---|
| 418 | { | 
|---|
| 419 | fn ("", &pdce->aInfos[i], path, state); | 
|---|
| 420 | } | 
|---|
| 421 |  | 
|---|
| 422 | rc = CacheOk; | 
|---|
| 423 | } | 
|---|
| 424 | } | 
|---|
| 425 |  | 
|---|
| 426 | if (rc == CacheOk) | 
|---|
| 427 | { | 
|---|
| 428 | *ptotal_received = (int)pdce->cInfos; | 
|---|
| 429 | } | 
|---|
| 430 | } | 
|---|
| 431 |  | 
|---|
| 432 | debuglocal(9, "CacheRead: [%s], %d\n", path, rc); | 
|---|
| 433 | } | 
|---|
| 434 |  | 
|---|
| 435 | return rc; | 
|---|
| 436 | } | 
|---|
| 437 |  | 
|---|
| 438 | static DirectoryCacheEntry *dcWriteBegin (DirectoryCache *pdc, const char *path, int cFiles) | 
|---|
| 439 | { | 
|---|
| 440 | DirectoryCacheEntry *pdce = NULL; | 
|---|
| 441 |  | 
|---|
| 442 | if (pdc->fEnabled) | 
|---|
| 443 | { | 
|---|
| 444 | pdce = dcFindDirCache (pdc, path, 0); | 
|---|
| 445 |  | 
|---|
| 446 | if (!pdce) | 
|---|
| 447 | { | 
|---|
| 448 | /* Does not exist in the cache yet. */ | 
|---|
| 449 | dceCreate (&pdce, pdc, path, cFiles); | 
|---|
| 450 | } | 
|---|
| 451 | else | 
|---|
| 452 | { | 
|---|
| 453 | /* Discard the listing. */ | 
|---|
| 454 | dceClear (pdce); | 
|---|
| 455 | /* Remove the entry from list. It will be added again in dircache_write_end. */ | 
|---|
| 456 | dcRemoveEntry (pdce); | 
|---|
| 457 | } | 
|---|
| 458 |  | 
|---|
| 459 | if (pdce) | 
|---|
| 460 | { | 
|---|
| 461 | pdce->ulLastUpdateTime = timesec (); | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | debuglocal(9, "CacheWriteBegin: %s\n", path); | 
|---|
| 465 | } | 
|---|
| 466 |  | 
|---|
| 467 | return pdce; | 
|---|
| 468 | } | 
|---|
| 469 |  | 
|---|
| 470 |  | 
|---|
| 471 | static void dcInvalidate (DirectoryCache *pdc, const char *path, int fPrefix) | 
|---|
| 472 | { | 
|---|
| 473 | DirectoryCacheEntry *pdce; | 
|---|
| 474 |  | 
|---|
| 475 | debuglocal(9, "CacheInvalidate: [%s]\n", path); | 
|---|
| 476 |  | 
|---|
| 477 | pdce = dcFindDirCache (pdc, path, fPrefix); | 
|---|
| 478 |  | 
|---|
| 479 | while (pdce) | 
|---|
| 480 | { | 
|---|
| 481 | dcRemoveEntry (pdce); | 
|---|
| 482 | dceDelete (pdce); | 
|---|
| 483 |  | 
|---|
| 484 | pdce = dcFindDirCache (pdc, path, fPrefix); | 
|---|
| 485 | } | 
|---|
| 486 | } | 
|---|
| 487 |  | 
|---|
| 488 | static int dcFindPath (DirectoryCache *pdc, | 
|---|
| 489 | const char *path, | 
|---|
| 490 | const char *parent, | 
|---|
| 491 | const char *name, | 
|---|
| 492 | smbwrp_fileinfo *finfo, | 
|---|
| 493 | unsigned long *pulAge) | 
|---|
| 494 | { | 
|---|
| 495 | DirectoryCacheEntry *pdce = pdc->pEntriesHead; | 
|---|
| 496 |  | 
|---|
| 497 | unsigned long hash = computehash (parent); | 
|---|
| 498 |  | 
|---|
| 499 | debuglocal(9, "dcFindPath: [%s][%s]\n", parent, name); | 
|---|
| 500 |  | 
|---|
| 501 | while (pdce != NULL) | 
|---|
| 502 | { | 
|---|
| 503 | debuglocal(9, "dcFindPath: entry [%s]\n", pdce->pszPath); | 
|---|
| 504 |  | 
|---|
| 505 | if (   pdce->ulHash == hash | 
|---|
| 506 | && dcePathEqualsTo (pdce, parent)) | 
|---|
| 507 | { | 
|---|
| 508 | /* This entry should contain the path. */ | 
|---|
| 509 | int i; | 
|---|
| 510 | for (i = 0; i < pdce->cInfos; i++) | 
|---|
| 511 | { | 
|---|
| 512 | if (ph->fsphStrICmp (pdce->aInfos[i].fname, name) == 0) | 
|---|
| 513 | { | 
|---|
| 514 | *finfo = pdce->aInfos[i]; | 
|---|
| 515 | *pulAge = timesec () - pdce->ulLastUpdateTime; | 
|---|
| 516 | debuglocal(9, "dircache: FindPath %s found, age %d\n", path, *pulAge); | 
|---|
| 517 | return 1; | 
|---|
| 518 | } | 
|---|
| 519 | } | 
|---|
| 520 | } | 
|---|
| 521 |  | 
|---|
| 522 | pdce = pdce->pNext; | 
|---|
| 523 | } | 
|---|
| 524 |  | 
|---|
| 525 | debuglocal(9, "dircache: FindPath %s not found\n", path); | 
|---|
| 526 | return 0; | 
|---|
| 527 | } | 
|---|
| 528 |  | 
|---|
| 529 | static int dcCreateDirPath(char *path, int cbPath, filelist_state *state) | 
|---|
| 530 | { | 
|---|
| 531 | /* State contains the original path passed to the plugin (fullpath) and | 
|---|
| 532 | * the actual filename mask (dir_mask), which should be used to filter | 
|---|
| 533 | * appropriate filenames from the full listing. | 
|---|
| 534 | * So the directory name can be constructed by removing the mask from the fullpath. | 
|---|
| 535 | */ | 
|---|
| 536 | int cbDir; | 
|---|
| 537 | int cbMask = strlen(state->dir_mask) + 1; | 
|---|
| 538 | if (cbMask > cbPath) | 
|---|
| 539 | { | 
|---|
| 540 | /* This actually should never happen, because mask is a part of path. | 
|---|
| 541 | * But still return a failure, better no dircache than a crash. | 
|---|
| 542 | */ | 
|---|
| 543 | return 0; | 
|---|
| 544 | } | 
|---|
| 545 | cbDir = cbPath - cbMask; | 
|---|
| 546 | if (cbDir > 0) | 
|---|
| 547 | { | 
|---|
| 548 | cbDir--; /* Exclude the slash. */ | 
|---|
| 549 | memcpy(path, state->fullpath, cbDir); | 
|---|
| 550 | } | 
|---|
| 551 | path[cbDir] = 0; | 
|---|
| 552 | return 1; | 
|---|
| 553 | } | 
|---|
| 554 |  | 
|---|
| 555 |  | 
|---|
| 556 | /* | 
|---|
| 557 | *  Public API. | 
|---|
| 558 | */ | 
|---|
| 559 |  | 
|---|
| 560 | int dircache_create(DirectoryCache **ppdc, unsigned long ulExpirationTime, int cMaxEntries) | 
|---|
| 561 | { | 
|---|
| 562 | int rc; | 
|---|
| 563 |  | 
|---|
| 564 | debuglocal(9, "dircache_create: %u seconds, %d entries\n", ulExpirationTime, cMaxEntries); | 
|---|
| 565 |  | 
|---|
| 566 | rc = dcCreate(ppdc); | 
|---|
| 567 |  | 
|---|
| 568 | if (rc == NO_ERROR) | 
|---|
| 569 | { | 
|---|
| 570 | dcEnable (*ppdc, 1, ulExpirationTime, cMaxEntries); | 
|---|
| 571 | } | 
|---|
| 572 |  | 
|---|
| 573 | debuglocal(9, "dircache_create: %p, rc = %d\n", *ppdc, rc); | 
|---|
| 574 | return rc; | 
|---|
| 575 | } | 
|---|
| 576 |  | 
|---|
| 577 | void dircache_delete(DirectoryCache *pdc) | 
|---|
| 578 | { | 
|---|
| 579 | debuglocal(9, "dircache_delete: %p\n", pdc); | 
|---|
| 580 |  | 
|---|
| 581 | if (pdc) | 
|---|
| 582 | { | 
|---|
| 583 | dcDelete(pdc); | 
|---|
| 584 | } | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 |  | 
|---|
| 588 | int dircache_list_files(PFNADDDIRENTRY fn, | 
|---|
| 589 | filelist_state *state, | 
|---|
| 590 | int *ptotal_received) | 
|---|
| 591 | { | 
|---|
| 592 | int rc; | 
|---|
| 593 | DirectoryCache *pdc = state->pConn->pRes->pdc; | 
|---|
| 594 |  | 
|---|
| 595 | int cbPath = strlen(state->fullpath) + 1; | 
|---|
| 596 | char *path = alloca(cbPath); | 
|---|
| 597 | if (!dcCreateDirPath(path, cbPath, state)) | 
|---|
| 598 | { | 
|---|
| 599 | return 0; | 
|---|
| 600 | } | 
|---|
| 601 |  | 
|---|
| 602 | debuglocal(9, "dircache_list_files [%s]\n", path); | 
|---|
| 603 |  | 
|---|
| 604 | if (!pdc) | 
|---|
| 605 | { | 
|---|
| 606 | return 0; | 
|---|
| 607 | } | 
|---|
| 608 |  | 
|---|
| 609 | lockRequest (pdc->mutex); | 
|---|
| 610 |  | 
|---|
| 611 | rc = dcRead (pdc, path, fn, state, ptotal_received, 0); | 
|---|
| 612 |  | 
|---|
| 613 | lockRelease (pdc->mutex); | 
|---|
| 614 |  | 
|---|
| 615 | return (rc == CacheOk); | 
|---|
| 616 | } | 
|---|
| 617 |  | 
|---|
| 618 | void *dircache_write_begin(filelist_state *state, | 
|---|
| 619 | int cFiles) | 
|---|
| 620 | { | 
|---|
| 621 | DirectoryCache *pdc = state->pConn->pRes->pdc; | 
|---|
| 622 | DirectoryCacheEntry *pdce = NULL; | 
|---|
| 623 |  | 
|---|
| 624 | int cbPath = strlen(state->fullpath) + 1; | 
|---|
| 625 | char *path = alloca(cbPath); | 
|---|
| 626 | if (!dcCreateDirPath(path, cbPath, state)) | 
|---|
| 627 | { | 
|---|
| 628 | return NULL; | 
|---|
| 629 | } | 
|---|
| 630 |  | 
|---|
| 631 | debuglocal(9, "dircache_write_begin pdc %p path [%s]\n", pdc, path); | 
|---|
| 632 |  | 
|---|
| 633 | if (!pdc) | 
|---|
| 634 | { | 
|---|
| 635 | return NULL; | 
|---|
| 636 | } | 
|---|
| 637 |  | 
|---|
| 638 | lockRequest (pdc->mutex); | 
|---|
| 639 |  | 
|---|
| 640 | if (pdc->cEntries >= pdc->cMaxEntries) | 
|---|
| 641 | { | 
|---|
| 642 | /* Remove oldest entry. */ | 
|---|
| 643 | pdce = pdc->pEntriesTail; | 
|---|
| 644 | dcRemoveEntry (pdce); | 
|---|
| 645 | dceDelete (pdce); | 
|---|
| 646 | pdce = NULL; | 
|---|
| 647 | } | 
|---|
| 648 |  | 
|---|
| 649 | pdce = dcWriteBegin (pdc, path, cFiles); | 
|---|
| 650 |  | 
|---|
| 651 | lockRelease (pdc->mutex); | 
|---|
| 652 |  | 
|---|
| 653 | debuglocal(9, "dircache_write_begin returning ctx %p\n", pdce); | 
|---|
| 654 | return (void *)pdce; | 
|---|
| 655 | } | 
|---|
| 656 |  | 
|---|
| 657 | void dircache_write_entry(void *dircachectx, const smbwrp_fileinfo *finfo) | 
|---|
| 658 | { | 
|---|
| 659 | DirectoryCacheEntry *pdce = (DirectoryCacheEntry *)dircachectx; | 
|---|
| 660 |  | 
|---|
| 661 | debuglocal(9, "dircache_write_entry %p\n", pdce); | 
|---|
| 662 |  | 
|---|
| 663 | if (!pdce) | 
|---|
| 664 | { | 
|---|
| 665 | return; | 
|---|
| 666 | } | 
|---|
| 667 |  | 
|---|
| 668 | lockRequest (pdce->pdc->mutex); | 
|---|
| 669 |  | 
|---|
| 670 | dceWriteEntry (pdce, finfo); | 
|---|
| 671 |  | 
|---|
| 672 | lockRelease (pdce->pdc->mutex); | 
|---|
| 673 | } | 
|---|
| 674 |  | 
|---|
| 675 | void dircache_write_end(void *dircachectx) | 
|---|
| 676 | { | 
|---|
| 677 | DirectoryCacheEntry *pdce = (DirectoryCacheEntry *)dircachectx; | 
|---|
| 678 | DirectoryCache *pdc; | 
|---|
| 679 |  | 
|---|
| 680 | debuglocal(9, "dircache_write_end: pdce %p\n", pdce); | 
|---|
| 681 |  | 
|---|
| 682 | if (!pdce) | 
|---|
| 683 | { | 
|---|
| 684 | return; | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | pdc = pdce->pdc; | 
|---|
| 688 |  | 
|---|
| 689 | lockRequest (pdc->mutex); | 
|---|
| 690 |  | 
|---|
| 691 | if (pdce->fInvalid) | 
|---|
| 692 | { | 
|---|
| 693 | /* Something happened during writing to the entry. Delete it. */ | 
|---|
| 694 | dceDelete (pdce); | 
|---|
| 695 | } | 
|---|
| 696 | else | 
|---|
| 697 | { | 
|---|
| 698 | dceAdjust (pdce); | 
|---|
| 699 | dcInsertEntry (pdce); | 
|---|
| 700 | } | 
|---|
| 701 |  | 
|---|
| 702 | lockRelease (pdc->mutex); | 
|---|
| 703 | } | 
|---|
| 704 |  | 
|---|
| 705 | void dircache_invalidate(const char *path, | 
|---|
| 706 | struct DirectoryCache *pdc, | 
|---|
| 707 | int fParent) | 
|---|
| 708 | { | 
|---|
| 709 | debuglocal(9, "dircache_invalidate [%s], parent %d\n", path, fParent); | 
|---|
| 710 |  | 
|---|
| 711 | if (!pdc) | 
|---|
| 712 | { | 
|---|
| 713 | return; | 
|---|
| 714 | } | 
|---|
| 715 |  | 
|---|
| 716 | lockRequest (pdc->mutex); | 
|---|
| 717 |  | 
|---|
| 718 | if (fParent) | 
|---|
| 719 | { | 
|---|
| 720 | int cb = strlen (path) + 1; | 
|---|
| 721 | char *p = (char *)alloca(cb); | 
|---|
| 722 | memcpy(p, path, cb); | 
|---|
| 723 | char *lastSlash = ph->fsphStrRChr(p, '\\'); | 
|---|
| 724 | if (lastSlash) | 
|---|
| 725 | { | 
|---|
| 726 | *lastSlash = 0; | 
|---|
| 727 | dcInvalidate (pdc, p, 0); | 
|---|
| 728 | } | 
|---|
| 729 | else | 
|---|
| 730 | { | 
|---|
| 731 | dcInvalidate (pdc, "", 0); | 
|---|
| 732 | } | 
|---|
| 733 | } | 
|---|
| 734 | else | 
|---|
| 735 | { | 
|---|
| 736 | dcInvalidate (pdc, path, 0); | 
|---|
| 737 | } | 
|---|
| 738 |  | 
|---|
| 739 | lockRelease (pdc->mutex); | 
|---|
| 740 |  | 
|---|
| 741 | return; | 
|---|
| 742 | } | 
|---|
| 743 |  | 
|---|
| 744 | int dircache_find_path(struct DirectoryCache *pdc, | 
|---|
| 745 | const char *path, | 
|---|
| 746 | smbwrp_fileinfo *finfo, | 
|---|
| 747 | unsigned long *pulAge) | 
|---|
| 748 | { | 
|---|
| 749 | int cb; | 
|---|
| 750 | char *p; | 
|---|
| 751 | char *lastSlash; | 
|---|
| 752 | int fFound = 0; | 
|---|
| 753 |  | 
|---|
| 754 | debuglocal(9, "dircache_find_path [%s]\n", path); | 
|---|
| 755 |  | 
|---|
| 756 | if (!pdc) | 
|---|
| 757 | { | 
|---|
| 758 | return 0; | 
|---|
| 759 | } | 
|---|
| 760 |  | 
|---|
| 761 | if (ph->fsphStrChr(path, '*') || ph->fsphStrChr(path, '?')) | 
|---|
| 762 | { | 
|---|
| 763 | /* Wildcards are not allowed in the input path. */ | 
|---|
| 764 | return 0; | 
|---|
| 765 | } | 
|---|
| 766 |  | 
|---|
| 767 | lockRequest (pdc->mutex); | 
|---|
| 768 |  | 
|---|
| 769 | /* Prepare the parent path. */ | 
|---|
| 770 | cb = strlen (path) + 1; | 
|---|
| 771 | p = (char *)alloca(cb); | 
|---|
| 772 | memcpy(p, path, cb); | 
|---|
| 773 | lastSlash = ph->fsphStrRChr(p, '\\'); | 
|---|
| 774 | if (lastSlash) | 
|---|
| 775 | { | 
|---|
| 776 | *lastSlash = 0; | 
|---|
| 777 | fFound = dcFindPath (pdc, path, p, lastSlash + 1, finfo, pulAge); | 
|---|
| 778 | } | 
|---|
| 779 | else | 
|---|
| 780 | { | 
|---|
| 781 | /* Find in the root directory. p is the name. */ | 
|---|
| 782 | fFound = dcFindPath (pdc, path, "", p, finfo, pulAge); | 
|---|
| 783 | } | 
|---|
| 784 |  | 
|---|
| 785 | lockRelease (pdc->mutex); | 
|---|
| 786 |  | 
|---|
| 787 | return fFound; | 
|---|
| 788 | } | 
|---|