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 }