1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "LockedFile.h"
29 #include <QCryptographicHash>
30 #include <QKeccakHash>
36 ///////////////////////////////////////////////////////////////////////////////
40 char error_msg[512]; \
41 strcpy_s(error_msg, 512, STR); \
45 // WARNING: Passing file descriptors into Qt does NOT work with dynamically linked CRT!
47 static const bool g_useFileDescr = 1;
49 static const bool g_useFileDescr = 0;
52 ///////////////////////////////////////////////////////////////////////////////
54 static const char *g_blnk = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
55 static const char *g_seed = "c375d83b4388329408dfcbb4d9a065b6e06d28272f25ef299c70b506e26600af79fd2f866ae24602daf38f25c9d4b7e1";
56 static const char *g_salt = "ee9f7bdabc170763d2200a7e3030045aafe380011aefc1730e547e9244c62308aac42a976feeca224ba553de0c4bb883";
58 static QByteArray fileHash(QFile &file)
60 QByteArray hash = QByteArray::fromHex(g_blnk);
62 if(file.isOpen() && file.reset())
66 QByteArray data = file.readAll();
67 QByteArray seed = QByteArray::fromHex(g_seed);
68 QByteArray salt = QByteArray::fromHex(g_salt);
70 if(keccak.startBatch(QKeccakHash::hb384))
73 ok[0] = keccak.putBatch(seed);
74 ok[1] = keccak.putBatch(data);
75 ok[2] = keccak.putBatch(salt);
76 if(ok[0] && ok[1] && ok[2])
78 if(keccak.stopBatch())
80 hash = keccak.toHex();
89 ///////////////////////////////////////////////////////////////////////////////
91 LockedFile::LockedFile(const QString &resourcePath, const QString &outPath, const QByteArray &expectedHash)
94 QResource resource(resourcePath);
96 //Make sure the resource is valid
97 if(!resource.isValid())
99 THROW(QString("Resource '%1' is invalid!").arg(QFileInfo(resourcePath).absoluteFilePath().replace(QRegExp("^:/"), QString())).toUtf8().constData());
102 QFile outFile(outPath);
103 m_filePath = QFileInfo(outFile).absoluteFilePath();
106 for(int i = 0; i < 64; i++)
108 if(outFile.open(QIODevice::WriteOnly)) break;
109 if(!i) qWarning("Failed to open file on first attemp, retrying...");
114 if(outFile.isOpen() && outFile.isWritable())
116 if(outFile.write(reinterpret_cast<const char*>(resource.data()), resource.size()) != resource.size())
118 QFile::remove(QFileInfo(outFile).canonicalFilePath());
119 THROW(QString("File '%1' could not be written!").arg(QFileInfo(outFile).fileName()).toUtf8().constData());
125 THROW(QString("File '%1' could not be created!").arg(QFileInfo(outFile).fileName()).toUtf8().constData());
129 for(int i = 0; i < 64; i++)
131 m_fileHandle = CreateFileW(QWCHAR(QDir::toNativeSeparators(m_filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
132 if((m_fileHandle != NULL) && (m_fileHandle != INVALID_HANDLE_VALUE)) break;
133 if(!i) qWarning("Failed to lock file on first attemp, retrying...");
137 //Locked successfully?
138 if((m_fileHandle == NULL) || (m_fileHandle == INVALID_HANDLE_VALUE))
140 QFile::remove(QFileInfo(outFile).canonicalFilePath());
142 strcpy_s(error_msg, 512, QString("File '%1' could not be locked!").arg(QFileInfo(outFile).fileName()).toLatin1().constData());
146 //Open file for reading
149 int fd = _open_osfhandle(reinterpret_cast<intptr_t>(m_fileHandle), _O_RDONLY | _O_BINARY);
150 if(fd >= 0) outFile.open(fd, QIODevice::ReadOnly);
154 for(int i = 0; i < 64; i++)
156 if(outFile.open(QIODevice::ReadOnly)) break;
157 if(!i) qWarning("Failed to re-open file on first attemp, retrying...");
162 //Verify file contents
166 hash = fileHash(outFile);
171 QFile::remove(m_filePath);
172 THROW(QString("File '%1' could not be read!").arg(QFileInfo(outFile).fileName()).toLatin1().constData());
176 if(hash.isNull() || _stricmp(hash.constData(), expectedHash.constData()))
178 qWarning("\nFile checksum error:\n A = %s\n B = %s\n", expectedHash.constData(), hash.constData());
179 LAMEXP_CLOSE(m_fileHandle);
180 QFile::remove(m_filePath);
181 THROW(QString("File '%1' is corruputed, take care!").arg(QFileInfo(resourcePath).absoluteFilePath().replace(QRegExp("^:/"), QString())).toLatin1().constData());
185 LockedFile::LockedFile(const QString &filePath)
188 QFileInfo existingFile(filePath);
189 existingFile.setCaching(false);
191 //Make sure the file exists, before we try to lock it
192 if(!existingFile.exists())
195 strcpy_s(error_msg, 256, QString("File '%1' does not exist!").arg(existingFile.fileName()).toLatin1().constData());
200 m_filePath = existingFile.canonicalFilePath();
203 for(int i = 0; i < 64; i++)
205 m_fileHandle = CreateFileW(QWCHAR(QDir::toNativeSeparators(filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
206 if((m_fileHandle != NULL) && (m_fileHandle != INVALID_HANDLE_VALUE)) break;
207 if(!i) qWarning("Failed to lock file on first attemp, retrying...");
211 //Locked successfully?
212 if((m_fileHandle == NULL) || (m_fileHandle == INVALID_HANDLE_VALUE))
214 THROW(QString("File '%1' could not be locked!").arg(existingFile.fileName()).toLatin1().constData());
218 LockedFile::~LockedFile(void)
220 LAMEXP_CLOSE(m_fileHandle);
223 const QString &LockedFile::filePath()