Annotation of sbbs/sbbs3/finddupes.c, revision 1.1.1.1

1.1       root        1: /* finddupes.c */
                      2: 
                      3: /* Search for (and optionally delete) duplicate files in multiple      */
                      4: /* directories based on size and either MD5 or CRC-32 "chksums".       */
                      5: 
                      6: #include <stdio.h>
                      7: #include <time.h>
                      8: 
                      9: #include "dirwrap.h"
                     10: #ifdef USE_MD5
                     11:        #include "md5.h"
                     12: #else  /* CRC-32 */
                     13:        #include "crc32.h"
                     14: #endif
                     15: 
                     16: typedef struct {
                     17:        char    path[MAX_PATH+1];
                     18:        long    length;
                     19:        time_t  date;
                     20: #ifdef USE_MD5
                     21:        BYTE    chksum[MD5_DIGEST_SIZE];
                     22: #else
                     23:        ulong   chksum;
                     24: #endif
                     25: } file_t;
                     26: 
                     27: file_t* file;
                     28: ulong  file_count=0;
                     29: 
                     30: #ifdef FREE
                     31: #undef FREE
                     32: #endif
                     33: #define FREE(x) if(x!=NULL) free(x);
                     34: 
                     35: int fchksum(const char* fname, long length,
                     36: #ifdef USE_MD5
                     37:                        BYTE*
                     38: #else
                     39:                        ulong*
                     40: #endif
                     41:                        chksum)
                     42: {
                     43:        BYTE* buf=NULL;
                     44:        FILE* fp;
                     45: 
                     46:        if((fp=fopen(fname,"rb"))==NULL) {
                     47:                perror(fname);
                     48:                return(-1);
                     49:        }
                     50:        
                     51:        if(length && (buf=malloc(length))==NULL) {
                     52:                printf("!Error allocating %ld bytes of memory for %s\n"
                     53:                        ,length,fname);
                     54:                fclose(fp);
                     55:                return(-1);
                     56:        }
                     57: 
                     58:        if(fread(buf,sizeof(BYTE),length,fp) != length) {
                     59:                perror(fname);
                     60:                fclose(fp);
                     61:                FREE(buf);
                     62:                return(-1);
                     63:        }
                     64: 
                     65:        fclose(fp);
                     66: #ifdef USE_MD5
                     67:        MD5_calc(chksum, buf, length);
                     68: #else
                     69:        *chksum = crc32(buf, length);
                     70: #endif
                     71:        FREE(buf);
                     72:        return(0);
                     73: }
                     74: 
                     75: char* timestr(void)
                     76: {
                     77:        char* p;
                     78:        time_t t=time(NULL);
                     79:        p=ctime(&t);
                     80:        p[19]=0;                /* chop off year and \n */
                     81:        return(p+4);    /* skip day-of-week */
                     82: }
                     83:        
                     84: int searchdir(const char* path, BOOL recursive, ulong compare_bytes)
                     85: {
                     86:        DIR* dir;
                     87:        struct dirent* ent;
                     88:        file_t* fp;
                     89:        char fpath[MAX_PATH+1];
                     90: 
                     91:        printf("%s begin searching %s\n",timestr(), path);
                     92:        if((dir = opendir(path))==NULL) {
                     93:                perror(path);
                     94:                return(1);
                     95:        }
                     96: 
                     97:        while((ent = readdir(dir))!=NULL) {
                     98:                if(kbhit())
                     99:                        break;
                    100:                if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
                    101:                        continue;
                    102:                strcpy(fpath,path);
                    103:                backslash(fpath);
                    104:                strcat(fpath,ent->d_name);
                    105:                if(isdir(fpath)) {
                    106:                        if(recursive)
                    107:                                searchdir(fpath, recursive, compare_bytes);
                    108:                        continue;
                    109:                }
                    110: 
                    111:                file=realloc(file,sizeof(file_t)*(file_count+1));
                    112:                if(file==NULL) {
                    113:                        printf("!Error allocating %lu bytes\n",sizeof(file_t)*(file_count+1));
                    114:                        exit(1);
                    115:                }
                    116:                fp=&file[file_count];
                    117:                memset(fp,0,sizeof(file_t));
                    118:                strcpy(fp->path,fpath);
                    119:                fp->date=fdate(fp->path);
                    120:                if((fp->length=flength(fp->path))==-1) {
                    121:                        printf("!Failed to get length of %s\n",fp->path);
                    122:                        continue;
                    123:                }
                    124:                if(compare_bytes && fp->length > compare_bytes)
                    125:                        fp->length = compare_bytes;
                    126:                if(fchksum(fp->path, fp->length,
                    127: #ifdef USE_MD5
                    128:                        fp->chksum
                    129: #else
                    130:                        &fp->chksum
                    131: #endif
                    132:                        ))
                    133:                        continue;
                    134:                file_count++;
                    135:                printf("%lu\r", file_count);
                    136:        }
                    137: 
                    138:        closedir(dir);
                    139:        printf("%s done searching %s\n",timestr(), path);
                    140:        return(0);
                    141: }
                    142: 
                    143: int compare_files(const file_t *f1, const file_t *f2 )
                    144: {
                    145:        int result;
                    146:        
                    147:        /* Sort first by size (descending) */
                    148:        if((result = f2->length - f1->length) != 0)
                    149:                return(result);
                    150: 
                    151:        /* Then by chksum (ascending) */
                    152:        if((result = memcmp(&f1->chksum, &f2->chksum, sizeof(f1->chksum))) != 0)
                    153:                return(result);
                    154: 
                    155:        /* Then by date (descending) */
                    156:        return(f2->date - f1->date);
                    157: }
                    158: 
                    159: int main(int argc, char** argv)
                    160: {
                    161:        char hex[32];
                    162:        int i;
                    163:        ulong fsize;
                    164:        ulong dupe_count=0;
                    165:        ulong del_files=0;
                    166:        ulong del_bytes=0;
                    167:        ulong compare_bytes=0;
                    168:        BOOL recursive=FALSE;
                    169:        BOOL del_dupes=FALSE;
                    170:        BOOL dir_specified=FALSE;
                    171: 
                    172:        for(i=1;i<argc;i++) {
                    173:                if(!stricmp(argv[i],"-d"))
                    174:                        del_dupes=TRUE;
                    175:                else if(!stricmp(argv[i],"-r"))
                    176:                        recursive=TRUE;
                    177:                else if(!stricmp(argv[i],"-b") && i<argc+1)
                    178:                        compare_bytes=atoi(argv[++i]);
                    179:                else if(!stricmp(argv[i],"-k") && i<argc+1)
                    180:                        compare_bytes=atoi(argv[++i])*1024;
                    181:                else if(argv[i][0]=='-') {
                    182:                        printf("%s [[-opt] [-opt] [...]] [[path] [path] [...]]\n", argv[0]);
                    183:                        printf("-r\t search directories recursively\n");
                    184:                        printf("-d\t delete duplicate files found\n");
                    185:                        printf("-b n\t compare up to n bytes of each file\n");
                    186:                        printf("-k n\t compare up to n kilobytes each of file\n");
                    187:                        exit(0);
                    188:                }
                    189:                else {
                    190:                        dir_specified=TRUE;
                    191:                        searchdir(argv[i], recursive, compare_bytes);
                    192:                }
                    193:        }
                    194:        if(!dir_specified)
                    195:                searchdir(".", recursive, compare_bytes);
                    196: 
                    197:        if(!file_count) {
                    198:                printf("no files.\n");
                    199:                return(0);
                    200:        }
                    201: 
                    202:        printf("%s begin sorting (%lu files)\n", timestr(), file_count);
                    203:        qsort(file,file_count,sizeof(file_t),compare_files);
                    204:        printf("%s end sorting\n", timestr());
                    205: 
                    206:        printf("%s comparing (%lu files)\n", timestr(), file_count);
                    207: 
                    208:        for(i=0;i<file_count-1;i++) {
                    209:                if(file[i].length != file[i+1].length)
                    210:                        continue; /* sizes must match */
                    211:                if(memcmp(&file[i].chksum, &file[i+1].chksum, sizeof(file[i].chksum)))
                    212:                        continue; /* chksums must match */
                    213: #ifdef USE_MD5
                    214:                MD5_hex(hex, file[i].chksum);
                    215: #else
                    216:                sprintf(hex, "%08lx", file[i].chksum);
                    217: #endif
                    218:                printf("Dupe: %s %7lu %s\n", hex, file[i].length, getfname(file[i].path));
                    219:                if(del_dupes) {
                    220:                        fsize=flength(file[i].path);
                    221:                        printf("Removing %s (%lu bytes)\n", file[i].path, fsize);
                    222:                        if(remove(file[i].path)!=0)
                    223:                                perror(file[i].path);
                    224:                        else {
                    225:                                del_files++;
                    226:                                del_bytes+=fsize;
                    227:                        }
                    228:                }
                    229:                dupe_count++;
                    230:        }
                    231: 
                    232:        printf("%s done (%lu duplicates found)\n", timestr(), dupe_count);
                    233:        if(del_files)
                    234:                printf("%lu bytes deleted in %lu files\n", del_bytes, del_files);
                    235:        return(0);
                    236: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.