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 const QByteArray data
= file
.readAll();
67 const QByteArray seed
= QByteArray::fromHex(g_seed
);
68 const QByteArray salt
= QByteArray::fromHex(g_salt
);
70 if(keccak
.init(QKeccakHash::hb384
))
73 ok
= ok
&& keccak
.addData(seed
);
74 ok
= ok
&& keccak
.addData(data
);
75 ok
= ok
&& keccak
.addData(salt
);
78 const QByteArray digest
= keccak
.finalize();
79 if(!digest
.isEmpty()) hash
= digest
.toHex();
87 ///////////////////////////////////////////////////////////////////////////////
89 LockedFile::LockedFile(const QString
&resourcePath
, const QString
&outPath
, const QByteArray
&expectedHash
)
92 QResource
resource(resourcePath
);
94 //Make sure the resource is valid
95 if(!resource
.isValid())
97 THROW(QString("Resource '%1' is invalid!").arg(QFileInfo(resourcePath
).absoluteFilePath().replace(QRegExp("^:/"), QString())).toUtf8().constData());
100 QFile
outFile(outPath
);
101 m_filePath
= QFileInfo(outFile
).absoluteFilePath();
104 for(int i
= 0; i
< 64; i
++)
106 if(outFile
.open(QIODevice::WriteOnly
)) break;
107 if(!i
) qWarning("Failed to open file on first attemp, retrying...");
112 if(outFile
.isOpen() && outFile
.isWritable())
114 if(outFile
.write(reinterpret_cast<const char*>(resource
.data()), resource
.size()) != resource
.size())
116 QFile::remove(QFileInfo(outFile
).canonicalFilePath());
117 THROW(QString("File '%1' could not be written!").arg(QFileInfo(outFile
).fileName()).toUtf8().constData());
123 THROW(QString("File '%1' could not be created!").arg(QFileInfo(outFile
).fileName()).toUtf8().constData());
127 for(int i
= 0; i
< 64; i
++)
129 m_fileHandle
= CreateFileW(QWCHAR(QDir::toNativeSeparators(m_filePath
)), GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, NULL
, NULL
);
130 if((m_fileHandle
!= NULL
) && (m_fileHandle
!= INVALID_HANDLE_VALUE
)) break;
131 if(!i
) qWarning("Failed to lock file on first attemp, retrying...");
135 //Locked successfully?
136 if((m_fileHandle
== NULL
) || (m_fileHandle
== INVALID_HANDLE_VALUE
))
138 QFile::remove(QFileInfo(outFile
).canonicalFilePath());
140 strcpy_s(error_msg
, 512, QString("File '%1' could not be locked!").arg(QFileInfo(outFile
).fileName()).toLatin1().constData());
144 //Open file for reading
147 int fd
= _open_osfhandle(reinterpret_cast<intptr_t>(m_fileHandle
), _O_RDONLY
| _O_BINARY
);
148 if(fd
>= 0) outFile
.open(fd
, QIODevice::ReadOnly
);
152 for(int i
= 0; i
< 64; i
++)
154 if(outFile
.open(QIODevice::ReadOnly
)) break;
155 if(!i
) qWarning("Failed to re-open file on first attemp, retrying...");
160 //Verify file contents
164 hash
= fileHash(outFile
);
169 QFile::remove(m_filePath
);
170 THROW(QString("File '%1' could not be read!").arg(QFileInfo(outFile
).fileName()).toLatin1().constData());
174 if(hash
.isNull() || _stricmp(hash
.constData(), expectedHash
.constData()))
176 qWarning("\nFile checksum error:\n A = %s\n B = %s\n", expectedHash
.constData(), hash
.constData());
177 LAMEXP_CLOSE(m_fileHandle
);
178 QFile::remove(m_filePath
);
179 THROW(QString("File '%1' is corruputed, take care!").arg(QFileInfo(resourcePath
).absoluteFilePath().replace(QRegExp("^:/"), QString())).toLatin1().constData());
183 LockedFile::LockedFile(const QString
&filePath
)
186 QFileInfo
existingFile(filePath
);
187 existingFile
.setCaching(false);
189 //Make sure the file exists, before we try to lock it
190 if(!existingFile
.exists())
193 strcpy_s(error_msg
, 256, QString("File '%1' does not exist!").arg(existingFile
.fileName()).toLatin1().constData());
198 m_filePath
= existingFile
.canonicalFilePath();
201 for(int i
= 0; i
< 64; i
++)
203 m_fileHandle
= CreateFileW(QWCHAR(QDir::toNativeSeparators(filePath
)), GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, NULL
, NULL
);
204 if((m_fileHandle
!= NULL
) && (m_fileHandle
!= INVALID_HANDLE_VALUE
)) break;
205 if(!i
) qWarning("Failed to lock file on first attemp, retrying...");
209 //Locked successfully?
210 if((m_fileHandle
== NULL
) || (m_fileHandle
== INVALID_HANDLE_VALUE
))
212 THROW(QString("File '%1' could not be locked!").arg(existingFile
.fileName()).toLatin1().constData());
216 LockedFile::~LockedFile(void)
218 LAMEXP_CLOSE(m_fileHandle
);
221 const QString
&LockedFile::filePath()
226 void LockedFile::selfTest()
228 if(!QKeccakHash::selfTest())
230 qFatal("QKeccakHash self-test has failed!");