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