1 /*
2 SPDX-FileCopyrightText: 1998-2007 Sebastian Trueg <trueg@k3b.org>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "k3bfilecompilationsizehandler.h"
7 #include "k3bfileitem.h"
8
9 #include <QDebug>
10 #include <QFile>
11 #include <QMap>
12 #include <QList>
13
14
15 // TODO: remove the items from the project if the savedSize differs
16 // with some info-widget: "Files xxx have changed on disk. Removing them from the project."
17 // or we just update the sizes!
18
19
usedBlocks(const KIO::filesize_t & bytes)20 static long usedBlocks( const KIO::filesize_t& bytes )
21 {
22 if( bytes % 2048 )
23 return bytes/2048 + 1;
24 else
25 return bytes/2048;
26 }
27
28
29 class InodeInfo
30 {
31 public:
InodeInfo()32 InodeInfo() {
33 number = 0;
34 savedSize = 0;
35 }
36
37 /**
38 * How often has the file with
39 * the corresponding inode been added
40 */
41 int number;
42
43 /**
44 * The size of the first added file. This has to be saved
45 * to check further addings and to avoid the following situation:
46 * A file with inode 1 is added, then deleted. Another file is created
47 * at inode 1 and added to the project. Now the first file gets
48 * removed and then the second. If we had not saved the size we would
49 * have added the size of the first and removed the size of the second
50 * file resulting in a corrupted project size.
51 * This way we always use the size of the first added file and may
52 * warn the user if sizes differ.
53 */
54 KIO::filesize_t savedSize;
55
completeSize() const56 KIO::filesize_t completeSize() const { return savedSize*number; }
57
58 /**
59 * In an iso9660 filesystem a file occupies complete blocks of 2048 bytes.
60 */
blocks() const61 K3b::Msf blocks() const { return K3b::Msf( usedBlocks(savedSize) ); }
62
63 QList<K3b::DataItem*> items;
64 };
65
66
67 class K3b::FileCompilationSizeHandler::Private
68 {
69 public:
Private()70 Private()
71 : size(0) {
72 }
73
clear()74 void clear() {
75 inodeMap.clear();
76 size = 0;
77 blocks = 0;
78 }
79
addFile(K3b::FileItem * item,bool followSymlinks)80 void addFile( K3b::FileItem* item, bool followSymlinks ) {
81 InodeInfo& inodeInfo = inodeMap[item->localId(followSymlinks)];
82
83 inodeInfo.items.append( item );
84
85 if( inodeInfo.number == 0 ) {
86 inodeInfo.savedSize = item->itemSize( followSymlinks );
87
88 size += inodeInfo.savedSize;
89 blocks += inodeInfo.blocks();
90 }
91
92 inodeInfo.number++;
93 }
94
addSpecialItem(K3b::DataItem * item)95 void addSpecialItem( K3b::DataItem* item ) {
96 // special files do not have a corresponding local file
97 // so we just add their k3bSize
98 size += item->size();
99 blocks += usedBlocks(item->size());
100 specialItems.append( item );
101 }
102
removeFile(K3b::FileItem * item,bool followSymlinks)103 void removeFile( K3b::FileItem* item, bool followSymlinks ) {
104 InodeInfo& inodeInfo = inodeMap[item->localId(followSymlinks)];
105
106 if( !inodeInfo.items.contains( item ) ) {
107 qCritical() << "(K3b::FileCompilationSizeHandler) "
108 << item->localPath()
109 << " has been removed without being added!" << endl;
110 }
111 else {
112 if( item->itemSize(followSymlinks) != inodeInfo.savedSize ) {
113 qCritical() << "(K3b::FileCompilationSizeHandler) savedSize differs!" << endl;
114 }
115
116 inodeInfo.items.removeOne( item );
117 inodeInfo.number--;
118 if( inodeInfo.number == 0 ) {
119 size -= inodeInfo.savedSize;
120 blocks -= inodeInfo.blocks();
121 }
122 }
123 }
124
removeSpecialItem(K3b::DataItem * item)125 void removeSpecialItem( K3b::DataItem* item ) {
126 // special files do not have a corresponding local file
127 // so we just subtract their k3bSize
128 if( !specialItems.contains( item ) ) {
129 qCritical() << "(K3b::FileCompilationSizeHandler) Special item "
130 << item->k3bName()
131 << " has been removed without being added!" << endl;
132 }
133 else {
134 specialItems.removeOne( item );
135 size -= item->size();
136 blocks -= usedBlocks(item->size());
137 }
138 }
139
140
141 /**
142 * This maps from inodes to the number of occurrences of the inode.
143 */
144 QMap<K3b::FileItem::Id, InodeInfo> inodeMap;
145
146 KIO::filesize_t size;
147 K3b::Msf blocks;
148
149 QList<K3b::DataItem*> specialItems;
150 };
151
152
153
FileCompilationSizeHandler()154 K3b::FileCompilationSizeHandler::FileCompilationSizeHandler()
155 {
156 d_symlinks = new Private;
157 d_noSymlinks = new Private;
158 }
159
~FileCompilationSizeHandler()160 K3b::FileCompilationSizeHandler::~FileCompilationSizeHandler()
161 {
162 delete d_symlinks;
163 delete d_noSymlinks;
164 }
165
166
size(bool followSymlinks) const167 const KIO::filesize_t& K3b::FileCompilationSizeHandler::size( bool followSymlinks ) const
168 {
169 if( followSymlinks )
170 return d_noSymlinks->size;
171 else
172 return d_symlinks->size;
173 }
174
175
blocks(bool followSymlinks) const176 const K3b::Msf& K3b::FileCompilationSizeHandler::blocks( bool followSymlinks ) const
177 {
178 if( followSymlinks )
179 return d_noSymlinks->blocks;
180 else
181 return d_symlinks->blocks;
182 }
183
184
addFile(K3b::DataItem * item)185 void K3b::FileCompilationSizeHandler::addFile( K3b::DataItem* item )
186 {
187 if( item->isSpecialFile() ) {
188 d_symlinks->addSpecialItem( item );
189 d_noSymlinks->addSpecialItem( item );
190 }
191 else if( item->isFile() ) {
192 K3b::FileItem* fileItem = static_cast<K3b::FileItem*>( item );
193 d_symlinks->addFile( fileItem, false );
194 d_noSymlinks->addFile( fileItem, true );
195 }
196 }
197
198
removeFile(K3b::DataItem * item)199 void K3b::FileCompilationSizeHandler::removeFile( K3b::DataItem* item )
200 {
201 if( item->isSpecialFile() ) {
202 d_symlinks->removeSpecialItem( item );
203 d_noSymlinks->removeSpecialItem( item );
204 }
205 else if( item->isFile() ) {
206 K3b::FileItem* fileItem = static_cast<K3b::FileItem*>( item );
207 d_symlinks->removeFile( fileItem, false );
208 d_noSymlinks->removeFile( fileItem, true );
209 }
210 }
211
212
clear()213 void K3b::FileCompilationSizeHandler::clear()
214 {
215 d_symlinks->clear();
216 d_noSymlinks->clear();
217 }
218