bool countFiles( const QStringList& l, const QString& dir ) { for( QStringList::const_iterator it = l.begin(); it != l.end(); ++it ) { if( m_canceled ) return false; k3b_struct_stat s; if( k3b_lstat( QFile::encodeName( dir + *it ), &s ) ) return false; if( S_ISLNK( s.st_mode ) ) { ++totalSymlinks; if( followSymlinks ) { if( k3b_stat( QFile::encodeName( dir + *it ), &s ) ) return false; } } if( S_ISDIR( s.st_mode ) ) { ++totalDirs; if( !countDir( dir + *it + '/' ) ) return false; } else if( !S_ISLNK( s.st_mode ) ) { ++totalFiles; totalSize += (KIO::filesize_t)s.st_size; } } return true; }
QString K3bIsoImager::dummyDir( K3bDirItem* dir ) { // // since we use virtual folders in order to have folders with different weight factors and different // permissions we create different dummy dirs to be passed to mkisofs // QDir _appDir( locateLocal( "appdata", "temp/" ) ); // // create a unique isoimager session id // This might become important in case we will allow multiple instances of the isoimager // to run at the same time. // QString jobId = qApp->sessionId() + "_" + QString::number( m_sessionNumber ); if( !_appDir.cd( jobId ) ) { _appDir.mkdir( jobId ); _appDir.cd( jobId ); } QString name( "dummydir_" ); name += QString::number( dir->sortWeight() ); bool perm = false; k3b_struct_stat statBuf; if( !dir->localPath().isEmpty() ) { // permissions if( k3b_stat( QFile::encodeName(dir->localPath()), &statBuf ) == 0 ) { name += "_"; name += QString::number( statBuf.st_uid ); name += "_"; name += QString::number( statBuf.st_gid ); name += "_"; name += QString::number( statBuf.st_mode ); name += "_"; name += QString::number( statBuf.st_mtime ); perm = true; } } if( !_appDir.cd( name ) ) { kdDebug() << "(K3bIsoImager) creating dummy dir: " << _appDir.absPath() << "/" << name << endl; _appDir.mkdir( name ); _appDir.cd( name ); if( perm ) { ::chmod( QFile::encodeName( _appDir.absPath() ), statBuf.st_mode ); ::chown( QFile::encodeName( _appDir.absPath() ), statBuf.st_uid, statBuf.st_gid ); struct utimbuf tb; tb.actime = tb.modtime = statBuf.st_mtime; ::utime( QFile::encodeName( _appDir.absPath() ), &tb ); } } return _appDir.absPath() + "/"; }
void K3bDataUrlAddingDialog::slotAddUrls() { if( m_bCanceled ) return; // add next url KURL url = m_urlQueue.first().first; K3bDirItem* dir = m_urlQueue.first().second; m_urlQueue.remove( m_urlQueue.begin() ); // // HINT: // we only use QFileInfo::absFilePath() and QFileInfo::isHidden() // both do not cause QFileInfo to stat, thus no speed improvement // can come from removing QFileInfo usage here. // QFileInfo info(url.path()); QString absFilePath( info.absFilePath() ); QString resolved( absFilePath ); bool valid = true; k3b_struct_stat statBuf, resolvedStatBuf; bool isSymLink = false; bool isDir = false; bool isFile = false; ++m_filesHandled; #if 0 m_infoLabel->setText( url.path() ); if( m_totalFiles == 0 ) m_counterLabel->setText( QString("(%1)").arg(m_filesHandled) ); else m_counterLabel->setText( QString("(%1/%2)").arg(m_filesHandled).arg(m_totalFiles) ); #endif // // 1. Check if we want and can add the url // if( !url.isLocalFile() ) { valid = false; m_nonLocalFiles.append( url.path() ); } else if( k3b_lstat( QFile::encodeName(absFilePath), &statBuf ) != 0 ) { valid = false; m_notFoundFiles.append( url.path() ); } else if( !m_encodingConverter->encodedLocally( QFile::encodeName( url.path() ) ) ) { valid = false; m_invalidFilenameEncodingFiles.append( url.path() ); } else { isSymLink = S_ISLNK(statBuf.st_mode); isFile = S_ISREG(statBuf.st_mode); isDir = S_ISDIR(statBuf.st_mode); // symlinks are always readable and can always be added to a project // but we need to know if the symlink points to a directory if( isSymLink ) { resolved = K3b::resolveLink( absFilePath ); k3b_stat( QFile::encodeName(resolved), &resolvedStatBuf ); isDir = S_ISDIR(resolvedStatBuf.st_mode); } else { if( ::access( QFile::encodeName( absFilePath ), R_OK ) != 0 ) { valid = false; m_unreadableFiles.append( url.path() ); } else if( isFile && (unsigned long long)statBuf.st_size >= 0xFFFFFFFFULL ) { if ( !k3bcore->externalBinManager()->binObject( "mkisofs" )->hasFeature( "no-4gb-limit" ) ) { valid = false; m_tooBigFiles.append( url.path() ); } } } // FIXME: if we do not add hidden dirs the progress gets messed up! // // check for hidden and system files // if( valid ) { if( info.isHidden() && !addHiddenFiles() ) valid = false; if( S_ISCHR(statBuf.st_mode) || S_ISBLK(statBuf.st_mode) || S_ISFIFO(statBuf.st_mode) || S_ISSOCK(statBuf.st_mode) ) if( !addSystemFiles() ) valid = false; if( isSymLink ) if( S_ISCHR(resolvedStatBuf.st_mode) || S_ISBLK(resolvedStatBuf.st_mode) || S_ISFIFO(resolvedStatBuf.st_mode) || S_ISSOCK(resolvedStatBuf.st_mode) ) if( !addSystemFiles() ) valid = false; } } // // 2. Handle the url // QString newName = url.fileName(); // filenames cannot end in backslashes (mkisofs problem. See comments in k3bisoimager.cpp (escapeGraftPoint())) bool bsAtEnd = false; while( newName[newName.length()-1] == '\\' ) { newName.truncate( newName.length()-1 ); bsAtEnd = true; } if( bsAtEnd ) m_mkisofsLimitationRenamedFiles.append( url.path() + " -> " + newName ); // backup dummy name if( newName.isEmpty() ) newName = "1"; K3bDirItem* newDirItem = 0; // // The source is valid. Now check if the project already contains a file with that name // and if so handle it properly // if( valid ) { if( K3bDataItem* oldItem = dir->find( newName ) ) { // // reuse an existing dir // if( oldItem->isDir() && isDir ) newDirItem = dynamic_cast<K3bDirItem*>(oldItem); // // we cannot replace files in the old session with dirs and vice versa (I think) // files are handled in K3bFileItem constructor and dirs handled above // else if( oldItem->isFromOldSession() && isDir != oldItem->isDir() ) { if( !getNewName( newName, dir, newName ) ) valid = false; } else if( m_bExistingItemsIgnoreAll ) valid = false; else if( oldItem->localPath() == resolved ) { // // Just ignore if the same file is added again // valid = false; } else if( m_bExistingItemsReplaceAll ) { // if we replace an item from an old session the K3bFileItem constructor takes care // of replacing the item if( !oldItem->isFromOldSession() ) delete oldItem; } // // Let the user choose // else { switch( K3bMultiChoiceDialog::choose( i18n("File already exists"), i18n("<p>File <em>%1</em> already exists in " "project folder <em>%2</em>.") .arg(newName) .arg('/' + dir->k3bPath()), QMessageBox::Warning, this, 0, 6, KGuiItem( i18n("Replace"), QString::null, i18n("Replace the existing file") ), KGuiItem( i18n("Replace All"), QString::null, i18n("Always replace existing files") ), KGuiItem( i18n("Ignore"), QString::null, i18n("Keep the existing file") ), KGuiItem( i18n("Ignore All"), QString::null, i18n("Always keep the existing file") ), KGuiItem( i18n("Rename"), QString::null, i18n("Rename the new file") ), KStdGuiItem::cancel() ) ) { case 2: // replace all m_bExistingItemsReplaceAll = true; // fallthrough case 1: // replace // if we replace an item from an old session the K3bFileItem constructor takes care // of replacing the item if( !oldItem->isFromOldSession() ) delete oldItem; break; case 4: // ignore all m_bExistingItemsIgnoreAll = true; // fallthrough case 3: // ignore valid = false; break; case 5: // rename if( !getNewName( newName, dir, newName ) ) valid = false; break; case 6: // cancel slotCancel(); return; } } } } // // One more thing to warn the user about: We cannot follow links to folders since that // would change the doc. So we simply ask the user what to do with a link to a folder // if( valid ) { // let's see if this link starts a loop // that means if it points to some folder above this one // if so we cannot follow it anyway if( isDir && isSymLink && !absFilePath.startsWith( resolved ) ) { bool followLink = dir->doc()->isoOptions().followSymbolicLinks() || m_bFolderLinksFollowAll; if( !followLink && !m_bFolderLinksAddAll ) { switch( K3bMultiChoiceDialog::choose( i18n("Adding link to folder"), i18n("<p>'%1' is a symbolic link to folder '%2'." "<p>If you intend to make K3b follow symbolic links you should consider letting K3b do this now " "since K3b will not be able to do so afterwards because symbolic links to folders inside a " "K3b project cannot be resolved." "<p><b>If you do not intend to enable the option <em>follow symbolic links</em> you may safely " "ignore this warning and choose to add the link to the project.</b>") .arg(absFilePath) .arg(resolved ), QMessageBox::Warning, this, 0, 5, i18n("Follow link now"), i18n("Always follow links"), i18n("Add link to project"), i18n("Always add links"), KStdGuiItem::cancel() ) ) { case 2: m_bFolderLinksFollowAll = true; case 1: followLink = true; break; case 4: m_bFolderLinksAddAll = true; case 3: followLink = false; break; case 5: slotCancel(); return; } } if( followLink ) { absFilePath = resolved; isSymLink = false; // count the files in the followed dir if( m_dirSizeJob->active() ) m_dirSizeQueue.append( KURL::fromPathOrURL(absFilePath) ); else { m_progressWidget->setTotalSteps( 0 ); m_dirSizeJob->setUrls( KURL::fromPathOrURL(absFilePath) ); m_dirSizeJob->start(); } } } } // // Project valid also (we overwrite or renamed) // now create the new item // if( valid ) { // // Set the volume id from the first added url // only if the doc was not changed yet // if( m_urls.count() == 1 && !dir->doc()->isModified() && !dir->doc()->isSaved() ) { dir->doc()->setVolumeID( K3b::removeFilenameExtension( newName ) ); } if( isDir && !isSymLink ) { if( !newDirItem ) { // maybe we reuse an already existing dir newDirItem = new K3bDirItem( newName , dir->doc(), dir ); newDirItem->setLocalPath( url.path() ); // HACK: see k3bdiritem.h } QDir newDir( absFilePath ); int dirFilter = QDir::All|QDir::Hidden|QDir::System; QStringList dlist = newDir.entryList( dirFilter ); const QString& dot = KGlobal::staticQString( "." ); const QString& dotdot = KGlobal::staticQString( ".." ); dlist.remove( dot ); dlist.remove( dotdot ); for( QStringList::Iterator it = dlist.begin(); it != dlist.end(); ++it ) { m_urlQueue.append( qMakePair( KURL::fromPathOrURL(absFilePath + '/' + *it), newDirItem ) ); } } else { (void)new K3bFileItem( &statBuf, &resolvedStatBuf, url.path(), dir->doc(), dir, newName ); } } if( m_urlQueue.isEmpty() ) { m_dirSizeJob->cancel(); m_progressWidget->setProgress( 100 ); accept(); } else { updateProgress(); QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); } }
bool K3b::Iso9660::open() { if( d->isOpen ) return true; if( !d->backend ) { // create a backend if( !m_filename.isEmpty() ) d->backend = new K3b::Iso9660FileBackend( m_filename ); else if( d->fd > 0 ) d->backend = new K3b::Iso9660FileBackend( d->fd ); else if( d->cdDevice ) { // now check if we have a scrambled video dvd if( d->cdDevice->copyrightProtectionSystemType() == K3b::Device::COPYRIGHT_PROTECTION_CSS ) { qDebug() << "(K3b::Iso9660) found encrypted dvd. using libdvdcss."; // open the libdvdcss stuff d->backend = new K3b::Iso9660LibDvdCssBackend( d->cdDevice ); if( !d->backend->open() ) { // fallback to devicebackend delete d->backend; d->backend = new K3b::Iso9660DeviceBackend( d->cdDevice ); } } else d->backend = new K3b::Iso9660DeviceBackend( d->cdDevice ); } else return false; } d->isOpen = d->backend->open(); if( !d->isOpen ) return false; iso_vol_desc *desc; QString path,tmp,uid,gid; k3b_struct_stat buf; int access,c_i,c_j; struct el_torito_boot_descriptor* bootdesc; // TODO implement win32 support /* We'll use the permission and user/group of the 'host' file except * in Rock Ridge, where the permissions are stored on the file system */ if ( k3b_stat( QFile::encodeName(m_filename), &buf ) < 0 ) { /* defaults, if stat fails */ memset(&buf,0,sizeof(k3b_struct_stat)); buf.st_mode=0777; } uid.setNum(buf.st_uid); gid.setNum(buf.st_gid); access = buf.st_mode & ~S_IFMT; int c_b=1; c_i=1;c_j=1; desc = ReadISO9660( &K3b::Iso9660::read_callback, d->startSector, this ); if (!desc) { qDebug() << "K3b::Iso9660::openArchive no volume descriptors"; close(); return false; } while (desc) { m_rr = false; switch (isonum_711(desc->data.type)) { case ISO_VD_BOOT: bootdesc=(struct el_torito_boot_descriptor*) &(desc->data); if( !memcmp( EL_TORITO_ID, bootdesc->system_id, ISODCL(8,39) ) ) { path="El Torito Boot"; if( c_b > 1 ) path += " (" + QString::number(c_b) + ')'; dirent = new K3b::Iso9660Directory( this, path, path, access | S_IFDIR, buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString() ); d->elToritoDirs.append( dirent ); addBoot(bootdesc); c_b++; } break; case ISO_VD_PRIMARY: createSimplePrimaryDesc( (struct iso_primary_descriptor*)&desc->data ); // fall through case ISO_VD_SUPPLEMENTARY: { struct iso_primary_descriptor* primaryDesc = (struct iso_primary_descriptor*)&desc->data; struct iso_directory_record* idr = (struct iso_directory_record*)&primaryDesc->root_directory_record; m_joliet = JolietLevel(&desc->data); // skip joliet in plain iso mode if( m_joliet && plainIso9660() ) break; if (m_joliet) { path = "Joliet level " + QString::number(m_joliet); if( c_j > 1 ) path += " (" + QString::number(c_j) + ')'; } else { path = QString::fromLocal8Bit( primaryDesc->volume_id, 32 ); if( c_i > 1 ) path += " (" + QString::number(c_i) + ')'; } dirent = new K3b::Iso9660Directory( this, path, path, access | S_IFDIR, buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString() ); // expand the root entry ProcessDir( &K3b::Iso9660::read_callback, isonum_733(idr->extent),isonum_733(idr->size),&K3b::Iso9660::isofs_callback,this); if (m_joliet) c_j++; else c_i++; if( m_joliet ) d->jolietDirs.append( dirent ); else { if( m_rr ) d->rrDirs.append( dirent ); d->isoDirs.append( dirent ); } break; } } desc = desc->next; } FreeISO9660(desc); return true; }