aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb/lock/flock.php
blob: af051afb5635cfad34bf591f1f937b5539206d9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/

namespace phpbb\lock;

/**
* File locking class
*/
class flock
{
	/**
	* Path to the file to which access is controlled
	*
	* @var string
	*/
	private $path;

	/**
	* File pointer for the lock file
	* @var string
	*/
	private $lock_fp;

	/**
	* Constructor.
	*
	* You have to call acquire() to actually acquire the lock.
	*
	* @param	string	$path	Path to the file to which access is controlled
	*/
	public function __construct($path)
	{
		$this->path = $path;
		$this->lock_fp = null;
	}

	/**
	* Tries to acquire the lock.
	*
	* If the lock is already held by another process, this call will block
	* until the other process releases the lock. If a lock is acquired and
	* is not released before script finishes but the process continues to
	* live (apache/fastcgi) then subsequent processes trying to acquire
	* the same lock will be blocked forever.
	*
	* If the lock is already held by the same process via another instance
	* of this class, this call will block forever.
	*
	* If flock function is disabled in php or fails to work, lock
	* acquisition will fail and false will be returned.
	*
	* @return	bool			true if lock was acquired
	*							false otherwise
	*/
	public function acquire()
	{
		if ($this->lock_fp)
		{
			return false;
		}

		// For systems that can't have two processes opening
		// one file for writing simultaneously
		if (file_exists($this->path . '.lock'))
		{
			$mode = 'rb';
		}
		else
		{
			$mode = 'wb';
		}

		$this->lock_fp = @fopen($this->path . '.lock', $mode);

		if ($mode == 'wb')
		{
			if (!$this->lock_fp)
			{
				// Two processes may attempt to create lock file at the same time.
				// Have the losing process try opening the lock file again for reading
				// on the assumption that the winning process created it
				$mode = 'rb';
				$this->lock_fp = @fopen($this->path . '.lock', $mode);
			}
			else
			{
				// Only need to set mode when the lock file is written
				@chmod($this->path . '.lock', 0666);
			}
		}

		if ($this->lock_fp)
		{
			if (!@flock($this->lock_fp, LOCK_EX))
			{
				throw new \phpbb\exception\http_exception(500, 'Failure while aqcuiring locks.');
			}
		}

		return (bool) $this->lock_fp;
	}

	/**
	* Does this process own the lock?
	*
	* @return	bool			true if lock is owned
	*							false otherwise
	*/
	public function owns_lock()
	{
		return (bool) $this->lock_fp;
	}

	/**
	* Releases the lock.
	*
	* The lock must have been previously obtained, that is, acquire() call
	* was issued and returned true.
	*
	* Note: Attempting to release a lock that is already released,
	* that is, calling release() multiple times, is harmless.
	*
	* @return null
	*/
	public function release()
	{
		if ($this->lock_fp)
		{
			@flock($this->lock_fp, LOCK_UN);
			fclose($this->lock_fp);
			$this->lock_fp = null;
		}
	}
}