File indexing completed on 2025-01-26 04:24:54
0001 /* 0002 Copyright (C) 2005-2014 Sergey A. Tachenov 0003 0004 This file is part of QuaZIP. 0005 0006 QuaZIP is free software: you can redistribute it and/or modify 0007 it under the terms of the GNU Lesser General Public License as published by 0008 the Free Software Foundation, either version 2.1 of the License, or 0009 (at your option) any later version. 0010 0011 QuaZIP is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU Lesser General Public License for more details. 0015 0016 You should have received a copy of the GNU Lesser General Public License 0017 along with QuaZIP. If not, see <http://www.gnu.org/licenses/>. 0018 0019 See COPYING file for the full LGPL text. 0020 0021 Original ZIP package is copyrighted by Gilles Vollant and contributors, 0022 see quazip/(un)zip.h files for details. Basically it's the zlib license. 0023 */ 0024 0025 #include <QFileInfo> 0026 0027 #include "quazipnewinfo.h" 0028 0029 #include <string.h> 0030 0031 static void QuaZipNewInfo_setPermissions(QuaZipNewInfo *info, 0032 QFile::Permissions perm, bool isDir, bool isSymLink = false) 0033 { 0034 quint32 uPerm = isDir ? 0040000 : 0100000; 0035 0036 if ( isSymLink ) { 0037 #ifdef Q_OS_WIN 0038 uPerm = 0200000; 0039 #else 0040 uPerm = 0120000; 0041 #endif 0042 } 0043 0044 if ((perm & QFile::ReadOwner) != 0) 0045 uPerm |= 0400; 0046 if ((perm & QFile::WriteOwner) != 0) 0047 uPerm |= 0200; 0048 if ((perm & QFile::ExeOwner) != 0) 0049 uPerm |= 0100; 0050 if ((perm & QFile::ReadGroup) != 0) 0051 uPerm |= 0040; 0052 if ((perm & QFile::WriteGroup) != 0) 0053 uPerm |= 0020; 0054 if ((perm & QFile::ExeGroup) != 0) 0055 uPerm |= 0010; 0056 if ((perm & QFile::ReadOther) != 0) 0057 uPerm |= 0004; 0058 if ((perm & QFile::WriteOther) != 0) 0059 uPerm |= 0002; 0060 if ((perm & QFile::ExeOther) != 0) 0061 uPerm |= 0001; 0062 info->externalAttr = (info->externalAttr & ~0xFFFF0000u) | (uPerm << 16); 0063 } 0064 0065 template<typename FileInfo> 0066 void QuaZipNewInfo_init(QuaZipNewInfo &self, const FileInfo &existing) 0067 { 0068 self.name = existing.name; 0069 self.dateTime = existing.dateTime; 0070 self.internalAttr = existing.internalAttr; 0071 self.externalAttr = existing.externalAttr; 0072 self.comment = existing.comment; 0073 self.extraLocal = existing.extra; 0074 self.extraGlobal = existing.extra; 0075 self.uncompressedSize = existing.uncompressedSize; 0076 } 0077 0078 QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo &existing) 0079 { 0080 QuaZipNewInfo_init(*this, existing); 0081 } 0082 0083 QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo64 &existing) 0084 { 0085 QuaZipNewInfo_init(*this, existing); 0086 } 0087 0088 QuaZipNewInfo::QuaZipNewInfo(const QString& name): 0089 name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0), 0090 uncompressedSize(0) 0091 { 0092 } 0093 0094 QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): 0095 name(name), internalAttr(0), externalAttr(0), uncompressedSize(0) 0096 { 0097 QFileInfo info(file); 0098 QDateTime lm = info.lastModified(); 0099 if (!info.exists()) { 0100 dateTime = QDateTime::currentDateTime(); 0101 } else { 0102 dateTime = lm; 0103 QuaZipNewInfo_setPermissions(this, info.permissions(), info.isDir(), info.isSymLink()); 0104 } 0105 } 0106 0107 void QuaZipNewInfo::setFileDateTime(const QString& file) 0108 { 0109 QFileInfo info(file); 0110 QDateTime lm = info.lastModified(); 0111 if (info.exists()) 0112 dateTime = lm; 0113 } 0114 0115 void QuaZipNewInfo::setFilePermissions(const QString &file) 0116 { 0117 QFileInfo info = QFileInfo(file); 0118 QFile::Permissions perm = info.permissions(); 0119 QuaZipNewInfo_setPermissions(this, perm, info.isDir(), info.isSymLink()); 0120 } 0121 0122 void QuaZipNewInfo::setPermissions(QFile::Permissions permissions) 0123 { 0124 QuaZipNewInfo_setPermissions(this, permissions, name.endsWith('/')); 0125 } 0126 0127 void QuaZipNewInfo::setFileNTFSTimes(const QString &fileName) 0128 { 0129 QFileInfo fi(fileName); 0130 if (!fi.exists()) { 0131 qWarning("QuaZipNewInfo::setFileNTFSTimes(): '%s' doesn't exist", 0132 fileName.toUtf8().constData()); 0133 return; 0134 } 0135 setFileNTFSmTime(fi.lastModified()); 0136 setFileNTFSaTime(fi.lastRead()); 0137 setFileNTFScTime(fi.created()); 0138 } 0139 0140 static void setNTFSTime(QByteArray &extra, const QDateTime &time, int position, 0141 int fineTicks) { 0142 int ntfsPos = -1, timesPos = -1; 0143 unsigned ntfsLength = 0, ntfsTimesLength = 0; 0144 for (int i = 0; i <= extra.size() - 4; ) { 0145 unsigned type = static_cast<unsigned>(static_cast<unsigned char>( 0146 extra.at(i))) 0147 | (static_cast<unsigned>(static_cast<unsigned char>( 0148 extra.at(i + 1))) << 8); 0149 i += 2; 0150 unsigned length = static_cast<unsigned>(static_cast<unsigned char>( 0151 extra.at(i))) 0152 | (static_cast<unsigned>(static_cast<unsigned char>( 0153 extra.at(i + 1))) << 8); 0154 i += 2; 0155 if (type == QUAZIP_EXTRA_NTFS_MAGIC) { 0156 ntfsPos = i - 4; // the beginning of the NTFS record 0157 ntfsLength = length; 0158 if (length <= 4) { 0159 break; // no times in the NTFS record 0160 } 0161 i += 4; // reserved 0162 while (i <= extra.size() - 4) { 0163 unsigned tag = static_cast<unsigned>( 0164 static_cast<unsigned char>(extra.at(i))) 0165 | (static_cast<unsigned>( 0166 static_cast<unsigned char>(extra.at(i + 1))) 0167 << 8); 0168 i += 2; 0169 unsigned tagsize = static_cast<unsigned>( 0170 static_cast<unsigned char>(extra.at(i))) 0171 | (static_cast<unsigned>( 0172 static_cast<unsigned char>(extra.at(i + 1))) 0173 << 8); 0174 i += 2; 0175 if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC) { 0176 timesPos = i - 4; // the beginning of the NTFS times tag 0177 ntfsTimesLength = tagsize; 0178 break; 0179 } else { 0180 i += tagsize; 0181 } 0182 } 0183 break; // I ain't going to search for yet another NTFS record! 0184 } else { 0185 i += length; 0186 } 0187 } 0188 if (ntfsPos == -1) { 0189 // No NTFS record, need to create one. 0190 ntfsPos = extra.size(); 0191 ntfsLength = 32; 0192 extra.resize(extra.size() + 4 + ntfsLength); 0193 // the NTFS record header 0194 extra[ntfsPos] = static_cast<char>(QUAZIP_EXTRA_NTFS_MAGIC); 0195 extra[ntfsPos + 1] = static_cast<char>(QUAZIP_EXTRA_NTFS_MAGIC >> 8); 0196 extra[ntfsPos + 2] = 32; // the 2-byte size in LittleEndian 0197 extra[ntfsPos + 3] = 0; 0198 // zero the record 0199 memset(extra.data() + ntfsPos + 4, 0, 32); 0200 timesPos = ntfsPos + 8; 0201 // now set the tag data 0202 extra[timesPos] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC); 0203 extra[timesPos + 1] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC 0204 >> 8); 0205 // the size: 0206 extra[timesPos + 2] = 24; 0207 extra[timesPos + 3] = 0; 0208 ntfsTimesLength = 24; 0209 } 0210 if (timesPos == -1) { 0211 // No time tag in the NTFS record, need to add one. 0212 timesPos = ntfsPos + 4 + ntfsLength; 0213 extra.resize(extra.size() + 28); 0214 // Now we need to move the rest of the field 0215 // (possibly zero bytes, but memmove() is OK with that). 0216 // 0 ......... ntfsPos .. ntfsPos + 4 ... timesPos 0217 // <some data> <header> <NTFS record> <need-to-move data> <end> 0218 memmove(extra.data() + timesPos + 28, extra.data() + timesPos, 0219 extra.size() - 28 - timesPos); 0220 ntfsLength += 28; 0221 // now set the tag data 0222 extra[timesPos] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC); 0223 extra[timesPos + 1] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC 0224 >> 8); 0225 // the size: 0226 extra[timesPos + 2] = 24; 0227 extra[timesPos + 3] = 0; 0228 // zero the record 0229 memset(extra.data() + timesPos + 4, 0, 24); 0230 ntfsTimesLength = 24; 0231 } 0232 if (ntfsTimesLength < 24) { 0233 // Broken times field. OK, this is really unlikely, but just in case... 0234 size_t timesEnd = timesPos + 4 + ntfsTimesLength; 0235 extra.resize(extra.size() + (24 - ntfsTimesLength)); 0236 // Move it! 0237 // 0 ......... timesPos .... timesPos + 4 .. timesEnd 0238 // <some data> <time header> <broken times> <need-to-move data> <end> 0239 memmove(extra.data() + timesEnd + (24 - ntfsTimesLength), 0240 extra.data() + timesEnd, 0241 extra.size() - (24 - ntfsTimesLength) - timesEnd); 0242 // Now we have to increase the NTFS record and time tag lengths. 0243 ntfsLength += (24 - ntfsTimesLength); 0244 ntfsTimesLength = 24; 0245 extra[ntfsPos + 2] = static_cast<char>(ntfsLength); 0246 extra[ntfsPos + 3] = static_cast<char>(ntfsLength >> 8); 0247 extra[timesPos + 2] = static_cast<char>(ntfsTimesLength); 0248 extra[timesPos + 3] = static_cast<char>(ntfsTimesLength >> 8); 0249 } 0250 QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC); 0251 #if (QT_VERSION >= 0x040700) 0252 quint64 ticks = base.msecsTo(time) * 10000 + fineTicks; 0253 #else 0254 QDateTime utc = time.toUTC(); 0255 quint64 ticks = (static_cast<qint64>(base.date().daysTo(utc.date())) 0256 * Q_INT64_C(86400000) 0257 + static_cast<qint64>(base.time().msecsTo(utc.time()))) 0258 * Q_INT64_C(10000) + fineTicks; 0259 #endif 0260 extra[timesPos + 4 + position] = static_cast<char>(ticks); 0261 extra[timesPos + 5 + position] = static_cast<char>(ticks >> 8); 0262 extra[timesPos + 6 + position] = static_cast<char>(ticks >> 16); 0263 extra[timesPos + 7 + position] = static_cast<char>(ticks >> 24); 0264 extra[timesPos + 8 + position] = static_cast<char>(ticks >> 32); 0265 extra[timesPos + 9 + position] = static_cast<char>(ticks >> 40); 0266 extra[timesPos + 10 + position] = static_cast<char>(ticks >> 48); 0267 extra[timesPos + 11 + position] = static_cast<char>(ticks >> 56); 0268 } 0269 0270 void QuaZipNewInfo::setFileNTFSmTime(const QDateTime &mTime, int fineTicks) 0271 { 0272 setNTFSTime(extraLocal, mTime, 0, fineTicks); 0273 setNTFSTime(extraGlobal, mTime, 0, fineTicks); 0274 } 0275 0276 void QuaZipNewInfo::setFileNTFSaTime(const QDateTime &aTime, int fineTicks) 0277 { 0278 setNTFSTime(extraLocal, aTime, 8, fineTicks); 0279 setNTFSTime(extraGlobal, aTime, 8, fineTicks); 0280 } 0281 0282 void QuaZipNewInfo::setFileNTFScTime(const QDateTime &cTime, int fineTicks) 0283 { 0284 setNTFSTime(extraLocal, cTime, 16, fineTicks); 0285 setNTFSTime(extraGlobal, cTime, 16, fineTicks); 0286 }