/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include // struct stat #include // memset() #include // for exit() #include // for memory file mapped mmap() #include // for memory file mapped mmap() #include // open() close() #include // open() close() #include // open() close() # include # include // opendir, readdir, dir/file structs # include // opendir, readdir, dir/file structs #include #define TRUE 1 #define FALSE 0 #define BOOL int BOOL verbose =FALSE; // 8Ko to store path + filename ! #define MAXPATHANDFILENAME 8192 char current_directory[MAXPATHANDFILENAME]; // 8192 the max. number of character for full path to current directory // local function declaration void findDoubleInDirectory(char *pSourceDirectory); void findDoubleOf(char *sourceFileName, char *pSourceDirectory); void compareFiles(char *source, char *destination); void error_msg_and_exit(); void str_replace(char *source, char char_old, char char_new); char *clean_filename(char *filename); /**************************************************************** browse all 'sourceFileDesc' files and compare them with 'destFileDesc' ****************************************************************/ int main (int argc, char *argv[]) { // some parameters are required... if(argc<2) { error_msg_and_exit(); } // look for the '-v' (verbose) tag int i; for(i=1;id_name,".")) || (!strcmp(sourceFile->d_name,"..")) || (!strcmp(sourceFile->d_name,"lost+found")) ) continue; char sourceFileName[MAXPATHANDFILENAME]; if ( sizeof(sourceFileName) <= (strlen(pSourceDirectory) + strlen(sourceFile->d_name) + 1) ) { // add 1 for '/' character printf("Filename too long : %s/%s\tLIMIT IS %d characters", pSourceDirectory, sourceFile->d_name, sizeof(sourceFileName) ); continue; } sprintf(sourceFileName, "%s/%s", pSourceDirectory, sourceFile->d_name); //printf("DEBUG : findDoubleInDirectory() : dir = %s\tfile = %s\n", pSourceDirectory, sourceFileName); // get file stat : is it a file or directory ? /* struct stat fileStat; if( stat (sourceFileName, &fileStat ) !=0) continue; switch(fileStat.st_mode & S_IFMT) { case S_IFDIR: findDoubleInDirectory( sourceFileName); break; // directory case S_IFREG: findDoubleOf(sourceFileName, current_directory); break;// regular files or links } // end of switch() */ if(sourceFile->d_type==DT_REG){ findDoubleOf(sourceFileName, current_directory); continue; } if(sourceFile->d_type==DT_DIR){ findDoubleInDirectory( sourceFileName); continue; } } closedir (sourceDir); } // end of findDoubleInDirectory() /******************************************* look for double of file 'sourceFileName' into 'pSourceDirectory' and all its sub-dir *******************************************/ void findDoubleOf(char *sourceFileName, char *pDestinationDirectory ) { //printf("DEBUG : findDoubleOf() : file = %s\tdir = %s\n",sourceFileName,pDestinationDirectory ); DIR *destinationDir = opendir(pDestinationDirectory ); if( destinationDir == NULL ) { printf("ERROR : unable to open '%s' directory.\n", pDestinationDirectory); return; } struct dirent *destinationFile; while( (destinationFile=readdir(destinationDir) )!=NULL ) { // special case for special files ... if( (!strcmp(destinationFile->d_name,".")) || (!strcmp(destinationFile->d_name,"..")) || (!strcmp(destinationFile->d_name,"lost+found")) ) continue; char destinationFileName[MAXPATHANDFILENAME]; if ( sizeof(destinationFileName) <= (strlen(pDestinationDirectory) + strlen(destinationFile->d_name) + 1) ) { // add 1 for '/' character printf("Filename too long : %s/%s\tLIMIT IS %d characters", pDestinationDirectory, destinationFile->d_name, sizeof(destinationFileName) ); continue; } sprintf(destinationFileName, "%s/%s", pDestinationDirectory, destinationFile->d_name); /* * i used this code to test the performance of the sprintf function strcpy(destinationFileName,pDestinationDirectory); strcat(destinationFileName,"/"); strcat(destinationFileName,destinationFile->d_name); */ //printf("DEBUG findDoubleOf() : source = %s\tdest = %s\n",sourceFileName, destinationFileName ); // get file stat : is it a file or directory ? /* struct stat fileStat; if( stat (destinationFileName, &fileStat ) !=0) continue; switch(fileStat.st_mode & S_IFMT) { case S_IFDIR: findDoubleOf( sourceFileName, destinationFileName); break; case S_IFREG: compareFiles( sourceFileName, destinationFileName); } // end of switch() */ if(destinationFile->d_type==DT_REG){ compareFiles( sourceFileName, destinationFileName); continue; } if(destinationFile->d_type==DT_DIR){ findDoubleOf( sourceFileName, destinationFileName); continue; } } closedir (destinationDir); } // end of findDoubleOf() /************************************************************** compare 2 files. Display a message if they are the same **************************************************************/ void compareFiles(char *source, char *destination) { char *source_clean = clean_filename(source); char *destination_clean = clean_filename(destination); // compare file's name : don't compare a file with itself ! if(!strcmp(source_clean,destination_clean )) return; if(verbose) printf("compare \t %s \t with\t %s\n", source_clean, destination_clean); // compare file size struct stat source_fileStat; struct stat destination_fileStat; if( stat (source, &source_fileStat ) !=0) return; if( stat (destination, &destination_fileStat) !=0 ) return; if( source_fileStat.st_size != destination_fileStat.st_size) return; if( (source_fileStat.st_size==0) || (destination_fileStat.st_size==0) ) return; // files have the same size => compare data // open source file int source_fd; // file descriptor if( (source_fd=open(source, O_RDONLY)) == -1) { printf ("ERROR : unable to open %s \n", source); return; } // read file as byte array char *source_data = mmap((caddr_t)0, source_fileStat.st_size, PROT_READ,MAP_SHARED, source_fd, 0); if ( source_data == MAP_FAILED) { printf("ERROR : unable to map source file %s with mmap\n err=%s\n",source,strerror(errno)); close(source_fd); return; } // open destination file int destination_fd; // file descriptor if( (destination_fd=open(destination, O_RDONLY)) == -1) { printf ("ERROR : unable to open %s \n", destination); munmap (source_data, source_fileStat.st_size); close(source_fd); return; } // read file as byte array char *destination_data = mmap((caddr_t)0, destination_fileStat.st_size, PROT_READ,MAP_SHARED, destination_fd, 0); if ( destination_data == MAP_FAILED) { printf("ERROR : unable to map destination file %s with mmap\n err=%s\n",destination,strerror(errno)); close(destination_fd); munmap (source_data, source_fileStat.st_size); close(source_fd); return; } // compare file's contents if ( memcmp( source_data, destination_data,source_fileStat.st_size ) ==0 ) printf("%s is the same as %s\n", source, destination); munmap (destination_data, destination_fileStat.st_size); munmap (source_data, source_fileStat.st_size); close(source_fd); close(destination_fd); } // end of compareFiles() /***************************************************************** Replace each 'char_old' character in 'source' with 'char_new' *****************************************************************/ void str_replace(char *source, char char_old, char char_new) { char *ptr = source; while (*ptr) { if ( (*ptr)==char_old ) (*ptr)=char_new; ptr++; } } /**************************************************************** Input : a filename, for instance : 1 ./rep1/file.txt 2 rep1/file.txt Output : remove the starting ./ rep1/file.txt *****************************************************************/ char *clean_filename(char *filename) { if( filename[0] == '.') if (filename[1] == '/') return filename+2; return filename; }