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