Warning, file /system/kup/kioworker/vfshelpers.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // SPDX-FileCopyrightText: 2020 Simon Persson <simon.persson@mykolab.com>
0002 //
0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "vfshelpers.h"
0006 
0007 #include <QBuffer>
0008 #include <QByteArray>
0009 #include <QDateTime>
0010 
0011 #include <unistd.h>
0012 #include <sys/stat.h>
0013 
0014 static const int cRecordEnd = 0;
0015 //static const int cRecordPath = 1;
0016 static const int cRecordCommonV1 = 2; // times, user, group, type, perms, etc. (legacy version 1)
0017 static const int cRecordSymlinkTarget = 3;
0018 //static const int cRecordPosix1eAcl = 4; // getfacl(1), setfacl(1), etc.
0019 //static const int cRecordNfsV4Acl = 5; // intended to supplant posix1e acls?
0020 //static const int cRecordLinuxAttr = 6; // lsattr(1) chattr(1)
0021 //static const int cRecordLinuxXattr = 7; // getfattr(1) setfattr(1)
0022 //static const int cRecordHardlinkTarget = 8;
0023 static const int cRecordCommonV2 = 9; // times, user, group, type, perms, etc.
0024 static const int cRecordCommonV3 = 10; // times, user, group, type, perms, etc.
0025 
0026 VintStream::VintStream(const void *pData, int pSize, QObject *pParent)
0027     : QObject(pParent),
0028       mByteArray(QByteArray::fromRawData(static_cast<const char *>(pData), pSize)),
0029       mBuffer(new QBuffer(&mByteArray, this))
0030 {
0031     mBuffer->open(QIODevice::ReadOnly);
0032 }
0033 
0034 VintStream &VintStream::operator>>(qint64 &pInt) {
0035     char c;
0036     if(!mBuffer->getChar(&c)) {
0037         throw 1;
0038     }
0039     int lOffset = 6;
0040     bool lNegative = (c & 0x40);
0041     pInt = c & 0x3F;
0042     while(c & 0x80) {
0043         if(!mBuffer->getChar(&c)) {
0044             throw 1;
0045         }
0046         pInt |= (c & 0x7F) << lOffset;
0047         lOffset += 7;
0048     }
0049     if(lNegative) {
0050         pInt = -pInt;
0051     }
0052     return *this;
0053 }
0054 
0055 VintStream &VintStream::operator >>(quint64 &pUint) {
0056     char c;
0057     int lOffset = 0;
0058     pUint = 0;
0059     do {
0060         if(!mBuffer->getChar(&c)) {
0061             throw 1;
0062         }
0063         pUint |= static_cast<quint64>((c & 0x7F) << lOffset);
0064         lOffset += 7;
0065     } while(c & 0x80);
0066     return *this;
0067 }
0068 
0069 VintStream &VintStream::operator >>(QString &pString) {
0070     QByteArray lBytes;
0071     *this >> lBytes;
0072     pString = QString::fromUtf8(lBytes);
0073     return *this;
0074 }
0075 
0076 VintStream &VintStream::operator >>(QByteArray &pByteArray) {
0077     quint64 lByteCount;
0078     *this >> lByteCount;
0079     pByteArray.resize(static_cast<int>(lByteCount));
0080     if(mBuffer->read(pByteArray.data(), pByteArray.length()) < pByteArray.length()) {
0081         throw 1;
0082     }
0083     return *this;
0084 }
0085 
0086 qint64 Metadata::mDefaultUid;
0087 qint64 Metadata::mDefaultGid;
0088 bool Metadata::mDefaultsResolved = false;
0089 
0090 Metadata::Metadata(qint64 pMode) {
0091     mMode = pMode;
0092     mAtime = 0;
0093     mMtime = 0;
0094     if(!mDefaultsResolved) {
0095         mDefaultUid = getuid();
0096         mDefaultGid = getgid();
0097         mDefaultsResolved = true;
0098     }
0099     mUid = mDefaultUid;
0100     mGid = mDefaultGid;
0101     mSize = -1;
0102 }
0103 
0104 int readMetadata(VintStream &pMetadataStream, Metadata &pMetadata) {
0105     try {
0106         quint64 lTag;
0107         do {
0108             pMetadataStream >> lTag;
0109             switch(lTag) {
0110             case cRecordCommonV1: {
0111                 qint64 lNotUsedInt;
0112                 quint64 lNotUsedUint, lTempUint;
0113                 QString lNotUsedString;
0114                 pMetadataStream >> lNotUsedUint >> lTempUint;
0115                 pMetadata.mMode = static_cast<qint64>(lTempUint);
0116                 pMetadataStream >> lTempUint >> lNotUsedString; // user name
0117                 pMetadata.mUid = static_cast<qint64>(lTempUint);
0118                 pMetadataStream >> lTempUint >> lNotUsedString; // group name
0119                 pMetadata.mGid = static_cast<qint64>(lTempUint);
0120                 pMetadataStream >> lNotUsedUint; // device number
0121                 pMetadataStream >> pMetadata.mAtime >> lNotUsedUint; //nanoseconds
0122                 pMetadataStream >> pMetadata.mMtime >> lNotUsedUint; // nanoseconds
0123                 pMetadataStream >> lNotUsedInt >> lNotUsedUint; // status change time
0124                 break;
0125             }
0126             case cRecordCommonV2: {
0127                 qint64 lNotUsedInt;
0128                 quint64 lNotUsedUint;
0129                 QString lNotUsedString;
0130                 pMetadataStream >> lNotUsedUint >> pMetadata.mMode;
0131                 pMetadataStream >> pMetadata.mUid >> lNotUsedString; // user name
0132                 pMetadataStream >> pMetadata.mGid >> lNotUsedString; // group name
0133                 pMetadataStream >> lNotUsedInt; // device number
0134                 pMetadataStream >> pMetadata.mAtime >> lNotUsedUint; //nanoseconds
0135                 pMetadataStream >> pMetadata.mMtime >> lNotUsedUint; // nanoseconds
0136                 pMetadataStream >> lNotUsedInt >> lNotUsedUint; // status change time
0137                 break;
0138             }
0139             case cRecordCommonV3: {
0140                 qint64 lNotUsedInt;
0141                 quint64 lNotUsedUint;
0142                 QString lNotUsedString;
0143                 pMetadataStream >> lNotUsedUint >> pMetadata.mMode;
0144                 pMetadataStream >> pMetadata.mUid >> lNotUsedString; // user name
0145                 pMetadataStream >> pMetadata.mGid >> lNotUsedString; // group name
0146                 pMetadataStream >> lNotUsedInt; // device number
0147                 pMetadataStream >> pMetadata.mAtime >> lNotUsedUint; //nanoseconds
0148                 pMetadataStream >> pMetadata.mMtime >> lNotUsedUint; // nanoseconds
0149                 pMetadataStream >> lNotUsedInt >> lNotUsedUint; // status change time
0150                 pMetadataStream >> pMetadata.mSize;
0151                 break;
0152             }
0153             case cRecordSymlinkTarget: {
0154                 pMetadataStream >> pMetadata.mSymlinkTarget;
0155                 break;
0156             }
0157             default: {
0158                 if(lTag != cRecordEnd) {
0159                     QByteArray lNotUsed;
0160                     pMetadataStream >> lNotUsed;
0161                 }
0162                 break;
0163             }
0164             }
0165         } while(lTag != cRecordEnd);
0166     } catch(int) {
0167         return 1;
0168     }
0169     return 0; // success
0170 }
0171 
0172 quint64 calculateChunkFileSize(const git_oid *pOid, git_repository *pRepository) {
0173     quint64 lLastChunkOffset = 0;
0174     quint64 lLastChunkSize = 0;
0175     uint lMode;
0176     do {
0177         git_tree *lTree;
0178         if(0 != git_tree_lookup(&lTree, pRepository, pOid)) {
0179             return 0;
0180         }
0181         ulong lEntryCount = git_tree_entrycount(lTree);
0182         const git_tree_entry *lEntry = git_tree_entry_byindex(lTree, lEntryCount - 1);
0183         quint64 lEntryOffset;
0184         if(!offsetFromName(lEntry, lEntryOffset)) {
0185             git_tree_free(lTree);
0186             return 0;
0187         }
0188         lLastChunkOffset += lEntryOffset;
0189         pOid = git_tree_entry_id(lEntry);
0190         lMode = git_tree_entry_filemode(lEntry);
0191         git_tree_free(lTree);
0192     } while(S_ISDIR(lMode));
0193 
0194     git_blob *lBlob;
0195     if(0 != git_blob_lookup(&lBlob, pRepository, pOid)) {
0196         return 0;
0197     }
0198     lLastChunkSize = static_cast<quint64>(git_blob_rawsize(lBlob));
0199     git_blob_free(lBlob);
0200     return lLastChunkOffset + lLastChunkSize;
0201 }
0202 
0203 bool offsetFromName(const git_tree_entry *pEntry, quint64 &pUint) {
0204     bool lParsedOk;
0205     pUint = QString::fromUtf8(git_tree_entry_name(pEntry)).toULongLong(&lParsedOk, 16);
0206     return lParsedOk;
0207 }
0208 
0209 
0210 void getEntryAttributes(const git_tree_entry *pTreeEntry, uint &pMode, bool &pChunked, const git_oid *&pOid, QString &pName) {
0211     pMode = git_tree_entry_filemode(pTreeEntry);
0212     pOid = git_tree_entry_id(pTreeEntry);
0213     pName = QString::fromUtf8(git_tree_entry_name(pTreeEntry));
0214     pChunked = false;
0215     if(pName.endsWith(QStringLiteral(".bupl"))) {
0216         pName.chop(5);
0217     } else if(pName.endsWith(QStringLiteral(".bup"))) {
0218         pName.chop(4);
0219         pMode = DEFAULT_MODE_FILE;
0220         pChunked = true;
0221     }
0222 }
0223 
0224 
0225 QString vfsTimeToString(git_time_t pTime) {
0226     QDateTime lDateTime;
0227     lDateTime.setSecsSinceEpoch(pTime);
0228     return lDateTime.toLocalTime().toString(QStringLiteral("yyyy-MM-dd hh:mm"));
0229 }