/* WHEREIS.C for OS/2 version 1.2 A file finder utility that searches the current or specified drive, starting with the root directory (\), for the specified pathname. Wildcard characters can be included. Long filenames are supported. If an extended attribute name and value is also supplied, that information is also used as a match criterion. Blanks can be embedded in the EA value by quoting. The current version of the program only knows how to handle length-preceded ASCII EAs. This program does not require Microsoft or IBM Programmer's Toolkit header files, but must be linked using LINK.EXE and DOSCALLS.LIB from retail OS/2 version 1.2. Compile: cl -c /Zi whereis.c link /CO whereis,whereis,,doscalls,whereis.def; Usage: whereis pathname [EAname=EAvalue] Examples: whereis *.ico (match filename only) whereis * .TYPE=Icon (match EA only) whereis *.ico .TYPE=Icon (match both) whereis *.txt ".TYPE=Plain Text" (match both) Copyright (C) 1989 Ziff-Davis Communications PC Magazine * Ray Duncan */ #include #include #include #include #define API unsigned extern far pascal // OS/2 API function prototypes API DosChDir(char far *, unsigned long); API DosFindClose(unsigned); API DosFindFirst2(char far *, unsigned far *, unsigned, void far *, unsigned, int far *, int, unsigned long); API DosFindNext(unsigned, void far *, int, int far *); API DosQPathInfo(void far *, unsigned, char far *, int, unsigned long); API DosSelectDisk(int); API DosWrite(unsigned, void far *, unsigned, unsigned far *); void showfile(char far *); // local function prototypes void schdir(char *); void schfile(void); #define NORM 0x00 // old file attribute bits #define RD_ONLY 0x01 #define HIDDEN 0x02 #define SYSTEM 0x04 #define DIR 0x10 #define ARCHIVE 0x20 // EA predefined value types #define EAT_BINARY 0x0fffe // Length-preceeded binary #define EAT_ASCII 0x0fffd // Length-preceeded ASCII #define EAT_BITMAP 0x0fffb // Length-preceeded bitmap #define EAT_METAFILE 0x0fffa // Metafile #define EAT_ICON 0x0fff9 // Length-preceeded icon #define EAT_EA 0x0ffee // ASCIIZ name of associated EA #define EAT_MVMT 0x0ffdf // Multi-value multi-type #define EAT_MVST 0x0ffde // Multi-value single-type #define EAT_ASN1 0x0ffdd // ASN.1 field // arbitrary buffer sizes #define SCHBUF_SIZE 4096 // size of search buffer #define TEAVAL_SIZE 260 // max size of EA target value #define GEALIST_SIZE 260 // max size of target GEAList #define MAXPATHNAME 260 // max length of pathname #define MAXFILENAME 255 // max length of filename struct _EA { // extended attribute header unsigned char flags; // critical flag etc. unsigned char nsize; // length of EA name (without null) unsigned vsize; // total size of EA value char name[1]; } ; // EA name and value begin here struct _EAval { // extended attribute value unsigned type; // EA value type unsigned size; // length of EA variable data char data[1]; } ; // actual data begins here struct _FEAList { // receives extended attributes unsigned long size; // total size of structure char data[1]; } ; // extended attributes begin here struct _GEA { // extended attribute target name unsigned char size; // length of name char name[1]; } ; // actual name begins here struct _GEAList { // holds names of EAs to get unsigned long size; // total size of structure struct _GEA GEA; } ; // name length and name text struct _EAOP { // used by all EA functions void far *pGEAList; // pointer to GEAList structure void far *pFEAList; // pointer to FEAList structure unsigned long oError; } ; // offset of error, if any struct _info1 { // result buffer format for unsigned cdate; // DosFindFirst2 info level 1 unsigned ctime; unsigned adate; unsigned atime; unsigned wdate; unsigned wtime; long fsize; long falloc; unsigned fattr; char fcount; char fname[MAXFILENAME]; } ; struct _info3 { // result buffer format for struct _EAOP EAOP; // DosFindFirst2 info level 3 unsigned cdate; unsigned ctime; unsigned adate; unsigned atime; unsigned wdate; unsigned wtime; long fsize; long falloc; unsigned fattr; long easize; struct _EA EA; } ; union _sbuf { struct _info1 info1; struct _info3 info3; } ; struct _GEAList *GEAList = NULL; // pointer to EA name buffer union _sbuf *sbuf = NULL; // pointer to search result buffer struct _EAval *tEAval = NULL; // pointer to EA value buffer char *tfname = NULL; // pointer to filename buffer int count = 0; // total files matched main(int argc, char *argv[]) { if((argc < 2) || (argc > 3)) // check command line { printf("\nUsage: whereis filename [EAname=EAvalue]\n"); printf("\n EA name is case-sensitive, EA value is not."); printf("\n Use quotes to embed blanks in EA value.\n"); printf("\nExamples: whereis *.ico"); printf("\n whereis * .TYPE=Icon"); printf("\n whereis *.ico .TYPE=Icon"); printf("\n whereis *.txt \".TYPE=Plain Text\"\n"); exit(1); } sbuf = malloc(SCHBUF_SIZE); // allocate buffers; note that GEAList = malloc(GEALIST_SIZE); // these sizes are arbitrary tEAval = malloc(TEAVAL_SIZE); tfname = malloc(MAXFILENAME); if((sbuf==NULL) || (GEAList==NULL) || (tEAval==NULL) || (tfname==NULL)) { printf("\nwhereis: heap allocation error\n"); exit(1); } if(((strlen(argv[1])) >= 2) && ((argv[1])[1] == ':')) { if(DosSelectDisk(((argv[1]) [0] | 0x20) - ('a'-1))) { printf("\nwhereis: bad drive\n"); exit(1); } argv[1] += 2; // advance past drive } strncpy(tfname, argv[1], MAXFILENAME); // save target filename if(argc == 3) // parse EA search target { // into name and value strings strcpy(GEAList->GEA.name, strtok(argv[2], " =\x0a")); GEAList->GEA.size = strlen(GEAList->GEA.name); GEAList->size = GEAList->GEA.size + 6; strcpy(tEAval->data, strtok(NULL, "\x0a")); tEAval->size = strlen(tEAval->data); } else // if no EA search target { // supplied, force length GEAList->GEA.size = 0; // of name and value to 0 tEAval->size = 0; GEAList->size = sizeof(GEAList->size); } schdir("\\"); // start search with root if(count == 0) // advise if no matches printf("\nwhereis: no files\n"); } /* SCHDIR: search specified directory for matching files and any other directories which can be searched recursively. */ void schdir(char *dirname) { unsigned shandle = -1; // search handle int scount = 1; // max search matches DosChDir(dirname, 0L); // select new directory schfile(); // find and list files // search for directories if(!DosFindFirst2("*.*", // match any name &shandle, // receives search handle NORM|DIR, // match normal files & dirs sbuf, // buffer receives match info SCHBUF_SIZE, // size of search buffer &scount, // receives match count 1, // info level 1 = no EAs 0L)) // reserved { do // recurse to search directories { // other than . and .. aliases if((sbuf->info1.fattr & DIR) && (sbuf->info1.fname[0] != '.')) { schdir(sbuf->info1.fname); DosChDir("..", 0L); // restore previous directory } // look for more directories } while(DosFindNext(shandle, sbuf, SCHBUF_SIZE, &scount) == 0); } DosFindClose(shandle); // close search handle } /* SCHFILE: search current directory for files matching supplied filename, also matching extended attribute name and value if any. */ void schfile(void) { struct _EAval *pEAval; // pointer to EA value in sbuf char far *pfname; // pointer to filename unsigned shandle = -1; // search handle int scount = 1; // max search matches sbuf->info3.EAOP.oError = 0L; // initialize EAOP pointers sbuf->info3.EAOP.pGEAList = GEAList; sbuf->info3.EAOP.pFEAList = NULL; if(!DosFindFirst2(tfname, // target filename for search &shandle, // receives search handle NORM, // match normal files only sbuf, // buffer receives match info SCHBUF_SIZE, // size of search buffer &scount, // receives match count 3, // info level 3 = get EAs too 0L)) // reserved { do { pfname = (char far *) // calc address of filename &sbuf->info3.easize + sbuf->info3.easize + 1; if(tEAval->size) // if EA entered, does it match? { (char *) pEAval = // calc address of EA value sbuf->info3.EA.name + sbuf->info3.EA.nsize + 1; if((sbuf->info3.EA.vsize) && (pEAval->size == tEAval->size) && (pEAval->type == EAT_ASCII) && (! memicmp(pEAval->data, tEAval->data, tEAval->size))) showfile(pfname); // EA matches, display filename } else showfile(pfname); // no EA entered, display filename } while(DosFindNext(shandle, sbuf, SCHBUF_SIZE, &scount) == 0); } DosFindClose(shandle); // close search handle } /* SHOWFILE: called with filename, displays fully qualified pathname. */ void showfile(char far *pfname) { char pathname[MAXPATHNAME]; // receives full pathname count++; // count matched files // qualify the filename DosQPathInfo(pfname, 5, pathname, sizeof(pathname), 0L); printf("%s\n", strlwr(pathname)); // and display it }