OSDN Git Service

Update MediaInfo binaries to v0.7.53 (2012-01-24), compiled with ICL 12.1.6 and MSVC...
[lamexp/LameXP.git] / src / LockedFile.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
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.
9 //
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.
14 //
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.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "LockedFile.h"
23 #include "Global.h"
24
25 #include <QResource>
26 #include <QFile>
27 #include <QFileInfo>
28 #include <QDir>
29 #include <QCryptographicHash>
30
31 #include <stdio.h>
32 #include <io.h>
33 #include <fcntl.h>
34
35 ///////////////////////////////////////////////////////////////////////////////
36
37 #define THROW(STR)                                      \
38 {                                                                       \
39         char error_msg[512];                    \
40         strcpy_s(error_msg, 512, STR);  \
41         throw error_msg;                                \
42 }
43
44 // WARNING: Passing file descriptors into Qt does NOT work with dynamically linked CRT!
45 #ifdef QT_NODLL
46         static const bool g_useFileDescr = 1;
47 #else
48         static const bool g_useFileDescr = 0;
49 #endif
50
51 ///////////////////////////////////////////////////////////////////////////////
52
53 static const char *g_seed = "b14bf0ed8d5a62311b366907a6450ea2d52ad8bbc7d520b70400f1dd8ddfa9339011a473";
54 static const char *g_salt = "80e0cce7af513880065488568071342e5889d6c5ee96190c303b7260e5c8356c350fbe44";
55
56 static QByteArray fileHash(QFile &file)
57 {
58         QByteArray hash = QByteArray::fromHex(g_seed);
59         QByteArray salt = QByteArray::fromHex(g_salt);
60         
61         if(file.isOpen() && file.reset())
62         {
63                 QByteArray data = file.readAll();
64                 QCryptographicHash sha(QCryptographicHash::Sha1);
65                 QCryptographicHash md5(QCryptographicHash::Md5);
66
67                 for(int r = 0; r < 8; r++)
68                 {
69                         sha.reset(); md5.reset();
70                         sha.addData(hash); md5.addData(hash);
71                         sha.addData(data); md5.addData(data);
72                         sha.addData(salt); md5.addData(salt);
73                         hash = sha.result() + md5.result();
74                 }
75         }
76
77         return hash;
78 }
79
80 ///////////////////////////////////////////////////////////////////////////////
81
82 LockedFile::LockedFile(const QString &resourcePath, const QString &outPath, const QByteArray &expectedHash)
83 {
84         m_fileHandle = NULL;
85         QResource resource(resourcePath);
86         
87         //Make sure the resource is valid
88         if(!resource.isValid())
89         {
90                 THROW(QString("Resource '%1' is invalid!").arg(QFileInfo(resourcePath).absoluteFilePath().replace(QRegExp("^:/"), QString())).toUtf8().constData());
91         }
92
93         QFile outFile(outPath);
94         m_filePath = QFileInfo(outFile).absoluteFilePath();
95         
96         //Open output file
97         for(int i = 0; i < 64; i++)
98         {
99                 if(outFile.open(QIODevice::WriteOnly)) break;
100                 if(!i) qWarning("Failed to open file on first attemp, retrying...");
101                 Sleep(100);
102         }
103         
104         //Write data to file
105         if(outFile.isOpen() && outFile.isWritable())
106         {
107                 if(outFile.write(reinterpret_cast<const char*>(resource.data()), resource.size()) != resource.size())
108                 {
109                         QFile::remove(QFileInfo(outFile).canonicalFilePath());
110                         THROW(QString("File '%1' could not be written!").arg(QFileInfo(outFile).fileName()).toUtf8().constData());
111                 }
112                 outFile.close();
113         }
114         else
115         {
116                 THROW(QString("File '%1' could not be created!").arg(QFileInfo(outFile).fileName()).toUtf8().constData());
117         }
118
119         //Now lock the file!
120         for(int i = 0; i < 64; i++)
121         {
122                 m_fileHandle = CreateFileW(QWCHAR(QDir::toNativeSeparators(m_filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
123                 if((m_fileHandle != NULL) && (m_fileHandle != INVALID_HANDLE_VALUE)) break;
124                 if(!i) qWarning("Failed to lock file on first attemp, retrying...");
125                 Sleep(100);
126         }
127         
128         //Locked successfully?
129         if((m_fileHandle == NULL) || (m_fileHandle == INVALID_HANDLE_VALUE))
130         {
131                 QFile::remove(QFileInfo(outFile).canonicalFilePath());
132                 char error_msg[512];
133                 strcpy_s(error_msg, 512, QString("File '%1' could not be locked!").arg(QFileInfo(outFile).fileName()).toLatin1().constData());
134                 throw error_msg;
135         }
136
137         //Open file for reading
138         if(g_useFileDescr)
139         {
140                 int fd = _open_osfhandle(reinterpret_cast<intptr_t>(m_fileHandle), _O_RDONLY | _O_BINARY);
141                 if(fd >= 0) outFile.open(fd, QIODevice::ReadOnly);
142         }
143         else
144         {
145                 for(int i = 0; i < 64; i++)
146                 {
147                         if(outFile.open(QIODevice::ReadOnly)) break;
148                         if(!i) qWarning("Failed to re-open file on first attemp, retrying...");
149                         Sleep(100);
150                 }
151         }
152
153         //Verify file contents
154         QByteArray hash;
155         if(outFile.isOpen())
156         {
157                 hash = fileHash(outFile).toHex();
158                 outFile.close();
159         }
160         else
161         {
162                 QFile::remove(m_filePath);
163                 THROW(QString("File '%1' could not be read!").arg(QFileInfo(outFile).fileName()).toLatin1().constData());
164         }
165
166         //Compare hashes
167         if(hash.isNull() || _stricmp(hash.constData(), expectedHash.constData()))
168         {
169                 qWarning("\nFile checksum error:\n A = %s\n B = %s\n", expectedHash.constData(), hash.constData());
170                 LAMEXP_CLOSE(m_fileHandle);
171                 QFile::remove(m_filePath);
172                 THROW(QString("File '%1' is corruputed, take care!").arg(QFileInfo(resourcePath).absoluteFilePath().replace(QRegExp("^:/"), QString())).toLatin1().constData());
173         }
174 }
175
176 LockedFile::LockedFile(const QString &filePath)
177 {
178         m_fileHandle = NULL;
179         QFileInfo existingFile(filePath);
180         existingFile.setCaching(false);
181         
182         //Make sure the file exists, before we try to lock it
183         if(!existingFile.exists())
184         {
185                 char error_msg[256];
186                 strcpy_s(error_msg, 256, QString("File '%1' does not exist!").arg(existingFile.fileName()).toLatin1().constData());
187                 throw error_msg;
188         }
189         
190         //Remember file path
191         m_filePath = existingFile.canonicalFilePath();
192
193         //Now lock the file
194         for(int i = 0; i < 64; i++)
195         {
196                 m_fileHandle = CreateFileW(QWCHAR(QDir::toNativeSeparators(filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
197                 if((m_fileHandle != NULL) && (m_fileHandle != INVALID_HANDLE_VALUE)) break;
198                 if(!i) qWarning("Failed to lock file on first attemp, retrying...");
199                 Sleep(100);
200         }
201
202         //Locked successfully?
203         if((m_fileHandle == NULL) || (m_fileHandle == INVALID_HANDLE_VALUE))
204         {
205                 THROW(QString("File '%1' could not be locked!").arg(existingFile.fileName()).toLatin1().constData());
206         }
207 }
208
209 LockedFile::~LockedFile(void)
210 {
211         LAMEXP_CLOSE(m_fileHandle);
212 }
213
214 const QString &LockedFile::filePath()
215 {
216         return m_filePath;
217 }