home *** CD-ROM | disk | FTP | other *** search
- /* filechk.c -- Disk file integrity checker.
- Reads all files on disk in current directory and in
- lower level subdirectories to verify readability and
- file size.
-
- by Arnold Cherdak, 8/11/88, Turbo C, Version 1.5
-
- RELEASED TO THE PUBLIC DOMAIN
-
- */
- #include <stdio.h>
- #include <dir.h>
- #include <dos.h>
- #include <fcntl.h>
- #include <sys\stat.h>
-
- #define NOT_ENUFF_SPACE "\nINSUFFICIENT MEMORY SPACE!\n"
- #define FILECHK "FILECHK"
- #define BUFFER_SIZE 0x2000
- #define BAD_FILE_SIZE ": FILE SIZE IS WRONG!"
- #define PATH_SIZE 128
- #define TRUE 0xffffu
- #define FALSE 0u
- #define TITLE "\nFILECHK version 1.0 by Arnold Cherdak, all rights reserved"
- #define HEADER "\nFile Name Size Date Time Attributes"
-
- /***************************************************************************
- In the DOS directory entry, DOS time and date parameters are bit strings
- that are to be interpreted as follows:
-
- bits 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- TIME h h h h h m m m m m m x x x x x
- DATE y y y y y y y M M M M d d d d d
-
- where:
- h is the binary number of hours (0-23)
- m is the binary number of minutes (0-59)
- x is the binary number of two-second increments (0-29) corresponding
- to 0-58 seconds
-
- y is the binary year number since 1980 (0-119) corresponding to
- 1980-2099 ( WOW! Think this program/operating system will be around
- ( that long?
- M is the binary number of the month (1-12)
- d is the binary number of the day of the month (1-31)
-
- The attribute byte is a bit field with interpretation as follows:
-
- BIT MEANING IF SET TO 1
- 0 read-only
- 1 hidden
- 2 system file
- 3 volume label
- 4 subdirectory file
- 5 archive bit
- 6 (reserved -- not used)
- 7 (reserved -- not used)
-
- ****************************************************************************/
-
- struct DOS_TIME /* bit field definitions for time */
- {
- unsigned twosecs:5; /* NOTE: LSB first */
- unsigned minute:6;
- unsigned hour:5;
- };
-
- struct DOS_DATE /* bit field definitions for date */
- {
- unsigned day:5;
- unsigned month:4;
- unsigned year:7;
- };
-
- struct DOS_ATTRIB /* bit field definitions for attributes */
- {
- unsigned R :1; /* read only */
- unsigned H :1; /* hidden */
- unsigned S :1; /* system */
- unsigned V :1; /* volume label */
- unsigned D :1; /* subdirectory */
- unsigned A :1; /* archive bit */
- unsigned yy:2; /* reserved */
- unsigned xx:8; /* filler, high-order 8-bits to make a full integer */
- };
-
- struct STACK_NODE
- {
- char path[PATH_SIZE];
- int attribs;
- struct ffblk dta;
- struct STACK_NODE *next; /* double-linked list */
- struct STACK_NODE *previous;
- };
-
-
- /**************************************************************************/
- void main(int argc, char *argv[])
- /**************************************************************************/
- {
- int j,files,ndirs,subdirs,handle,amount,retn,nfiles,nbrfiles,nerrs,flag;
- int helpmax,i;
- unsigned DOption;
- long total,grand_total,dir_total;
- char attr[6],*buffer,thisdir[PATH_SIZE],c;
- struct STACK_NODE *dir = NULL;
- union
- {
- struct DOS_DATE date;
- struct DOS_TIME time;
- struct DOS_ATTRIB attrib;
- int value;
- } entry;
-
- char *help[] = {
- "\n\nDisk File Integrity Checker: Reads all files on a disk or in",
- "\none or more (sub)directories to verify that the directory entry",
- "\nfor each file is correct and that the file is readable.",
- "\n\nUsage: FILECHK [-D] [-H] [-?] [directoryname]",
- "\n Default operation (without command line entries) causes FILECHK",
- "\n to read all files in the current directory and all files in",
- "\n subdirectories below the current directory.",
- "\n\n -D option causes FILECHK to process files in the current directory,",
- "\n only.",
- "\n\n -H and -? options provide the help screen (this one).",
- "\n\n The presence of a string, 'directoryname', causes FILECHK to begin",
- "\n processing in the directory having the name, 'directoryname'.\n"};
-
- helpmax = 12; /* there are 12 lines in the help screen */
-
- /* print program header */
- printf(TITLE);
-
- /* allocate a file buffer */
- if((buffer = (char *) malloc(BUFFER_SIZE)) == NULL)
- {
- printf(NOT_ENUFF_SPACE);
- exit(1);
- }
-
- /* allocate a root directory node */
- if((dir = (struct STACK_NODE *) calloc(1, sizeof(struct STACK_NODE))) == NULL)
- {
- printf(NOT_ENUFF_SPACE);
- exit(1);
- }
- dir->previous = NULL;
- dir->next = NULL;
-
- /* Get current working directory. */
- if(getcwd(thisdir, PATH_SIZE) == NULL)
- {
- printf("\n");
- perror(FILECHK);
- exit(1);
- }
- strcpy(dir->path, thisdir);
-
- /* See if there are any command line parameters */
- DOption = FALSE;
- if(argc > 1)
- {
- /* find switches first */
- for(j=1;j<argc;j++)
- if(argv[j][0] == '-' || argv[j][0] == '/')
- if((c = toupper(argv[j][1])) == 'D')
- DOption = TRUE;
- else if(c == 'H' | c == '?')
- {
- for(i=0;i<helpmax;i++)
- printf(help[i]);
- exit(0);
- }
-
- /* Now see if this is to take place in some other directory */
- for(j=1;j<argc;j++)
- if(argv[j][0] != '-' && argv[j][0] != '/')
- {
- strcpy(dir->path,argv[j]);
- if(chdir(dir->path) < 0)
- {
- perror(FILECHK);
- exit(1);
- }
- break;
- }
- }
-
- /* Set up search criteria. These are file attributes defined in
- header file, dos.h
- */
- files = FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH;
- subdirs = FA_DIREC;
- dir->attribs = files;
- flag = files;
-
- /* Get the first file. */
- if((retn = findfirst("*.*", &(dir->dta), dir->attribs)) != 0)
- {
- perror(FILECHK);
- exit(1);
- }
-
- /* print path */
- printf("\n\nSTARTING AT: %s",dir->path);
-
- /* print file listing header */
- printf(HEADER);
-
- /* Now, print a structured directory listing and then examine the file.
- Repeat this for all files in the current and lower subdirectories.
- */
-
- ndirs = 1;
- nfiles = nbrfiles = nerrs = 0;
- grand_total = dir_total = 0L;
- while(TRUE)
- {
- if(retn == -1)
- /* at end */
- {
- if(dir->previous == NULL && dir->attribs == subdirs)
- /* all done */
- {
- printf("\n\n%d Files Processed in %d (Sub)Directories",nfiles,ndirs);
- printf("\n%ld Characters Processed",grand_total);
- printf("\n%d Errors Detected\n",nerrs);
- chdir(thisdir);
- exit(0);
- }
- else if(dir->attribs == subdirs)
- /* go back to next higher level subdirectory */
- {
- dir = dir->previous;
- free(dir->next);
-
- /* Change back to old subdirectory */
- if(chdir(dir->path) < 0)
- {
- perror(FILECHK);
- exit(1);
- }
-
- /* Get the next file. */
- retn = findnext(&(dir->dta));
- }
- else /* attribs == files */
- {
- dir->attribs = subdirs;
- flag = subdirs;
-
- printf("\nThis Directory Total Files Processed = %d",nbrfiles);
- printf("\nThis Directory Total Characters Processed = %ld",dir_total);
- dir_total = 0L;
- nbrfiles = 0;
-
- if(DOption == TRUE)
- retn = -1;
- else
- /* Get the first subdirectory. */
- retn = findfirst("*.*", &(dir->dta), dir->attribs);
- }
- }
- else
- /* not at end of current subdirectory */
- {
- /* This is NOT a subdirectory. */
- if(!(dir->dta.ff_attrib & FA_DIREC) && flag == files)
- {
- /* We are not looking for subdirectories here -- this is needed
- because DOS will return ALL files even though we ask
- only for subdirs. See DOS call 21h, function 4eh.
-
- Print directory data.
- */
- printf("\n%-12s",dir->dta.ff_name);
- printf("%8ld",dir->dta.ff_fsize);
-
- /* set up date */
- entry.value = dir->dta.ff_fdate;
-
- /* now print the date */
- printf(" %2d-%02d-%2d",entry.date.month, entry.date.day,
- entry.date.year + 80);
-
- /* set up time */
- entry.value = dir->dta.ff_ftime;
-
- /* now print the file time */
- printf(" %2d:%02d:%02d",entry.time.hour, entry.time.minute,
- entry.time.twosecs * 2);
-
- /* set up attributes */
- entry.value = dir->dta.ff_attrib;
-
- /* now print the attributes */
- attr[0] = '\0';
- if (entry.attrib.R == 1) strcat(attr,"R");
- if (entry.attrib.H == 1) strcat(attr,"H");
- if (entry.attrib.S == 1) strcat(attr,"S");
- if (entry.attrib.D == 1) strcat(attr,"D");
- if (entry.attrib.A == 1) strcat(attr,"A");
- printf(" %s",attr);
- nfiles++;
- nbrfiles++;
-
- /* Now verify the file by opening it and reading it. */
- if((handle = open(dir->dta.ff_name, O_RDONLY | O_BINARY)) < 0)
- {
- /* error on open */
- perror("");
- nerrs++;
- }
- else
- {
- total = 0;
- while((amount = read(handle, buffer, BUFFER_SIZE)) > 0)
- total += amount;
-
- if(amount < 0)
- {
- perror("");
- nerrs++;
- }
-
- if(total != dir->dta.ff_fsize)
- {
- printf(BAD_FILE_SIZE);
- nerrs++;
- }
-
- grand_total += total;
- dir_total += total;
- close(handle);
- }
-
- /* Now get the next directory entry */
- retn = findnext(&(dir->dta));
-
- } /* end: if file is not a subdirectory... */
-
- else if(strcmp(dir->dta.ff_name,".") != 0 &&
- strcmp(dir->dta.ff_name,"..") != 0 &&
- (dir->dta.ff_attrib & subdirs))
- /* file IS a proper subdirectory */
- {
-
- /* Change directory to go to the new subdirectory */
- if(chdir(dir->dta.ff_name) < 0)
- {
- perror(FILECHK);
- exit(1);
- }
-
- /* Allocate a stack node. */
- if((dir->next = (struct STACK_NODE *)
- calloc(1, sizeof(struct STACK_NODE))) == NULL)
- {
- printf(NOT_ENUFF_SPACE);
- exit(1);
- }
-
- /* push it on the stack */
- dir->next->previous = dir;
- dir = dir->next;
-
- /* Get current working directory. */
- if(getcwd(dir->path, PATH_SIZE) == NULL)
- {
- printf("\n");
- perror(FILECHK);
- exit(1);
- }
-
- /* print path */
- printf("\n\nSUBDIRECTORY: %s",dir->path);
-
- /* print file listing header */
- printf(HEADER);
-
- /* count directories */
- ndirs++;
-
- /* Get the first file. */
- dir->attribs = files;
- flag = files;
- retn = findfirst("*.*", &(dir->dta), dir->attribs);
-
- } /* end: if file IS a proper subdirectory */
- else
- /* not "." or ".." - not a proper subdirectory */
- /* get next */
- retn = findnext(&(dir->dta));
-
- } /* end: else - not at end of current subdirectory */
-
- } /* end: while(TRUE) */
-
- } /* end: main */