File indexing completed on 2024-04-28 15:39:59
0001 /* SPDX-FileCopyrightText: 2018 Robert Krawitz <rlk@alum.mit.edu> 0002 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "OptimizedFileList.h" 0007 0008 #include "FastDir.h" 0009 0010 #include <kpabase/Logging.h> 0011 0012 extern "C" { 0013 #include <dirent.h> 0014 #include <sys/stat.h> 0015 #include <sys/types.h> 0016 #include <unistd.h> 0017 } 0018 0019 #include <QCryptographicHash> 0020 #include <QFile> 0021 #include <QLoggingCategory> 0022 0023 DB::OptimizedFileList::OptimizedFileList(const QStringList &files) 0024 : m_fileList(files) 0025 , m_haveOptimizedFiles(false) 0026 { 0027 optimizeFiles(); 0028 } 0029 0030 DB::OptimizedFileList::OptimizedFileList(const DB::FileNameList &files) 0031 : m_fileList(files.toStringList(DB::AbsolutePath)) 0032 , m_haveOptimizedFiles(false) 0033 { 0034 optimizeFiles(); 0035 } 0036 0037 QString DB::OptimizedFileList::getDirName(const QString &path) 0038 { 0039 static const QString pathSep(QString::fromLatin1("/")); 0040 int lastChar = path.lastIndexOf(pathSep); 0041 if (lastChar <= 0) 0042 return QString::fromLatin1("./"); 0043 else 0044 return path.left(lastChar + 1); 0045 } 0046 0047 void DB::OptimizedFileList::optimizeFiles() const 0048 { 0049 if (m_haveOptimizedFiles) 0050 return; 0051 DirMap dirMap; 0052 QStringList dirList; 0053 // Map files to directories 0054 for (const QString &fileName : m_fileList) { 0055 QString dir = getDirName(fileName); 0056 if (!dirMap.contains(dir)) { 0057 StringSet newDir; 0058 dirMap.insert(dir, newDir); 0059 dirList << dir; 0060 } 0061 dirMap[dir] << fileName; 0062 } 0063 struct stat statbuf; 0064 for (const QString &dirName : dirList) { 0065 const StringSet &files(dirMap[dirName]); 0066 FastDir dir(dirName); 0067 QStringList sortedList = dir.sortFileList(files); 0068 QString fsName(QString::fromLatin1("NULLFS")); 0069 if (stat(QByteArray(QFile::encodeName(dirName)).constData(), &statbuf) == 0) { 0070 QCryptographicHash md5calculator(QCryptographicHash::Md5); 0071 QByteArray md5Buffer((const char *)&(statbuf.st_dev), sizeof(statbuf.st_dev)); 0072 md5calculator.addData(md5Buffer); 0073 fsName = QString::fromLatin1(md5calculator.result().toHex()); 0074 } 0075 if (!m_fsMap.contains(fsName)) { 0076 QStringList newList; 0077 m_fsMap.insert(fsName, newList); 0078 } 0079 m_fsMap[fsName] += sortedList; 0080 } 0081 FSMap tmpFsMap(m_fsMap); 0082 while (tmpFsMap.size() > 1) { 0083 QStringList filesystemsToRemove; 0084 for (FSMap::iterator it = tmpFsMap.begin(); it != tmpFsMap.end(); ++it) { 0085 if (it.value().length() > 0) { 0086 m_optimizedList.append(it.value().takeFirst()); 0087 } else { 0088 filesystemsToRemove << it.key(); 0089 } 0090 } 0091 for (const QString &fs : filesystemsToRemove) { 0092 tmpFsMap.remove(fs); 0093 } 0094 } 0095 if (tmpFsMap.size() > 0) { 0096 QStringList &remainder(tmpFsMap.last()); 0097 m_optimizedList += remainder; 0098 } 0099 // for (QStringList::iterator it = m_optimizedList.begin(); it != m_optimizedList.end(); ++it) { 0100 // qDebug() << *it; 0101 // } 0102 m_haveOptimizedFiles = true; 0103 } 0104 0105 QStringList DB::OptimizedFileList::optimizedFiles() const 0106 { 0107 return m_optimizedList; 0108 } 0109 0110 DB::FileNameList DB::OptimizedFileList::optimizedDbFiles() const 0111 { 0112 return FileNameList(m_optimizedList); 0113 } 0114 0115 // vi:expandtab:tabstop=4 shiftwidth=4: