Fixed problem in the CFile write_safe concept
[amule.git] / src / FileLock.h
blobf8d9054e87fb643825aeabb19050ce83a81764c2
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2006-2011 Mikkel Schubert ( xaignar@users.sourceforge.net )
5 // Copyright (c) 2006-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #ifndef FILELOCK_H
27 #define FILELOCK_H
29 #include <fcntl.h>
30 #include <cerrno>
31 #ifndef _MSC_VER
32 #include <unistd.h> // Do_not_auto_remove (Needed for OpenBSD)
33 #endif
34 #include <string> // Do_not_auto_remove (g++-4.0.1 except win32)
37 /**
38 * This class provides an easy way to lock non-critical
39 * files used by multiple applications. However, since
40 * the implementation relies on fcntl, it may not work
41 * on all filesystems (NFS) and thus locking is not
42 * certain.
44 * Currently, this lock holds an exclusive lock on the
45 * file in question. It is assumed that the file will
46 * be read/written by all users.
49 class CFileLock
51 public:
52 /**
53 * Locks the lock-file for the specified file.
55 * The lock-file is a file named file + "_lock", and
56 * will be created if it does not already exist. This
57 * file is not removed afterwards.
59 CFileLock(const std::string& file)
60 #ifdef _WIN32
61 : m_ok(false)
63 hd = CreateFileA((file + "_lock").c_str(),
64 GENERIC_READ | GENERIC_WRITE,
65 FILE_SHARE_READ | FILE_SHARE_WRITE, // share - shareable
66 NULL, // security - not inheritable
67 CREATE_ALWAYS,
68 FILE_ATTRIBUTE_ARCHIVE,
69 NULL);
70 if (hd != INVALID_HANDLE_VALUE) {
71 m_ok = SetLock(true);
75 /** Releases the lock, if any is held. */
76 ~CFileLock() {
77 if (m_ok) {
78 SetLock(false);
81 if (hd != INVALID_HANDLE_VALUE) {
82 CloseHandle(hd);
86 private:
87 //! Not copyable.
88 CFileLock(const CFileLock&);
89 //! Not assignable.
90 CFileLock& operator=(const CFileLock&);
92 /** Locks or unlocks the lock-file, returning true on success. */
93 bool SetLock(bool doLock) {
94 // lock/unlock first byte in the file
95 OVERLAPPED ov;
96 ov.Offset = ov.OffsetHigh = 0;
97 BOOL ret;
98 if (doLock) {
99 // http://msdn.microsoft.com/en-us/library/ms891385.aspx
100 ret = LockFileEx(hd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ov);
101 } else {
102 // http://msdn.microsoft.com/en-us/library/ms892364.aspx
103 ret = UnlockFileEx(hd, 0, 1, 0, &ov);
105 return ret != 0;
109 //! Desriptor of the file being locked.
110 HANDLE hd;
112 //! Specifies if the file-lock was aquired.
113 bool m_ok;
114 #else
115 : m_fd(-1),
116 m_ok(false)
118 // File must be open with O_WRONLY to be able to set write-locks.
119 m_fd = ::open((file + "_lock").c_str(), O_CREAT | O_WRONLY, 0600);
120 if (m_fd != -1) {
121 m_ok = SetLock(true);
125 /** Releases the lock, if any is held. */
126 ~CFileLock() {
127 if (m_ok) {
128 SetLock(false);
131 if (m_fd != -1) {
132 close(m_fd);
136 private:
137 //! Not copyable.
138 CFileLock(const CFileLock&);
139 //! Not assignable.
140 CFileLock& operator=(const CFileLock&);
142 /** Locks or unlocks the lock-file, returning true on success. */
143 bool SetLock(bool doLock) {
144 struct flock lock;
145 lock.l_type = (doLock ? F_WRLCK : F_UNLCK);
147 // Lock the entire file
148 lock.l_whence = SEEK_SET;
149 lock.l_start = 0;
150 lock.l_len = 0;
152 // Keep trying if interrupted by a signal.
153 while (true) {
154 if (fcntl(m_fd, F_SETLKW, &lock) == 0) {
155 return true;
156 } else if ((errno != EACCES) && (errno != EAGAIN) && (errno != EINTR)) {
157 // Not an error we can recover from.
158 break;
162 return false;
166 //! Desribtor of the file being locked.
167 int m_fd;
169 //! Specifies if the file-lock was aquired.
170 bool m_ok;
171 #endif
174 #endif
175 // File_checked_for_headers