/* ** fp971031/020112/030901 check files */ #include #include #include #include #include #include #ifndef OK #define OK 0 #endif #define MAXEQU 100 unsigned char scratchpath[MAXPATH+1]; unsigned char fname[MAXPATH+1]; unsigned char mfname[MAXPATH+1]; /* used for makefname function */ int mfnameinx; /* used for makefname function */ unsigned char *filebuf; #define INSTALLNEW 0 #define INSTALLOLD 1 #define INSTALLERR -1 #define HASHSIZE 32 /* label hash entries */ struct fi /* file info struct */ { struct fi *next; struct fi *parent; char attrib; unsigned ftime; unsigned fdate; long fsize; unsigned long fsum; int mark; char name[1]; /* must be last */ }; struct fi *fiptr; static struct fi *fitree[HASHSIZE]; static struct fi **sfilist; int totalfiles; int totalinstalled; typedef enum { READY, USAGE, OPTION, FOPERR, FCLERR, FSKERR, FRDERR, FWRERR, MEMERR, REASON, NSPERR, TBDERR } reason; void quit(int e, unsigned char *p) { switch(e) { case READY : break; case OPTION : fprintf(stderr, "unknown option %s\n", p); break; case USAGE : fprintf(stderr, "Usage: fchk path\n"); fprintf(stderr, "This program lists equal files in the given path.\n"); fprintf(stderr, "A file is assumed equal if the filesize a CRC both are equal.\n"); fprintf(stderr, "Files are deleted only if in the path the string 'maydelete' is found.\n"); fprintf(stderr, "At least one of the equal files is not deleted.\n"); fprintf(stderr, "All files in the path must not be in use.\n"); fprintf(stderr, "Read-only files are not deleted.\n"); fprintf(stderr, "Maximum %d equal files can be processed for deletion.\n", MAXEQU); fprintf(stderr, "Note: empty files are always equal.\n"); break; case FOPERR : fprintf(stderr, "can't open file %s\n", p); break; case MEMERR : fprintf(stderr, "not enough memory\n"); break; case NSPERR : fprintf(stderr, "path not found\n"); break; case REASON : fprintf(stderr, "aborted: %s\n", p); break; default : fprintf(stderr, "undefined error: %d %s\n", e, p); break; } exit(e); } int hash(unsigned char *s) { int i, j=0; while((i=*s++)!='\0') j+=i; return(j%HASHSIZE); } struct fi * lookup(unsigned char *s) { int r; struct fi *p; for(p=fitree[hash(s)]; p!=NULL; p=p->next) { if((r=strcmp(p->name, s))>0) break; if(r==0) return(p); } return(NULL); } int install(struct ffblk *fin, struct fi *par) { struct fi *p1, *p2; int h; int r=-1; h=hash(fin->ff_name); p1=p2=fitree[h]; while(p2!=NULL) { if((r=strcmp(p2->name, fin->ff_name))>=0) break; p1=p2; p2=p2->next; } fiptr=(struct fi *)malloc(sizeof(struct fi)+strlen(fin->ff_name)); if(fiptr==NULL) return(INSTALLERR); /* indicate out of memory */ if(fitree[h]==p2) fitree[h]=fiptr; else p1->next=fiptr; fiptr->next=p2; fiptr->attrib=fin->ff_attrib; fiptr->ftime=fin->ff_ftime; fiptr->fdate=fin->ff_fdate; fiptr->fsize=fin->ff_fsize; strcpy(fiptr->name,fin->ff_name); fiptr->parent=par; totalinstalled++; if( (fiptr->attrib&(FA_LABEL|FA_DIREC)) ==0) totalfiles++; return(INSTALLNEW); /* indicate symbol installed */ } /* ** make array of pointers to file info ** array only contains files */ void makefilearray(void) { struct fi *p; int i, j=0; sfilist=(struct fi **)malloc(sizeof(struct fi *)*totalfiles); if(sfilist==NULL) quit(MEMERR, ""); for(i=0; inext) if( (p->attrib&(FA_LABEL|FA_DIREC)) ==0) sfilist[j++]=p; } void sortname(void) { struct fi *p; int g, i, j=0; for(g=totalfiles/2; g>0; g/=2) for(i=g; i=0; j-=g) { if(strcmp(sfilist[j]->name, sfilist[j+g]->name)<0) break; if(strcmp(sfilist[j]->name, sfilist[j+g]->name)==0) if(sfilist[j]->fsize<=sfilist[j+g]->fsize) break; p=sfilist[j]; sfilist[j]=sfilist[j+g]; sfilist[j+g]=p; } } void makefname2(struct fi *fip) { if(fip->parent!=NULL) makefname2(fip->parent); mfnameinx+=sprintf(&mfname[mfnameinx], "%s\\", fip->name); } void makefname(struct fi *fip) { mfnameinx=0; if(fip->parent!=NULL) makefname2(fip->parent); /* recursive part */ mfnameinx+=sprintf(&mfname[mfnameinx], "%s", fip->name); } void printlist(FILE *fp) { struct fi *p; int i; for(i=0; inext) { if( (p->attrib&(FA_LABEL|FA_DIREC)) ==0) { makefname(p); fprintf(fp, "%s\n", mfname); } } } } void printslist(FILE *fp) { struct fi *p; int i; for(i=0; ifsize); fprintf(fp, "%lu ", p->fsum); fprintf(fp, "\n"); } } void printslistequ(FILE *fp) { int i; int j; j=0; for(i=1; iname, sfilist[j]->name)!=0) || (sfilist[i]->fsize!=sfilist[j]->fsize) ) { if((j+1)fsize); j++; } i--; } j=i; } } } void findequsizesum(FILE *fp) { int i, j; int count=0; for(i=0; imark=0; for(i=0; imark==0) { for(j=i+1; jfsize==sfilist[j]->fsize) { if(sfilist[i]->fsum==sfilist[j]->fsum) { if(sfilist[i]->mark==0) { ++count; sfilist[i]->mark=count; makefname(sfilist[i]); fprintf(fp, "%05d %s", count, mfname); } sfilist[j]->mark=count; makefname(sfilist[j]); fprintf(fp, " = %s", mfname); } } } if(sfilist[i]->mark!=0) fprintf(fp, "\n"); } } } int filedelete(void) { int count=1; int i; int fnum; int fequ[MAXEQU]; int ndel; int start; int deleted=0; while(count>0) { fnum=0; for(i=0; imark==count) if(fnum=0) { makefname(sfilist[fequ[i]]); fprintf(stdout, "deleting %05d %s\n", count, mfname); unlink(mfname); deleted++; } } } count++; } return(deleted); } #define FBUFLEN 16384 void getfilesums(void) { FILE *fp; struct fi *p; int i, j, ch, b; unsigned long sum, t; long l; filebuf=(unsigned char *)malloc(FBUFLEN); if(filebuf==NULL) quit(MEMERR, ""); for(i=0; i>31; sum=sum<<1; sum=sum^((ch>>b)&1)^t^(t<<13); } /* sum+=filebuf[j]; -- apeared unreliable */ } fclose(fp); p->fsum=sum; /* fprintf(stdout, "%s %ld %lu\n", mfname, p->fsize, sum); */ fprintf(stderr, "%d\r", i); } free(filebuf); } void search_files(struct fi *par) { int len; int ret; struct ffblk fileinfo; len=strlen(scratchpath); sprintf(&scratchpath[len], "\\%s", fname); ret=findfirst(scratchpath, &fileinfo, FA_HIDDEN|FA_RDONLY); scratchpath[len]='\0'; while(ret==OK) { switch(install(&fileinfo, par)) { case INSTALLERR : quit(MEMERR, ""); default : break; } /* fprintf(stdout, "%s %s %04u/%02u/%02u %02u:%02u:%02u %lu\n", scratchpath, fileinfo.ff_name, (fileinfo.ff_fdate>>9)+1980, (fileinfo.ff_fdate>>5)&15, (fileinfo.ff_fdate&31), (fileinfo.ff_ftime>>11)&31, (fileinfo.ff_ftime>>5)&63, (fileinfo.ff_ftime&31)*2, fileinfo.ff_fsize); */ ret=findnext(&fileinfo); } } int search_dir(struct fi *par) { int len; int ret; struct fi *newpar; struct ffblk fileinfo; len=strlen(scratchpath); sprintf(&scratchpath[len], "\\*.*"); ret=findfirst(scratchpath, &fileinfo, FA_DIREC); if(ret!=OK) return(ret); while(ret==OK) { if((fileinfo.ff_attrib & FA_DIREC) && (strcmp(fileinfo.ff_name, "..")!=0) && (strcmp(fileinfo.ff_name, ".") != 0)) /* file is directory entry */ { sprintf(&scratchpath[len], "\\%s", fileinfo.ff_name); switch(install(&fileinfo, par)) { case INSTALLERR : quit(MEMERR, ""); default : break; } newpar=fiptr; search_dir(newpar); search_files(newpar); } ret=findnext(&fileinfo); } scratchpath[len]='\0'; return(OK); } void main(int argc, char *argv[]) { struct fi *orgpar; int i; /* int next; int j; */ fprintf(stderr, "file check fp030901\n"); if (argc < 2 ) quit(USAGE, argv[0]); strcpy(fname, "*.*"); /* default filename */ totalfiles=0; totalinstalled=0; /* next=2; options=0; while(next=MAXPATH) quit(REASON, "search path too long"); strcpy(scratchpath, argv[1]); while((i=strlen(scratchpath))>0) if(scratchpath[--i]!='\\') break; else scratchpath[i]='\0'; orgpar=(struct fi *)malloc(sizeof(struct fi)+strlen(scratchpath)); if(orgpar==NULL) quit(MEMERR, ""); orgpar->next=NULL; orgpar->parent=NULL; orgpar->attrib=0; orgpar->ftime=0; orgpar->fdate=0; orgpar->fsize=0; strcpy(orgpar->name, scratchpath); fprintf(stderr, "scanning %s\n", orgpar->name); if(search_dir(orgpar)!=OK) quit(NSPERR, orgpar->name); search_files(orgpar); /* printlist(stdout); */ makefilearray(); fprintf(stderr, "%d files in %d directories\n", totalfiles, totalinstalled-totalfiles); fprintf(stderr, "sorting\n"); sortname(); /* printslist(stdout); */ /* printslistequ(stdout); */ fprintf(stderr, "getting file sums\n"); getfilesums(); fprintf(stderr, "finding equal files\n"); findequsizesum(stdout); fprintf(stderr, "deleting files\n"); fprintf(stderr, "%d files deleted\n", filedelete()); quit(READY, ""); }