xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/ClientConnection.cpp (revision 56430ad8002b8fd1ac69b590e9cc130de6d9e852)
1 // ClientConnection.cpp
2 
3 #include "ClientConnection.h"
4 
5 #include <new>
6 #include <typeinfo>
7 
8 #include <dirent.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <utime.h>
14 
15 #include <AutoDeleter.h>
16 #include <AutoLocker.h>
17 #include <Entry.h>
18 #include <fs_query.h>
19 #include <GraphicsDefs.h>
20 #include <HashMap.h>
21 #include <NodeMonitor.h>
22 #include <Path.h>
23 #include <Rect.h>
24 #include <Mime.h>
25 
26 #include <fsproto.h>
27 
28 #include "Compatibility.h"
29 #include "Connection.h"
30 #include "DebugSupport.h"
31 #include "Directory.h"
32 #include "Entry.h"
33 #include "FDManager.h"
34 #include "NodeHandle.h"
35 #include "NodeHandleMap.h"
36 #include "NodeMonitoringEvent.h"
37 #include "Path.h"
38 #include "RequestBufferReplacer.h"
39 #include "RequestChannel.h"
40 #include "RequestConnection.h"
41 #include "RequestDumper.h"
42 #include "RequestFlattener.h"
43 #include "Requests.h"
44 #include "SecurityContext.h"
45 #include "ServerNodeID.h"
46 #include "UserSecurityContext.h"
47 #include "Utils.h"
48 #include "Volume.h"
49 #include "VolumeManager.h"
50 
51 static const int32 kMaxSaneReadLinkSize		= 10240;	// 10 KB
52 static const int32 kMaxReadBufferSize		= 10240;	// 10 KB
53 static const int32 kMaxReadDirBufferSize	= 10240;
54 
55 // Locking:
56 //
57 // fLock: Guards fReferenceCount and fClosed.
58 // fSecurityContextLock: Guards fSecurityContext.
59 // fVolumes: Guards the map itself.
60 
61 
62 // #pragma mark -
63 // #pragma mark ----- ClientConnection -----
64 
65 // ConnectionReference
66 class ClientConnection::ConnectionReference {
67 public:
68 	ConnectionReference(ClientConnection* connection)
69 		: fConnection(connection)
70 	{
71 		if (!fConnection || !fConnection->GetReference())
72 			fConnection = NULL;
73 	}
74 
75 	~ConnectionReference()
76 	{
77 		if (fConnection)
78 			fConnection->PutReference();
79 	}
80 
81 	bool IsValid() const
82 	{
83 		return fConnection;
84 	}
85 
86 private:
87 	ClientConnection*	fConnection;
88 };
89 
90 // VolumeMap
91 struct ClientConnection::VolumeMap
92 	: public SynchronizedHashMap<HashKey32<int32>, ClientVolume*> {
93 };
94 
95 // ClientVolumePutter
96 class ClientConnection::ClientVolumePutter {
97 public:
98 	ClientVolumePutter(ClientConnection* connection, ClientVolume* volume)
99 		: fConnection(connection),
100 		  fVolume(volume)
101 	{
102 	}
103 
104 	~ClientVolumePutter()
105 	{
106 		if (fConnection && fVolume)
107 			fConnection->_PutVolume(fVolume);
108 	}
109 
110 	void Detach()
111 	{
112 		fConnection = NULL;
113 		fVolume = NULL;
114 	}
115 
116 private:
117 	ClientConnection*	fConnection;
118 	ClientVolume*		fVolume;
119 };
120 
121 // VolumeNodeMonitoringEvent
122 struct ClientConnection::VolumeNodeMonitoringEvent {
123 	VolumeNodeMonitoringEvent(int32 volumeID, NodeMonitoringEvent* event)
124 		: volumeID(volumeID),
125 		  event(event)
126 	{
127 		if (event)
128 			event->AcquireReference();
129 	}
130 
131 	~VolumeNodeMonitoringEvent()
132 	{
133 		if (event)
134 			event->ReleaseReference();
135 	}
136 
137 	int32					volumeID;
138 	NodeMonitoringEvent*	event;
139 };
140 
141 // NodeMonitoringEventQueue
142 struct ClientConnection::NodeMonitoringEventQueue
143 	: BlockingQueue<NodeMonitoringRequest> {
144 	NodeMonitoringEventQueue()
145 		: BlockingQueue<NodeMonitoringRequest>("client NM requests")
146 	{
147 	}
148 };
149 
150 // QueryHandleUnlocker
151 struct ClientConnection::QueryHandleUnlocker {
152 	QueryHandleUnlocker(ClientConnection* connection, NodeHandle* nodeHandle)
153 		: fConnection(connection),
154 		  fHandle(nodeHandle)
155 	{
156 	}
157 
158 	~QueryHandleUnlocker()
159 	{
160 		if (fConnection && fHandle) {
161 			fConnection->_UnlockQueryHandle(fHandle);
162 			fConnection = NULL;
163 			fHandle = NULL;
164 		}
165 	}
166 
167 private:
168 	ClientConnection*	fConnection;
169 	NodeHandle*			fHandle;
170 };
171 
172 // ClientVolumeFilter
173 struct ClientConnection::ClientVolumeFilter {
174 	virtual ~ClientVolumeFilter() {}
175 
176 	virtual bool FilterVolume(ClientConnection* connection,
177 		ClientVolume* volume) = 0;
178 };
179 
180 // HasQueryPermissionClientVolumeFilter
181 struct ClientConnection::HasQueryPermissionClientVolumeFilter
182 	: ClientConnection::ClientVolumeFilter {
183 	virtual bool FilterVolume(ClientConnection* connection,
184 		ClientVolume* volume)
185 	{
186 		return volume->GetSharePermissions().ImpliesQuerySharePermission();
187 	}
188 };
189 
190 
191 // #pragma mark -
192 
193 // constructor
194 ClientConnection::ClientConnection(Connection* connection,
195 	SecurityContext* securityContext, User* user,
196 	ClientConnectionListener* listener)
197 	: RequestHandler(),
198 	  ClientVolume::NodeMonitoringProcessor(),
199 	  fConnection(NULL),
200 	  fSecurityContext(securityContext),
201 	  fSecurityContextLock("security context lock"),
202 	  fUser(user),
203 	  fVolumes(NULL),
204 	  fQueryHandles(NULL),
205 	  fListener(listener),
206 	  fNodeMonitoringEvents(NULL),
207 	  fNodeMonitoringProcessor(-1),
208 	  fLock("client connection locker"),
209 	  fReferenceCount(0),
210 	  fInitialized(0),
211 	  fClosed(false),
212 	  fError(false),
213 	  fInverseClientEndianess(false)
214 {
215 	fConnection = new(std::nothrow) RequestConnection(connection, this);
216 	if (!fConnection)
217 		delete connection;
218 }
219 
220 // destructor
221 ClientConnection::~ClientConnection()
222 {
223 	_Close();
224 	delete fConnection;
225 
226 	// delete all volumes
227 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();)
228 		delete it.Next().value;
229 	delete fVolumes;
230 
231 	delete fQueryHandles;
232 	delete fNodeMonitoringEvents;
233 }
234 
235 // Init
236 status_t
237 ClientConnection::Init()
238 {
239 	// create a client volume map
240 	fVolumes = new(std::nothrow) VolumeMap;
241 	if (!fVolumes)
242 		return B_NO_MEMORY;
243 	status_t error = fVolumes->InitCheck();
244 	if (error != B_OK)
245 		return error;
246 
247 	// create the query handle map
248 	fQueryHandles = new(std::nothrow) NodeHandleMap("query handles");
249 	if (!fQueryHandles)
250 		return B_NO_MEMORY;
251 	error = fQueryHandles->Init();
252 	if (error != B_OK)
253 		return error;
254 
255 	// create the node monitoring event queue
256 	fNodeMonitoringEvents = new(std::nothrow) NodeMonitoringEventQueue;
257 	if (!fNodeMonitoringEvents)
258 		return B_NO_MEMORY;
259 	error = fNodeMonitoringEvents->InitCheck();
260 	if (error != B_OK)
261 		return error;
262 
263 	// initialize the connection
264 	error = fConnection->Init();
265 	if (error != B_OK)
266 		return error;
267 
268 	// start the node monitoring processor
269 	fNodeMonitoringProcessor = spawn_thread(_NodeMonitoringProcessorEntry,
270 		"client connection NM processor", B_NORMAL_PRIORITY, this);
271 	if (fNodeMonitoringProcessor < 0) {
272 		_Close();
273 		return fNodeMonitoringProcessor;
274 	}
275 	resume_thread(fNodeMonitoringProcessor);
276 	return B_OK;
277 }
278 
279 // Close
280 /*!
281 	Called by the NetFSServer. Not for internal use. Waits for the connection
282 	to be closed (at least for the node monitoring thread to be gone).
283 */
284 void
285 ClientConnection::Close()
286 {
287 	{
288 		ConnectionReference connectionReference(this);
289 		if (connectionReference.IsValid())
290 			_MarkClosed(false);
291 		fListener = NULL;
292 	}
293 
294 	// Wait at least for the node monitoring processor; this is not perfect,
295 	// but not too bad either.
296 	if (fNodeMonitoringProcessor >= 0
297 		&& find_thread(NULL) != fNodeMonitoringProcessor) {
298 		int32 result;
299 		wait_for_thread(fNodeMonitoringProcessor, &result);
300 	}
301 }
302 
303 // GetReference
304 bool
305 ClientConnection::GetReference()
306 {
307 	AutoLocker<Locker> _(fLock);
308 	if (fClosed || !atomic_or(&fInitialized, 0))
309 		return false;
310 	fReferenceCount++;
311 	return true;
312 }
313 
314 // PutReference
315 void
316 ClientConnection::PutReference()
317 {
318 	bool close = false;
319 	{
320 		AutoLocker<Locker> _(fLock);
321 		--fReferenceCount;
322 		if (fClosed)
323 			close = (fReferenceCount == 0);
324 	}
325 	if (close)
326 		_Close();
327 }
328 
329 // UserRemoved
330 void
331 ClientConnection::UserRemoved(User* user)
332 {
333 	// get all volumes
334 	ClientVolume** volumes = NULL;
335 	int32 volumeCount = 0;
336 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
337 	volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()];
338 	if (!volumes) {
339 		ERROR(("ClientConnection::UserRemoved(): ERROR: Failed to "
340 			"allocate memory for volume array.\n"));
341 		volumesLocker.Unlock();
342 		_UnmountAllVolumes();
343 		return;
344 	}
345 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
346 		if (ClientVolume* volume = _GetVolume(it.Next().value->GetID()))
347 			volumes[volumeCount++] = volume;
348 	}
349 	volumesLocker.Unlock();
350 
351 	// unmount the concerned volumes
352 	for (int32 i = 0; i < volumeCount; i++) {
353 		ClientVolume* volume = volumes[i];
354 
355 		fSecurityContextLock.Lock();
356 		bool unmount = (volume->GetSecurityContext()->GetUser() == user);
357 		fSecurityContextLock.Unlock();
358 
359 		if (unmount)
360 			_UnmountVolume(volume);
361 	}
362 
363 	// put the volumes
364 	for (int32 i = 0; i < volumeCount; i++)
365 		_PutVolume(volumes[i]);
366 	delete[] volumes;
367 }
368 
369 // ShareRemoved
370 void
371 ClientConnection::ShareRemoved(Share* share)
372 {
373 	// get all volumes
374 	ClientVolume** volumes = NULL;
375 	int32 volumeCount = 0;
376 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
377 	volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()];
378 	if (!volumes) {
379 		ERROR(("ClientConnection::ShareRemoved(): ERROR: Failed to "
380 			"allocate memory for volume array.\n"));
381 		volumesLocker.Unlock();
382 		_UnmountAllVolumes();
383 		return;
384 	}
385 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
386 		if (ClientVolume* volume = _GetVolume(it.Next().value->GetID()))
387 			volumes[volumeCount++] = volume;
388 	}
389 	volumesLocker.Unlock();
390 
391 	// unmount the concerned volumes
392 	for (int32 i = 0; i < volumeCount; i++) {
393 		ClientVolume* volume = volumes[i];
394 
395 		fSecurityContextLock.Lock();
396 		bool unmount = (volume->GetShare() == share);
397 		fSecurityContextLock.Unlock();
398 
399 		if (unmount)
400 			_UnmountVolume(volume);
401 	}
402 
403 	// put the volumes
404 	for (int32 i = 0; i < volumeCount; i++)
405 		_PutVolume(volumes[i]);
406 	delete[] volumes;
407 }
408 
409 // UserPermissionsChanged
410 void
411 ClientConnection::UserPermissionsChanged(Share* share, User* user,
412 	Permissions permissions)
413 {
414 	bool unmountAll = (!permissions.ImpliesMountSharePermission());
415 
416 	// get all volumes
417 	ClientVolume** volumes = NULL;
418 	int32 volumeCount = 0;
419 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
420 	volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()];
421 	if (!volumes) {
422 		ERROR(("ClientConnection::ShareRemoved(): ERROR: Failed to "
423 			"allocate memory for volume array.\n"));
424 		volumesLocker.Unlock();
425 		_UnmountAllVolumes();
426 		return;
427 	}
428 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
429 		if (ClientVolume* volume = _GetVolume(it.Next().value->GetID()))
430 			volumes[volumeCount++] = volume;
431 	}
432 	volumesLocker.Unlock();
433 
434 	// update the concerned volumes
435 	for (int32 i = 0; i < volumeCount; i++) {
436 		ClientVolume* volume = volumes[i];
437 
438 		fSecurityContextLock.Lock();
439 		bool concerned = (volume->GetShare() == share
440 			&& volume->GetSecurityContext()->GetUser() == user);
441 		fSecurityContextLock.Unlock();
442 
443 		if (concerned) {
444 			// create a new user security context for the volume
445 			status_t error = B_OK;
446 
447 			if (unmountAll) {
448 				_UnmountVolume(volume);
449 			} else {
450 				// create a new user security context
451 				AutoLocker<Locker> securityContextLocker(fSecurityContextLock);
452 				UserSecurityContext* userSecurityContext
453 					= new(std::nothrow) UserSecurityContext;
454 
455 				// init it
456 				if (userSecurityContext) {
457 					error = fSecurityContext->GetUserSecurityContext(user,
458 						userSecurityContext);
459 				} else
460 					error = B_NO_MEMORY;
461 				if (error != B_OK) {
462 					delete userSecurityContext;
463 					securityContextLocker.Unlock();
464 					_UnmountVolume(volume);
465 					continue;
466 				}
467 
468 				// set the volume's new user security context
469 				securityContextLocker.Unlock();
470 				volume->SetSecurityContext(userSecurityContext);
471 			}
472 		}
473 	}
474 
475 	// put the volumes
476 	for (int32 i = 0; i < volumeCount; i++)
477 		_PutVolume(volumes[i]);
478 	delete[] volumes;
479 }
480 
481 
482 // #pragma mark -
483 
484 // VisitConnectionBrokenRequest
485 status_t
486 ClientConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request)
487 {
488 	ConnectionReference connectionReference(this);
489 	if (!connectionReference.IsValid())
490 		return B_OK;
491 
492 	_MarkClosed(true);
493 	return B_OK;
494 }
495 
496 // VisitInitConnectionRequest
497 status_t
498 ClientConnection::VisitInitConnectionRequest(InitConnectionRequest* request)
499 {
500 	bool alreadyInitialized = atomic_or(&fInitialized, ~0);
501 
502 	ConnectionReference connectionReference(this);
503 	if (!connectionReference.IsValid())
504 		return B_OK;
505 
506 	if (!alreadyInitialized)
507 		fInverseClientEndianess = (request->bigEndian != B_HOST_IS_BENDIAN);
508 
509 	// prepare the reply
510 	InitConnectionReply reply;
511 
512 	// send the reply
513 	reply.error = (alreadyInitialized ? B_BAD_VALUE : B_OK);
514 	status_t error = GetChannel()->SendRequest(&reply);
515 
516 	// on error just close
517 	if (error != B_OK)
518 		_MarkClosed(true);
519 	return B_OK;
520 }
521 
522 // VisitMountRequest
523 status_t
524 ClientConnection::VisitMountRequest(MountRequest* request)
525 {
526 	ConnectionReference connectionReference(this);
527 	if (!connectionReference.IsValid())
528 		return B_OK;
529 
530 	status_t result = B_OK;
531 	const char* shareName = request->share.GetString();
532 	if (!shareName)
533 		SET_ERROR(result, B_BAD_DATA);
534 
535 	// create a volume
536 	ClientVolume* volume = NULL;
537 	if (result == B_OK)
538 		result = _CreateVolume(&volume);
539 	ClientVolumePutter volumePutter(this, volume);
540 
541 	// if we haven't been supplied with a user yet, use the info from the
542 	// mount request for authentication
543 	VolumeManagerLocker managerLocker;
544 	AutoLocker<Locker> securityContextLocker(fSecurityContextLock);
545 	const char* userName = request->user.GetString();
546 	User* user = fUser;
547 	BReference<User> userReference(user);
548 	bool noPermission = false;
549 	if (result == B_OK && !user) {
550 		if (userName) {
551 			SET_ERROR(result, fSecurityContext->AuthenticateUser(userName,
552 				request->password.GetString(), &user));
553 			if (result == B_OK)
554 				userReference.SetTo(user, true);
555 		} else
556 			result = B_PERMISSION_DENIED;
557 		if (result == B_PERMISSION_DENIED)
558 			noPermission = true;
559 	}
560 
561 	// create a user security context
562 	UserSecurityContext* securityContext = NULL;
563 	if (result == B_OK) {
564 		securityContext = new(std::nothrow) UserSecurityContext;
565 		if (securityContext) {
566 			SET_ERROR(result, fSecurityContext->GetUserSecurityContext(user,
567 				securityContext));
568 		} else
569 			SET_ERROR(result, B_NO_MEMORY);
570 	}
571 	ObjectDeleter<UserSecurityContext> securityContextDeleter(securityContext);
572 
573 	// get the share
574 	Share* share = NULL;
575 	Permissions sharePermissions;
576 	node_ref mountPoint;
577 	if (result == B_OK) {
578 		AutoLocker<SecurityContext> _(fSecurityContext);
579 		share = fSecurityContext->FindShare(shareName);
580 		if (share) {
581 			mountPoint = share->GetNodeRef();
582 			sharePermissions = securityContext->GetNodePermissions(
583 				mountPoint);
584 			if (!sharePermissions.ImpliesMountSharePermission()) {
585 				SET_ERROR(result, B_PERMISSION_DENIED);
586 				noPermission = true;
587 			}
588 		} else
589 			SET_ERROR(result, B_ENTRY_NOT_FOUND);
590 	}
591 	BReference<Share> shareReference(share, true);
592 
593 	// mount the volume
594 	MountReply reply;
595 	if (result == B_OK) {
596 		SET_ERROR(result, volume->Mount(securityContext, share));
597 		securityContextDeleter.Detach();
598 	}
599 	if (result == B_OK) {
600 		_GetNodeInfo(volume->GetRootDirectory(), &reply.nodeInfo);
601 		reply.sharePermissions = sharePermissions.GetPermissions();
602 		reply.volumeID = volume->GetID();
603 	}
604 
605 	// make sure, the volume is removed on error
606 	if (result != B_OK && volume) {
607 		AutoLocker<VolumeMap> volumeMapLocker(fVolumes);
608 		volume->MarkRemoved();
609 	}
610 
611 	securityContextLocker.Unlock();
612 	managerLocker.Unlock();
613 
614 	// send the reply
615 	reply.error = result;
616 	reply.noPermission = noPermission;
617 	return GetChannel()->SendRequest(&reply);
618 }
619 
620 // VisitUnmountRequest
621 status_t
622 ClientConnection::VisitUnmountRequest(UnmountRequest* request)
623 {
624 	ConnectionReference connectionReference(this);
625 	if (!connectionReference.IsValid())
626 		return B_OK;
627 
628 	if (ClientVolume* volume = _GetVolume(request->volumeID)) {
629 		_UnmountVolume(volume);
630 		_PutVolume(volume);
631 	}
632 
633 	return B_OK;
634 }
635 
636 // VisitReadVNodeRequest
637 status_t
638 ClientConnection::VisitReadVNodeRequest(ReadVNodeRequest* request)
639 {
640 	ConnectionReference connectionReference(this);
641 	if (!connectionReference.IsValid())
642 		return B_OK;
643 
644 	// get the volume
645 	status_t result = B_OK;
646 	ClientVolume* volume = _GetVolume(request->volumeID);
647 	if (!volume)
648 		result = B_BAD_VALUE;
649 	ClientVolumePutter volumePutter(this, volume);
650 
651 	VolumeManagerLocker managerLocker;
652 
653 	// get the node
654 	Node* node = NULL;
655 	if (result == B_OK) {
656 		node = volume->GetNode(request->nodeID);
657 		if (!node)
658 			result = B_ENTRY_NOT_FOUND;
659 	}
660 
661 	// prepare the reply
662 	ReadVNodeReply reply;
663 	if (result == B_OK)
664 		_GetNodeInfo(node, &reply.nodeInfo);
665 
666 	managerLocker.Unlock();
667 
668 	// send the reply
669 	reply.error = result;
670 	return GetChannel()->SendRequest(&reply);
671 }
672 
673 // VisitWriteStatRequest
674 status_t
675 ClientConnection::VisitWriteStatRequest(WriteStatRequest* request)
676 {
677 	ConnectionReference connectionReference(this);
678 	if (!connectionReference.IsValid())
679 		return B_OK;
680 
681 	// get the volume
682 	status_t result = B_OK;
683 	ClientVolume* volume = _GetVolume(request->volumeID);
684 	if (!volume)
685 		result = B_BAD_VALUE;
686 	ClientVolumePutter volumePutter(this, volume);
687 
688 	VolumeManagerLocker managerLocker;
689 
690 	// get the node
691 	Node* node = NULL;
692 	if (result == B_OK) {
693 		node = volume->GetNode(request->nodeID);
694 		if (!node)
695 			result = B_ENTRY_NOT_FOUND;
696 	}
697 
698 	// check permissions
699 	if (result == B_OK) {
700 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
701 			result = B_PERMISSION_DENIED;
702 	}
703 
704 	// get the path
705 	Path path;
706 	if (result == B_OK)
707 		result = node->GetPath(&path);
708 
709 	// write the stat
710 	uint32 mask = request->mask;
711 	// size
712 	if (result == B_OK && (mask & WSTAT_SIZE)) {
713 		if (truncate(path.GetPath(), request->nodeInfo.st.st_size) < 0)
714 			result = errno;
715 	}
716 	// mode
717 	if (result == B_OK && (mask & WSTAT_MODE)) {
718 		if (chmod(path.GetPath(), request->nodeInfo.st.st_mode) < 0)
719 			result = errno;
720 	}
721 	// mtime
722 	if (result == B_OK && (mask & (WSTAT_ATIME | WSTAT_MTIME))) {
723 		utimbuf buffer;
724 		buffer.actime = (mask & WSTAT_ATIME)
725 			? request->nodeInfo.st.st_atime
726 			: node->GetStat().st_atime;
727 		buffer.modtime = (mask & WSTAT_MTIME)
728 			? request->nodeInfo.st.st_mtime
729 			: node->GetStat().st_mtime;
730 		if (utime(path.GetPath(), &buffer) < 0)
731 			result = errno;
732 	}
733 	// ignore WSTAT_CRTIME, WSTAT_UID, WSTAT_GID for the time being
734 
735 	// prepare the reply
736 	WriteStatReply reply;
737 	// update the node stat
738 	reply.nodeInfoValid = false;
739 	if (node) {
740 		if (node->UpdateStat() == B_OK) {
741 			_GetNodeInfo(node, &reply.nodeInfo);
742 			reply.nodeInfoValid = true;
743 		}
744 	}
745 
746 	managerLocker.Unlock();
747 
748 	// send the reply
749 	reply.error = result;
750 	return GetChannel()->SendRequest(&reply);
751 }
752 
753 // VisitCreateFileRequest
754 status_t
755 ClientConnection::VisitCreateFileRequest(CreateFileRequest* request)
756 {
757 	ConnectionReference connectionReference(this);
758 	if (!connectionReference.IsValid())
759 		return B_OK;
760 
761 	// get the volume
762 	status_t result = B_OK;
763 	ClientVolume* volume = _GetVolume(request->volumeID);
764 	if (!volume)
765 		result = B_BAD_VALUE;
766 	ClientVolumePutter volumePutter(this, volume);
767 
768 	VolumeManagerLocker managerLocker;
769 
770 	// get the directory
771 	Directory* directory = NULL;
772 	if (result == B_OK) {
773 		Node* node = volume->GetNode(request->directoryID);
774 		if (node) {
775 			directory = dynamic_cast<Directory*>(node);
776 			if (!directory)
777 				result = B_NOT_A_DIRECTORY;
778 		} else
779 			result = B_ENTRY_NOT_FOUND;
780 	}
781 
782 	// check permissions
783 	int openMode = request->openMode;
784 	if (result == B_OK) {
785 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
786 			result = B_PERMISSION_DENIED;
787 	}
788 
789 	// get the path
790 	Path path;
791 	if (result == B_OK) {
792 		result = directory->GetPath(&path);
793 		if (result == B_OK)
794 			result = path.Append(request->name.GetString());
795 	}
796 
797 	// create the file
798 	if (result == B_OK) {
799 		int fd = -1;
800 		result = FDManager::Open(path.GetPath(),
801 			openMode | O_CREAT | O_NOTRAVERSE, request->mode, fd);
802 		if (result == B_OK)
803 			close(fd);
804 	}
805 
806 	// load the new entry
807 	Entry* entry = NULL;
808 	if (result == B_OK) {
809 		VolumeManager* volumeManager = VolumeManager::GetDefault();
810 
811 		// if there existed an entry before, we need to delete it, to avoid that
812 		// we open the wrong node
813 		entry = volumeManager->GetEntry(directory->GetVolumeID(),
814 			directory->GetID(), request->name.GetString());
815 		if (entry)
816 			volumeManager->DeleteEntry(entry, false);
817 
818 		// load the new entry
819 		entry = NULL;
820 		result = volume->LoadEntry(directory, request->name.GetString(),
821 			&entry);
822 	}
823 
824 	// open the node
825 	FileHandle* handle = NULL;
826 	if (result == B_OK) {
827 		openMode &= ~(O_CREAT | O_EXCL | O_TRUNC);
828 		result = volume->Open(entry->GetNode(), openMode, &handle);
829 	}
830 	NodeHandleUnlocker handleUnlocker(volume, handle);
831 
832 	// prepare the reply
833 	CreateFileReply reply;
834 	if (result == B_OK) {
835 		_GetEntryInfo(entry, &reply.entryInfo);
836 		reply.cookie = handle->GetCookie();
837 	}
838 
839 	managerLocker.Unlock();
840 
841 	// send the reply
842 	reply.error = result;
843 	status_t error = GetChannel()->SendRequest(&reply);
844 
845 	// close the handle, if a send error occurred
846 	if (error != B_OK && result == B_OK)
847 		volume->Close(handle);
848 
849 	return error;
850 }
851 
852 // VisitOpenRequest
853 status_t
854 ClientConnection::VisitOpenRequest(OpenRequest* request)
855 {
856 	ConnectionReference connectionReference(this);
857 	if (!connectionReference.IsValid())
858 		return B_OK;
859 
860 	// get the volume
861 	status_t result = B_OK;
862 	ClientVolume* volume = _GetVolume(request->volumeID);
863 	if (!volume)
864 		result = B_BAD_VALUE;
865 	ClientVolumePutter volumePutter(this, volume);
866 
867 	VolumeManagerLocker managerLocker;
868 
869 	// get the node
870 	Node* node = NULL;
871 	if (result == B_OK) {
872 		node = volume->GetNode(request->nodeID);
873 		if (!node)
874 			result = B_ENTRY_NOT_FOUND;
875 	}
876 
877 	// check permissions
878 	int openMode = request->openMode;
879 	if (result == B_OK) {
880 		Permissions permissions = volume->GetNodePermissions(node);
881 		if ((openMode & O_RWMASK) == O_RDWR) {
882 			// read+write: fall back to read/write only, if the other permission
883 			// is missing
884 			if (!permissions.ImpliesReadPermission())
885 				openMode = (openMode & ~O_RWMASK) | O_WRONLY;
886 			else if (!permissions.ImpliesWritePermission())
887 				openMode = (openMode & ~O_RWMASK) | O_RDONLY;
888 		}
889 		if ((openMode & O_RWMASK) == O_RDONLY) {
890 			if (!permissions.ImpliesReadPermission())
891 				result = B_PERMISSION_DENIED;
892 		} else if ((openMode & O_RWMASK) == O_WRONLY) {
893 			if (!permissions.ImpliesWritePermission())
894 				result = B_PERMISSION_DENIED;
895 		}
896 	}
897 
898 	// open the node
899 	FileHandle* handle = NULL;
900 	if (result == B_OK)
901 		result = volume->Open(node, openMode, &handle);
902 	NodeHandleUnlocker handleUnlocker(volume, handle);
903 
904 	// prepare the reply
905 	OpenReply reply;
906 	if (result == B_OK) {
907 		_GetNodeInfo(node, &reply.nodeInfo);
908 		reply.cookie = handle->GetCookie();
909 	}
910 
911 	managerLocker.Unlock();
912 
913 	// send the reply
914 	reply.error = result;
915 	status_t error = GetChannel()->SendRequest(&reply);
916 
917 	// close the handle, if a send error occurred
918 	if (error != B_OK && result == B_OK)
919 		volume->Close(handle);
920 
921 	return error;
922 }
923 
924 // VisitCloseRequest
925 status_t
926 ClientConnection::VisitCloseRequest(CloseRequest* request)
927 {
928 	ConnectionReference connectionReference(this);
929 	if (!connectionReference.IsValid())
930 		return B_OK;
931 
932 	status_t result = B_OK;
933 
934 	if (request->volumeID >= 0) {
935 		// get the volume
936 		ClientVolume* volume = _GetVolume(request->volumeID);
937 		if (!volume)
938 			SET_ERROR(result, B_BAD_VALUE);
939 		ClientVolumePutter volumePutter(this, volume);
940 
941 		// get the node handle
942 		NodeHandle* handle = NULL;
943 		if (result == B_OK)
944 			SET_ERROR(result, volume->LockNodeHandle(request->cookie, &handle));
945 		NodeHandleUnlocker handleUnlocker(volume, handle);
946 
947 		VolumeManagerLocker managerLocker;
948 
949 		// close it
950 		if (result == B_OK)
951 			SET_ERROR(result, volume->Close(handle));
952 
953 		managerLocker.Unlock();
954 	} else {
955 		// no volume ID given, so this is a query handle
956 		// lock the handle
957 		QueryHandle* handle = NULL;
958 		if (result == B_OK)
959 			SET_ERROR(result, _LockQueryHandle(request->cookie, &handle));
960 		QueryHandleUnlocker handleUnlocker(this, handle);
961 
962 		// close it
963 		if (result == B_OK)
964 			SET_ERROR(result, _CloseQuery(handle));
965 	}
966 
967 	// send the reply
968 	CloseReply reply;
969 	reply.error = result;
970 	return GetChannel()->SendRequest(&reply);
971 }
972 
973 // VisitReadRequest
974 status_t
975 ClientConnection::VisitReadRequest(ReadRequest* request)
976 {
977 	ConnectionReference connectionReference(this);
978 	if (!connectionReference.IsValid())
979 		return B_OK;
980 
981 	// get the volume
982 	status_t result = B_OK;
983 	ClientVolume* volume = _GetVolume(request->volumeID);
984 	if (!volume)
985 		result = B_BAD_VALUE;
986 	ClientVolumePutter volumePutter(this, volume);
987 
988 	// get the node handle
989 	NodeHandle* handle = NULL;
990 	if (result == B_OK)
991 		result = volume->LockNodeHandle(request->cookie, &handle);
992 	NodeHandleUnlocker handleUnlocker(volume, handle);
993 
994 	// check if it is a file handle
995 	FileHandle* fileHandle = NULL;
996 	if (result == B_OK) {
997 		fileHandle = dynamic_cast<FileHandle*>(handle);
998 		if (!fileHandle)
999 			result = B_BAD_VALUE;
1000 	}
1001 
1002 	VolumeManagerLocker managerLocker;
1003 
1004 	// check read permission
1005 	if (result == B_OK) {
1006 		Node* node = volume->GetNode(fileHandle->GetNodeRef());
1007 		if (!node || !volume->GetNodePermissions(node).ImpliesReadPermission())
1008 			result = B_PERMISSION_DENIED;
1009 	}
1010 
1011 	managerLocker.Unlock();
1012 
1013 	off_t pos = request->pos;
1014 	int32 size = request->size;
1015 	int32 bufferSize = min(size, kMaxReadBufferSize);
1016 	// allocate a buffer
1017 	uint8* buffer = NULL;
1018 	if (result == B_OK) {
1019 		buffer = (uint8*)malloc(bufferSize);
1020 		if (!buffer)
1021 			result = B_NO_MEMORY;
1022 	}
1023 	MemoryDeleter bufferDeleter(buffer);
1024 
1025 	// read as long as there are bytes left to read or an error occurs
1026 	bool moreToRead = true;
1027 	do {
1028 		int32 bytesToRead = min(size, bufferSize);
1029 		size_t bytesRead = 0;
1030 		if (result == B_OK)
1031 			result = fileHandle->Read(pos, buffer, bytesToRead, &bytesRead);
1032 		moreToRead = (result == B_OK && bytesRead > 0
1033 			&& (int32)bytesRead < size);
1034 
1035 		// prepare the reply
1036 		ReadReply reply;
1037 		if (result == B_OK) {
1038 			reply.pos = pos;
1039 			reply.data.SetTo(buffer, bytesRead);
1040 			reply.moreToCome = moreToRead;
1041 			pos += bytesRead;
1042 			size -= bytesRead;
1043 		}
1044 
1045 		// send the reply
1046 		reply.error = result;
1047 		status_t error = GetChannel()->SendRequest(&reply);
1048 		if (error != B_OK)
1049 			return error;
1050 	} while (moreToRead);
1051 
1052 	return B_OK;
1053 }
1054 
1055 // VisitWriteRequest
1056 status_t
1057 ClientConnection::VisitWriteRequest(WriteRequest* request)
1058 {
1059 	ConnectionReference connectionReference(this);
1060 	if (!connectionReference.IsValid())
1061 		return B_OK;
1062 
1063 	// get the volume
1064 	status_t result = B_OK;
1065 	ClientVolume* volume = _GetVolume(request->volumeID);
1066 	if (!volume)
1067 		result = B_BAD_VALUE;
1068 	ClientVolumePutter volumePutter(this, volume);
1069 
1070 	// get the node handle
1071 	NodeHandle* handle = NULL;
1072 	if (result == B_OK)
1073 		result = volume->LockNodeHandle(request->cookie, &handle);
1074 	NodeHandleUnlocker handleUnlocker(volume, handle);
1075 
1076 	// check if it is a file handle
1077 	FileHandle* fileHandle = NULL;
1078 	if (result == B_OK) {
1079 		fileHandle = dynamic_cast<FileHandle*>(handle);
1080 		if (!fileHandle)
1081 			result = B_BAD_VALUE;
1082 	}
1083 
1084 	VolumeManagerLocker managerLocker;
1085 
1086 	// check read permission
1087 	if (result == B_OK) {
1088 		Node* node = volume->GetNode(fileHandle->GetNodeRef());
1089 		if (!node || !volume->GetNodePermissions(node).ImpliesWritePermission())
1090 			result = B_PERMISSION_DENIED;
1091 	}
1092 
1093 	managerLocker.Unlock();
1094 
1095 	// write until all has been written or an error occurs
1096 	off_t pos = request->pos;
1097 	int32 size = request->data.GetSize();
1098 	const char* buffer = (const char*)request->data.GetData();
1099 	while (result == B_OK && size > 0) {
1100 		size_t bytesWritten;
1101 		result = fileHandle->Write(pos, buffer, size, &bytesWritten);
1102 		if (result == B_OK) {
1103 			pos += bytesWritten;
1104 			buffer += bytesWritten;
1105 			size -= bytesWritten;
1106 		}
1107 	}
1108 
1109 	// prepare the reply
1110 	WriteReply reply;
1111 	// send the reply
1112 	reply.error = result;
1113 	return GetChannel()->SendRequest(&reply);
1114 }
1115 
1116 // VisitCreateLinkRequest
1117 status_t
1118 ClientConnection::VisitCreateLinkRequest(CreateLinkRequest* request)
1119 {
1120 	ConnectionReference connectionReference(this);
1121 	if (!connectionReference.IsValid())
1122 		return B_OK;
1123 
1124 	// get the volume
1125 	status_t result = B_OK;
1126 	ClientVolume* volume = _GetVolume(request->volumeID);
1127 	if (!volume)
1128 		result = B_BAD_VALUE;
1129 	ClientVolumePutter volumePutter(this, volume);
1130 
1131 	VolumeManagerLocker managerLocker;
1132 
1133 	// get the target node
1134 	Node* node = NULL;
1135 	if (result == B_OK) {
1136 		node = volume->GetNode(request->nodeID);
1137 		if (!node)
1138 			result = B_ENTRY_NOT_FOUND;
1139 	}
1140 
1141 	// get the target node path
1142 	Path targetPath;
1143 	if (result == B_OK)
1144 		result = node->GetPath(&targetPath);
1145 
1146 	// get the directory
1147 	Directory* directory = NULL;
1148 	if (result == B_OK) {
1149 		Node* node = volume->GetNode(request->directoryID);
1150 		if (node) {
1151 			directory = dynamic_cast<Directory*>(node);
1152 			if (!directory)
1153 				result = B_NOT_A_DIRECTORY;
1154 		} else
1155 			result = B_ENTRY_NOT_FOUND;
1156 	}
1157 
1158 	// check permissions
1159 	if (result == B_OK) {
1160 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1161 			result = B_PERMISSION_DENIED;
1162 	}
1163 
1164 	// get the new entry's path
1165 	Path path;
1166 	if (result == B_OK) {
1167 		result = directory->GetPath(&path);
1168 		if (result == B_OK)
1169 			result = path.Append(request->name.GetString());
1170 	}
1171 
1172 	managerLocker.Unlock();
1173 
1174 	// create the link
1175 	if (result == B_OK) {
1176 		if (link(targetPath.GetPath(), path.GetPath()) < 0)
1177 			result = errno;
1178 	}
1179 
1180 	// prepare the reply
1181 	CreateSymlinkReply reply;
1182 	// send the reply
1183 	reply.error = result;
1184 	return GetChannel()->SendRequest(&reply);
1185 }
1186 
1187 // VisitUnlinkRequest
1188 status_t
1189 ClientConnection::VisitUnlinkRequest(UnlinkRequest* request)
1190 {
1191 	ConnectionReference connectionReference(this);
1192 	if (!connectionReference.IsValid())
1193 		return B_OK;
1194 
1195 	// get the volume
1196 	status_t result = B_OK;
1197 	ClientVolume* volume = _GetVolume(request->volumeID);
1198 	if (!volume)
1199 		result = B_BAD_VALUE;
1200 	ClientVolumePutter volumePutter(this, volume);
1201 
1202 	VolumeManagerLocker managerLocker;
1203 
1204 	// get the directory
1205 	Directory* directory = NULL;
1206 	if (result == B_OK) {
1207 		Node* node = volume->GetNode(request->directoryID);
1208 		if (node) {
1209 			directory = dynamic_cast<Directory*>(node);
1210 			if (!directory)
1211 				result = B_NOT_A_DIRECTORY;
1212 		} else
1213 			result = B_ENTRY_NOT_FOUND;
1214 	}
1215 
1216 	// check permissions
1217 	if (result == B_OK) {
1218 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1219 			result = B_PERMISSION_DENIED;
1220 	}
1221 
1222 	// get the entry's path
1223 	Path path;
1224 	if (result == B_OK) {
1225 		result = directory->GetPath(&path);
1226 		if (result == B_OK)
1227 			result = path.Append(request->name.GetString());
1228 	}
1229 
1230 	managerLocker.Unlock();
1231 
1232 	// remove the entry
1233 	if (result == B_OK) {
1234 		if (unlink(path.GetPath()) < 0)
1235 			result = errno;
1236 	}
1237 
1238 	// prepare the reply
1239 	UnlinkReply reply;
1240 	// send the reply
1241 	reply.error = result;
1242 	return GetChannel()->SendRequest(&reply);
1243 }
1244 
1245 // VisitCreateSymlinkRequest
1246 status_t
1247 ClientConnection::VisitCreateSymlinkRequest(CreateSymlinkRequest* request)
1248 {
1249 	ConnectionReference connectionReference(this);
1250 	if (!connectionReference.IsValid())
1251 		return B_OK;
1252 
1253 	// get the volume
1254 	status_t result = B_OK;
1255 	ClientVolume* volume = _GetVolume(request->volumeID);
1256 	if (!volume)
1257 		result = B_BAD_VALUE;
1258 	ClientVolumePutter volumePutter(this, volume);
1259 
1260 	VolumeManagerLocker managerLocker;
1261 
1262 	// get the directory
1263 	Directory* directory = NULL;
1264 	if (result == B_OK) {
1265 		Node* node = volume->GetNode(request->directoryID);
1266 		if (node) {
1267 			directory = dynamic_cast<Directory*>(node);
1268 			if (!directory)
1269 				result = B_NOT_A_DIRECTORY;
1270 		} else
1271 			result = B_ENTRY_NOT_FOUND;
1272 	}
1273 
1274 	// check permissions
1275 	if (result == B_OK) {
1276 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1277 			result = B_PERMISSION_DENIED;
1278 	}
1279 
1280 	// get the new entry's path
1281 	Path path;
1282 	if (result == B_OK) {
1283 		result = directory->GetPath(&path);
1284 		if (result == B_OK)
1285 			result = path.Append(request->name.GetString());
1286 	}
1287 
1288 	managerLocker.Unlock();
1289 
1290 	// create the symlink
1291 	if (result == B_OK) {
1292 		if (symlink(request->target.GetString(), path.GetPath()) < 0)
1293 			result = errno;
1294 	}
1295 
1296 	// prepare the reply
1297 	CreateSymlinkReply reply;
1298 	// send the reply
1299 	reply.error = result;
1300 	return GetChannel()->SendRequest(&reply);
1301 }
1302 
1303 // VisitReadLinkRequest
1304 status_t
1305 ClientConnection::VisitReadLinkRequest(ReadLinkRequest* request)
1306 {
1307 	ConnectionReference connectionReference(this);
1308 	if (!connectionReference.IsValid())
1309 		return B_OK;
1310 
1311 	// get the volume
1312 	status_t result = B_OK;
1313 	ClientVolume* volume = _GetVolume(request->volumeID);
1314 	if (!volume)
1315 		result = B_BAD_VALUE;
1316 	ClientVolumePutter volumePutter(this, volume);
1317 
1318 	VolumeManagerLocker managerLocker;
1319 
1320 	// get the node
1321 	Node* node = NULL;
1322 	if (result == B_OK) {
1323 		node = volume->GetNode(request->nodeID);
1324 		if (!node)
1325 			result = B_ENTRY_NOT_FOUND;
1326 	}
1327 
1328 	int32 bufferSize = request->maxSize;
1329 
1330 	// check read permission
1331 	if (result == B_OK) {
1332 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1333 			result = B_PERMISSION_DENIED;
1334 	}
1335 
1336 	// allocate a buffer
1337 	void* buffer = NULL;
1338 	if (result == B_OK) {
1339 		if (bufferSize < 0 || bufferSize > kMaxSaneReadLinkSize)
1340 			result = B_BAD_DATA;
1341 	}
1342 	if (result == B_OK) {
1343 		buffer = malloc(bufferSize);
1344 		if (!buffer)
1345 			result = B_NO_MEMORY;
1346 	}
1347 	MemoryDeleter bufferDeleter(buffer);
1348 
1349 	// read the link and prepare the reply
1350 	ReadLinkReply reply;
1351 	int32 bytesRead = 0;
1352 	if (result == B_OK)
1353 		result = node->ReadSymlink((char*)buffer, bufferSize, &bytesRead);
1354 	if (result == B_OK) {
1355 		reply.data.SetTo(buffer, bytesRead);
1356 		_GetNodeInfo(node, &reply.nodeInfo);
1357 	}
1358 
1359 	managerLocker.Unlock();
1360 
1361 	// send the reply
1362 	reply.error = result;
1363 	return GetChannel()->SendRequest(&reply);
1364 }
1365 
1366 // VisitRenameRequest
1367 status_t
1368 ClientConnection::VisitRenameRequest(RenameRequest* request)
1369 {
1370 	ConnectionReference connectionReference(this);
1371 	if (!connectionReference.IsValid())
1372 		return B_OK;
1373 
1374 	// get the volume
1375 	status_t result = B_OK;
1376 	ClientVolume* volume = _GetVolume(request->volumeID);
1377 	if (!volume)
1378 		result = B_BAD_VALUE;
1379 	ClientVolumePutter volumePutter(this, volume);
1380 
1381 	VolumeManagerLocker managerLocker;
1382 
1383 	// get the new directory
1384 	Directory* newDirectory = NULL;
1385 	if (result == B_OK) {
1386 		Node* node = volume->GetNode(request->newDirectoryID);
1387 		if (node) {
1388 			newDirectory = dynamic_cast<Directory*>(node);
1389 			if (!newDirectory)
1390 				result = B_NOT_A_DIRECTORY;
1391 		} else
1392 			result = B_ENTRY_NOT_FOUND;
1393 	}
1394 
1395 	// check permissions
1396 	if (result == B_OK) {
1397 		if (!volume->GetNodePermissions(newDirectory).ImpliesWritePermission())
1398 			result = B_PERMISSION_DENIED;
1399 	}
1400 
1401 	// get the new path
1402 	Path newPath;
1403 	if (result == B_OK) {
1404 		result = newDirectory->GetPath(&newPath);
1405 		if (result == B_OK)
1406 			result = newPath.Append(request->newName.GetString());
1407 	}
1408 
1409 	// get the old directory
1410 	Directory* oldDirectory = NULL;
1411 	if (result == B_OK) {
1412 		Node* node = volume->GetNode(request->oldDirectoryID);
1413 		if (node) {
1414 			oldDirectory = dynamic_cast<Directory*>(node);
1415 			if (!oldDirectory)
1416 				result = B_NOT_A_DIRECTORY;
1417 		} else
1418 			result = B_ENTRY_NOT_FOUND;
1419 	}
1420 
1421 	// check permissions
1422 	if (result == B_OK) {
1423 		if (!volume->GetNodePermissions(oldDirectory).ImpliesWritePermission())
1424 			result = B_PERMISSION_DENIED;
1425 	}
1426 
1427 	// get the new path
1428 	Path oldPath;
1429 	if (result == B_OK) {
1430 		result = oldDirectory->GetPath(&oldPath);
1431 		if (result == B_OK)
1432 			result = oldPath.Append(request->oldName.GetString());
1433 	}
1434 
1435 	managerLocker.Unlock();
1436 
1437 	// rename the entry
1438 	if (result == B_OK) {
1439 		if (rename(oldPath.GetPath(), newPath.GetPath()) < 0)
1440 			result = errno;
1441 	}
1442 
1443 	// prepare the reply
1444 	RenameReply reply;
1445 	// send the reply
1446 	reply.error = result;
1447 	return GetChannel()->SendRequest(&reply);
1448 }
1449 
1450 // VisitMakeDirRequest
1451 status_t
1452 ClientConnection::VisitMakeDirRequest(MakeDirRequest* request)
1453 {
1454 	ConnectionReference connectionReference(this);
1455 	if (!connectionReference.IsValid())
1456 		return B_OK;
1457 
1458 	// get the volume
1459 	status_t result = B_OK;
1460 	ClientVolume* volume = _GetVolume(request->volumeID);
1461 	if (!volume)
1462 		result = B_BAD_VALUE;
1463 	ClientVolumePutter volumePutter(this, volume);
1464 
1465 	VolumeManagerLocker managerLocker;
1466 
1467 	// get the directory
1468 	Directory* directory = NULL;
1469 	if (result == B_OK) {
1470 		Node* node = volume->GetNode(request->directoryID);
1471 		if (node) {
1472 			directory = dynamic_cast<Directory*>(node);
1473 			if (!directory)
1474 				result = B_NOT_A_DIRECTORY;
1475 		} else
1476 			result = B_ENTRY_NOT_FOUND;
1477 	}
1478 
1479 	// check permissions
1480 	if (result == B_OK) {
1481 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1482 			result = B_PERMISSION_DENIED;
1483 	}
1484 
1485 	// get the path
1486 	Path path;
1487 	if (result == B_OK) {
1488 		result = directory->GetPath(&path);
1489 		if (result == B_OK)
1490 			result = path.Append(request->name.GetString());
1491 	}
1492 
1493 	managerLocker.Unlock();
1494 
1495 	// create the directory
1496 	if (result == B_OK) {
1497 		if (mkdir(path.GetPath(), request->mode) < 0)
1498 			result = errno;
1499 	}
1500 
1501 	// prepare the reply
1502 	MakeDirReply reply;
1503 	// send the reply
1504 	reply.error = result;
1505 	return GetChannel()->SendRequest(&reply);
1506 }
1507 
1508 // VisitRemoveDirRequest
1509 status_t
1510 ClientConnection::VisitRemoveDirRequest(RemoveDirRequest* request)
1511 {
1512 	ConnectionReference connectionReference(this);
1513 	if (!connectionReference.IsValid())
1514 		return B_OK;
1515 
1516 	// get the volume
1517 	status_t result = B_OK;
1518 	ClientVolume* volume = _GetVolume(request->volumeID);
1519 	if (!volume)
1520 		result = B_BAD_VALUE;
1521 	ClientVolumePutter volumePutter(this, volume);
1522 
1523 	VolumeManagerLocker managerLocker;
1524 
1525 	// get the directory
1526 	Directory* directory = NULL;
1527 	if (result == B_OK) {
1528 		Node* node = volume->GetNode(request->directoryID);
1529 		if (node) {
1530 			directory = dynamic_cast<Directory*>(node);
1531 			if (!directory)
1532 				result = B_NOT_A_DIRECTORY;
1533 		} else
1534 			result = B_ENTRY_NOT_FOUND;
1535 	}
1536 
1537 	// check permissions
1538 	if (result == B_OK) {
1539 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1540 			result = B_PERMISSION_DENIED;
1541 	}
1542 
1543 	// get the path
1544 	Path path;
1545 	if (result == B_OK) {
1546 		result = directory->GetPath(&path);
1547 		if (result == B_OK)
1548 			result = path.Append(request->name.GetString());
1549 	}
1550 
1551 	managerLocker.Unlock();
1552 
1553 	// remove the directory
1554 	if (result == B_OK) {
1555 		if (rmdir(path.GetPath()) < 0)
1556 			result = errno;
1557 	}
1558 
1559 	// prepare the reply
1560 	RemoveDirReply reply;
1561 	// send the reply
1562 	reply.error = result;
1563 	return GetChannel()->SendRequest(&reply);
1564 }
1565 
1566 // VisitOpenDirRequest
1567 status_t
1568 ClientConnection::VisitOpenDirRequest(OpenDirRequest* request)
1569 {
1570 	ConnectionReference connectionReference(this);
1571 	if (!connectionReference.IsValid())
1572 		return B_OK;
1573 
1574 	// get the volume
1575 	status_t result = B_OK;
1576 	ClientVolume* volume = _GetVolume(request->volumeID);
1577 	if (!volume)
1578 		result = B_BAD_VALUE;
1579 	ClientVolumePutter volumePutter(this, volume);
1580 
1581 	VolumeManagerLocker managerLocker;
1582 
1583 	// get the directory
1584 	Directory* directory = NULL;
1585 	if (result == B_OK) {
1586 		Node* node = volume->GetNode(request->nodeID);
1587 		if (node) {
1588 			directory = dynamic_cast<Directory*>(node);
1589 			if (!directory)
1590 				result = B_NOT_A_DIRECTORY;
1591 		} else
1592 			result = B_ENTRY_NOT_FOUND;
1593 	}
1594 
1595 	// check permission
1596 	if (result == B_OK) {
1597 		if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission())
1598 			result = B_PERMISSION_DENIED;
1599 	}
1600 
1601 	// open the directory
1602 	DirIterator* handle = NULL;
1603 	if (result == B_OK)
1604 		result = volume->OpenDir(directory, &handle);
1605 	NodeHandleUnlocker handleUnlocker(volume, handle);
1606 
1607 	// prepare the reply
1608 	OpenDirReply reply;
1609 	if (result == B_OK) {
1610 		_GetNodeInfo(directory, &reply.nodeInfo);
1611 		reply.cookie = handle->GetCookie();
1612 	}
1613 else {
1614 if (directory)
1615 PRINT("OpenDir() failed: client volume: %ld, node: (%ld, %lld)\n",
1616 volume->GetID(), directory->GetVolumeID(), directory->GetID());
1617 }
1618 
1619 	managerLocker.Unlock();
1620 
1621 	// send the reply
1622 	reply.error = result;
1623 	status_t error = GetChannel()->SendRequest(&reply);
1624 
1625 	// close the handle, if a send error occurred
1626 	if (error != B_OK && result == B_OK)
1627 		volume->Close(handle);
1628 
1629 	return error;
1630 }
1631 
1632 // VisitReadDirRequest
1633 status_t
1634 ClientConnection::VisitReadDirRequest(ReadDirRequest* request)
1635 {
1636 	ConnectionReference connectionReference(this);
1637 	if (!connectionReference.IsValid())
1638 		return B_OK;
1639 
1640 	// get the volume
1641 	status_t result = B_OK;
1642 	ClientVolume* volume = _GetVolume(request->volumeID);
1643 	if (!volume)
1644 		result = B_BAD_VALUE;
1645 	ClientVolumePutter volumePutter(this, volume);
1646 
1647 	// get the node handle
1648 	NodeHandle* handle = NULL;
1649 	if (result == B_OK)
1650 		result = volume->LockNodeHandle(request->cookie, &handle);
1651 	NodeHandleUnlocker handleUnlocker(volume, handle);
1652 
1653 	// check if it is a directory iterator
1654 	DirIterator* iterator = NULL;
1655 	if (result == B_OK) {
1656 		iterator = dynamic_cast<DirIterator*>(handle);
1657 		if (!iterator)
1658 			result = B_BAD_VALUE;
1659 	}
1660 
1661 	VolumeManagerLocker managerLocker;
1662 
1663 	// get the directory
1664 	Directory* directory = NULL;
1665 	if (result == B_OK) {
1666 		Node* node = volume->GetNode(iterator->GetNodeRef());
1667 		if (node) {
1668 			directory = dynamic_cast<Directory*>(node);
1669 			if (!directory)
1670 				result = B_NOT_A_DIRECTORY;
1671 		} else
1672 			result = B_ENTRY_NOT_FOUND;
1673 	}
1674 
1675 	// check read permission
1676 	if (result == B_OK) {
1677 		if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission())
1678 			result = B_PERMISSION_DENIED;
1679 	}
1680 
1681 if (result == B_OK) {
1682 	PRINT("ReadDir: (%ld, %lld)\n", request->volumeID, directory->GetID());
1683 }
1684 
1685 	// rewind, if requested
1686 	if (result == B_OK && request->rewind)
1687 		iterator->Rewind();
1688 
1689 	// read the directory
1690 	bool done = false;
1691 	ReadDirReply reply;
1692 	int32 toRead = request->count;
1693 	while (result == B_OK && toRead > 0) {
1694 		// get the next entry
1695 		Entry* entry = iterator->NextEntry();
1696 		if (!entry) {
1697 			done = true;
1698 			break;
1699 		}
1700 
1701 		// get and add an entry info
1702 		EntryInfo entryInfo;
1703 		_GetEntryInfo(entry, &entryInfo);
1704 		result = reply.entryInfos.Append(entryInfo);
1705 
1706 		toRead--;
1707 	}
1708 
1709 	reply.revision = VolumeManager::GetDefault()->GetRevision();
1710 
1711 //PRINT(("ReadDir: (%lld) -> (%lx, %ld, dir: %lld, node: %lld, `%s')\n",
1712 //directoryID, reply.error, reply.entryInfos.CountElements(),
1713 //reply.entryInfo.directoryID,
1714 //reply.entryInfo.nodeID, reply.entryInfo.name.GetString()));
1715 if (directory) {
1716 PRINT("ReadDir done: volume: %ld, (%ld, %lld) -> (%lx, %ld)\n",
1717 volume->GetID(), directory->GetVolumeID(), directory->GetID(), result,
1718 reply.entryInfos.CountElements());
1719 }
1720 
1721 	managerLocker.Unlock();
1722 
1723 	// send the reply
1724 	reply.error = result;
1725 	reply.done = (result != B_OK || done);
1726 	return GetChannel()->SendRequest(&reply);
1727 }
1728 
1729 // VisitWalkRequest
1730 status_t
1731 ClientConnection::VisitWalkRequest(WalkRequest* request)
1732 {
1733 	ConnectionReference connectionReference(this);
1734 	if (!connectionReference.IsValid())
1735 		return B_OK;
1736 
1737 	// get the volume
1738 	status_t result = B_OK;
1739 	ClientVolume* volume = _GetVolume(request->volumeID);
1740 	if (!volume)
1741 		result = B_BAD_VALUE;
1742 	ClientVolumePutter volumePutter(this, volume);
1743 
1744 	VolumeManagerLocker managerLocker;
1745 
1746 	// get the directory
1747 	Directory* directory = NULL;
1748 	if (result == B_OK) {
1749 		Node* node = volume->GetNode(request->nodeID);
1750 		if (node) {
1751 			directory = dynamic_cast<Directory*>(node);
1752 			if (!directory)
1753 				result = B_NOT_A_DIRECTORY;
1754 		} else
1755 			result = B_ENTRY_NOT_FOUND;
1756 	}
1757 
1758 	// check permission
1759 	if (result == B_OK) {
1760 		if (!volume->GetNodePermissions(directory)
1761 				.ImpliesResolveDirEntryPermission()) {
1762 			result = B_PERMISSION_DENIED;
1763 		}
1764 	}
1765 
1766 	WalkReply reply;
1767 	char linkPath[B_PATH_NAME_LENGTH];
1768 	if (result == B_OK) {
1769 		// load the entry
1770 		Entry* entry;
1771 		result = volume->LoadEntry(directory, request->name.GetString(),
1772 			&entry);
1773 
1774 		// fill in the reply
1775 		if (result == B_OK) {
1776 			_GetEntryInfo(entry, &reply.entryInfo);
1777 
1778 			// resolve a symlink, if desired
1779 			Node* node = entry->GetNode();
1780 			if (request->resolveLink && node->IsSymlink()) {
1781 				result = node->ReadSymlink(linkPath, B_PATH_NAME_LENGTH);
1782 				if (result == B_OK)
1783 					reply.linkPath.SetTo(linkPath);
1784 			}
1785 		}
1786 	}
1787 
1788 	managerLocker.Unlock();
1789 
1790 	// send the reply
1791 	reply.error = result;
1792 	PRINT("Walk: (%ld, %lld, `%s') -> (%lx, (%ld, %lld), `%s')\n",
1793 		request->nodeID.volumeID, request->nodeID.nodeID,
1794 		request->name.GetString(), result,
1795 		reply.entryInfo.nodeInfo.st.st_dev,
1796 		reply.entryInfo.nodeInfo.st.st_ino, reply.linkPath.GetString());
1797 	return GetChannel()->SendRequest(&reply);
1798 }
1799 
1800 // VisitMultiWalkRequest
1801 status_t
1802 ClientConnection::VisitMultiWalkRequest(MultiWalkRequest* request)
1803 {
1804 	ConnectionReference connectionReference(this);
1805 	if (!connectionReference.IsValid())
1806 		return B_OK;
1807 
1808 	// get the volume
1809 	status_t result = B_OK;
1810 	ClientVolume* volume = _GetVolume(request->volumeID);
1811 	if (!volume)
1812 		result = B_BAD_VALUE;
1813 	ClientVolumePutter volumePutter(this, volume);
1814 
1815 	VolumeManagerLocker managerLocker;
1816 
1817 	// get the directory
1818 	Directory* directory = NULL;
1819 	if (result == B_OK) {
1820 		Node* node = volume->GetNode(request->nodeID);
1821 		if (node) {
1822 			directory = dynamic_cast<Directory*>(node);
1823 			if (!directory)
1824 				result = B_NOT_A_DIRECTORY;
1825 		} else
1826 			result = B_ENTRY_NOT_FOUND;
1827 	}
1828 
1829 	// check permission
1830 	if (result == B_OK) {
1831 		if (!volume->GetNodePermissions(directory)
1832 				.ImpliesResolveDirEntryPermission()) {
1833 			result = B_PERMISSION_DENIED;
1834 		}
1835 	}
1836 
1837 	MultiWalkReply reply;
1838 	StringData* names = request->names.GetElements();
1839 	int32 count = request->names.CountElements();
1840 	for (int32 i = 0; result == B_OK && i < count; i++) {
1841 		// load the entry
1842 		Entry* entry;
1843 		if (volume->LoadEntry(directory, names[i].GetString(), &entry)
1844 				== B_OK) {
1845 			// add an entry info
1846 			EntryInfo entryInfo;
1847 			_GetEntryInfo(entry, &entryInfo);
1848 
1849 			// append the info
1850 			result = reply.entryInfos.Append(entryInfo);
1851 		}
1852 	}
1853 
1854 	managerLocker.Unlock();
1855 
1856 	// send the reply
1857 	reply.error = result;
1858 	PRINT("MultiWalk: (%ld, %lld, %ld) -> (%lx, %ld)\n",
1859 		request->nodeID.volumeID, request->nodeID.nodeID, count,
1860 		result, reply.entryInfos.CountElements());
1861 	return GetChannel()->SendRequest(&reply);
1862 }
1863 
1864 // VisitOpenAttrDirRequest
1865 status_t
1866 ClientConnection::VisitOpenAttrDirRequest(OpenAttrDirRequest* request)
1867 {
1868 	ConnectionReference connectionReference(this);
1869 	if (!connectionReference.IsValid())
1870 		return B_OK;
1871 
1872 	// get the volume
1873 	status_t result = B_OK;
1874 	ClientVolume* volume = _GetVolume(request->volumeID);
1875 	if (!volume)
1876 		result = B_BAD_VALUE;
1877 	ClientVolumePutter volumePutter(this, volume);
1878 
1879 	VolumeManagerLocker managerLocker;
1880 
1881 	// get the node
1882 	Node* node = NULL;
1883 	if (result == B_OK) {
1884 		node = volume->GetNode(request->nodeID);
1885 		if (!node)
1886 			result = B_ENTRY_NOT_FOUND;
1887 	}
1888 
1889 	// check permission
1890 	if (result == B_OK) {
1891 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1892 			result = B_PERMISSION_DENIED;
1893 	}
1894 
1895 	// load/cache the attribute directory
1896 	bool attrDirCached = (node->LoadAttrDir() == B_OK);
1897 
1898 	// open the attribute directory, if caching it failed
1899 	AttrDirIterator* handle = NULL;
1900 	if (result == B_OK && !attrDirCached)
1901 		result = volume->OpenAttrDir(node, &handle);
1902 	NodeHandleUnlocker handleUnlocker(volume, handle);
1903 
1904 	// prepare the reply
1905 	OpenAttrDirReply reply;
1906 	if (result == B_OK) {
1907 		if (handle) {
1908 			reply.cookie = handle->GetCookie();
1909 		} else {
1910 			// the attribute directory is cached
1911 			reply.cookie = -1;
1912 			result = _GetAttrDirInfo(request, node, &reply.attrDirInfo);
1913 		}
1914 	}
1915 
1916 	managerLocker.Unlock();
1917 
1918 	// send the reply
1919 	reply.error = result;
1920 	status_t error = GetChannel()->SendRequest(&reply);
1921 
1922 	// close the handle, if a send error occurred
1923 	if (error != B_OK && result == B_OK && handle)
1924 		volume->Close(handle);
1925 
1926 	return error;
1927 }
1928 
1929 // VisitReadAttrDirRequest
1930 status_t
1931 ClientConnection::VisitReadAttrDirRequest(ReadAttrDirRequest* request)
1932 {
1933 	ConnectionReference connectionReference(this);
1934 	if (!connectionReference.IsValid())
1935 		return B_OK;
1936 
1937 	// get the volume
1938 	status_t result = B_OK;
1939 	ClientVolume* volume = _GetVolume(request->volumeID);
1940 	if (!volume)
1941 		result = B_BAD_VALUE;
1942 	ClientVolumePutter volumePutter(this, volume);
1943 
1944 	// get the node handle
1945 	NodeHandle* handle = NULL;
1946 	if (result == B_OK)
1947 		result = volume->LockNodeHandle(request->cookie, &handle);
1948 	NodeHandleUnlocker handleUnlocker(volume, handle);
1949 
1950 	// check if it is a attribute directory iterator
1951 	AttrDirIterator* iterator = NULL;
1952 	if (result == B_OK) {
1953 		iterator = dynamic_cast<AttrDirIterator*>(handle);
1954 		if (!iterator)
1955 			result = B_BAD_VALUE;
1956 	}
1957 
1958 	VolumeManagerLocker managerLocker;
1959 
1960 	// get the node
1961 	Node* node = NULL;
1962 	if (result == B_OK) {
1963 		node = volume->GetNode(iterator->GetNodeRef());
1964 		if (!node)
1965 			result = B_ENTRY_NOT_FOUND;
1966 	}
1967 
1968 	// check read permission (we already checked when opening, but anyway...)
1969 	if (result == B_OK) {
1970 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1971 			result = B_PERMISSION_DENIED;
1972 	}
1973 
1974 	managerLocker.Unlock();
1975 
1976 	// read the attribute directory
1977 	uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
1978 	struct dirent* dirEntry = (struct dirent*)buffer;
1979 	int32 countRead = 0;
1980 	bool done = true;
1981 	if (result == B_OK) {
1982 		if (request->rewind)
1983 			result = iterator->RewindDir();
1984 		if (result == B_OK) {
1985 			result = iterator->ReadDir(dirEntry, sizeof(buffer), 1,
1986 				&countRead, &done);
1987 		}
1988 	}
1989 
1990 	// prepare the reply
1991 	ReadAttrDirReply reply;
1992 	reply.name.SetTo(dirEntry->d_name);
1993 
1994 	// send the reply
1995 	reply.error = result;
1996 	reply.count = countRead;
1997 	return GetChannel()->SendRequest(&reply);
1998 }
1999 
2000 // VisitReadAttrRequest
2001 status_t
2002 ClientConnection::VisitReadAttrRequest(ReadAttrRequest* request)
2003 {
2004 	ConnectionReference connectionReference(this);
2005 	if (!connectionReference.IsValid())
2006 		return B_OK;
2007 
2008 	// get the volume
2009 	status_t result = B_OK;
2010 	ClientVolume* volume = _GetVolume(request->volumeID);
2011 	if (!volume)
2012 		result = B_BAD_VALUE;
2013 	ClientVolumePutter volumePutter(this, volume);
2014 
2015 	VolumeManagerLocker managerLocker;
2016 
2017 	// get the node
2018 	Node* node = NULL;
2019 	if (result == B_OK) {
2020 		node = volume->GetNode(request->nodeID);
2021 		if (!node)
2022 			result = B_ENTRY_NOT_FOUND;
2023 	}
2024 
2025 	// check read permission
2026 	if (result == B_OK) {
2027 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2028 			result = B_PERMISSION_DENIED;
2029 	}
2030 
2031 	// open the node
2032 	FileHandle* handle = NULL;
2033 	if (result == B_OK)
2034 		result = volume->Open(node, O_RDONLY, &handle);
2035 	NodeHandleUnlocker handleUnlocker(volume, handle);
2036 
2037 	managerLocker.Unlock();
2038 
2039 	// read the attribute
2040 	if (result == B_OK) {
2041 		// Due to a bug in BFS the `pos' is ignored. This means that the loop
2042 		// below won't work if the attribute is non-empty and the buffer is
2043 		// larger than the attribute, because the we would again and again
2044 		// read the beginning of the attribute until the buffer is full.
2045 		// Hence we first get an attr_info and don't try to read more than
2046 		// the size of the attribute.
2047 		attr_info info;
2048 		result = handle->StatAttr(request->name.GetString(), &info);
2049 		off_t originalPos = max(request->pos, 0LL);
2050 		int32 originalSize = max(request->size, 0L);
2051 		off_t pos = originalPos;
2052 		int32 size = originalSize;
2053 		type_code type = B_SWAP_INT32(request->type);
2054 		bool convert = false;
2055 
2056 		if (result == B_OK) {
2057 			originalSize = min((off_t)originalSize, max(0LL, info.size - pos));
2058 			size = originalSize;
2059 
2060 			// deal with inverse endianess clients
2061 			if (fInverseClientEndianess) {
2062 				convert = _KnownAttributeType(info.type);
2063 				if (convert) {
2064 					// read the whole attribute
2065 					pos = 0;
2066 					size = info.size;
2067 				} else
2068 					type = B_SWAP_INT32(request->type);
2069 			}
2070 		}
2071 		int32 bufferSize = min(size, kMaxReadBufferSize);
2072 
2073 		// allocate a buffer
2074 		uint8* buffer = NULL;
2075 		if (result == B_OK) {
2076 			buffer = (uint8*)malloc(bufferSize);
2077 			if (!buffer)
2078 				result = B_NO_MEMORY;
2079 		}
2080 		MemoryDeleter bufferDeleter(buffer);
2081 
2082 		if (convert) {
2083 			// read the whole attribute and convert it
2084 			if (result == B_OK) {
2085 				// read
2086 				size_t bytesRead = 0;
2087 				result = handle->ReadAttr(request->name.GetString(),
2088 					type, 0, buffer, size, &bytesRead);
2089 				if (result == B_OK && (int32)bytesRead != size)
2090 					result = B_ERROR;
2091 
2092 				// convert
2093 				if (result == B_OK)
2094 					_ConvertAttribute(info, buffer);
2095 			}
2096 
2097 			// prepare the reply
2098 			ReadAttrReply reply;
2099 			if (result == B_OK) {
2100 				reply.pos = originalPos;
2101 				reply.data.SetTo(buffer + originalPos, originalSize);
2102 				reply.moreToCome = false;
2103 			}
2104 
2105 			// send the reply
2106 			reply.error = result;
2107 			status_t error = GetChannel()->SendRequest(&reply);
2108 			if (error != B_OK)
2109 				return error;
2110 		} else {
2111 			// read as long as there are bytes left to read or an error occurs
2112 			bool moreToRead = true;
2113 			do {
2114 				int32 bytesToRead = min(size, bufferSize);
2115 				size_t bytesRead = 0;
2116 				if (result == B_OK) {
2117 					result = handle->ReadAttr(request->name.GetString(),
2118 						request->type, pos, buffer, bytesToRead, &bytesRead);
2119 				}
2120 				moreToRead = (result == B_OK && bytesRead > 0
2121 					&& (int32)bytesRead < size);
2122 
2123 				// prepare the reply
2124 				ReadAttrReply reply;
2125 				if (result == B_OK) {
2126 					reply.pos = pos;
2127 					reply.data.SetTo(buffer, bytesRead);
2128 					reply.moreToCome = moreToRead;
2129 					pos += bytesRead;
2130 					size -= bytesRead;
2131 				}
2132 
2133 				// send the reply
2134 				reply.error = result;
2135 				status_t error = GetChannel()->SendRequest(&reply);
2136 				if (error != B_OK)
2137 					return error;
2138 			} while (moreToRead);
2139 		}
2140 
2141 		// close the handle
2142 		volume->Close(handle);
2143 	} else {
2144 		// opening the node failed (or something even earlier): send an error
2145 		// reply
2146 		ReadAttrReply reply;
2147 		reply.error = result;
2148 		status_t error = GetChannel()->SendRequest(&reply);
2149 		if (error != B_OK)
2150 			return error;
2151 	}
2152 
2153 	return B_OK;
2154 }
2155 
2156 // VisitWriteAttrRequest
2157 status_t
2158 ClientConnection::VisitWriteAttrRequest(WriteAttrRequest* request)
2159 {
2160 	ConnectionReference connectionReference(this);
2161 	if (!connectionReference.IsValid())
2162 		return B_OK;
2163 
2164 	// get the volume
2165 	status_t result = B_OK;
2166 	ClientVolume* volume = _GetVolume(request->volumeID);
2167 	if (!volume)
2168 		result = B_BAD_VALUE;
2169 	ClientVolumePutter volumePutter(this, volume);
2170 
2171 	VolumeManagerLocker managerLocker;
2172 
2173 	// get the node
2174 	Node* node = NULL;
2175 	if (result == B_OK) {
2176 		node = volume->GetNode(request->nodeID);
2177 		if (!node)
2178 			result = B_ENTRY_NOT_FOUND;
2179 	}
2180 
2181 	// check read permission
2182 	if (result == B_OK) {
2183 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2184 			result = B_PERMISSION_DENIED;
2185 	}
2186 
2187 	// open the node
2188 	FileHandle* handle = NULL;
2189 	if (result == B_OK)
2190 		result = volume->Open(node, O_RDWR, &handle);
2191 	NodeHandleUnlocker handleUnlocker(volume, handle);
2192 
2193 	managerLocker.Unlock();
2194 
2195 	if (result == B_OK) {
2196 		off_t pos = max(request->pos, 0LL);
2197 		int32 size = request->data.GetSize();
2198 		type_code type = request->type;
2199 		char* buffer = (char*)request->data.GetData();
2200 
2201 		// convert the data, if necessary
2202 		if (fInverseClientEndianess) {
2203 			if (_KnownAttributeType(type)) {
2204 				if (pos != 0) {
2205 					WARN("WriteAttr(): WARNING: Need to convert attribute "
2206 						"endianess, but position is not 0: attribute: %s, "
2207 						"pos: %lld, size: %ld\n", request->name.GetString(),
2208 						pos, size);
2209 				}
2210 				swap_data(type, buffer, size, B_SWAP_ALWAYS);
2211 			} else
2212 				type = B_SWAP_INT32(type);
2213 		}
2214 
2215 		// write the data
2216 		while (result == B_OK && size > 0) {
2217 			size_t bytesWritten;
2218 			result = handle->WriteAttr(request->name.GetString(),
2219 				type, pos, buffer, size, &bytesWritten);
2220 			if (result == B_OK) {
2221 				pos += bytesWritten;
2222 				buffer += bytesWritten;
2223 				size -= bytesWritten;
2224 			}
2225 		}
2226 
2227 		// close the handle
2228 		volume->Close(handle);
2229 	}
2230 
2231 	// prepare the reply
2232 	WriteAttrReply reply;
2233 	// send the reply
2234 	reply.error = result;
2235 	return GetChannel()->SendRequest(&reply);
2236 }
2237 
2238 // VisitRemoveAttrRequest
2239 status_t
2240 ClientConnection::VisitRemoveAttrRequest(RemoveAttrRequest* request)
2241 {
2242 	ConnectionReference connectionReference(this);
2243 	if (!connectionReference.IsValid())
2244 		return B_OK;
2245 
2246 	// get the volume
2247 	status_t result = B_OK;
2248 	ClientVolume* volume = _GetVolume(request->volumeID);
2249 	if (!volume)
2250 		result = B_BAD_VALUE;
2251 	ClientVolumePutter volumePutter(this, volume);
2252 
2253 	VolumeManagerLocker managerLocker;
2254 
2255 	// get the node
2256 	Node* node = NULL;
2257 	if (result == B_OK) {
2258 		node = volume->GetNode(request->nodeID);
2259 		if (!node)
2260 			result = B_ENTRY_NOT_FOUND;
2261 	}
2262 
2263 	// check read permission
2264 	if (result == B_OK) {
2265 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2266 			result = B_PERMISSION_DENIED;
2267 	}
2268 
2269 	// open the node
2270 	FileHandle* handle = NULL;
2271 	if (result == B_OK)
2272 		result = volume->Open(node, O_RDWR, &handle);
2273 	NodeHandleUnlocker handleUnlocker(volume, handle);
2274 
2275 	managerLocker.Unlock();
2276 
2277 	// remove the attribute and close the node
2278 	if (result == B_OK) {
2279 		result = handle->RemoveAttr(request->name.GetString());
2280 		volume->Close(handle);
2281 	}
2282 
2283 	// send the reply
2284 	RemoveAttrReply reply;
2285 	reply.error = result;
2286 	return GetChannel()->SendRequest(&reply);
2287 }
2288 
2289 // VisitRenameAttrRequest
2290 status_t
2291 ClientConnection::VisitRenameAttrRequest(RenameAttrRequest* request)
2292 {
2293 	// Not supported, since there's no API function to rename an attribute.
2294 	// send the reply
2295 	RemoveAttrReply reply;
2296 	reply.error = B_UNSUPPORTED;
2297 	return GetChannel()->SendRequest(&reply);
2298 }
2299 
2300 // VisitStatAttrRequest
2301 status_t
2302 ClientConnection::VisitStatAttrRequest(StatAttrRequest* request)
2303 {
2304 	ConnectionReference connectionReference(this);
2305 	if (!connectionReference.IsValid())
2306 		return B_OK;
2307 
2308 	// get the volume
2309 	status_t result = B_OK;
2310 	ClientVolume* volume = _GetVolume(request->volumeID);
2311 	if (!volume)
2312 		result = B_BAD_VALUE;
2313 	ClientVolumePutter volumePutter(this, volume);
2314 
2315 	VolumeManagerLocker managerLocker;
2316 
2317 	// get the node
2318 	Node* node = NULL;
2319 	if (result == B_OK) {
2320 		node = volume->GetNode(request->nodeID);
2321 		if (!node)
2322 			result = B_ENTRY_NOT_FOUND;
2323 	}
2324 
2325 	// check read permission
2326 	if (result == B_OK) {
2327 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2328 			result = B_PERMISSION_DENIED;
2329 	}
2330 
2331 	// open the node
2332 	FileHandle* handle = NULL;
2333 	if (result == B_OK)
2334 		result = volume->Open(node, O_RDONLY, &handle);
2335 	NodeHandleUnlocker handleUnlocker(volume, handle);
2336 
2337 	managerLocker.Unlock();
2338 
2339 	// stat the attribute and close the node
2340 	attr_info attrInfo;
2341 	StatAttrReply reply;
2342 	if (result == B_OK) {
2343 		result = handle->StatAttr(request->name.GetString(), &attrInfo);
2344 		volume->Close(handle);
2345 	}
2346 
2347 	// set the attribute info
2348 	if (result == B_OK) {
2349 		result = _GetAttrInfo(request, request->name.GetString(), attrInfo,
2350 			NULL, &reply.attrInfo);
2351 	}
2352 
2353 	// send the reply
2354 	reply.error = result;
2355 	return GetChannel()->SendRequest(&reply);
2356 }
2357 
2358 // VisitOpenQueryRequest
2359 status_t
2360 ClientConnection::VisitOpenQueryRequest(OpenQueryRequest* request)
2361 {
2362 	ConnectionReference connectionReference(this);
2363 	if (!connectionReference.IsValid())
2364 		return B_OK;
2365 
2366 	VolumeManagerLocker managerLocker;
2367 
2368 	// open the query
2369 	status_t result = B_OK;
2370 	QueryHandle* handle = NULL;
2371 	if (result == B_OK) {
2372 		result = _OpenQuery(request->queryString.GetString(),
2373 			request->flags, request->port, request->token, &handle);
2374 	}
2375 	QueryHandleUnlocker handleUnlocker(this, handle);
2376 
2377 	// prepare the reply
2378 	OpenQueryReply reply;
2379 	if (result == B_OK)
2380 		reply.cookie = handle->GetCookie();
2381 
2382 	managerLocker.Unlock();
2383 
2384 	// send the reply
2385 	reply.error = result;
2386 	status_t error = GetChannel()->SendRequest(&reply);
2387 
2388 	// close the handle, if a send error occurred
2389 	if (error != B_OK && result == B_OK)
2390 		_CloseQuery(handle);
2391 
2392 	return error;
2393 }
2394 
2395 // VisitReadQueryRequest
2396 status_t
2397 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request)
2398 {
2399 	ConnectionReference connectionReference(this);
2400 	if (!connectionReference.IsValid())
2401 		return B_OK;
2402 
2403 	// create an array for the IDs of the client volumes a found entry may
2404 	// reside on
2405 	status_t result = B_OK;
2406 	int32 volumeCount = fVolumes->Size();
2407 	int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2408 	if (!volumeIDs)
2409 		result = B_NO_MEMORY;
2410 	ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2411 
2412 	// get the query handle
2413 	QueryHandle* handle = NULL;
2414 	if (result == B_OK)
2415 		result = _LockQueryHandle(request->cookie, &handle);
2416 	QueryHandleUnlocker handleUnlocker(this, handle);
2417 
2418 	// check if it is a query handle
2419 	QueryHandle* queryHandle = NULL;
2420 	if (result == B_OK) {
2421 		queryHandle = dynamic_cast<QueryHandle*>(handle);
2422 		if (!queryHandle)
2423 			result = B_BAD_VALUE;
2424 	}
2425 
2426 	// read the query
2427 	ReadQueryReply reply;
2428 	int32 countRead = 0;
2429 	while (result == B_OK) {
2430 		uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
2431 		struct dirent* dirEntry = (struct dirent*)buffer;
2432 
2433 		result = queryHandle->ReadDir(dirEntry, 1, &countRead);
2434 		if (result != B_OK)
2435 			break;
2436 		if (countRead == 0)
2437 			break;
2438 		PRINT("  query entry: %ld, %lld, \"%s\"\n",
2439 			dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name);
2440 
2441 		VolumeManagerLocker managerLocker;
2442 		VolumeManager* volumeManager = VolumeManager::GetDefault();
2443 
2444 		// load the entry
2445 		Entry* entry = NULL;
2446 		result = volumeManager->LoadEntry(dirEntry->d_pdev,
2447 			dirEntry->d_pino, dirEntry->d_name, true, &entry);
2448 
2449 		// if at least one client volume contains the entry, get an entry info
2450 		if (result == B_OK) {
2451 			HasQueryPermissionClientVolumeFilter filter;
2452 			int32 entryVolumeCount = _GetContainingClientVolumes(
2453 				entry->GetDirectory(), volumeIDs, volumeCount, &filter);
2454 			if (entryVolumeCount > 0) {
2455 				// store all the client volume IDs in the reply
2456 				for (int32 i = 0; i < entryVolumeCount; i++) {
2457 					result = reply.clientVolumeIDs.Append(volumeIDs[i]);
2458 					if (result != B_OK)
2459 						break;
2460 				}
2461 
2462 				// get an entry info
2463 				_GetNodeInfo(entry->GetDirectory(), &reply.dirInfo);
2464 				_GetEntryInfo(entry, &reply.entryInfo);
2465 				break;
2466 			}
2467 else
2468 PRINT(("  -> no client volumes\n"));
2469 		}
2470 
2471 		// entry is not in the volume: next round...
2472 		result = B_OK;
2473 	}
2474 
2475 	// send the reply
2476 	reply.error = result;
2477 	reply.count = countRead;
2478 	PRINT("ReadQuery: (%lx, %ld, dir: (%ld, %lld), node: (%ld, %lld, `%s')"
2479 		"\n", reply.error, reply.count,
2480 		reply.entryInfo.directoryID.volumeID,
2481 		reply.entryInfo.directoryID.nodeID,
2482 		reply.entryInfo.nodeInfo.st.st_dev,
2483 		reply.entryInfo.nodeInfo.st.st_ino,
2484 		reply.entryInfo.name.GetString());
2485 	return GetChannel()->SendRequest(&reply);
2486 }
2487 
2488 
2489 // #pragma mark -
2490 
2491 // ProcessNodeMonitoringEvent
2492 void
2493 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID,
2494 	NodeMonitoringEvent* event)
2495 {
2496 	// get a connection reference
2497 	ConnectionReference connectionReference(this);
2498 	if (!connectionReference.IsValid())
2499 		return;
2500 
2501 	_PushNodeMonitoringEvent(volumeID, event);
2502 }
2503 
2504 // CloseNodeMonitoringEventQueue
2505 void
2506 ClientConnection::CloseNodeMonitoringEventQueue()
2507 {
2508 	typedef Vector<NodeMonitoringRequest*> RequestVector;
2509 	const RequestVector* requests = NULL;
2510 	if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) {
2511 		for (RequestVector::ConstIterator it = requests->Begin();
2512 			 it != requests->End();
2513 			 it++) {
2514 			delete *it;
2515 		}
2516 	}
2517 }
2518 
2519 
2520 // #pragma mark -
2521 
2522 // QueryDomainIntersectsWith
2523 bool
2524 ClientConnection::QueryDomainIntersectsWith(Volume* volume)
2525 {
2526 	// Iterate through the the client volumes and check whether any one contains
2527 	// the supplied volume or its root dir is on the volume. We don't check
2528 	// directory inclusion for the latter, since we don't need to query the
2529 	// volume, if the client volume is located on a volume mounted somewhere
2530 	// under the supplied volume (e.g. the root FS contains everything, but does
2531 	// seldomly need to be queried).
2532 	VolumeManager* volumeManager = VolumeManager::GetDefault();
2533 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
2534 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2535 		ClientVolume* clientVolume = it.Next().value;
2536 		Directory* volumeRoot = volume->GetRootDirectory();
2537 		Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
2538 		if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true)
2539 			|| volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) {
2540 			return true;
2541 		}
2542 	}
2543 
2544 	return false;
2545 }
2546 
2547 // ProcessQueryEvent
2548 void
2549 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event)
2550 {
2551 	dev_t volumeID;
2552 	ino_t directoryID;
2553 	if (event->opcode == B_ENTRY_CREATED) {
2554 		// "entry created" event
2555 		EntryCreatedEvent* createdEvent
2556 			= dynamic_cast<EntryCreatedEvent*>(event);
2557 		if (!createdEvent)
2558 			return;
2559 		volumeID = createdEvent->volumeID;
2560 		directoryID = createdEvent->directoryID;
2561 
2562 	} else if (event->opcode == B_ENTRY_REMOVED) {
2563 		// "entry removed" event
2564 		EntryRemovedEvent* removedEvent
2565 			= dynamic_cast<EntryRemovedEvent*>(event);
2566 		if (!removedEvent)
2567 			return;
2568 		volumeID = removedEvent->volumeID;
2569 		directoryID = removedEvent->directoryID;
2570 
2571 	} else {
2572 		// We only support "entry created" and "entry removed" query events.
2573 		// "entry moved" is split by the volume manager into those.
2574 		ERROR("Ignoring unexpected query event: opcode: 0x%lx\n",
2575 			event->opcode);
2576 		return;
2577 	}
2578 	PRINT("ClientConnection::ProcessQueryEvent(): event: %p, type: %s:"
2579 		" directory: (%ld, %lld)\n", event, typeid(event).name(),
2580 		volumeID, directoryID);
2581 
2582 	// create an array for the IDs of the client volumes a found entry may
2583 	// reside on
2584 	status_t result = B_OK;
2585 	int32 volumeCount = fVolumes->Size();
2586 	int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2587 	if (!volumeIDs)
2588 		result = B_NO_MEMORY;
2589 	ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2590 
2591 	HasQueryPermissionClientVolumeFilter filter;
2592 
2593 	// load the directory the concerned entry belongs/belonged to
2594 	Directory* directory;
2595 	int32 concernedVolumes = 0;
2596 	if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID,
2597 			&directory) == B_OK) {
2598 		// find out, which client volumes the directory is located in
2599 		concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs,
2600 			volumeCount, &filter);
2601 	} else {
2602 		// Failed to load the directory, so maybe it has already been
2603 		// deleted. For "entry removed" events, we consider all client
2604 		// volumes to be notified -- those that don't know the entry will
2605 		// ignore the event.
2606 		if (event->opcode == B_ENTRY_REMOVED) {
2607 			concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount,
2608 				&filter);
2609 		}
2610 	}
2611 
2612 	// now push the event for each concerned client volume
2613 	for (int32 i = 0; i < concernedVolumes; i++)
2614 		_PushNodeMonitoringEvent(volumeIDs[i], event);
2615 	// TODO: More than one volume will usually only be concerned in case of
2616 	// nested client volumes. We could optimize the case by having an array of
2617 	// volume IDs in the respective requests sent over the net (just as in the
2618 	// ReadQueryReply).
2619 }
2620 
2621 
2622 // #pragma mark -
2623 
2624 // _Close
2625 void
2626 ClientConnection::_Close()
2627 {
2628 	// terminate node monitoring processor
2629 	CloseNodeMonitoringEventQueue();
2630 	if (fNodeMonitoringProcessor >= 0
2631 		&& find_thread(NULL) != fNodeMonitoringProcessor) {
2632 		int32 result;
2633 		wait_for_thread(fNodeMonitoringProcessor, &result);
2634 		// The variable is not unset, when this is the node monitoring
2635 		// processor thread -- which is good, since the destructor will
2636 		// wait for the thread in this case.
2637 		fNodeMonitoringProcessor = -1;
2638 	}
2639 	if (fConnection)
2640 		fConnection->Close();
2641 	// notify the listener
2642 	ClientConnectionListener* listener = fListener;
2643 	fListener = NULL;
2644 	if (listener)
2645 		listener->ClientConnectionClosed(this, fError);
2646 }
2647 
2648 // _MarkClosed
2649 void
2650 ClientConnection::_MarkClosed(bool error)
2651 {
2652 	AutoLocker<Locker> _(fLock);
2653 	if (!fClosed) {
2654 		fClosed = true;
2655 		fError = error;
2656 	}
2657 }
2658 
2659 // _GetNodeInfo
2660 void
2661 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info)
2662 {
2663 	if (node && info) {
2664 		info->st = node->GetStat();
2665 		info->revision = VolumeManager::GetDefault()->GetRevision();
2666 	}
2667 }
2668 
2669 // _GetEntryInfo
2670 void
2671 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info)
2672 {
2673 	if (entry && info) {
2674 		info->directoryID.volumeID = entry->GetVolumeID();
2675 		info->directoryID.nodeID = entry->GetDirectoryID();
2676 		info->name.SetTo(entry->GetName());
2677 		_GetNodeInfo(entry->GetNode(), &info->nodeInfo);
2678 	}
2679 }
2680 
2681 // _GetAttrInfo
2682 status_t
2683 ClientConnection::_GetAttrInfo(Request* request, const char* name,
2684 	const attr_info& attrInfo, const void* data, AttributeInfo* info)
2685 {
2686 	if (!request || !name || !info)
2687 		return B_BAD_VALUE;
2688 
2689 	info->name.SetTo(name);
2690 	info->info = attrInfo;
2691 	data = (attrInfo.size > 0 ? data : NULL);
2692 	int32 dataSize = (data ? attrInfo.size : 0);
2693 	info->data.SetTo(data, dataSize);
2694 
2695 	// if the client has inverse endianess, swap the type, if we don't know it
2696 	if (fInverseClientEndianess) {
2697 		if (_KnownAttributeType(info->info.type)) {
2698 			// we need to convert the data, if supplied
2699 			if (data) {
2700 				// allocate a buffer
2701 				RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize);
2702 				if (!requestBuffer)
2703 					return B_NO_MEMORY;
2704 
2705 				// convert the data
2706 				memcpy(requestBuffer->GetData(), data, dataSize);
2707 				_ConvertAttribute(info->info, requestBuffer->GetData());
2708 			}
2709 		} else
2710 			info->info.type = B_SWAP_INT32(info->info.type);
2711 	}
2712 
2713 	return B_OK;
2714 }
2715 
2716 // _GetAttrDirInfo
2717 status_t
2718 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir,
2719 	AttrDirInfo* info)
2720 {
2721 	if (!request || !attrDir || !info || !attrDir->IsAttrDirValid())
2722 		return B_BAD_VALUE;
2723 
2724 	// add the attribute infos
2725 	for (Attribute* attribute = attrDir->GetFirstAttribute();
2726 		 attribute;
2727 		 attribute = attrDir->GetNextAttribute(attribute)) {
2728 		// get the attribute info
2729 		AttributeInfo attrInfo;
2730 		attr_info bAttrInfo;
2731 		attribute->GetInfo(&bAttrInfo);
2732 		status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo,
2733 			attribute->GetData(), &attrInfo);
2734 
2735 		// append it
2736 		if (error == B_OK)
2737 			error = info->attributeInfos.Append(attrInfo);
2738 		if (error != B_OK)
2739 			return error;
2740 	}
2741 
2742 	info->revision = VolumeManager::GetDefault()->GetRevision();
2743 	info->isValid = true;
2744 
2745 	return B_OK;
2746 }
2747 
2748 // _CreateVolume
2749 status_t
2750 ClientConnection::_CreateVolume(ClientVolume** _volume)
2751 {
2752 	// create and init the volume
2753 	ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock,
2754 		this);
2755 	if (!volume)
2756 		return B_NO_MEMORY;
2757 	status_t error = volume->Init();
2758 	if (error != B_OK) {
2759 		delete volume;
2760 		return error;
2761 	}
2762 
2763 	// add it to the volume map
2764 	AutoLocker<VolumeMap> locker(fVolumes);
2765 	error = fVolumes->Put(volume->GetID(), volume);
2766 	locker.Unlock();
2767 
2768 	if (error == B_OK)
2769 		*_volume = volume;
2770 	else
2771 		delete volume;
2772 
2773 	return error;
2774 }
2775 
2776 // _GetVolume
2777 ClientVolume*
2778 ClientConnection::_GetVolume(int32 id)
2779 {
2780 	AutoLocker<VolumeMap> _(fVolumes);
2781 	ClientVolume* volume = fVolumes->Get(id);
2782 	if (!volume || volume->IsRemoved())
2783 		return NULL;
2784 	volume->AcquireReference();
2785 	return volume;
2786 }
2787 
2788 // _PutVolume
2789 //
2790 // The VolumeManager may be locked, but no other lock must be held.
2791 void
2792 ClientConnection::_PutVolume(ClientVolume* volume)
2793 {
2794 	if (!volume)
2795 		return;
2796 
2797 	// decrement reference counter and remove the volume, if 0
2798 	AutoLocker<VolumeMap> locker(fVolumes);
2799 	bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved());
2800 	if (removed)
2801 		fVolumes->Remove(volume->GetID());
2802 	locker.Unlock();
2803 
2804 	if (removed) {
2805 		VolumeManagerLocker managerLocker;
2806 		delete volume;
2807 	}
2808 }
2809 
2810 // _UnmountVolume
2811 //
2812 // The caller must have a reference to the volume.
2813 void
2814 ClientConnection::_UnmountVolume(ClientVolume* volume)
2815 {
2816 	if (!volume)
2817 		return;
2818 	AutoLocker<VolumeMap> locker(fVolumes);
2819 	volume->MarkRemoved();
2820 	locker.Unlock();
2821 
2822 	// push a notification event
2823 	if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) {
2824 		VolumeManagerLocker managerLocker;
2825 
2826 		event->opcode = B_DEVICE_UNMOUNTED;
2827 		_PushNodeMonitoringEvent(volume->GetID(), event);
2828 		event->ReleaseReference();
2829 	}
2830 }
2831 
2832 // _UnmountAllVolumes
2833 void
2834 ClientConnection::_UnmountAllVolumes()
2835 {
2836 	while (true) {
2837 		// To avoid heap allocation (which can fail) we unmount the volumes
2838 		// chunkwise.
2839 		// get the volumes
2840 		const int32 volumeChunkSize = 32;
2841 		ClientVolume* volumes[volumeChunkSize];
2842 		int32 volumeCount = 0;
2843 		AutoLocker<VolumeMap> volumesLocker(fVolumes);
2844 		for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2845 			if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) {
2846 				volumes[volumeCount++] = volume;
2847 			}
2848 			if (volumeCount == volumeChunkSize)
2849 				break;
2850 		}
2851 		volumesLocker.Unlock();
2852 
2853 		// unmount and put the volumes
2854 		for (int32 i = 0; i < volumeCount; i++) {
2855 			ClientVolume* volume = volumes[i];
2856 			_UnmountVolume(volume);
2857 			_PutVolume(volume);
2858 		}
2859 
2860 		if (volumeCount < volumeChunkSize)
2861 			break;
2862 	}
2863 }
2864 
2865 // _NodeMonitoringProcessorEntry
2866 int32
2867 ClientConnection::_NodeMonitoringProcessorEntry(void* data)
2868 {
2869 	return ((ClientConnection*)data)->_NodeMonitoringProcessor();
2870 }
2871 
2872 
2873 // _NodeMonitoringProcessor
2874 int32
2875 ClientConnection::_NodeMonitoringProcessor()
2876 {
2877 	while (!fClosed) {
2878 		// get the next request
2879 		NodeMonitoringRequest* request = NULL;
2880 		status_t error = fNodeMonitoringEvents->Pop(&request);
2881 
2882 		// get a client connection reference
2883 		ConnectionReference connectionReference(this);
2884 		if (!connectionReference.IsValid())
2885 			return B_OK;
2886 
2887 		// No request? Next round...
2888 		if (error != B_OK)
2889 			continue;
2890 		ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2891 
2892 		// send the request
2893 		if (error == B_OK) {
2894 			error = fConnection->SendRequest(request);
2895 			if (error != B_OK) {
2896 				ERROR(("ClientConnection::_NodeMonitoringProcessor(): "
2897 					"Failed to send request.\n"));
2898 			}
2899 		}
2900 	}
2901 	return 0;
2902 }
2903 
2904 
2905 // _PushNodeMonitoringEvent
2906 //
2907 // The caller must have a connection reference. Moreover the VolumeManager
2908 // must be locked.
2909 status_t
2910 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID,
2911 	NodeMonitoringEvent* event)
2912 {
2913 	if (!event)
2914 		return B_BAD_VALUE;
2915 
2916 	// get the volume
2917 	ClientVolume* volume = _GetVolume(volumeID);
2918 	if (!volume && event->opcode != B_DEVICE_UNMOUNTED)
2919 		return B_BAD_VALUE;
2920 	ClientVolumePutter volumePutter(this, volume);
2921 
2922 	// create a node monitoring request
2923 	NodeMonitoringRequest* request = NULL;
2924 	status_t error = B_ERROR;
2925 	switch (event->opcode) {
2926 		case B_ENTRY_CREATED:
2927 			error = _EntryCreated(volume,
2928 				dynamic_cast<EntryCreatedEvent*>(event), request);
2929 			break;
2930 		case B_ENTRY_REMOVED:
2931 			error = _EntryRemoved(volume,
2932 				dynamic_cast<EntryRemovedEvent*>(event), request);
2933 			break;
2934 		case B_ENTRY_MOVED:
2935 			error = _EntryMoved(volume,
2936 				dynamic_cast<EntryMovedEvent*>(event), request);
2937 			break;
2938 		case B_STAT_CHANGED:
2939 			error = _NodeStatChanged(volume,
2940 				dynamic_cast<StatChangedEvent*>(event), request);
2941 			break;
2942 		case B_ATTR_CHANGED:
2943 			error = _NodeAttributeChanged(volume,
2944 				dynamic_cast<AttributeChangedEvent*>(event), request);
2945 			break;
2946 		case B_DEVICE_UNMOUNTED:
2947 			error = B_OK;
2948 			break;
2949 	}
2950 
2951 	// replace all data buffers -- when the request is actually sent, they
2952 	// might no longer exist
2953 	if (error == B_OK)
2954 		error = RequestBufferReplacer().ReplaceBuffer(request);
2955 
2956 	if (error == B_OK) {
2957 		// common initialization
2958 		request->volumeID = volumeID;
2959 		request->opcode = event->opcode;
2960 		request->revision = VolumeManager::GetDefault()->GetRevision();
2961 
2962 		// push the request
2963 		error = fNodeMonitoringEvents->Push(request);
2964 		if (error != B_OK)
2965 			delete request;
2966 	}
2967 
2968 	return error;
2969 }
2970 
2971 // _EntryCreated
2972 status_t
2973 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event,
2974 	NodeMonitoringRequest*& _request)
2975 {
2976 	// allocate the request
2977 	EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest;
2978 	if (!request)
2979 		return B_NO_MEMORY;
2980 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2981 
2982 	// get the name
2983 	const char* name = event->name.GetString();
2984 
2985 	// set the request fields
2986 	request->directoryID = NodeID(event->volumeID, event->directoryID);
2987 	request->nodeID = NodeID(event->volumeID, event->nodeID);
2988 	request->name.SetTo(name);
2989 	if (event->queryHandler) {
2990 		request->port = event->remotePort;
2991 		request->token = event->remoteToken;
2992 		request->queryUpdate = true;
2993 	} else
2994 		request->queryUpdate = false;
2995 
2996 	// try to get an entry info
2997 	Entry* entry;
2998 	if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
2999 			event->directoryID, name, true, &entry) == B_OK
3000 		&& entry->GetNode()->GetVolumeID() == event->volumeID
3001 		&& entry->GetNode()->GetID() == event->nodeID) {
3002 		_GetEntryInfo(entry, &request->entryInfo);
3003 		request->entryInfoValid = true;
3004 	} else
3005 		request->entryInfoValid = false;
3006 
3007 	requestDeleter.Detach();
3008 	_request = request;
3009 	return B_OK;
3010 }
3011 
3012 // _EntryRemoved
3013 status_t
3014 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event,
3015 	NodeMonitoringRequest*& _request)
3016 {
3017 	// special handling, if it is the root node of the client volume that has
3018 	// been removed
3019 	if (!event->queryHandler
3020 		&& NodeRef(event->nodeVolumeID, event->nodeID)
3021 			== volume->GetRootNodeRef()) {
3022 		NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, ".");
3023 		BEntry entry;
3024 		if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists())
3025 			_UnmountVolume(volume);
3026 
3027 		// don't send the "entry removed" event
3028 		return B_ERROR;
3029 	}
3030 
3031 	// allocate the request
3032 	EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest;
3033 	if (!request)
3034 		return B_NO_MEMORY;
3035 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3036 
3037 	// get the name
3038 	const char* name = event->name.GetString();
3039 
3040 	// set the request fields
3041 	request->directoryID = NodeID(event->volumeID, event->directoryID);
3042 	request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3043 	request->name.SetTo(name);
3044 	if (event->queryHandler) {
3045 		request->port = event->remotePort;
3046 		request->token = event->remoteToken;
3047 		request->queryUpdate = true;
3048 	} else
3049 		request->queryUpdate = false;
3050 
3051 	requestDeleter.Detach();
3052 	_request = request;
3053 	return B_OK;
3054 }
3055 
3056 // _EntryMoved
3057 status_t
3058 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event,
3059 	NodeMonitoringRequest*& _request)
3060 {
3061 	// allocate the request
3062 	EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest;
3063 	if (!request)
3064 		return B_NO_MEMORY;
3065 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3066 
3067 	// allocate memory for the names
3068 	int32 fromNameLen = event->fromName.GetLength();
3069 	const char* fromName
3070 		= (fromNameLen > 0 ? event->fromName.GetString() : NULL);
3071 	const char* toName = event->toName.GetString();
3072 
3073 	// set the request fields
3074 	request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID);
3075 	request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID);
3076 	request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3077 	request->fromName.SetTo(fromName);
3078 	request->toName.SetTo(toName);
3079 	request->queryUpdate = false;
3080 
3081 	// try to get an entry info
3082 	Entry* entry;
3083 	if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
3084 			event->toDirectoryID, toName, true, &entry) == B_OK
3085 		&& entry->GetNode()->GetVolumeID() == event->nodeVolumeID
3086 		&& entry->GetNode()->GetID() == event->nodeID) {
3087 		_GetEntryInfo(entry, &request->entryInfo);
3088 		request->entryInfoValid = true;
3089 	} else
3090 		request->entryInfoValid = false;
3091 
3092 	requestDeleter.Detach();
3093 	_request = request;
3094 	return B_OK;
3095 }
3096 
3097 // _NodeStatChanged
3098 status_t
3099 ClientConnection::_NodeStatChanged(ClientVolume* volume,
3100 	StatChangedEvent* event, NodeMonitoringRequest*& _request)
3101 {
3102 	// get the node
3103 	Node* node = volume->GetNode(event->volumeID, event->nodeID);
3104 	if (!node)
3105 		return B_ENTRY_NOT_FOUND;
3106 
3107 	// allocate the request
3108 	StatChangedRequest* request = new(std::nothrow) StatChangedRequest;
3109 	if (!request)
3110 		return B_NO_MEMORY;
3111 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3112 
3113 	// set the request fields
3114 	request->nodeID = NodeID(event->volumeID, event->nodeID);
3115 	_GetNodeInfo(node, &request->nodeInfo);
3116 	request->queryUpdate = false;
3117 
3118 	requestDeleter.Detach();
3119 	_request = request;
3120 	return B_OK;
3121 }
3122 
3123 // _NodeAttributeChanged
3124 status_t
3125 ClientConnection::_NodeAttributeChanged(ClientVolume* volume,
3126 	AttributeChangedEvent* event, NodeMonitoringRequest*& _request)
3127 {
3128 	// get the node
3129 	Node* node = volume->GetNode(event->volumeID, event->nodeID);
3130 	if (!node)
3131 		return B_ENTRY_NOT_FOUND;
3132 
3133 	// update the attribute directory
3134 	bool removed = false;
3135 	bool valid = false;
3136 	attr_info info;
3137 	const void* data = NULL;
3138 	status_t error = node->UpdateAttribute(event->attribute.GetString(),
3139 		&removed, &info, &data);
3140 	valid = (error == B_OK);
3141 
3142 	// allocate the request
3143 	AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest;
3144 	if (!request)
3145 		return B_NO_MEMORY;
3146 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3147 
3148 	// get an attr dir info, if the directory is valid
3149 	if (node->IsAttrDirValid()) {
3150 		status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo);
3151 		if (error != B_OK)
3152 			return error;
3153 	}
3154 
3155 	// get name and the data size
3156 	int32 dataSize = (data ? info.size : 0);
3157 	const char* name = event->attribute.GetString();
3158 
3159 	// set the request fields
3160 	request->nodeID = NodeID(event->volumeID, event->nodeID);
3161 	request->attrInfo.name.SetTo(name);
3162 	request->valid = valid;
3163 	request->removed = removed;
3164 	if (!removed && valid) {
3165 		request->attrInfo.info = info;
3166 		request->attrInfo.data.SetTo(data, dataSize);
3167 	}
3168 	request->queryUpdate = false;
3169 
3170 	requestDeleter.Detach();
3171 	_request = request;
3172 	return B_OK;
3173 }
3174 
3175 // _KnownAttributeType
3176 bool
3177 ClientConnection::_KnownAttributeType(type_code type)
3178 {
3179 	if (!fInverseClientEndianess)
3180 		return false;
3181 
3182 	switch (type) {
3183 		case B_BOOL_TYPE:
3184 		case B_CHAR_TYPE:
3185 		case B_COLOR_8_BIT_TYPE:
3186 		case B_DOUBLE_TYPE:
3187 		case B_FLOAT_TYPE:
3188 		case B_GRAYSCALE_8_BIT_TYPE:
3189 		case B_INT64_TYPE:
3190 		case B_INT32_TYPE:
3191 		case B_INT16_TYPE:
3192 		case B_INT8_TYPE:
3193 		case B_MESSAGE_TYPE:
3194 		case B_MESSENGER_TYPE:
3195 		case B_MIME_TYPE:
3196 		case B_MONOCHROME_1_BIT_TYPE:
3197 		case B_OFF_T_TYPE:
3198 		case B_POINTER_TYPE:
3199 		case B_POINT_TYPE:
3200 		case B_RECT_TYPE:
3201 		case B_REF_TYPE:
3202 		case B_RGB_COLOR_TYPE:
3203 		case B_SIZE_T_TYPE:
3204 		case B_SSIZE_T_TYPE:
3205 		case B_STRING_TYPE:
3206 		case B_TIME_TYPE:
3207 		case B_UINT64_TYPE:
3208 		case B_UINT32_TYPE:
3209 		case B_UINT16_TYPE:
3210 		case B_UINT8_TYPE:
3211 		case B_ASCII_TYPE:
3212 		case B_MIME_STRING_TYPE:
3213 			return true;
3214 
3215 		//B_RGB_32_BIT_TYPE: We could translate it, but it's heavy...
3216 	}
3217 
3218 	return false;
3219 }
3220 
3221 // _ConvertAttribute
3222 void
3223 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer)
3224 {
3225 	swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS);
3226 }
3227 
3228 
3229 // #pragma mark -
3230 
3231 // _OpenQuery
3232 status_t
3233 ClientConnection::_OpenQuery(const char* queryString, uint32 flags,
3234 	port_id remotePort, int32 remoteToken, QueryHandle** _handle)
3235 {
3236 	if (!queryString || !_handle)
3237 		return B_BAD_VALUE;
3238 
3239 	// open query
3240 	QueryHandle* queryHandle;
3241 	status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString,
3242 		flags, remotePort, remoteToken, &queryHandle);
3243 	if (error != B_OK)
3244 		return error;
3245 	BReference<QueryHandle> handleReference(queryHandle, true);
3246 
3247 	// lock the handle
3248 	queryHandle->Lock();
3249 
3250 	// add the handle
3251 	error = fQueryHandles->AddNodeHandle(queryHandle);
3252 	if (error != B_OK)
3253 		return error;
3254 
3255 	handleReference.Detach();
3256 	*_handle = queryHandle;
3257 	return B_OK;
3258 }
3259 
3260 // _CloseQuery
3261 status_t
3262 ClientConnection::_CloseQuery(QueryHandle* handle)
3263 {
3264 	if (!handle || !fQueryHandles->RemoveNodeHandle(handle))
3265 		return B_BAD_VALUE;
3266 
3267 	return B_OK;
3268 }
3269 
3270 // _LockQueryHandle
3271 //
3272 // VolumeManager must NOT be locked.
3273 status_t
3274 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle)
3275 {
3276 	NodeHandle* handle;
3277 	status_t error = fQueryHandles->LockNodeHandle(cookie, &handle);
3278 	if (error == B_OK)
3279 		*_handle = static_cast<QueryHandle*>(handle);
3280 	return error;
3281 }
3282 
3283 // _UnlockQueryHandle
3284 //
3285 // VolumeManager may or may not be locked.
3286 void
3287 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle)
3288 {
3289 	fQueryHandles->UnlockNodeHandle(nodeHandle);
3290 }
3291 
3292 
3293 // #pragma mark -
3294 
3295 // _GetAllClientVolumeIDs
3296 int32
3297 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize,
3298 	ClientVolumeFilter* filter)
3299 {
3300 	int32 count = 0;
3301 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
3302 	for (VolumeMap::Iterator it = fVolumes->GetIterator();
3303 		 it.HasNext() && arraySize > count;) {
3304 		ClientVolume* clientVolume = it.Next().value;
3305 		if (!filter || filter->FilterVolume(this, clientVolume))
3306 			volumeIDs[count++] = clientVolume->GetID();
3307 	}
3308 
3309 	return count;
3310 }
3311 
3312 // _GetContainingClientVolumes
3313 int32
3314 ClientConnection::_GetContainingClientVolumes(Directory* directory,
3315 	int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter)
3316 {
3317 	int32 count = 0;
3318 	VolumeManager* volumeManager = VolumeManager::GetDefault();
3319 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
3320 	for (VolumeMap::Iterator it = fVolumes->GetIterator();
3321 		 it.HasNext() && arraySize > count;) {
3322 		ClientVolume* clientVolume = it.Next().value;
3323 		Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
3324 		if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true)
3325 			&& (!filter || filter->FilterVolume(this, clientVolume))) {
3326 			volumeIDs[count++] = clientVolume->GetID();
3327 		}
3328 	}
3329 
3330 	return count;
3331 }
3332 
3333 
3334 // #pragma mark -
3335 // #pragma mark ----- ClientConnectionListener -----
3336 
3337 // constructor
3338 ClientConnectionListener::ClientConnectionListener()
3339 {
3340 }
3341 
3342 // destructor
3343 ClientConnectionListener::~ClientConnectionListener()
3344 {
3345 }
3346 
3347