1 /*
2 Copyright (C) 2005-2014 Sergey A. Tachenov
3
4 This file is part of QuaZip.
5
6 QuaZip is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 2.1 of the License, or
9 (at your option) any later version.
10
11 QuaZip is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with QuaZip. If not, see <http://www.gnu.org/licenses/>.
18
19 See COPYING file for the full LGPL text.
20
21 Original ZIP package is copyrighted by Gilles Vollant and contributors,
22 see quazip/(un)zip.h files for details. Basically it's the zlib license.
23 */
24
25 #include "quazipfileinfo.h"
26
27 #include <QtCore/QDataStream>
28
permissionsFromExternalAttr(quint32 externalAttr)29 static QFile::Permissions permissionsFromExternalAttr(quint32 externalAttr) {
30 quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16;
31 QFile::Permissions perm;
32 if ((uPerm & 0400) != 0)
33 perm |= QFile::ReadOwner;
34 if ((uPerm & 0200) != 0)
35 perm |= QFile::WriteOwner;
36 if ((uPerm & 0100) != 0)
37 perm |= QFile::ExeOwner;
38 if ((uPerm & 0040) != 0)
39 perm |= QFile::ReadGroup;
40 if ((uPerm & 0020) != 0)
41 perm |= QFile::WriteGroup;
42 if ((uPerm & 0010) != 0)
43 perm |= QFile::ExeGroup;
44 if ((uPerm & 0004) != 0)
45 perm |= QFile::ReadOther;
46 if ((uPerm & 0002) != 0)
47 perm |= QFile::WriteOther;
48 if ((uPerm & 0001) != 0)
49 perm |= QFile::ExeOther;
50 return perm;
51
52 }
53
getPermissions() const54 QFile::Permissions QuaZipFileInfo::getPermissions() const
55 {
56 return permissionsFromExternalAttr(externalAttr);
57 }
58
getPermissions() const59 QFile::Permissions QuaZipFileInfo64::getPermissions() const
60 {
61 return permissionsFromExternalAttr(externalAttr);
62 }
63
isSymbolicLink() const64 bool QuaZipFileInfo64::isSymbolicLink() const
65 {
66 quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16;
67 return (uPerm & 0170000) == 0120000;
68 }
69
toQuaZipFileInfo(QuaZipFileInfo & info) const70 bool QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo &info) const
71 {
72 bool noOverflow = true;
73 info.name = name;
74 info.versionCreated = versionCreated;
75 info.versionNeeded = versionNeeded;
76 info.flags = flags;
77 info.method = method;
78 info.dateTime = dateTime;
79 info.crc = crc;
80 if (compressedSize > 0xFFFFFFFFu) {
81 info.compressedSize = 0xFFFFFFFFu;
82 noOverflow = false;
83 } else {
84 info.compressedSize = compressedSize;
85 }
86 if (uncompressedSize > 0xFFFFFFFFu) {
87 info.uncompressedSize = 0xFFFFFFFFu;
88 noOverflow = false;
89 } else {
90 info.uncompressedSize = uncompressedSize;
91 }
92 info.diskNumberStart = diskNumberStart;
93 info.internalAttr = internalAttr;
94 info.externalAttr = externalAttr;
95 info.comment = comment;
96 info.extra = extra;
97 return noOverflow;
98 }
99
getNTFSTime(const QByteArray & extra,int position,int * fineTicks)100 static QDateTime getNTFSTime(const QByteArray &extra, int position,
101 int *fineTicks)
102 {
103 QDateTime dateTime;
104 QuaExtraFieldHash extraHash = QuaZipFileInfo64::parseExtraField(extra);
105 QList<QByteArray> ntfsExtraFields = extraHash[QUAZIP_EXTRA_NTFS_MAGIC];
106 if (ntfsExtraFields.isEmpty())
107 return dateTime;
108 QByteArray ntfsExtraField = ntfsExtraFields.at(0);
109 if (ntfsExtraField.length() <= 4)
110 return dateTime;
111 QByteArray ntfsAttributes = ntfsExtraField.mid(4);
112 QuaExtraFieldHash ntfsHash = QuaZipFileInfo64::parseExtraField(ntfsAttributes);
113 QList<QByteArray> ntfsTimeAttributes = ntfsHash[QUAZIP_EXTRA_NTFS_TIME_MAGIC];
114 if (ntfsTimeAttributes.isEmpty())
115 return dateTime;
116 QByteArray ntfsTimes = ntfsTimeAttributes.at(0);
117 if (ntfsTimes.size() < 24)
118 return dateTime;
119 QDataStream timeReader(ntfsTimes);
120 timeReader.setByteOrder(QDataStream::LittleEndian);
121 timeReader.device()->seek(position);
122 quint64 time;
123 timeReader >> time;
124 if (time == 0)
125 return dateTime;
126 QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
127 dateTime = base.addMSecs(time / 10000);
128 if (fineTicks != nullptr) {
129 *fineTicks = static_cast<int>(time % 10000);
130 }
131 return dateTime;
132 }
133
getNTFSmTime(int * fineTicks) const134 QDateTime QuaZipFileInfo64::getNTFSmTime(int *fineTicks) const
135 {
136 return getNTFSTime(extra, 0, fineTicks);
137 }
138
getNTFSaTime(int * fineTicks) const139 QDateTime QuaZipFileInfo64::getNTFSaTime(int *fineTicks) const
140 {
141 return getNTFSTime(extra, 8, fineTicks);
142 }
143
getNTFScTime(int * fineTicks) const144 QDateTime QuaZipFileInfo64::getNTFScTime(int *fineTicks) const
145 {
146 return getNTFSTime(extra, 16, fineTicks);
147 }
148
getExtTime(const QByteArray & extra,int flag)149 QDateTime QuaZipFileInfo64::getExtTime(const QByteArray &extra, int flag)
150 {
151 QDateTime dateTime;
152 QuaExtraFieldHash extraHash = QuaZipFileInfo64::parseExtraField(extra);
153 QList<QByteArray> extTimeFields = extraHash[QUAZIP_EXTRA_EXT_TIME_MAGIC];
154 if (extTimeFields.isEmpty())
155 return dateTime;
156 QByteArray extTimeField = extTimeFields.at(0);
157 if (extTimeField.length() < 1)
158 return dateTime;
159 QDataStream input(extTimeField);
160 input.setByteOrder(QDataStream::LittleEndian);
161 quint8 flags;
162 input >> flags;
163 int flagsRemaining = flags;
164 while (!input.atEnd()) {
165 int nextFlag = flagsRemaining & -flagsRemaining;
166 flagsRemaining &= flagsRemaining - 1;
167 qint32 time;
168 input >> time;
169 if (nextFlag == flag) {
170 QDateTime base(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC);
171 dateTime = base.addSecs(time);
172 return dateTime;
173 }
174 }
175 return dateTime;
176 }
177
getExtModTime() const178 QDateTime QuaZipFileInfo64::getExtModTime() const
179 {
180 return getExtTime(extra, 1);
181 }
182
parseExtraField(const QByteArray & extraField)183 QuaExtraFieldHash QuaZipFileInfo64::parseExtraField(const QByteArray &extraField)
184 {
185 QDataStream input(extraField);
186 input.setByteOrder(QDataStream::LittleEndian);
187 QHash<quint16, QList<QByteArray> > result;
188 while (!input.atEnd()) {
189 quint16 id, size;
190 input >> id;
191 if (input.status() == QDataStream::ReadPastEnd)
192 return result;
193 input >> size;
194 if (input.status() == QDataStream::ReadPastEnd)
195 return result;
196 QByteArray data;
197 data.resize(size);
198 int read = input.readRawData(data.data(), data.size());
199 if (read < data.size())
200 return result;
201 result[id] << data;
202 }
203 return result;
204 }
205