| | @@ -2406,5 +2406,92 @@ |
| 2406 | 2406 | */ |
| 2407 | 2407 | const char * file_extension(const char *zFileName){ |
| 2408 | 2408 | const char * zExt = zFileName ? strrchr(zFileName, '.') : 0; |
| 2409 | 2409 | return zExt ? &zExt[1] : 0; |
| 2410 | 2410 | } |
| 2411 | + |
| 2412 | +/* |
| 2413 | +** Returns true if the given filename ends with any of fossil's |
| 2414 | +** checkout database filenames: _FOSSIL_ or .fslckout. Specifically, |
| 2415 | +** it returns 1 if it's an exact match and 2 if it's the tail match |
| 2416 | +** on a longer input. |
| 2417 | +** |
| 2418 | +** zFilename must, for efficiency's sake, be a |
| 2419 | +** canonicalized/normalized name, e.g. using only '/' as directory |
| 2420 | +** separators. |
| 2421 | +** |
| 2422 | +** nFilename must be the strlen of zFilename. If it is negative, |
| 2423 | +** strlen() is used to calculate it. |
| 2424 | +*/ |
| 2425 | +int filename_is_ckout_db(const char *zFilename, int nFilename){ |
| 2426 | + const char *zEnd; /* one-after-the-end of zFilename */ |
| 2427 | + int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */ |
| 2428 | + |
| 2429 | + assert(zFilename && "API misuse"); |
| 2430 | + if(nFilename<0) nFilename = (int)strlen(zFilename); |
| 2431 | + if(nFilename<8/*strlen _FOSSIL_*/) return 0; |
| 2432 | + zEnd = zFilename + nFilename; |
| 2433 | + if(nFilename>=12/*strlen _FOSSIL_-(shm|wal)*/){ |
| 2434 | + /* Check for (-wal, -shm, -journal) suffixes, with an eye towards |
| 2435 | + ** runtime speed. */ |
| 2436 | + if('-'==zEnd[-4]){ |
| 2437 | + if(fossil_stricmp("wal", &zEnd[-3]) |
| 2438 | + && fossil_stricmp("shm", &zEnd[-3])){ |
| 2439 | + return 0; |
| 2440 | + } |
| 2441 | + gotSuffix = 4; |
| 2442 | + }else if(nFilename>=16/*strlen _FOSSIL_-journal*/ && '-'==zEnd[-8]){ |
| 2443 | + if(fossil_stricmp("journal",&zEnd[-7])){ |
| 2444 | + return 0; |
| 2445 | + } |
| 2446 | + gotSuffix = 8; |
| 2447 | + } |
| 2448 | + if(gotSuffix){ |
| 2449 | + assert(4==gotSuffix || 8==gotSuffix); |
| 2450 | + zEnd -= gotSuffix; |
| 2451 | + nFilename -= gotSuffix; |
| 2452 | + gotSuffix = 1; |
| 2453 | + } |
| 2454 | + assert(nFilename>=8 && "strlen _FOSSIL_"); |
| 2455 | + assert(gotSuffix==0 || gotSuffix==1); |
| 2456 | + } |
| 2457 | + switch(zEnd[-1]){ |
| 2458 | + case '_': { |
| 2459 | + return fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) |
| 2460 | + ? 0 : (8==nFilename |
| 2461 | + ? 1 |
| 2462 | + : ('/'==zEnd[-9] ? 2 : gotSuffix)); |
| 2463 | + } |
| 2464 | + case 't': { |
| 2465 | + return (nFilename<9 |
| 2466 | + || '.'!=zEnd[-9] |
| 2467 | + || fossil_strnicmp(".fslckout", &zEnd[-9], 9)) |
| 2468 | + ? 0 : (9==nFilename |
| 2469 | + ? 1 |
| 2470 | + : ('/'==zEnd[-10] ? 2 : gotSuffix)); |
| 2471 | + } |
| 2472 | + default: { |
| 2473 | + return 0; |
| 2474 | + } |
| 2475 | + } |
| 2476 | +} |
| 2477 | + |
| 2478 | +/* |
| 2479 | +** COMMAND: test-is-ckout-db |
| 2480 | +** |
| 2481 | +** Usage: %fossil test-is-ckout-db FILENAMES... |
| 2482 | +** |
| 2483 | +** Passes each given name to filename_is_ckout_db() and outputs one |
| 2484 | +** line per file: the result value of that function followed by the |
| 2485 | +** name. |
| 2486 | +*/ |
| 2487 | +void test_is_ckout_name_cmd(void){ |
| 2488 | + int i; |
| 2489 | + |
| 2490 | + if(g.argc<3){ |
| 2491 | + usage("FILENAME_1 [...FILENAME_N]"); |
| 2492 | + } |
| 2493 | + for( i = 2; i < g.argc; ++i ){ |
| 2494 | + const int check = filename_is_ckout_db(g.argv[i], -1); |
| 2495 | + fossil_print("%d %s\n", check, g.argv[i]); |
| 2496 | + } |
| 2497 | +} |
| 2411 | 2498 | |