1 #include "filezilla.h"
2 
3 #include "controlsocket.h"
4 #include "oplock_manager.h"
5 
6 #include <assert.h>
7 
OpLock(OpLockManager * mgr,size_t socket,size_t lock)8 OpLock::OpLock(OpLockManager * mgr, size_t socket, size_t lock)
9 	: mgr_(mgr)
10 	, socket_(socket)
11 	, lock_(lock)
12 {
13 }
14 
~OpLock()15 OpLock::~OpLock()
16 {
17 	if (mgr_) {
18 		mgr_->Unlock(*this);
19 		mgr_ = nullptr;
20 	}
21 }
22 
OpLock(OpLock && op)23 OpLock::OpLock(OpLock && op) noexcept
24 {
25 	if (mgr_) {
26 		mgr_->Unlock(*this);
27 	}
28 	mgr_ = op.mgr_;
29 	socket_ = op.socket_;
30 	lock_ = op.lock_;
31 
32 	op.mgr_ = nullptr;
33 }
34 
operator =(OpLock && op)35 OpLock& OpLock::operator=(OpLock && op) noexcept
36 {
37 	if (this != &op) {
38 		if (mgr_) {
39 			mgr_->Unlock(*this);
40 		}
41 		mgr_ = op.mgr_;
42 		socket_ = op.socket_;
43 		lock_ = op.lock_;
44 
45 		op.mgr_ = nullptr;
46 	}
47 
48 	return *this;
49 }
50 
waiting() const51 bool OpLock::waiting() const
52 {
53 	if (mgr_) {
54 		return mgr_->Waiting(*this);
55 	}
56 
57 	return false;
58 }
59 
Lock(CControlSocket * socket,locking_reason reason,CServerPath const & path,bool inclusive)60 OpLock OpLockManager::Lock(CControlSocket * socket, locking_reason reason, CServerPath const& path, bool inclusive)
61 {
62 	fz::scoped_lock l(mtx_);
63 
64 	size_t socket_index = get_or_create(socket);
65 	auto & sli = socket_locks_[socket_index];
66 
67 	lock_info info;
68 	info.reason = reason;
69 	info.inclusive = inclusive;
70 	info.path = path;
71 
72 	for (auto const& other_sli : socket_locks_) {
73 		if (other_sli.control_socket_ == socket || other_sli.server_ != sli.server_) {
74 			continue;
75 		}
76 
77 		for (auto const& lock : other_sli.locks_) {
78 			if (reason != lock.reason || lock.waiting || lock.released) {
79 				continue;
80 			}
81 			if (lock.path == path || (lock.inclusive && lock.path.IsParentOf(path, false))) {
82 				info.waiting = true;
83 				break;
84 			}
85 			if (inclusive && path.IsParentOf(lock.path, false)) {
86 				info.waiting = true;
87 				break;
88 			}
89 		}
90 		if (info.waiting) {
91 			break;
92 		}
93 	}
94 
95 	sli.locks_.push_back(info);
96 
97 	return OpLock(this, socket_index, sli.locks_.size() - 1);
98 }
99 
Unlock(OpLock & lock)100 void OpLockManager::Unlock(OpLock & lock)
101 {
102 	fz::scoped_lock l(mtx_);
103 	assert(lock.socket_ < socket_locks_.size());
104 	assert(lock.lock_ < socket_locks_[lock.socket_].locks_.size());
105 
106 	bool was_waiting = false;
107 
108 	auto & sli = socket_locks_[lock.socket_];
109 
110 	was_waiting = sli.locks_[lock.lock_].waiting;
111 
112 	if (lock.lock_ + 1 == sli.locks_.size()) {
113 		sli.locks_.pop_back();
114 		while (!sli.locks_.empty() && sli.locks_.back().released) {
115 			sli.locks_.pop_back();
116 		}
117 		if (sli.locks_.empty()) {
118 			if (lock.socket_ + 1 == socket_locks_.size()) {
119 				socket_locks_.pop_back();
120 				while (!socket_locks_.empty() && !socket_locks_.back().control_socket_) {
121 					socket_locks_.pop_back();
122 				}
123 			}
124 			else {
125 				socket_locks_[lock.socket_].control_socket_ = nullptr;
126 			}
127 		}
128 	}
129 	else {
130 		sli.locks_[lock.lock_].waiting = false;
131 		sli.locks_[lock.lock_].released = true;
132 	}
133 
134 	lock.mgr_ = nullptr;
135 
136 	if (!was_waiting) {
137 		Wakeup();
138 	}
139 }
140 
Wakeup()141 void OpLockManager::Wakeup()
142 {
143 	for (auto & sli : socket_locks_) {
144 		for (auto & lock : sli.locks_) {
145 			if (lock.waiting) {
146 				sli.control_socket_->send_event<CObtainLockEvent>();
147 				break;
148 			}
149 		}
150 	}
151 }
152 
ObtainWaiting(CControlSocket * socket)153 bool OpLockManager::ObtainWaiting(CControlSocket * socket)
154 {
155 	bool obtained = false;
156 
157 	fz::scoped_lock l(mtx_);
158 	for (auto & sli : socket_locks_) {
159 		if (sli.control_socket_ == socket) {
160 			for (auto & lock : sli.locks_) {
161 				if (lock.waiting) {
162 					obtained |= ObtainWaiting(sli, lock);
163 				}
164 			}
165 		}
166 	}
167 
168 	return obtained;
169 }
170 
ObtainWaiting(socket_lock_info const & sli,lock_info & lock)171 bool OpLockManager::ObtainWaiting(socket_lock_info const& sli, lock_info& lock)
172 {
173 	for (auto const& other_sli : socket_locks_) {
174 		if (&other_sli == &sli) {
175 			continue;
176 		}
177 
178 		for (auto const& other_lock : other_sli.locks_) {
179 			if (lock.reason != other_lock.reason || other_lock.waiting || other_lock.released) {
180 				continue;
181 			}
182 			if (other_lock.path == lock.path || (other_lock.inclusive && other_lock.path.IsParentOf(lock.path, false))) {
183 				return false;
184 			}
185 			if (lock.inclusive && lock.path.IsParentOf(other_lock.path, false)) {
186 				return false;
187 			}
188 		}
189 	}
190 
191 	lock.waiting = false;
192 	return true;
193 }
194 
get_or_create(CControlSocket * socket)195 size_t OpLockManager::get_or_create(CControlSocket * socket)
196 {
197 	for (size_t i = 0; i < socket_locks_.size(); ++i) {
198 		if (socket_locks_[i].control_socket_ == socket) {
199 			return i;
200 		}
201 	}
202 
203 	socket_lock_info info;
204 	info.control_socket_ = socket;
205 	info.server_ = socket->GetCurrentServer();
206 	socket_locks_.push_back(info);
207 
208 	return socket_locks_.size() - 1;
209 }
210 
Waiting(OpLock const & lock) const211 bool OpLockManager::Waiting(OpLock const& lock) const
212 {
213 	fz::scoped_lock l(mtx_);
214 	assert(lock.socket_ < socket_locks_.size());
215 	assert(lock.lock_ < socket_locks_[lock.socket_].locks_.size());
216 
217 	auto & sli = socket_locks_[lock.socket_];
218 	return sli.locks_[lock.lock_].waiting;
219 }
220 
Waiting(CControlSocket * socket) const221 bool OpLockManager::Waiting(CControlSocket * socket) const
222 {
223 	fz::scoped_lock l(mtx_);
224 	for (auto const& sli : socket_locks_) {
225 		if (sli.control_socket_ == socket) {
226 			for (auto const& lock : sli.locks_) {
227 				if (lock.waiting) {
228 					return true;
229 				}
230 			}
231 		}
232 	}
233 
234 	return false;
235 }
236