File indexing completed on 2024-05-12 04:51:05

0001 /*
0002     SPDX-FileCopyrightText: 1998-2007 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "k3bfilecompilationsizehandler.h"
0007 #include "k3bfileitem.h"
0008 
0009 #include <QDebug>
0010 #include <QFile>
0011 #include <QMap>
0012 #include <QList>
0013 
0014 
0015 // TODO: remove the items from the project if the savedSize differs
0016 // with some info-widget: "Files xxx have changed on disk. Removing them from the project."
0017 // or we just update the sizes!
0018 
0019 
0020 static long usedBlocks( const KIO::filesize_t& bytes )
0021 {
0022     if( bytes % 2048 )
0023         return bytes/2048 + 1;
0024     else
0025         return bytes/2048;
0026 }
0027 
0028 
0029 class InodeInfo
0030 {
0031 public:
0032     InodeInfo() {
0033         number = 0;
0034         savedSize = 0;
0035     }
0036 
0037     /**
0038      * How often has the file with
0039      * the corresponding inode been added
0040      */
0041     int number;
0042 
0043     /**
0044      * The size of the first added file. This has to be saved
0045      * to check further addings and to avoid the following situation:
0046      * A file with inode 1 is added, then deleted. Another file is created
0047      * at inode 1 and added to the project. Now the first file gets
0048      * removed and then the second. If we had not saved the size we would
0049      * have added the size of the first and removed the size of the second
0050      * file resulting in a corrupted project size.
0051      * This way we always use the size of the first added file and may
0052      * warn the user if sizes differ.
0053      */
0054     KIO::filesize_t savedSize;
0055 
0056     KIO::filesize_t completeSize() const { return savedSize*number; }
0057 
0058     /**
0059      * In an iso9660 filesystem a file occupies complete blocks of 2048 bytes.
0060      */
0061     K3b::Msf blocks() const { return K3b::Msf( usedBlocks(savedSize) ); }
0062 
0063     QList<K3b::DataItem*> items;
0064 };
0065 
0066 
0067 class K3b::FileCompilationSizeHandler::Private
0068 {
0069 public:
0070     Private()
0071         : size(0) {
0072     }
0073 
0074     void clear() {
0075         inodeMap.clear();
0076         size = 0;
0077         blocks = 0;
0078     }
0079 
0080     void addFile( K3b::FileItem* item, bool followSymlinks ) {
0081         InodeInfo& inodeInfo = inodeMap[item->localId(followSymlinks)];
0082 
0083         inodeInfo.items.append( item );
0084 
0085         if( inodeInfo.number == 0 ) {
0086             inodeInfo.savedSize = item->itemSize( followSymlinks );
0087 
0088             size += inodeInfo.savedSize;
0089             blocks += inodeInfo.blocks();
0090         }
0091 
0092         inodeInfo.number++;
0093     }
0094 
0095     void addSpecialItem( K3b::DataItem* item ) {
0096         // special files do not have a corresponding local file
0097         // so we just add their k3bSize
0098         size += item->size();
0099         blocks += usedBlocks(item->size());
0100         specialItems.append( item );
0101     }
0102 
0103     void removeFile( K3b::FileItem* item, bool followSymlinks ) {
0104         InodeInfo& inodeInfo = inodeMap[item->localId(followSymlinks)];
0105 
0106         if( !inodeInfo.items.contains( item ) ) {
0107             qCritical() << "(K3b::FileCompilationSizeHandler) "
0108                      << item->localPath()
0109                      << " has been removed without being added!" << Qt::endl;
0110         }
0111         else {
0112             if( item->itemSize(followSymlinks) != inodeInfo.savedSize ) {
0113                 qCritical() << "(K3b::FileCompilationSizeHandler) savedSize differs!" << Qt::endl;
0114             }
0115 
0116             inodeInfo.items.removeOne( item );
0117             inodeInfo.number--;
0118             if( inodeInfo.number == 0 ) {
0119                 size -= inodeInfo.savedSize;
0120                 blocks -= inodeInfo.blocks();
0121             }
0122         }
0123     }
0124 
0125     void removeSpecialItem( K3b::DataItem* item ) {
0126         // special files do not have a corresponding local file
0127         // so we just subtract their k3bSize
0128         if( !specialItems.contains( item ) ) {
0129             qCritical() << "(K3b::FileCompilationSizeHandler) Special item "
0130                      << item->k3bName()
0131                      << " has been removed without being added!" << Qt::endl;
0132         }
0133         else {
0134             specialItems.removeOne( item );
0135             size -= item->size();
0136             blocks -= usedBlocks(item->size());
0137         }
0138     }
0139 
0140 
0141     /**
0142      * This maps from inodes to the number of occurrences of the inode.
0143      */
0144     QMap<K3b::FileItem::Id, InodeInfo> inodeMap;
0145 
0146     KIO::filesize_t size;
0147     K3b::Msf blocks;
0148 
0149     QList<K3b::DataItem*> specialItems;
0150 };
0151 
0152 
0153 
0154 K3b::FileCompilationSizeHandler::FileCompilationSizeHandler()
0155 {
0156     d_symlinks = new Private;
0157     d_noSymlinks = new Private;
0158 }
0159 
0160 K3b::FileCompilationSizeHandler::~FileCompilationSizeHandler()
0161 {
0162     delete d_symlinks;
0163     delete d_noSymlinks;
0164 }
0165 
0166 
0167 const KIO::filesize_t& K3b::FileCompilationSizeHandler::size( bool followSymlinks ) const
0168 {
0169     if( followSymlinks )
0170         return d_noSymlinks->size;
0171     else
0172         return d_symlinks->size;
0173 }
0174 
0175 
0176 const K3b::Msf& K3b::FileCompilationSizeHandler::blocks( bool followSymlinks ) const
0177 {
0178     if( followSymlinks )
0179         return d_noSymlinks->blocks;
0180     else
0181         return d_symlinks->blocks;
0182 }
0183 
0184 
0185 void K3b::FileCompilationSizeHandler::addFile( K3b::DataItem* item )
0186 {
0187     if( item->isSpecialFile() ) {
0188         d_symlinks->addSpecialItem( item );
0189         d_noSymlinks->addSpecialItem( item );
0190     }
0191     else if( item->isFile() ) {
0192         K3b::FileItem* fileItem = static_cast<K3b::FileItem*>( item );
0193         d_symlinks->addFile( fileItem, false );
0194         d_noSymlinks->addFile( fileItem, true );
0195     }
0196 }
0197 
0198 
0199 void K3b::FileCompilationSizeHandler::removeFile( K3b::DataItem* item )
0200 {
0201     if( item->isSpecialFile() ) {
0202         d_symlinks->removeSpecialItem( item );
0203         d_noSymlinks->removeSpecialItem( item );
0204     }
0205     else if( item->isFile() ) {
0206         K3b::FileItem* fileItem = static_cast<K3b::FileItem*>( item );
0207         d_symlinks->removeFile( fileItem, false );
0208         d_noSymlinks->removeFile( fileItem, true );
0209     }
0210 }
0211 
0212 
0213 void K3b::FileCompilationSizeHandler::clear()
0214 {
0215     d_symlinks->clear();
0216     d_noSymlinks->clear();
0217 }