bool KTar::doWriteDir(const QString &name, const QString &user, const QString &group, mode_t perm, const QDateTime & /*atime*/, const QDateTime &mtime, const QDateTime & /*ctime*/) { if ( !isOpen() ) { //qWarning() << "You must open the tar file before writing to it\n"; return false; } if ( !(mode() & QIODevice::WriteOnly) ) { //qWarning() << "You must open the tar file for writing\n"; return false; } // In some tar files we can find dir/./ => call cleanPath QString dirName ( QDir::cleanPath( name ) ); // Need trailing '/' if ( !dirName.endsWith( QLatin1Char( '/' ) ) ) dirName += QLatin1Char( '/' ); if ( d->dirList.contains( dirName ) ) return true; // already there char buffer[ 0x201 ]; memset( buffer, 0, 0x200 ); if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite ) device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read // provide converted stuff we need lateron QByteArray encodedDirname = QFile::encodeName(dirName); QByteArray uname = user.toLocal8Bit(); QByteArray gname = group.toLocal8Bit(); // If more than 100 chars, we need to use the LongLink trick if ( dirName.length() > 99 ) d->writeLonglink(buffer,encodedDirname,'L',uname.constData(),gname.constData()); // Write (potentially truncated) name strncpy( buffer, encodedDirname.constData(), 99 ); buffer[99] = 0; // zero out the rest (except for what gets filled anyways) memset(buffer+0x9d, 0, 0x200 - 0x9d); QByteArray permstr = QByteArray::number( (unsigned int)perm, 8 ); permstr = permstr.rightJustified(6, ' '); d->fillBuffer( buffer, permstr.constData(), 0, mtime, 0x35, uname.constData(), gname.constData()); // Write header device()->write( buffer, 0x200 ); if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite ) d->tarEnd = device()->pos(); d->dirList.append( dirName ); // contains trailing slash return true; // TODO if wanted, better error control }
bool KTar::doWriteSymLink(const QString &name, const QString &target, const QString &user, const QString &group, mode_t perm, const QDateTime & /*atime*/, const QDateTime &mtime, const QDateTime & /*ctime*/) { if ( !isOpen() ) { //qWarning() << "You must open the tar file before writing to it\n"; return false; } if ( !(mode() & QIODevice::WriteOnly) ) { //qWarning() << "You must open the tar file for writing\n"; return false; } // In some tar files we can find dir/./file => call cleanPath QString fileName ( QDir::cleanPath( name ) ); char buffer[ 0x201 ]; memset( buffer, 0, 0x200 ); if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite ) device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read // provide converted stuff we need lateron QByteArray encodedFileName = QFile::encodeName(fileName); QByteArray encodedTarget = QFile::encodeName(target); QByteArray uname = user.toLocal8Bit(); QByteArray gname = group.toLocal8Bit(); // If more than 100 chars, we need to use the LongLink trick if (target.length() > 99) d->writeLonglink(buffer,encodedTarget,'K',uname.constData(),gname.constData()); if ( fileName.length() > 99 ) d->writeLonglink(buffer,encodedFileName,'L',uname.constData(),gname.constData()); // Write (potentially truncated) name strncpy( buffer, encodedFileName.constData(), 99 ); buffer[99] = 0; // Write (potentially truncated) symlink target strncpy(buffer+0x9d, encodedTarget.constData(), 99); buffer[0x9d+99] = 0; // zero out the rest memset(buffer+0x9d+100, 0, 0x200 - 100 - 0x9d); QByteArray permstr = QByteArray::number( (unsigned int)perm, 8 ); permstr = permstr.rightJustified(6, ' '); d->fillBuffer(buffer, permstr.constData(), 0, mtime, 0x32, uname.constData(), gname.constData()); // Write header bool retval = device()->write( buffer, 0x200 ) == 0x200; if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite ) d->tarEnd = device()->pos(); return retval; }
void tst_QByteArray::rightJustified() { QByteArray a; a="ABC"; QCOMPARE(a.rightJustified(5,'-'),QByteArray("--ABC")); QCOMPARE(a.rightJustified(4,'-'),QByteArray("-ABC")); QCOMPARE(a.rightJustified(4),QByteArray(" ABC")); QCOMPARE(a.rightJustified(3),QByteArray("ABC")); QCOMPARE(a.rightJustified(2),QByteArray("ABC")); QCOMPARE(a.rightJustified(1),QByteArray("ABC")); QCOMPARE(a.rightJustified(0),QByteArray("ABC")); QByteArray n; QVERIFY(!n.rightJustified(3).isNull()); // I expected true QCOMPARE(a.rightJustified(4,'-',true),QByteArray("-ABC")); QCOMPARE(a.rightJustified(4,' ',true),QByteArray(" ABC")); QCOMPARE(a.rightJustified(3,' ',true),QByteArray("ABC")); QCOMPARE(a.rightJustified(2,' ',true),QByteArray("AB")); QCOMPARE(a.rightJustified(1,' ',true),QByteArray("A")); QCOMPARE(a.rightJustified(0,' ',true),QByteArray("")); QCOMPARE(a,QByteArray("ABC")); }
bool KTar::doPrepareWriting(const QString &name, const QString &user, const QString &group, qint64 size, mode_t perm, const QDateTime & /*atime*/, const QDateTime &mtime, const QDateTime & /*ctime*/) { if ( !isOpen() ) { //qWarning() << "You must open the tar file before writing to it\n"; return false; } if ( !(mode() & QIODevice::WriteOnly) ) { //qWarning() << "You must open the tar file for writing\n"; return false; } // In some tar files we can find dir/./file => call cleanPath QString fileName ( QDir::cleanPath( name ) ); /* // Create toplevel dirs // Commented out by David since it's not necessary, and if anybody thinks it is, // he needs to implement a findOrCreate equivalent in writeDir. // But as KTar and the "tar" program both handle tar files without // dir entries, there's really no need for that QString tmp ( fileName ); int i = tmp.lastIndexOf( '/' ); if ( i != -1 ) { QString d = tmp.left( i + 1 ); // contains trailing slash if ( !m_dirList.contains( d ) ) { tmp = tmp.mid( i + 1 ); writeDir( d, user, group ); // WARNING : this one doesn't create its toplevel dirs } } */ char buffer[ 0x201 ]; memset( buffer, 0, 0x200 ); if ( ( mode() & QIODevice::ReadWrite ) == QIODevice::ReadWrite ) device()->seek(d->tarEnd); // Go to end of archive as might have moved with a read // provide converted stuff we need later on const QByteArray encodedFileName = QFile::encodeName(fileName); const QByteArray uname = user.toLocal8Bit(); const QByteArray gname = group.toLocal8Bit(); // If more than 100 chars, we need to use the LongLink trick if ( fileName.length() > 99 ) d->writeLonglink(buffer,encodedFileName,'L',uname.constData(),gname.constData()); // Write (potentially truncated) name strncpy( buffer, encodedFileName.constData(), 99 ); buffer[99] = 0; // zero out the rest (except for what gets filled anyways) memset(buffer+0x9d, 0, 0x200 - 0x9d); QByteArray permstr = QByteArray::number( (unsigned int)perm, 8 ); permstr = permstr.rightJustified(6, '0'); d->fillBuffer(buffer, permstr.constData(), size, mtime, 0x30, uname.constData(), gname.constData()); // Write header return device()->write( buffer, 0x200 ) == 0x200; }
void KTar::KTarPrivate::fillBuffer(char *buffer, const char *mode, qint64 size, const QDateTime &mtime, char typeflag, const char *uname, const char *gname) { // mode (as in stpos()) assert( strlen(mode) == 6 ); memcpy( buffer+0x64, mode, 6 ); buffer[ 0x6a ] = ' '; buffer[ 0x6b ] = '\0'; // dummy uid strcpy( buffer + 0x6c, " 765 "); // 501 in decimal // dummy gid strcpy( buffer + 0x74, " 144 "); // 100 in decimal // size QByteArray s = QByteArray::number( size, 8 ); // octal s = s.rightJustified( 11, '0' ); memcpy( buffer + 0x7c, s.data(), 11 ); buffer[ 0x87 ] = ' '; // space-terminate (no null after) // modification time const QDateTime modificationTime = mtime.isValid() ? mtime : QDateTime::currentDateTime(); s = QByteArray::number( static_cast<qulonglong>(modificationTime.toMSecsSinceEpoch() / 1000), 8 ); // octal s = s.rightJustified( 11, '0' ); memcpy( buffer + 0x88, s.data(), 11 ); buffer[ 0x93 ] = ' '; // space-terminate (no null after) -- well current tar writes a null byte // spaces, replaced by the check sum later buffer[ 0x94 ] = 0x20; buffer[ 0x95 ] = 0x20; buffer[ 0x96 ] = 0x20; buffer[ 0x97 ] = 0x20; buffer[ 0x98 ] = 0x20; buffer[ 0x99 ] = 0x20; /* From the tar sources : Fill in the checksum field. It's formatted differently from the other fields: it has [6] digits, a null, then a space -- rather than digits, a space, then a null. */ buffer[ 0x9a ] = '\0'; buffer[ 0x9b ] = ' '; // type flag (dir, file, link) buffer[ 0x9c ] = typeflag; // magic + version strcpy( buffer + 0x101, "ustar"); strcpy( buffer + 0x107, "00" ); // user strcpy( buffer + 0x109, uname ); // group strcpy( buffer + 0x129, gname ); // Header check sum int check = 32; for( uint j = 0; j < 0x200; ++j ) check += buffer[j]; s = QByteArray::number( check, 8 ); // octal s = s.rightJustified( 6, '0' ); memcpy( buffer + 0x94, s.constData(), 6 ); }