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: