32 #include <QtCore/QMap>
33 #include <QtCore/QDir>
34 #include <QtCore/QFile>
44 #include <sys/types.h>
72 QIODevice::OpenMode mode;
82 : d(new KArchivePrivate)
84 Q_ASSERT( !fileName.isEmpty() );
91 : d(new KArchivePrivate)
106 Q_ASSERT( mode != QIODevice::NotOpen );
111 if ( !d->fileName.isEmpty() )
120 if ( !d->dev->isOpen() && !d->dev->open( mode ) )
125 Q_ASSERT( !d->rootDir );
134 case QIODevice::WriteOnly:
135 if ( !d->fileName.isEmpty() ) {
138 d->saveFile =
new KSaveFile( d->fileName );
139 if ( !d->saveFile->open() ) {
140 kWarning() <<
"KSaveFile creation for " << d->fileName <<
" failed, " << d->saveFile->errorString();
145 d->dev = d->saveFile;
149 case QIODevice::ReadOnly:
150 case QIODevice::ReadWrite:
152 if ( !d->fileName.isEmpty() ) {
153 d->dev =
new QFile( d->fileName );
154 d->deviceOwned =
true;
158 kWarning() <<
"Unsupported mode " << d->mode;
172 bool closeSucceeded =
true;
175 if ( d->mode == QIODevice::WriteOnly && !closeSucceeded )
184 closeSucceeded = d->saveFile->finalize();
187 }
if ( d->deviceOwned ) {
193 d->mode = QIODevice::NotOpen;
195 return closeSucceeded;
207 QFileInfo fileInfo( fileName );
208 if ( !fileInfo.isFile() && !fileInfo.isSymLink() )
210 kWarning() << fileName <<
"doesn't exist or is not a regular file.";
216 kWarning() <<
"stat'ing" << fileName
217 <<
"failed:" << strerror(errno);
221 if (fileInfo.isSymLink()) {
225 #if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
226 const QByteArray encodedFileName = QFile::encodeName(fileName);
228 #if defined(PATH_MAX)
229 s.resize(PATH_MAX+1);
231 int path_max = pathconf(encodedFileName.data(), _PC_PATH_MAX);
237 int len = readlink(encodedFileName.data(), s.data(), s.size() - 1);
240 symLinkTarget = QFile::decodeName(s);
243 if (symLinkTarget.isEmpty())
244 symLinkTarget = fileInfo.symLinkTarget();
245 return writeSymLink(destName, symLinkTarget, fileInfo.owner(),
246 fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime,
250 qint64 size = fileInfo.size();
255 QFile file( fileName );
256 if ( !file.open( QIODevice::ReadOnly ) )
262 if ( !
prepareWriting( destName, fileInfo.owner(), fileInfo.group(), size,
263 fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime ) )
265 kWarning() <<
" prepareWriting" << destName <<
"failed";
271 array.resize(
int( qMin(
qint64( 1024 * 1024 ), size ) ) );
274 while ( ( n = file.read( array.data(), array.size() ) ) > 0 )
283 Q_ASSERT( total == size );
287 kWarning() <<
"finishWriting failed";
298 dir.setFilter(dir.filter() | QDir::Hidden);
300 for ( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
302 if ( *it != QLatin1String(
".") && *it != QLatin1String(
"..") )
306 QString dest = destName.isEmpty() ? *it : (destName + QLatin1Char(
'/') + *it);
307 QFileInfo fileInfo( fileName );
309 if ( fileInfo.isFile() || fileInfo.isSymLink() )
311 else if ( fileInfo.isDir() )
321 mode_t perm, time_t atime, time_t mtime, time_t ctime )
323 if ( !
prepareWriting( name, user, group, size, perm, atime, mtime, ctime ) )
325 kWarning() <<
"prepareWriting failed";
331 if ( data && size && !
writeData( data, size ) )
339 kWarning() <<
"finishWriting failed";
347 bool ok =
device()->write( data, size ) == size;
360 mode_t perm, time_t atime,
361 time_t mtime, time_t ctime )
363 return doWriteDir( name, user, group, perm | 040000, atime, mtime, ctime );
368 mode_t perm, time_t atime,
369 time_t mtime, time_t ctime )
371 return doWriteSymLink( name, target, user, group, perm, atime, mtime, ctime );
377 mode_t perm, time_t atime,
378 time_t mtime, time_t ctime )
380 bool ok =
doPrepareWriting( name, user, group, size, perm, atime, mtime, ctime );
396 struct passwd* pw = getpwuid( getuid() );
397 struct group* grp = getgrgid( getgid() );
398 QString username = pw ? QFile::decodeName(pw->pw_name) : QString::number( getuid() );
399 QString groupname = grp ? QFile::decodeName(grp->gr_name) : QString::number( getgid() );
401 d->rootDir =
new KArchiveDirectory(
this, QLatin1String(
"/"), (
int)(0777 + S_IFDIR), 0, username, groupname,
QString() );
409 if ( path.isEmpty() || path == QLatin1String(
"/") || path == QLatin1String(
".") )
428 kWarning() <<
"Found" << path <<
"but it's not a directory";
432 int pos = path.lastIndexOf( QLatin1Char(
'/') );
442 QString left = path.left( pos );
443 dirname = path.mid( pos + 1 );
450 d->rootDir->date(), d->rootDir->user(),
451 d->rootDir->group(),
QString() );
458 if ( d->deviceOwned )
461 d->deviceOwned =
false;
466 Q_ASSERT( !d->rootDir );
482 return d->mode != QIODevice::NotOpen;
490 void KArchivePrivate::abortWriting()
504 class KArchiveEntryPrivate
507 KArchiveEntryPrivate(
KArchive* _archive,
const QString& _name,
int _access,
530 d(new KArchiveEntryPrivate(t,name,access,date,user,group,symlink))
542 datetimeobj.setTime_t( d->date );
595 class KArchiveFilePrivate
610 :
KArchiveEntry( t, name, access, date, user, group, symlink ),
611 d( new KArchiveFilePrivate(pos, size) )
639 kWarning() <<
"Failed to sync to" << d->pos <<
"to read" <<
name();
647 Q_ASSERT( arr.size() == d->size );
664 QFile f( dest + QLatin1Char(
'/') +
name() );
665 if ( f.open( QIODevice::ReadWrite | QIODevice::Truncate ) )
670 const qint64 chunkSize = 1024 * 1024;
671 qint64 remainingSize = d->size;
673 array.resize(
int( qMin( chunkSize, remainingSize ) ) );
675 while ( remainingSize > 0 ) {
676 const qint64 currentChunkSize = qMin( chunkSize, remainingSize );
677 const qint64 n = inputDev->read( array.data(), currentChunkSize );
678 Q_ASSERT( n == currentChunkSize );
679 f.write( array.data(), currentChunkSize );
680 remainingSize -= currentChunkSize;
692 class KArchiveDirectoryPrivate
695 ~KArchiveDirectoryPrivate()
706 :
KArchiveEntry( t, name, access, date, user, group, symlink ),
707 d( new KArchiveDirectoryPrivate )
718 return d->entries.keys();
724 int pos = name.indexOf( QLatin1Char(
'/') );
729 name = name.mid( 1 );
730 pos = name.indexOf( QLatin1Char(
'/') );
736 if ( pos != -1 && pos == name.length()-1 )
738 name = name.left( pos );
739 pos = name.indexOf( QLatin1Char(
'/') );
743 const QString left = name.left(pos);
744 const QString right = name.mid(pos + 1);
754 return d->entries.value( name );
759 if( entry->
name().isEmpty() )
762 if( d->entries.value( entry->
name() ) ) {
764 <<
"has entry" << entry->
name() <<
"already";
766 d->entries.insert( entry->
name(),
entry );
786 QStack<const KArchiveDirectory *> dirStack;
787 QStack<QString> dirNameStack;
789 dirStack.push(
this );
790 dirNameStack.push( dest );
793 const QString curDirName = dirNameStack.pop();
794 root.mkdir(curDirName);
797 for ( QStringList::const_iterator it = dirEntries.begin(); it != dirEntries.end(); ++it ) {
800 const QString linkName = curDirName+QLatin1Char(
'/')+curEntry->
name();
802 if (!::symlink(curEntry->
symLinkTarget().toLocal8Bit(), linkName.toLocal8Bit())) {
803 kDebug() <<
"symlink(" << curEntry->
symLinkTarget() <<
',' << linkName <<
") failed:" << strerror(errno);
809 if ( curEntry->
isFile() ) {
812 fileList.append( curFile );
813 fileToDir.insert( curFile->
position(), curDirName );
821 dirNameStack.push( curDirName + QLatin1Char(
'/') + curEntry->
name() );
826 }
while (!dirStack.isEmpty());
834 f->
copyTo( fileToDir[pos] );