/* * Find file name from locatedb database. * * Compile and run updatedb command first to create locate.db file. Then, * compile this program with Visual Studio and run the program in console with * a file name argument. For example, the command * * locate autoexec * * might output something like * * c:/AUTOEXEC.BAT * c:/WINDOWS/repair/autoexec.nt * c:/WINDOWS/system32/AUTOEXEC.NT * * Be ware that this file uses wide-character API which is not compatible * with Linux or other major Unixes. * * Copyright (C) 1998-2019 Toni Ronkko * This file is part of dirent. Dirent may be freely distributed * under the MIT license. For all details and documentation, see * https://github.com/tronkko/dirent */ #include #include #include #include #ifdef WIN32 # include # include #endif #include /* File name and location of database file */ #define DB_LOCATION L"locate.db" /* Forward-decl */ static int db_locate(const wchar_t *pattern); static int db_match(const wchar_t *fn, const wchar_t *pattern); static void db_open(void); static void db_close(void); static int db_read(wchar_t *buffer, size_t max); /* Module local variables */ static FILE *db = NULL; #ifdef _MSC_VER int wmain(int argc, wchar_t *argv[]) { /* Prepare for unicode output */ _setmode(_fileno(stdout), _O_U16TEXT); /* For each pattern in command line */ int i = 1; while (i < argc) { int count = 0; /* Find files matching pattern */ count = db_locate(argv[i]); /* Output warning if string is not found */ if (count == 0) { wprintf(L"%s not found\n", argv[i]); } i++; } if (argc < 2) { wprintf(L"Usage: locate pattern\n"); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } #else int main(int argc, char *argv[]) { printf("locate only works on Microsoft Windows\n"); return EXIT_SUCCESS; } #endif /* Match pattern against files in locate.db file */ static int db_locate(const wchar_t *pattern) { int count = 0; #ifdef WIN32 wchar_t buffer[PATH_MAX + 1]; /* Open locate.db for read */ db_open(); /* Read one directory and file name at a time from database file */ while (db_read(buffer, PATH_MAX + 1)) { /* See if file name in buffer matches the search pattern */ if (db_match(buffer, pattern)) { /* Match found => output file name and path */ wprintf(L"%s\n", buffer); count++; } } db_close(); #endif return count; } /* Match pattern against file name */ static int db_match(const wchar_t *fn, const wchar_t *pattern) { int found = 0; #ifdef WIN32 /* Locate zero-terminator from fn */ wchar_t *p = wcschr(fn, '\0'); /* Find base name from buffer */ int done = 0; while (fn < p && !done) { switch (p[-1]) { case ':': case '/': case '\\': /* Final path separator found */ done = 1; break; default: /* No path separator yet */ p--; } } /* Convert base name to lower case */ int i = 0; wchar_t base[PATH_MAX + 1]; while (i < PATH_MAX && p[i] != '\0') { base[i] = towlower(p[i]); i++; } base[i] = '\0'; /* Convert search pattern to lower case */ i = 0; wchar_t patt[PATH_MAX + 1]; while (i < PATH_MAX && pattern[i] != '\0') { patt[i] = towlower(pattern[i]); i++; } patt[i] = '\0'; /* See if file name matches pattern */ if (wcsstr(base, patt) != NULL) { found = 1; } else { found = 0; } #endif return found; } /* * Read line from locate.db. This function is same as fgetws() except * that new-line at the end of line is not included. */ static int db_read(wchar_t *buffer, size_t max) { int ok = 0; #ifdef WIN32 size_t i = 0; wchar_t c; int done = 0; if (!db) { wprintf(L"Database not open\n"); exit(EXIT_SUCCESS); } do { /* Read wide-character from stream */ c = fgetwc(db); /* Determine how to process character */ switch (c) { case '\r': /* Ignore, should be handled by run-time libraries */ /*NOP*/; break; case '\n': /* End of string => return file name */ done = 1; ok = 1; break; case /*EOF*/WEOF: /* End of file */ done = 1; if (i == 0) { /* No data in buffer => return false */ ok = 0; } else { /* Data in buffer => return file name */ ok = 1; } break; default: /* Store character */ if (i < max - 1) { buffer[i++] = c; } else { buffer[max - 1] = '\0'; wprintf(L"Buffer too small: %s", buffer); exit(EXIT_FAILURE); } } } while (!done); /* Zero-terminate buffer */ buffer[i] = '\0'; #endif return ok; } /* Open database file locate.db */ static void db_open(void) { #ifdef WIN32 if (db) return; /* Open file for writing */ errno_t error = _wfopen_s(&db, DB_LOCATION, L"rt, ccs=UNICODE"); if (error) { wprintf(L"Cannot open %s\n", DB_LOCATION); exit(EXIT_FAILURE); } #endif } /* Close database file */ static void db_close(void) { if (!db) return; fclose(db); db = NULL; }