File indexing completed on 2024-05-19 04:38:46
0001 /**************************************************************************** 0002 ** 0003 ** Copyright (C) 2016 The Qt Company Ltd. 0004 ** Contact: https://www.qt.io/licensing/ 0005 ** 0006 ** This file is part of Qt Creator. 0007 ** 0008 ** Commercial License Usage 0009 ** Licensees holding valid commercial Qt licenses may use this file in 0010 ** accordance with the commercial license agreement provided with the 0011 ** Software or, alternatively, in accordance with the terms contained in 0012 ** a written agreement between you and The Qt Company. For licensing terms 0013 ** and conditions see https://www.qt.io/terms-conditions. For further 0014 ** information use the contact form at https://www.qt.io/contact-us. 0015 ** 0016 ** GNU General Public License Usage 0017 ** Alternatively, this file may be used under the terms of the GNU 0018 ** General Public License version 3 as published by the Free Software 0019 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 0020 ** included in the packaging of this file. Please review the following 0021 ** information to ensure the GNU General Public License requirements will 0022 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 0023 ** 0024 ****************************************************************************/ 0025 0026 #include "qtlockedfile.h" 0027 0028 #include <qt_windows.h> 0029 #include <QFileInfo> 0030 0031 namespace SharedTools { 0032 0033 #define SEMAPHORE_PREFIX "QtLockedFile semaphore " 0034 #define MUTEX_PREFIX "QtLockedFile mutex " 0035 #define SEMAPHORE_MAX 100 0036 0037 static QString errorCodeToString(DWORD errorCode) 0038 { 0039 QString result; 0040 char *data = 0; 0041 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0042 0, errorCode, 0, 0043 (char*)&data, 0, 0); 0044 result = QString::fromLocal8Bit(data); 0045 if (data != 0) 0046 LocalFree(data); 0047 0048 if (result.endsWith(QLatin1Char('\n'))) 0049 result.truncate(result.length() - 1); 0050 0051 return result; 0052 } 0053 0054 bool QtLockedFile::lock(LockMode mode, bool block) 0055 { 0056 if (!isOpen()) { 0057 qWarning("QtLockedFile::lock(): file is not opened"); 0058 return false; 0059 } 0060 0061 if (mode == m_lock_mode) 0062 return true; 0063 0064 if (m_lock_mode != 0) 0065 unlock(); 0066 0067 if (m_semaphore_hnd == 0) { 0068 QFileInfo fi(*this); 0069 QString sem_name = QString::fromLatin1(SEMAPHORE_PREFIX) 0070 + fi.absoluteFilePath().toLower(); 0071 0072 m_semaphore_hnd = CreateSemaphoreW(0, SEMAPHORE_MAX, SEMAPHORE_MAX, 0073 (TCHAR*)sem_name.utf16()); 0074 0075 if (m_semaphore_hnd == 0) { 0076 qWarning("QtLockedFile::lock(): CreateSemaphore: %s", 0077 errorCodeToString(GetLastError()).toLatin1().constData()); 0078 return false; 0079 } 0080 } 0081 0082 bool gotMutex = false; 0083 int decrement; 0084 if (mode == ReadLock) { 0085 decrement = 1; 0086 } else { 0087 decrement = SEMAPHORE_MAX; 0088 if (m_mutex_hnd == 0) { 0089 QFileInfo fi(*this); 0090 QString mut_name = QString::fromLatin1(MUTEX_PREFIX) 0091 + fi.absoluteFilePath().toLower(); 0092 0093 m_mutex_hnd = CreateMutexW(NULL, FALSE, (TCHAR*)mut_name.utf16()); 0094 0095 if (m_mutex_hnd == 0) { 0096 qWarning("QtLockedFile::lock(): CreateMutex: %s", 0097 errorCodeToString(GetLastError()).toLatin1().constData()); 0098 return false; 0099 } 0100 } 0101 DWORD res = WaitForSingleObject(m_mutex_hnd, block ? INFINITE : 0); 0102 if (res == WAIT_TIMEOUT) 0103 return false; 0104 if (res == WAIT_FAILED) { 0105 qWarning("QtLockedFile::lock(): WaitForSingleObject (mutex): %s", 0106 errorCodeToString(GetLastError()).toLatin1().constData()); 0107 return false; 0108 } 0109 gotMutex = true; 0110 } 0111 0112 for (int i = 0; i < decrement; ++i) { 0113 DWORD res = WaitForSingleObject(m_semaphore_hnd, block ? INFINITE : 0); 0114 if (res == WAIT_TIMEOUT) { 0115 if (i) { 0116 // A failed nonblocking rw locking. Undo changes to semaphore. 0117 if (ReleaseSemaphore(m_semaphore_hnd, i, NULL) == 0) { 0118 qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s", 0119 errorCodeToString(GetLastError()).toLatin1().constData()); 0120 // Fall through 0121 } 0122 } 0123 if (gotMutex) 0124 ReleaseMutex(m_mutex_hnd); 0125 return false; 0126 } 0127 if (res != WAIT_OBJECT_0) { 0128 if (gotMutex) 0129 ReleaseMutex(m_mutex_hnd); 0130 qWarning("QtLockedFile::lock(): WaitForSingleObject (semaphore): %s", 0131 errorCodeToString(GetLastError()).toLatin1().constData()); 0132 return false; 0133 } 0134 } 0135 0136 m_lock_mode = mode; 0137 if (gotMutex) 0138 ReleaseMutex(m_mutex_hnd); 0139 return true; 0140 } 0141 0142 bool QtLockedFile::unlock() 0143 { 0144 if (!isOpen()) { 0145 qWarning("QtLockedFile::unlock(): file is not opened"); 0146 return false; 0147 } 0148 0149 if (!isLocked()) 0150 return true; 0151 0152 int increment; 0153 if (m_lock_mode == ReadLock) 0154 increment = 1; 0155 else 0156 increment = SEMAPHORE_MAX; 0157 0158 DWORD ret = ReleaseSemaphore(m_semaphore_hnd, increment, 0); 0159 if (ret == 0) { 0160 qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s", 0161 errorCodeToString(GetLastError()).toLatin1().constData()); 0162 return false; 0163 } 0164 0165 m_lock_mode = QtLockedFile::NoLock; 0166 remove(); 0167 return true; 0168 } 0169 0170 QtLockedFile::~QtLockedFile() 0171 { 0172 if (isOpen()) 0173 unlock(); 0174 if (m_mutex_hnd != 0) { 0175 DWORD ret = CloseHandle(m_mutex_hnd); 0176 if (ret == 0) { 0177 qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (mutex): %s", 0178 errorCodeToString(GetLastError()).toLatin1().constData()); 0179 } 0180 m_mutex_hnd = 0; 0181 } 0182 if (m_semaphore_hnd != 0) { 0183 DWORD ret = CloseHandle(m_semaphore_hnd); 0184 if (ret == 0) { 0185 qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (semaphore): %s", 0186 errorCodeToString(GetLastError()).toLatin1().constData()); 0187 } 0188 m_semaphore_hnd = 0; 0189 } 0190 } 0191 0192 } // namespace SharedTools