#include #include #include #include #include #include #include #include #include #include int main( int argc, char **argv ) { if( argc < 4 ) { printf( "qduper finds duplicate files in a directory (and sub-directories), moves one of each duplicate set to a master directory, and then sym-links all the other duplicates to it. It preserves all files names.\n" ); printf( "\n" ); printf( "Usage: %s [ ... ]\n", argv[0] ); return 1; } QString fileSuffix( argv[1] ); QString masterDirectory( argv[2] ); QSet directorySet; for( int i=3; i > md5map; foreach( QString directory, directorySet ) { QDirIterator dirIterator( directory, QDirIterator::Subdirectories ); while( dirIterator.hasNext() ) { QString fileName = dirIterator.next(); QFileInfo fileInfo( fileName ); fileName = fileInfo.canonicalFilePath(); if( fileInfo.isFile() && fileName.endsWith( fileSuffix ) ) { if( fileInfo.dir() == QDir(masterDirectory) ) { qDebug() << "Skipping" << fileName << "beacuse it is inside the master directory."; continue; } else if( fileInfo.isSymLink() ) { qDebug() << "Skipping" << fileName << "beacuse it is a symbolic link."; continue; } QProcess process; process.start( "md5sum", QStringList() << fileName, QIODevice::ReadOnly ); process.waitForFinished( -1 ); if( process.exitCode() == 0 && process.exitStatus() == QProcess::NormalExit ) { QString md5output = process.readAllStandardOutput(); if( md5regex.indexIn( md5output ) != -1 ) { QString md5 = md5regex.cap(1); md5map[ md5 ].insert( fileName ); } } else { qWarning() << "Warning:" << process.readAllStandardError().trimmed(); } } } } int duplicateCount = 0; foreach( QString md5, md5map.keys() ) { QStringList duplicateFileNames = md5map[md5].toList(); if( duplicateFileNames.count() > 1 ) { duplicateCount += duplicateFileNames.count(); QString masterFile = duplicateFileNames[0]; qDebug() << "I will move" << masterFile << "to directory" << masterDirectory; qDebug() << " And sym-link the following files to it:"; for( int i=1; i 1 ) { QString masterFile = duplicateFileNames[0]; QString masterFileNewName = masterDirectory + "/" + QFileInfo(masterFile).fileName(); if( QProcess::execute( "mv", QStringList() << "-v" << masterFile << masterFileNewName ) == 0 ) { Q_ASSERT( ! QFile::exists(masterFile) ); if( QProcess::execute( "ln", QStringList() << "-s" << masterFileNewName << masterFile ) == 0 ) { for( int i=1; i