File indexing completed on 2024-05-12 04:51:05
0001 /* 0002 SPDX-FileCopyrightText: 2009 Michal Malek <michalm@jabster.pl> 0003 SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "k3bfileitem.h" 0009 #include "k3bdatadoc.h" 0010 #include "k3bdiritem.h" 0011 #include "k3bglobals.h" 0012 #include "k3bisooptions.h" 0013 #include <config-k3b.h> 0014 0015 #include <QDebug> 0016 #include <QFile> 0017 #include <QFileInfo> 0018 #include <QMimeDatabase> 0019 #include <QRegularExpression> 0020 #include <QString> 0021 #include <QStringList> 0022 #include <QUrl> 0023 0024 #include <errno.h> 0025 #include <string.h> 0026 0027 0028 bool K3b::operator==( const K3b::FileItem::Id& id1, const K3b::FileItem::Id& id2 ) 0029 { 0030 return ( id1.device == id2.device && id1.inode == id2.inode ); 0031 } 0032 0033 0034 bool K3b::operator<( const K3b::FileItem::Id& id1, const K3b::FileItem::Id& id2 ) 0035 { 0036 if( id1.device == id2.device ) 0037 return ( id1.inode < id2.inode ); 0038 else 0039 return ( id1.device < id2.device ); 0040 } 0041 0042 0043 bool K3b::operator>( const K3b::FileItem::Id& id1, const K3b::FileItem::Id& id2 ) 0044 { 0045 return !( id2 < id1 || id1 == id2 ); 0046 } 0047 0048 0049 0050 K3b::FileItem::FileItem( const QString& filePath, K3b::DataDoc& doc, const QString& k3bName, const ItemFlags& flags ) 0051 : K3b::DataItem( flags | FILE ), 0052 m_replacedItemFromOldSession(0), 0053 m_localPath(filePath) 0054 { 0055 k3b_struct_stat statBuf; 0056 k3b_struct_stat followedStatBuf; 0057 // we determine the size here to avoid problems with removed or renamed files 0058 // we need to use lstat here since for symlinks both KDE and QT return the size of the file pointed to 0059 // instead the size of the link. 0060 if( k3b_lstat( QFile::encodeName(filePath), &statBuf ) == 0 ) { 0061 if( k3b_stat( QFile::encodeName(filePath), &followedStatBuf ) == 0 ) { 0062 init( filePath, k3bName, doc, &statBuf, &followedStatBuf ); 0063 } 0064 else { 0065 init( filePath, k3bName, doc, &statBuf, 0 ); 0066 qCritical() << "(KFileItem) stat failed: " << QString::fromLocal8Bit( ::strerror(errno) ) << Qt::endl; 0067 } 0068 } 0069 else { 0070 qCritical() << "(KFileItem) lstat failed: " << QString::fromLocal8Bit( ::strerror(errno) ) << Qt::endl; 0071 if( k3b_stat( QFile::encodeName(filePath), &followedStatBuf ) == 0 ) { 0072 init( filePath, k3bName, doc, 0, &followedStatBuf ); 0073 } 0074 else { 0075 init( filePath, k3bName, doc, 0, 0 ); 0076 qCritical() << "(KFileItem) stat failed: " << QString::fromLocal8Bit( ::strerror(errno) ) << Qt::endl; 0077 } 0078 } 0079 } 0080 0081 0082 K3b::FileItem::FileItem( const k3b_struct_stat* stat, 0083 const k3b_struct_stat* followedStat, 0084 const QString& filePath, K3b::DataDoc& doc, const QString& k3bName, const ItemFlags& flags ) 0085 : K3b::DataItem( flags | FILE ), 0086 m_replacedItemFromOldSession(0), 0087 m_localPath(filePath) 0088 { 0089 init( filePath, k3bName, doc, stat, followedStat ); 0090 } 0091 0092 0093 K3b::FileItem::FileItem( const K3b::FileItem& item ) 0094 : K3b::DataItem( item ), 0095 m_replacedItemFromOldSession(0), 0096 m_size( item.m_size ), 0097 m_sizeFollowed( item.m_sizeFollowed ), 0098 m_id( item.m_id ), 0099 m_idFollowed( item.m_idFollowed ), 0100 m_localPath( item.m_localPath ), 0101 m_mimeType( item.m_mimeType ) 0102 { 0103 } 0104 0105 0106 K3b::FileItem::~FileItem() 0107 { 0108 // remove this from parentdir 0109 take(); 0110 } 0111 0112 0113 K3b::DataItem* K3b::FileItem::copy() const 0114 { 0115 return new K3b::FileItem( *this ); 0116 } 0117 0118 0119 QMimeType K3b::FileItem::mimeType() const 0120 { 0121 return m_mimeType; 0122 } 0123 0124 0125 KIO::filesize_t K3b::FileItem::itemSize( bool followSymlinks ) const 0126 { 0127 if( followSymlinks ) 0128 return m_sizeFollowed; 0129 else 0130 return m_size; 0131 } 0132 0133 0134 K3b::FileItem::Id K3b::FileItem::localId() const 0135 { 0136 if( DataDoc* doc = getDoc() ) 0137 return localId( doc->isoOptions().followSymbolicLinks() || !doc->isoOptions().createRockRidge() ); 0138 else 0139 return localId( false ); 0140 } 0141 0142 0143 K3b::FileItem::Id K3b::FileItem::localId( bool followSymlinks ) const 0144 { 0145 if( followSymlinks ) 0146 return m_idFollowed; 0147 else 0148 return m_id; 0149 } 0150 0151 0152 bool K3b::FileItem::exists() const 0153 { 0154 return true; 0155 } 0156 0157 QString K3b::FileItem::absIsoPath() 0158 { 0159 // return m_dir->absIsoPath() + m_isoName; 0160 return QString(); 0161 } 0162 0163 0164 QString K3b::FileItem::localPath() const 0165 { 0166 return m_localPath; 0167 } 0168 0169 0170 K3b::DirItem* K3b::FileItem::getDirItem() const 0171 { 0172 return parent(); 0173 } 0174 0175 0176 QString K3b::FileItem::linkDest() const 0177 { 0178 return QFileInfo( localPath() ).symLinkTarget(); 0179 } 0180 0181 0182 bool K3b::FileItem::isValid() const 0183 { 0184 if( isSymLink() ) { 0185 0186 // this link is not valid if we cannot follow it if we want to 0187 if( DataDoc* doc = getDoc() ) { 0188 if( doc->isoOptions().followSymbolicLinks() ) { 0189 return QFile::exists( K3b::resolveLink( localPath() ) ); 0190 } 0191 } 0192 0193 QString dest = linkDest(); 0194 0195 if( dest[0] == '/' ) 0196 return false; // absolute links can never be part of the compilation! 0197 0198 // parse the link 0199 K3b::DirItem* dir = parent(); 0200 0201 static const QRegularExpression rx("/+"); 0202 QStringList tokens = dest.split( rx ); // two slashes or more do the same as one does! 0203 0204 int i = 0; 0205 while( i < tokens.size() ) { 0206 if( tokens[i] == "." ) { 0207 // ignore it 0208 } 0209 else if( tokens[i] == ".." ) { 0210 // change the directory 0211 dir = dir->parent(); 0212 if( dir == 0 ) 0213 return false; 0214 } 0215 else { 0216 // search for the item in dir 0217 K3b::DataItem* d = dir->find( tokens[i] ); 0218 if( d == 0 ) 0219 return false; 0220 0221 if( d->isDir() ) { 0222 // change directory 0223 dir = (K3b::DirItem*)d; 0224 } 0225 else { 0226 if( i+1 != tokens.size() ) 0227 return false; // if di is a file we need to be at the last token 0228 else 0229 return (dest[dest.length()-1] != '/'); // if the link destination ends with a slash 0230 // it can only point to a directory! 0231 } 0232 } 0233 0234 i++; 0235 } 0236 0237 return true; 0238 } 0239 else 0240 return true; 0241 } 0242 0243 0244 void K3b::FileItem::init( const QString& filePath, 0245 const QString& k3bName, 0246 DataDoc& doc, 0247 const k3b_struct_stat* stat, 0248 const k3b_struct_stat* followedStat ) 0249 { 0250 if( k3bName.isEmpty() ) 0251 m_k3bName = filePath.section( '/', -1 ); 0252 else 0253 m_k3bName = k3bName; 0254 0255 if( stat != 0 ) { 0256 m_size = (KIO::filesize_t)stat->st_size; 0257 if( S_ISLNK(stat->st_mode) ) 0258 setFlags( flags() | SYMLINK ); 0259 0260 // 0261 // integrate the device number into the inode since files on different 0262 // devices may have the same inode number! 0263 // 0264 m_id.inode = stat->st_ino; 0265 m_id.device = stat->st_dev; 0266 } 0267 else { 0268 m_size = QFileInfo(filePath).size(); 0269 m_id.inode = 0; 0270 m_id.device = 0; 0271 0272 // since we have no proper inode info, disable the inode caching in the doc 0273 K3b::IsoOptions o( doc.isoOptions() ); 0274 o.setDoNotCacheInodes( true ); 0275 doc.setIsoOptions( o ); 0276 } 0277 0278 if( isSymLink() ) { 0279 if( QFile::exists( K3b::resolveLink( filePath ) ) && followedStat != 0 ) { 0280 m_sizeFollowed = (KIO::filesize_t)followedStat->st_size; 0281 m_idFollowed.inode = followedStat->st_ino; 0282 m_idFollowed.device = followedStat->st_dev; 0283 } 0284 else if( followedStat == 0 ) { 0285 m_sizeFollowed = m_size; 0286 m_idFollowed.inode = 0; 0287 m_idFollowed.device = 0; 0288 } 0289 else { 0290 // This means the link is broken, so size of target equals 0 0291 m_sizeFollowed = 0; 0292 } 0293 } 0294 else { 0295 m_sizeFollowed = m_size; 0296 m_idFollowed = m_id; 0297 } 0298 0299 m_mimeType = QMimeDatabase().mimeTypeForFile( filePath ); 0300 0301 // add automagically like a qlistviewitem 0302 if( parent() ) 0303 parent()->addDataItem( this ); 0304 }