xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/ClientConnection.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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 		SET_ERROR(result, _LockQueryHandle(request->cookie, &handle));
959 		QueryHandleUnlocker handleUnlocker(this, handle);
960 
961 		// close it
962 		if (result == B_OK)
963 			SET_ERROR(result, _CloseQuery(handle));
964 	}
965 
966 	// send the reply
967 	CloseReply reply;
968 	reply.error = result;
969 	return GetChannel()->SendRequest(&reply);
970 }
971 
972 // VisitReadRequest
973 status_t
974 ClientConnection::VisitReadRequest(ReadRequest* request)
975 {
976 	ConnectionReference connectionReference(this);
977 	if (!connectionReference.IsValid())
978 		return B_OK;
979 
980 	// get the volume
981 	status_t result = B_OK;
982 	ClientVolume* volume = _GetVolume(request->volumeID);
983 	if (!volume)
984 		result = B_BAD_VALUE;
985 	ClientVolumePutter volumePutter(this, volume);
986 
987 	// get the node handle
988 	NodeHandle* handle = NULL;
989 	if (result == B_OK)
990 		result = volume->LockNodeHandle(request->cookie, &handle);
991 	NodeHandleUnlocker handleUnlocker(volume, handle);
992 
993 	// check if it is a file handle
994 	FileHandle* fileHandle = NULL;
995 	if (result == B_OK) {
996 		fileHandle = dynamic_cast<FileHandle*>(handle);
997 		if (!fileHandle)
998 			result = B_BAD_VALUE;
999 	}
1000 
1001 	VolumeManagerLocker managerLocker;
1002 
1003 	// check read permission
1004 	if (result == B_OK) {
1005 		Node* node = volume->GetNode(fileHandle->GetNodeRef());
1006 		if (!node || !volume->GetNodePermissions(node).ImpliesReadPermission())
1007 			result = B_PERMISSION_DENIED;
1008 	}
1009 
1010 	managerLocker.Unlock();
1011 
1012 	off_t pos = request->pos;
1013 	int32 size = request->size;
1014 	int32 bufferSize = min(size, kMaxReadBufferSize);
1015 	// allocate a buffer
1016 	uint8* buffer = NULL;
1017 	if (result == B_OK) {
1018 		buffer = (uint8*)malloc(bufferSize);
1019 		if (!buffer)
1020 			result = B_NO_MEMORY;
1021 	}
1022 	MemoryDeleter bufferDeleter(buffer);
1023 
1024 	// read as long as there are bytes left to read or an error occurs
1025 	bool moreToRead = true;
1026 	do {
1027 		int32 bytesToRead = min(size, bufferSize);
1028 		size_t bytesRead = 0;
1029 		if (result == B_OK)
1030 			result = fileHandle->Read(pos, buffer, bytesToRead, &bytesRead);
1031 		moreToRead = (result == B_OK && bytesRead > 0
1032 			&& (int32)bytesRead < size);
1033 
1034 		// prepare the reply
1035 		ReadReply reply;
1036 		if (result == B_OK) {
1037 			reply.pos = pos;
1038 			reply.data.SetTo(buffer, bytesRead);
1039 			reply.moreToCome = moreToRead;
1040 			pos += bytesRead;
1041 			size -= bytesRead;
1042 		}
1043 
1044 		// send the reply
1045 		reply.error = result;
1046 		status_t error = GetChannel()->SendRequest(&reply);
1047 		if (error != B_OK)
1048 			return error;
1049 	} while (moreToRead);
1050 
1051 	return B_OK;
1052 }
1053 
1054 // VisitWriteRequest
1055 status_t
1056 ClientConnection::VisitWriteRequest(WriteRequest* request)
1057 {
1058 	ConnectionReference connectionReference(this);
1059 	if (!connectionReference.IsValid())
1060 		return B_OK;
1061 
1062 	// get the volume
1063 	status_t result = B_OK;
1064 	ClientVolume* volume = _GetVolume(request->volumeID);
1065 	if (!volume)
1066 		result = B_BAD_VALUE;
1067 	ClientVolumePutter volumePutter(this, volume);
1068 
1069 	// get the node handle
1070 	NodeHandle* handle = NULL;
1071 	if (result == B_OK)
1072 		result = volume->LockNodeHandle(request->cookie, &handle);
1073 	NodeHandleUnlocker handleUnlocker(volume, handle);
1074 
1075 	// check if it is a file handle
1076 	FileHandle* fileHandle = NULL;
1077 	if (result == B_OK) {
1078 		fileHandle = dynamic_cast<FileHandle*>(handle);
1079 		if (!fileHandle)
1080 			result = B_BAD_VALUE;
1081 	}
1082 
1083 	VolumeManagerLocker managerLocker;
1084 
1085 	// check read permission
1086 	if (result == B_OK) {
1087 		Node* node = volume->GetNode(fileHandle->GetNodeRef());
1088 		if (!node || !volume->GetNodePermissions(node).ImpliesWritePermission())
1089 			result = B_PERMISSION_DENIED;
1090 	}
1091 
1092 	managerLocker.Unlock();
1093 
1094 	// write until all has been written or an error occurs
1095 	off_t pos = request->pos;
1096 	int32 size = request->data.GetSize();
1097 	const char* buffer = (const char*)request->data.GetData();
1098 	while (result == B_OK && size > 0) {
1099 		size_t bytesWritten;
1100 		result = fileHandle->Write(pos, buffer, size, &bytesWritten);
1101 		if (result == B_OK) {
1102 			pos += bytesWritten;
1103 			buffer += bytesWritten;
1104 			size -= bytesWritten;
1105 		}
1106 	}
1107 
1108 	// prepare the reply
1109 	WriteReply reply;
1110 	// send the reply
1111 	reply.error = result;
1112 	return GetChannel()->SendRequest(&reply);
1113 }
1114 
1115 // VisitCreateLinkRequest
1116 status_t
1117 ClientConnection::VisitCreateLinkRequest(CreateLinkRequest* request)
1118 {
1119 	ConnectionReference connectionReference(this);
1120 	if (!connectionReference.IsValid())
1121 		return B_OK;
1122 
1123 	// get the volume
1124 	status_t result = B_OK;
1125 	ClientVolume* volume = _GetVolume(request->volumeID);
1126 	if (!volume)
1127 		result = B_BAD_VALUE;
1128 	ClientVolumePutter volumePutter(this, volume);
1129 
1130 	VolumeManagerLocker managerLocker;
1131 
1132 	// get the target node
1133 	Node* node = NULL;
1134 	if (result == B_OK) {
1135 		node = volume->GetNode(request->nodeID);
1136 		if (!node)
1137 			result = B_ENTRY_NOT_FOUND;
1138 	}
1139 
1140 	// get the target node path
1141 	Path targetPath;
1142 	if (result == B_OK)
1143 		result = node->GetPath(&targetPath);
1144 
1145 	// get the directory
1146 	Directory* directory = NULL;
1147 	if (result == B_OK) {
1148 		Node* node = volume->GetNode(request->directoryID);
1149 		if (node) {
1150 			directory = dynamic_cast<Directory*>(node);
1151 			if (!directory)
1152 				result = B_NOT_A_DIRECTORY;
1153 		} else
1154 			result = B_ENTRY_NOT_FOUND;
1155 	}
1156 
1157 	// check permissions
1158 	if (result == B_OK) {
1159 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1160 			result = B_PERMISSION_DENIED;
1161 	}
1162 
1163 	// get the new entry's path
1164 	Path path;
1165 	if (result == B_OK) {
1166 		result = directory->GetPath(&path);
1167 		if (result == B_OK)
1168 			result = path.Append(request->name.GetString());
1169 	}
1170 
1171 	managerLocker.Unlock();
1172 
1173 	// create the link
1174 	if (result == B_OK) {
1175 		if (link(targetPath.GetPath(), path.GetPath()) < 0)
1176 			result = errno;
1177 	}
1178 
1179 	// prepare the reply
1180 	CreateSymlinkReply reply;
1181 	// send the reply
1182 	reply.error = result;
1183 	return GetChannel()->SendRequest(&reply);
1184 }
1185 
1186 // VisitUnlinkRequest
1187 status_t
1188 ClientConnection::VisitUnlinkRequest(UnlinkRequest* request)
1189 {
1190 	ConnectionReference connectionReference(this);
1191 	if (!connectionReference.IsValid())
1192 		return B_OK;
1193 
1194 	// get the volume
1195 	status_t result = B_OK;
1196 	ClientVolume* volume = _GetVolume(request->volumeID);
1197 	if (!volume)
1198 		result = B_BAD_VALUE;
1199 	ClientVolumePutter volumePutter(this, volume);
1200 
1201 	VolumeManagerLocker managerLocker;
1202 
1203 	// get the directory
1204 	Directory* directory = NULL;
1205 	if (result == B_OK) {
1206 		Node* node = volume->GetNode(request->directoryID);
1207 		if (node) {
1208 			directory = dynamic_cast<Directory*>(node);
1209 			if (!directory)
1210 				result = B_NOT_A_DIRECTORY;
1211 		} else
1212 			result = B_ENTRY_NOT_FOUND;
1213 	}
1214 
1215 	// check permissions
1216 	if (result == B_OK) {
1217 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1218 			result = B_PERMISSION_DENIED;
1219 	}
1220 
1221 	// get the entry's path
1222 	Path path;
1223 	if (result == B_OK) {
1224 		result = directory->GetPath(&path);
1225 		if (result == B_OK)
1226 			result = path.Append(request->name.GetString());
1227 	}
1228 
1229 	managerLocker.Unlock();
1230 
1231 	// remove the entry
1232 	if (result == B_OK) {
1233 		if (unlink(path.GetPath()) < 0)
1234 			result = errno;
1235 	}
1236 
1237 	// prepare the reply
1238 	UnlinkReply reply;
1239 	// send the reply
1240 	reply.error = result;
1241 	return GetChannel()->SendRequest(&reply);
1242 }
1243 
1244 // VisitCreateSymlinkRequest
1245 status_t
1246 ClientConnection::VisitCreateSymlinkRequest(CreateSymlinkRequest* request)
1247 {
1248 	ConnectionReference connectionReference(this);
1249 	if (!connectionReference.IsValid())
1250 		return B_OK;
1251 
1252 	// get the volume
1253 	status_t result = B_OK;
1254 	ClientVolume* volume = _GetVolume(request->volumeID);
1255 	if (!volume)
1256 		result = B_BAD_VALUE;
1257 	ClientVolumePutter volumePutter(this, volume);
1258 
1259 	VolumeManagerLocker managerLocker;
1260 
1261 	// get the directory
1262 	Directory* directory = NULL;
1263 	if (result == B_OK) {
1264 		Node* node = volume->GetNode(request->directoryID);
1265 		if (node) {
1266 			directory = dynamic_cast<Directory*>(node);
1267 			if (!directory)
1268 				result = B_NOT_A_DIRECTORY;
1269 		} else
1270 			result = B_ENTRY_NOT_FOUND;
1271 	}
1272 
1273 	// check permissions
1274 	if (result == B_OK) {
1275 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1276 			result = B_PERMISSION_DENIED;
1277 	}
1278 
1279 	// get the new entry's path
1280 	Path path;
1281 	if (result == B_OK) {
1282 		result = directory->GetPath(&path);
1283 		if (result == B_OK)
1284 			result = path.Append(request->name.GetString());
1285 	}
1286 
1287 	managerLocker.Unlock();
1288 
1289 	// create the symlink
1290 	if (result == B_OK) {
1291 		if (symlink(request->target.GetString(), path.GetPath()) < 0)
1292 			result = errno;
1293 	}
1294 
1295 	// prepare the reply
1296 	CreateSymlinkReply reply;
1297 	// send the reply
1298 	reply.error = result;
1299 	return GetChannel()->SendRequest(&reply);
1300 }
1301 
1302 // VisitReadLinkRequest
1303 status_t
1304 ClientConnection::VisitReadLinkRequest(ReadLinkRequest* request)
1305 {
1306 	ConnectionReference connectionReference(this);
1307 	if (!connectionReference.IsValid())
1308 		return B_OK;
1309 
1310 	// get the volume
1311 	status_t result = B_OK;
1312 	ClientVolume* volume = _GetVolume(request->volumeID);
1313 	if (!volume)
1314 		result = B_BAD_VALUE;
1315 	ClientVolumePutter volumePutter(this, volume);
1316 
1317 	VolumeManagerLocker managerLocker;
1318 
1319 	// get the node
1320 	Node* node = NULL;
1321 	if (result == B_OK) {
1322 		node = volume->GetNode(request->nodeID);
1323 		if (!node)
1324 			result = B_ENTRY_NOT_FOUND;
1325 	}
1326 
1327 	int32 bufferSize = request->maxSize;
1328 
1329 	// check read permission
1330 	if (result == B_OK) {
1331 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1332 			result = B_PERMISSION_DENIED;
1333 	}
1334 
1335 	// allocate a buffer
1336 	void* buffer = NULL;
1337 	if (result == B_OK) {
1338 		if (bufferSize < 0 || bufferSize > kMaxSaneReadLinkSize)
1339 			result = B_BAD_DATA;
1340 	}
1341 	if (result == B_OK) {
1342 		buffer = malloc(bufferSize);
1343 		if (!buffer)
1344 			result = B_NO_MEMORY;
1345 	}
1346 	MemoryDeleter bufferDeleter(buffer);
1347 
1348 	// read the link and prepare the reply
1349 	ReadLinkReply reply;
1350 	int32 bytesRead = 0;
1351 	if (result == B_OK)
1352 		result = node->ReadSymlink((char*)buffer, bufferSize, &bytesRead);
1353 	if (result == B_OK) {
1354 		reply.data.SetTo(buffer, bytesRead);
1355 		_GetNodeInfo(node, &reply.nodeInfo);
1356 	}
1357 
1358 	managerLocker.Unlock();
1359 
1360 	// send the reply
1361 	reply.error = result;
1362 	return GetChannel()->SendRequest(&reply);
1363 }
1364 
1365 // VisitRenameRequest
1366 status_t
1367 ClientConnection::VisitRenameRequest(RenameRequest* request)
1368 {
1369 	ConnectionReference connectionReference(this);
1370 	if (!connectionReference.IsValid())
1371 		return B_OK;
1372 
1373 	// get the volume
1374 	status_t result = B_OK;
1375 	ClientVolume* volume = _GetVolume(request->volumeID);
1376 	if (!volume)
1377 		result = B_BAD_VALUE;
1378 	ClientVolumePutter volumePutter(this, volume);
1379 
1380 	VolumeManagerLocker managerLocker;
1381 
1382 	// get the new directory
1383 	Directory* newDirectory = NULL;
1384 	if (result == B_OK) {
1385 		Node* node = volume->GetNode(request->newDirectoryID);
1386 		if (node) {
1387 			newDirectory = dynamic_cast<Directory*>(node);
1388 			if (!newDirectory)
1389 				result = B_NOT_A_DIRECTORY;
1390 		} else
1391 			result = B_ENTRY_NOT_FOUND;
1392 	}
1393 
1394 	// check permissions
1395 	if (result == B_OK) {
1396 		if (!volume->GetNodePermissions(newDirectory).ImpliesWritePermission())
1397 			result = B_PERMISSION_DENIED;
1398 	}
1399 
1400 	// get the new path
1401 	Path newPath;
1402 	if (result == B_OK) {
1403 		result = newDirectory->GetPath(&newPath);
1404 		if (result == B_OK)
1405 			result = newPath.Append(request->newName.GetString());
1406 	}
1407 
1408 	// get the old directory
1409 	Directory* oldDirectory = NULL;
1410 	if (result == B_OK) {
1411 		Node* node = volume->GetNode(request->oldDirectoryID);
1412 		if (node) {
1413 			oldDirectory = dynamic_cast<Directory*>(node);
1414 			if (!oldDirectory)
1415 				result = B_NOT_A_DIRECTORY;
1416 		} else
1417 			result = B_ENTRY_NOT_FOUND;
1418 	}
1419 
1420 	// check permissions
1421 	if (result == B_OK) {
1422 		if (!volume->GetNodePermissions(oldDirectory).ImpliesWritePermission())
1423 			result = B_PERMISSION_DENIED;
1424 	}
1425 
1426 	// get the new path
1427 	Path oldPath;
1428 	if (result == B_OK) {
1429 		result = oldDirectory->GetPath(&oldPath);
1430 		if (result == B_OK)
1431 			result = oldPath.Append(request->oldName.GetString());
1432 	}
1433 
1434 	managerLocker.Unlock();
1435 
1436 	// rename the entry
1437 	if (result == B_OK) {
1438 		if (rename(oldPath.GetPath(), newPath.GetPath()) < 0)
1439 			result = errno;
1440 	}
1441 
1442 	// prepare the reply
1443 	RenameReply reply;
1444 	// send the reply
1445 	reply.error = result;
1446 	return GetChannel()->SendRequest(&reply);
1447 }
1448 
1449 // VisitMakeDirRequest
1450 status_t
1451 ClientConnection::VisitMakeDirRequest(MakeDirRequest* request)
1452 {
1453 	ConnectionReference connectionReference(this);
1454 	if (!connectionReference.IsValid())
1455 		return B_OK;
1456 
1457 	// get the volume
1458 	status_t result = B_OK;
1459 	ClientVolume* volume = _GetVolume(request->volumeID);
1460 	if (!volume)
1461 		result = B_BAD_VALUE;
1462 	ClientVolumePutter volumePutter(this, volume);
1463 
1464 	VolumeManagerLocker managerLocker;
1465 
1466 	// get the directory
1467 	Directory* directory = NULL;
1468 	if (result == B_OK) {
1469 		Node* node = volume->GetNode(request->directoryID);
1470 		if (node) {
1471 			directory = dynamic_cast<Directory*>(node);
1472 			if (!directory)
1473 				result = B_NOT_A_DIRECTORY;
1474 		} else
1475 			result = B_ENTRY_NOT_FOUND;
1476 	}
1477 
1478 	// check permissions
1479 	if (result == B_OK) {
1480 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1481 			result = B_PERMISSION_DENIED;
1482 	}
1483 
1484 	// get the path
1485 	Path path;
1486 	if (result == B_OK) {
1487 		result = directory->GetPath(&path);
1488 		if (result == B_OK)
1489 			result = path.Append(request->name.GetString());
1490 	}
1491 
1492 	managerLocker.Unlock();
1493 
1494 	// create the directory
1495 	if (result == B_OK) {
1496 		if (mkdir(path.GetPath(), request->mode) < 0)
1497 			result = errno;
1498 	}
1499 
1500 	// prepare the reply
1501 	MakeDirReply reply;
1502 	// send the reply
1503 	reply.error = result;
1504 	return GetChannel()->SendRequest(&reply);
1505 }
1506 
1507 // VisitRemoveDirRequest
1508 status_t
1509 ClientConnection::VisitRemoveDirRequest(RemoveDirRequest* request)
1510 {
1511 	ConnectionReference connectionReference(this);
1512 	if (!connectionReference.IsValid())
1513 		return B_OK;
1514 
1515 	// get the volume
1516 	status_t result = B_OK;
1517 	ClientVolume* volume = _GetVolume(request->volumeID);
1518 	if (!volume)
1519 		result = B_BAD_VALUE;
1520 	ClientVolumePutter volumePutter(this, volume);
1521 
1522 	VolumeManagerLocker managerLocker;
1523 
1524 	// get the directory
1525 	Directory* directory = NULL;
1526 	if (result == B_OK) {
1527 		Node* node = volume->GetNode(request->directoryID);
1528 		if (node) {
1529 			directory = dynamic_cast<Directory*>(node);
1530 			if (!directory)
1531 				result = B_NOT_A_DIRECTORY;
1532 		} else
1533 			result = B_ENTRY_NOT_FOUND;
1534 	}
1535 
1536 	// check permissions
1537 	if (result == B_OK) {
1538 		if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1539 			result = B_PERMISSION_DENIED;
1540 	}
1541 
1542 	// get the path
1543 	Path path;
1544 	if (result == B_OK) {
1545 		result = directory->GetPath(&path);
1546 		if (result == B_OK)
1547 			result = path.Append(request->name.GetString());
1548 	}
1549 
1550 	managerLocker.Unlock();
1551 
1552 	// remove the directory
1553 	if (result == B_OK) {
1554 		if (rmdir(path.GetPath()) < 0)
1555 			result = errno;
1556 	}
1557 
1558 	// prepare the reply
1559 	RemoveDirReply reply;
1560 	// send the reply
1561 	reply.error = result;
1562 	return GetChannel()->SendRequest(&reply);
1563 }
1564 
1565 // VisitOpenDirRequest
1566 status_t
1567 ClientConnection::VisitOpenDirRequest(OpenDirRequest* request)
1568 {
1569 	ConnectionReference connectionReference(this);
1570 	if (!connectionReference.IsValid())
1571 		return B_OK;
1572 
1573 	// get the volume
1574 	status_t result = B_OK;
1575 	ClientVolume* volume = _GetVolume(request->volumeID);
1576 	if (!volume)
1577 		result = B_BAD_VALUE;
1578 	ClientVolumePutter volumePutter(this, volume);
1579 
1580 	VolumeManagerLocker managerLocker;
1581 
1582 	// get the directory
1583 	Directory* directory = NULL;
1584 	if (result == B_OK) {
1585 		Node* node = volume->GetNode(request->nodeID);
1586 		if (node) {
1587 			directory = dynamic_cast<Directory*>(node);
1588 			if (!directory)
1589 				result = B_NOT_A_DIRECTORY;
1590 		} else
1591 			result = B_ENTRY_NOT_FOUND;
1592 	}
1593 
1594 	// check permission
1595 	if (result == B_OK) {
1596 		if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission())
1597 			result = B_PERMISSION_DENIED;
1598 	}
1599 
1600 	// open the directory
1601 	DirIterator* handle = NULL;
1602 	if (result == B_OK)
1603 		result = volume->OpenDir(directory, &handle);
1604 	NodeHandleUnlocker handleUnlocker(volume, handle);
1605 
1606 	// prepare the reply
1607 	OpenDirReply reply;
1608 	if (result == B_OK) {
1609 		_GetNodeInfo(directory, &reply.nodeInfo);
1610 		reply.cookie = handle->GetCookie();
1611 	} else {
1612 		if (directory != NULL) {
1613 			PRINT("OpenDir() failed: client volume: %" B_PRId32 ", "
1614 				"node: (%" B_PRIdDEV ", %" B_PRIdINO ")\n",
1615 				volume->GetID(), directory->GetVolumeID(), directory->GetID());
1616 		}
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: (%" B_PRId32 ", %" B_PRIdINO ")\n", request->volumeID,
1683 			directory->GetID());
1684 	}
1685 
1686 	// rewind, if requested
1687 	if (result == B_OK && request->rewind)
1688 		iterator->Rewind();
1689 
1690 	// read the directory
1691 	bool done = false;
1692 	ReadDirReply reply;
1693 	int32 toRead = request->count;
1694 	while (result == B_OK && toRead > 0) {
1695 		// get the next entry
1696 		Entry* entry = iterator->NextEntry();
1697 		if (!entry) {
1698 			done = true;
1699 			break;
1700 		}
1701 
1702 		// get and add an entry info
1703 		EntryInfo entryInfo;
1704 		_GetEntryInfo(entry, &entryInfo);
1705 		result = reply.entryInfos.Append(entryInfo);
1706 
1707 		toRead--;
1708 	}
1709 
1710 	reply.revision = VolumeManager::GetDefault()->GetRevision();
1711 
1712 //PRINT(("ReadDir: (%lld) -> (%lx, %ld, dir: %lld, node: %lld, `%s')\n",
1713 //directoryID, reply.error, reply.entryInfos.CountElements(),
1714 //reply.entryInfo.directoryID,
1715 //reply.entryInfo.nodeID, reply.entryInfo.name.GetString()));
1716 	if (directory != NULL) {
1717 		PRINT("ReadDir done: volume: %" B_PRId32 ", "
1718 			"(%" B_PRIdDEV ", %" B_PRIdINO ") -> "
1719 			"(%" B_PRIx32 ", %" B_PRId32 ")\n",
1720 			volume->GetID(), directory->GetVolumeID(), directory->GetID(),
1721 			result, reply.entryInfos.CountElements());
1722 	}
1723 
1724 	managerLocker.Unlock();
1725 
1726 	// send the reply
1727 	reply.error = result;
1728 	reply.done = (result != B_OK || done);
1729 	return GetChannel()->SendRequest(&reply);
1730 }
1731 
1732 // VisitWalkRequest
1733 status_t
1734 ClientConnection::VisitWalkRequest(WalkRequest* request)
1735 {
1736 	ConnectionReference connectionReference(this);
1737 	if (!connectionReference.IsValid())
1738 		return B_OK;
1739 
1740 	// get the volume
1741 	status_t result = B_OK;
1742 	ClientVolume* volume = _GetVolume(request->volumeID);
1743 	if (!volume)
1744 		result = B_BAD_VALUE;
1745 	ClientVolumePutter volumePutter(this, volume);
1746 
1747 	VolumeManagerLocker managerLocker;
1748 
1749 	// get the directory
1750 	Directory* directory = NULL;
1751 	if (result == B_OK) {
1752 		Node* node = volume->GetNode(request->nodeID);
1753 		if (node) {
1754 			directory = dynamic_cast<Directory*>(node);
1755 			if (!directory)
1756 				result = B_NOT_A_DIRECTORY;
1757 		} else
1758 			result = B_ENTRY_NOT_FOUND;
1759 	}
1760 
1761 	// check permission
1762 	if (result == B_OK) {
1763 		if (!volume->GetNodePermissions(directory)
1764 				.ImpliesResolveDirEntryPermission()) {
1765 			result = B_PERMISSION_DENIED;
1766 		}
1767 	}
1768 
1769 	WalkReply reply;
1770 	char linkPath[B_PATH_NAME_LENGTH];
1771 	if (result == B_OK) {
1772 		// load the entry
1773 		Entry* entry;
1774 		result = volume->LoadEntry(directory, request->name.GetString(),
1775 			&entry);
1776 
1777 		// fill in the reply
1778 		if (result == B_OK) {
1779 			_GetEntryInfo(entry, &reply.entryInfo);
1780 
1781 			// resolve a symlink, if desired
1782 			Node* node = entry->GetNode();
1783 			if (request->resolveLink && node->IsSymlink()) {
1784 				result = node->ReadSymlink(linkPath, B_PATH_NAME_LENGTH);
1785 				if (result == B_OK)
1786 					reply.linkPath.SetTo(linkPath);
1787 			}
1788 		}
1789 	}
1790 
1791 	managerLocker.Unlock();
1792 
1793 	// send the reply
1794 	reply.error = result;
1795 	PRINT("Walk: (%" B_PRIdDEV ", %" B_PRIdINO ", `%s') -> "
1796 		"(%" B_PRIx32 ", (%" B_PRIdDEV ", %" B_PRIdINO "), `%s')\n",
1797 		request->nodeID.volumeID, request->nodeID.nodeID,
1798 		request->name.GetString(), result,
1799 		reply.entryInfo.nodeInfo.st.st_dev,
1800 		reply.entryInfo.nodeInfo.st.st_ino, reply.linkPath.GetString());
1801 	return GetChannel()->SendRequest(&reply);
1802 }
1803 
1804 // VisitMultiWalkRequest
1805 status_t
1806 ClientConnection::VisitMultiWalkRequest(MultiWalkRequest* request)
1807 {
1808 	ConnectionReference connectionReference(this);
1809 	if (!connectionReference.IsValid())
1810 		return B_OK;
1811 
1812 	// get the volume
1813 	status_t result = B_OK;
1814 	ClientVolume* volume = _GetVolume(request->volumeID);
1815 	if (!volume)
1816 		result = B_BAD_VALUE;
1817 	ClientVolumePutter volumePutter(this, volume);
1818 
1819 	VolumeManagerLocker managerLocker;
1820 
1821 	// get the directory
1822 	Directory* directory = NULL;
1823 	if (result == B_OK) {
1824 		Node* node = volume->GetNode(request->nodeID);
1825 		if (node) {
1826 			directory = dynamic_cast<Directory*>(node);
1827 			if (!directory)
1828 				result = B_NOT_A_DIRECTORY;
1829 		} else
1830 			result = B_ENTRY_NOT_FOUND;
1831 	}
1832 
1833 	// check permission
1834 	if (result == B_OK) {
1835 		if (!volume->GetNodePermissions(directory)
1836 				.ImpliesResolveDirEntryPermission()) {
1837 			result = B_PERMISSION_DENIED;
1838 		}
1839 	}
1840 
1841 	MultiWalkReply reply;
1842 	StringData* names = request->names.GetElements();
1843 	int32 count = request->names.CountElements();
1844 	for (int32 i = 0; result == B_OK && i < count; i++) {
1845 		// load the entry
1846 		Entry* entry;
1847 		if (volume->LoadEntry(directory, names[i].GetString(), &entry)
1848 				== B_OK) {
1849 			// add an entry info
1850 			EntryInfo entryInfo;
1851 			_GetEntryInfo(entry, &entryInfo);
1852 
1853 			// append the info
1854 			result = reply.entryInfos.Append(entryInfo);
1855 		}
1856 	}
1857 
1858 	managerLocker.Unlock();
1859 
1860 	// send the reply
1861 	reply.error = result;
1862 	PRINT("MultiWalk: (%" B_PRIdDEV ", %" B_PRIdINO ", %" B_PRId32 ") -> "
1863 		"(%" B_PRIx32 ", %" B_PRId32 ")\n",
1864 		request->nodeID.volumeID, request->nodeID.nodeID, count,
1865 		result, reply.entryInfos.CountElements());
1866 	return GetChannel()->SendRequest(&reply);
1867 }
1868 
1869 // VisitOpenAttrDirRequest
1870 status_t
1871 ClientConnection::VisitOpenAttrDirRequest(OpenAttrDirRequest* request)
1872 {
1873 	ConnectionReference connectionReference(this);
1874 	if (!connectionReference.IsValid())
1875 		return B_OK;
1876 
1877 	// get the volume
1878 	status_t result = B_OK;
1879 	ClientVolume* volume = _GetVolume(request->volumeID);
1880 	if (!volume)
1881 		result = B_BAD_VALUE;
1882 	ClientVolumePutter volumePutter(this, volume);
1883 
1884 	VolumeManagerLocker managerLocker;
1885 
1886 	// get the node
1887 	Node* node = NULL;
1888 	if (result == B_OK) {
1889 		node = volume->GetNode(request->nodeID);
1890 		if (!node)
1891 			result = B_ENTRY_NOT_FOUND;
1892 	}
1893 
1894 	// check permission
1895 	if (result == B_OK) {
1896 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1897 			result = B_PERMISSION_DENIED;
1898 	}
1899 
1900 	// load/cache the attribute directory
1901 	bool attrDirCached = (node->LoadAttrDir() == B_OK);
1902 
1903 	// open the attribute directory, if caching it failed
1904 	AttrDirIterator* handle = NULL;
1905 	if (result == B_OK && !attrDirCached)
1906 		result = volume->OpenAttrDir(node, &handle);
1907 	NodeHandleUnlocker handleUnlocker(volume, handle);
1908 
1909 	// prepare the reply
1910 	OpenAttrDirReply reply;
1911 	if (result == B_OK) {
1912 		if (handle) {
1913 			reply.cookie = handle->GetCookie();
1914 		} else {
1915 			// the attribute directory is cached
1916 			reply.cookie = -1;
1917 			result = _GetAttrDirInfo(request, node, &reply.attrDirInfo);
1918 		}
1919 	}
1920 
1921 	managerLocker.Unlock();
1922 
1923 	// send the reply
1924 	reply.error = result;
1925 	status_t error = GetChannel()->SendRequest(&reply);
1926 
1927 	// close the handle, if a send error occurred
1928 	if (error != B_OK && result == B_OK && handle)
1929 		volume->Close(handle);
1930 
1931 	return error;
1932 }
1933 
1934 // VisitReadAttrDirRequest
1935 status_t
1936 ClientConnection::VisitReadAttrDirRequest(ReadAttrDirRequest* request)
1937 {
1938 	ConnectionReference connectionReference(this);
1939 	if (!connectionReference.IsValid())
1940 		return B_OK;
1941 
1942 	// get the volume
1943 	status_t result = B_OK;
1944 	ClientVolume* volume = _GetVolume(request->volumeID);
1945 	if (!volume)
1946 		result = B_BAD_VALUE;
1947 	ClientVolumePutter volumePutter(this, volume);
1948 
1949 	// get the node handle
1950 	NodeHandle* handle = NULL;
1951 	if (result == B_OK)
1952 		result = volume->LockNodeHandle(request->cookie, &handle);
1953 	NodeHandleUnlocker handleUnlocker(volume, handle);
1954 
1955 	// check if it is a attribute directory iterator
1956 	AttrDirIterator* iterator = NULL;
1957 	if (result == B_OK) {
1958 		iterator = dynamic_cast<AttrDirIterator*>(handle);
1959 		if (!iterator)
1960 			result = B_BAD_VALUE;
1961 	}
1962 
1963 	VolumeManagerLocker managerLocker;
1964 
1965 	// get the node
1966 	Node* node = NULL;
1967 	if (result == B_OK) {
1968 		node = volume->GetNode(iterator->GetNodeRef());
1969 		if (!node)
1970 			result = B_ENTRY_NOT_FOUND;
1971 	}
1972 
1973 	// check read permission (we already checked when opening, but anyway...)
1974 	if (result == B_OK) {
1975 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1976 			result = B_PERMISSION_DENIED;
1977 	}
1978 
1979 	managerLocker.Unlock();
1980 
1981 	// read the attribute directory
1982 	uint8 buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH];
1983 	struct dirent* dirEntry = (struct dirent*)buffer;
1984 	int32 countRead = 0;
1985 	bool done = true;
1986 	if (result == B_OK) {
1987 		if (request->rewind)
1988 			result = iterator->RewindDir();
1989 		if (result == B_OK) {
1990 			result = iterator->ReadDir(dirEntry, sizeof(buffer), 1,
1991 				&countRead, &done);
1992 		}
1993 	}
1994 
1995 	// prepare the reply
1996 	ReadAttrDirReply reply;
1997 	reply.name.SetTo(dirEntry->d_name);
1998 
1999 	// send the reply
2000 	reply.error = result;
2001 	reply.count = countRead;
2002 	return GetChannel()->SendRequest(&reply);
2003 }
2004 
2005 // VisitReadAttrRequest
2006 status_t
2007 ClientConnection::VisitReadAttrRequest(ReadAttrRequest* request)
2008 {
2009 	ConnectionReference connectionReference(this);
2010 	if (!connectionReference.IsValid())
2011 		return B_OK;
2012 
2013 	// get the volume
2014 	status_t result = B_OK;
2015 	ClientVolume* volume = _GetVolume(request->volumeID);
2016 	if (!volume)
2017 		result = B_BAD_VALUE;
2018 	ClientVolumePutter volumePutter(this, volume);
2019 
2020 	VolumeManagerLocker managerLocker;
2021 
2022 	// get the node
2023 	Node* node = NULL;
2024 	if (result == B_OK) {
2025 		node = volume->GetNode(request->nodeID);
2026 		if (!node)
2027 			result = B_ENTRY_NOT_FOUND;
2028 	}
2029 
2030 	// check read permission
2031 	if (result == B_OK) {
2032 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2033 			result = B_PERMISSION_DENIED;
2034 	}
2035 
2036 	// open the node
2037 	FileHandle* handle = NULL;
2038 	if (result == B_OK)
2039 		result = volume->Open(node, O_RDONLY, &handle);
2040 	NodeHandleUnlocker handleUnlocker(volume, handle);
2041 
2042 	managerLocker.Unlock();
2043 
2044 	// read the attribute
2045 	if (result == B_OK) {
2046 		// Due to a bug in BFS the `pos' is ignored. This means that the loop
2047 		// below won't work if the attribute is non-empty and the buffer is
2048 		// larger than the attribute, because the we would again and again
2049 		// read the beginning of the attribute until the buffer is full.
2050 		// Hence we first get an attr_info and don't try to read more than
2051 		// the size of the attribute.
2052 		attr_info info;
2053 		result = handle->StatAttr(request->name.GetString(), &info);
2054 		off_t originalPos = max(request->pos, (off_t)0);
2055 		int32 originalSize = max(request->size, (int32)0);
2056 		off_t pos = originalPos;
2057 		int32 size = originalSize;
2058 		type_code type = B_SWAP_INT32(request->type);
2059 		bool convert = false;
2060 
2061 		if (result == B_OK) {
2062 			originalSize = min((off_t)originalSize, max((off_t)0, info.size - pos));
2063 			size = originalSize;
2064 
2065 			// deal with inverse endianess clients
2066 			if (fInverseClientEndianess) {
2067 				convert = _KnownAttributeType(info.type);
2068 				if (convert) {
2069 					// read the whole attribute
2070 					pos = 0;
2071 					size = info.size;
2072 				} else
2073 					type = B_SWAP_INT32(request->type);
2074 			}
2075 		}
2076 		int32 bufferSize = min(size, kMaxReadBufferSize);
2077 
2078 		// allocate a buffer
2079 		uint8* buffer = NULL;
2080 		if (result == B_OK) {
2081 			buffer = (uint8*)malloc(bufferSize);
2082 			if (!buffer)
2083 				result = B_NO_MEMORY;
2084 		}
2085 		MemoryDeleter bufferDeleter(buffer);
2086 
2087 		if (convert) {
2088 			// read the whole attribute and convert it
2089 			if (result == B_OK) {
2090 				// read
2091 				size_t bytesRead = 0;
2092 				result = handle->ReadAttr(request->name.GetString(),
2093 					type, 0, buffer, size, &bytesRead);
2094 				if (result == B_OK && (int32)bytesRead != size)
2095 					result = B_ERROR;
2096 
2097 				// convert
2098 				if (result == B_OK)
2099 					_ConvertAttribute(info, buffer);
2100 			}
2101 
2102 			// prepare the reply
2103 			ReadAttrReply reply;
2104 			if (result == B_OK) {
2105 				reply.pos = originalPos;
2106 				reply.data.SetTo(buffer + originalPos, originalSize);
2107 				reply.moreToCome = false;
2108 			}
2109 
2110 			// send the reply
2111 			reply.error = result;
2112 			status_t error = GetChannel()->SendRequest(&reply);
2113 			if (error != B_OK)
2114 				return error;
2115 		} else {
2116 			// read as long as there are bytes left to read or an error occurs
2117 			bool moreToRead = true;
2118 			do {
2119 				int32 bytesToRead = min(size, bufferSize);
2120 				size_t bytesRead = 0;
2121 				if (result == B_OK) {
2122 					result = handle->ReadAttr(request->name.GetString(),
2123 						request->type, pos, buffer, bytesToRead, &bytesRead);
2124 				}
2125 				moreToRead = (result == B_OK && bytesRead > 0
2126 					&& (int32)bytesRead < size);
2127 
2128 				// prepare the reply
2129 				ReadAttrReply reply;
2130 				if (result == B_OK) {
2131 					reply.pos = pos;
2132 					reply.data.SetTo(buffer, bytesRead);
2133 					reply.moreToCome = moreToRead;
2134 					pos += bytesRead;
2135 					size -= bytesRead;
2136 				}
2137 
2138 				// send the reply
2139 				reply.error = result;
2140 				status_t error = GetChannel()->SendRequest(&reply);
2141 				if (error != B_OK)
2142 					return error;
2143 			} while (moreToRead);
2144 		}
2145 
2146 		// close the handle
2147 		volume->Close(handle);
2148 	} else {
2149 		// opening the node failed (or something even earlier): send an error
2150 		// reply
2151 		ReadAttrReply reply;
2152 		reply.error = result;
2153 		status_t error = GetChannel()->SendRequest(&reply);
2154 		if (error != B_OK)
2155 			return error;
2156 	}
2157 
2158 	return B_OK;
2159 }
2160 
2161 // VisitWriteAttrRequest
2162 status_t
2163 ClientConnection::VisitWriteAttrRequest(WriteAttrRequest* request)
2164 {
2165 	ConnectionReference connectionReference(this);
2166 	if (!connectionReference.IsValid())
2167 		return B_OK;
2168 
2169 	// get the volume
2170 	status_t result = B_OK;
2171 	ClientVolume* volume = _GetVolume(request->volumeID);
2172 	if (!volume)
2173 		result = B_BAD_VALUE;
2174 	ClientVolumePutter volumePutter(this, volume);
2175 
2176 	VolumeManagerLocker managerLocker;
2177 
2178 	// get the node
2179 	Node* node = NULL;
2180 	if (result == B_OK) {
2181 		node = volume->GetNode(request->nodeID);
2182 		if (!node)
2183 			result = B_ENTRY_NOT_FOUND;
2184 	}
2185 
2186 	// check read permission
2187 	if (result == B_OK) {
2188 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2189 			result = B_PERMISSION_DENIED;
2190 	}
2191 
2192 	// open the node
2193 	FileHandle* handle = NULL;
2194 	if (result == B_OK)
2195 		result = volume->Open(node, O_RDWR, &handle);
2196 	NodeHandleUnlocker handleUnlocker(volume, handle);
2197 
2198 	managerLocker.Unlock();
2199 
2200 	if (result == B_OK) {
2201 		off_t pos = max(request->pos, (off_t)0);
2202 		int32 size = request->data.GetSize();
2203 		type_code type = request->type;
2204 		char* buffer = (char*)request->data.GetData();
2205 
2206 		// convert the data, if necessary
2207 		if (fInverseClientEndianess) {
2208 			if (_KnownAttributeType(type)) {
2209 				if (pos != 0) {
2210 					WARN("WriteAttr(): WARNING: Need to convert attribute "
2211 						"endianess, but position is not 0: attribute: %s, "
2212 						"pos: %" B_PRIdOFF ", size: %" B_PRId32 "\n",
2213 						request->name.GetString(), pos, size);
2214 				}
2215 				swap_data(type, buffer, size, B_SWAP_ALWAYS);
2216 			} else
2217 				type = B_SWAP_INT32(type);
2218 		}
2219 
2220 		// write the data
2221 		while (result == B_OK && size > 0) {
2222 			size_t bytesWritten;
2223 			result = handle->WriteAttr(request->name.GetString(),
2224 				type, pos, buffer, size, &bytesWritten);
2225 			if (result == B_OK) {
2226 				pos += bytesWritten;
2227 				buffer += bytesWritten;
2228 				size -= bytesWritten;
2229 			}
2230 		}
2231 
2232 		// close the handle
2233 		volume->Close(handle);
2234 	}
2235 
2236 	// prepare the reply
2237 	WriteAttrReply reply;
2238 	// send the reply
2239 	reply.error = result;
2240 	return GetChannel()->SendRequest(&reply);
2241 }
2242 
2243 // VisitRemoveAttrRequest
2244 status_t
2245 ClientConnection::VisitRemoveAttrRequest(RemoveAttrRequest* request)
2246 {
2247 	ConnectionReference connectionReference(this);
2248 	if (!connectionReference.IsValid())
2249 		return B_OK;
2250 
2251 	// get the volume
2252 	status_t result = B_OK;
2253 	ClientVolume* volume = _GetVolume(request->volumeID);
2254 	if (!volume)
2255 		result = B_BAD_VALUE;
2256 	ClientVolumePutter volumePutter(this, volume);
2257 
2258 	VolumeManagerLocker managerLocker;
2259 
2260 	// get the node
2261 	Node* node = NULL;
2262 	if (result == B_OK) {
2263 		node = volume->GetNode(request->nodeID);
2264 		if (!node)
2265 			result = B_ENTRY_NOT_FOUND;
2266 	}
2267 
2268 	// check read permission
2269 	if (result == B_OK) {
2270 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2271 			result = B_PERMISSION_DENIED;
2272 	}
2273 
2274 	// open the node
2275 	FileHandle* handle = NULL;
2276 	if (result == B_OK)
2277 		result = volume->Open(node, O_RDWR, &handle);
2278 	NodeHandleUnlocker handleUnlocker(volume, handle);
2279 
2280 	managerLocker.Unlock();
2281 
2282 	// remove the attribute and close the node
2283 	if (result == B_OK) {
2284 		result = handle->RemoveAttr(request->name.GetString());
2285 		volume->Close(handle);
2286 	}
2287 
2288 	// send the reply
2289 	RemoveAttrReply reply;
2290 	reply.error = result;
2291 	return GetChannel()->SendRequest(&reply);
2292 }
2293 
2294 // VisitRenameAttrRequest
2295 status_t
2296 ClientConnection::VisitRenameAttrRequest(RenameAttrRequest* request)
2297 {
2298 	// Not supported, since there's no API function to rename an attribute.
2299 	// send the reply
2300 	RemoveAttrReply reply;
2301 	reply.error = B_UNSUPPORTED;
2302 	return GetChannel()->SendRequest(&reply);
2303 }
2304 
2305 // VisitStatAttrRequest
2306 status_t
2307 ClientConnection::VisitStatAttrRequest(StatAttrRequest* request)
2308 {
2309 	ConnectionReference connectionReference(this);
2310 	if (!connectionReference.IsValid())
2311 		return B_OK;
2312 
2313 	// get the volume
2314 	status_t result = B_OK;
2315 	ClientVolume* volume = _GetVolume(request->volumeID);
2316 	if (!volume)
2317 		result = B_BAD_VALUE;
2318 	ClientVolumePutter volumePutter(this, volume);
2319 
2320 	VolumeManagerLocker managerLocker;
2321 
2322 	// get the node
2323 	Node* node = NULL;
2324 	if (result == B_OK) {
2325 		node = volume->GetNode(request->nodeID);
2326 		if (!node)
2327 			result = B_ENTRY_NOT_FOUND;
2328 	}
2329 
2330 	// check read permission
2331 	if (result == B_OK) {
2332 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2333 			result = B_PERMISSION_DENIED;
2334 	}
2335 
2336 	// open the node
2337 	FileHandle* handle = NULL;
2338 	if (result == B_OK)
2339 		result = volume->Open(node, O_RDONLY, &handle);
2340 	NodeHandleUnlocker handleUnlocker(volume, handle);
2341 
2342 	managerLocker.Unlock();
2343 
2344 	// stat the attribute and close the node
2345 	attr_info attrInfo;
2346 	StatAttrReply reply;
2347 	if (result == B_OK) {
2348 		result = handle->StatAttr(request->name.GetString(), &attrInfo);
2349 		volume->Close(handle);
2350 	}
2351 
2352 	// set the attribute info
2353 	if (result == B_OK) {
2354 		result = _GetAttrInfo(request, request->name.GetString(), attrInfo,
2355 			NULL, &reply.attrInfo);
2356 	}
2357 
2358 	// send the reply
2359 	reply.error = result;
2360 	return GetChannel()->SendRequest(&reply);
2361 }
2362 
2363 // VisitOpenQueryRequest
2364 status_t
2365 ClientConnection::VisitOpenQueryRequest(OpenQueryRequest* request)
2366 {
2367 	ConnectionReference connectionReference(this);
2368 	if (!connectionReference.IsValid())
2369 		return B_OK;
2370 
2371 	VolumeManagerLocker managerLocker;
2372 
2373 	// open the query
2374 	status_t result;
2375 	QueryHandle* handle = NULL;
2376 	result = _OpenQuery(request->queryString.GetString(),
2377 			request->flags, request->port, request->token, &handle);
2378 	QueryHandleUnlocker handleUnlocker(this, handle);
2379 
2380 	// prepare the reply
2381 	OpenQueryReply reply;
2382 	if (result == B_OK)
2383 		reply.cookie = handle->GetCookie();
2384 
2385 	managerLocker.Unlock();
2386 
2387 	// send the reply
2388 	reply.error = result;
2389 	status_t error = GetChannel()->SendRequest(&reply);
2390 
2391 	// close the handle, if a send error occurred
2392 	if (error != B_OK && result == B_OK)
2393 		_CloseQuery(handle);
2394 
2395 	return error;
2396 }
2397 
2398 // VisitReadQueryRequest
2399 status_t
2400 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request)
2401 {
2402 	ConnectionReference connectionReference(this);
2403 	if (!connectionReference.IsValid())
2404 		return B_OK;
2405 
2406 	// create an array for the IDs of the client volumes a found entry may
2407 	// reside on
2408 	status_t result = B_OK;
2409 	int32 volumeCount = fVolumes->Size();
2410 	int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2411 	if (!volumeIDs)
2412 		result = B_NO_MEMORY;
2413 
2414 	ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2415 
2416 	// get the query handle
2417 	QueryHandle* handle = NULL;
2418 	if (result == B_OK)
2419 		result = _LockQueryHandle(request->cookie, &handle);
2420 	QueryHandleUnlocker handleUnlocker(this, handle);
2421 
2422 	// check if it is a query handle
2423 	QueryHandle* queryHandle = NULL;
2424 	if (result == B_OK) {
2425 		queryHandle = dynamic_cast<QueryHandle*>(handle);
2426 		if (!queryHandle)
2427 			result = B_BAD_VALUE;
2428 	}
2429 
2430 	// read the query
2431 	ReadQueryReply reply;
2432 	int32 countRead = 0;
2433 	while (result == B_OK) {
2434 		uint8 buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH];
2435 		struct dirent* dirEntry = (struct dirent*)buffer;
2436 
2437 		result = queryHandle->ReadDir(dirEntry, 1, &countRead);
2438 		if (result != B_OK)
2439 			break;
2440 		if (countRead == 0)
2441 			break;
2442 		PRINT("  query entry: %" B_PRIdDEV ", %" B_PRIdINO ", \"%s\"\n",
2443 			dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name);
2444 
2445 		VolumeManagerLocker managerLocker;
2446 		VolumeManager* volumeManager = VolumeManager::GetDefault();
2447 
2448 		// load the entry
2449 		Entry* entry = NULL;
2450 		result = volumeManager->LoadEntry(dirEntry->d_pdev,
2451 			dirEntry->d_pino, dirEntry->d_name, true, &entry);
2452 
2453 		// if at least one client volume contains the entry, get an entry info
2454 		if (result == B_OK) {
2455 			HasQueryPermissionClientVolumeFilter filter;
2456 			int32 entryVolumeCount = _GetContainingClientVolumes(
2457 				entry->GetDirectory(), volumeIDs, volumeCount, &filter);
2458 			if (entryVolumeCount > 0) {
2459 				// store all the client volume IDs in the reply
2460 				for (int32 i = 0; i < entryVolumeCount; i++) {
2461 					result = reply.clientVolumeIDs.Append(volumeIDs[i]);
2462 					if (result != B_OK)
2463 						break;
2464 				}
2465 
2466 				// get an entry info
2467 				_GetNodeInfo(entry->GetDirectory(), &reply.dirInfo);
2468 				_GetEntryInfo(entry, &reply.entryInfo);
2469 				break;
2470 			} else
2471 				PRINT(("  -> no client volumes\n"));
2472 		}
2473 
2474 		// entry is not in the volume: next round...
2475 		result = B_OK;
2476 	}
2477 
2478 	// send the reply
2479 	reply.error = result;
2480 	reply.count = countRead;
2481 	PRINT("ReadQuery: (%" B_PRIx32 ", %" B_PRId32 ", "
2482 		"dir: (%" B_PRIdDEV ", %" B_PRIdINO "), "
2483 		"node: (%" B_PRIdDEV ", %" B_PRIdINO ", `%s')\n",
2484 		reply.error, reply.count,
2485 		reply.entryInfo.directoryID.volumeID,
2486 		reply.entryInfo.directoryID.nodeID,
2487 		reply.entryInfo.nodeInfo.st.st_dev,
2488 		reply.entryInfo.nodeInfo.st.st_ino,
2489 		reply.entryInfo.name.GetString());
2490 	return GetChannel()->SendRequest(&reply);
2491 }
2492 
2493 
2494 // #pragma mark -
2495 
2496 // ProcessNodeMonitoringEvent
2497 void
2498 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID,
2499 	NodeMonitoringEvent* event)
2500 {
2501 	// get a connection reference
2502 	ConnectionReference connectionReference(this);
2503 	if (!connectionReference.IsValid())
2504 		return;
2505 
2506 	_PushNodeMonitoringEvent(volumeID, event);
2507 }
2508 
2509 // CloseNodeMonitoringEventQueue
2510 void
2511 ClientConnection::CloseNodeMonitoringEventQueue()
2512 {
2513 	typedef Vector<NodeMonitoringRequest*> RequestVector;
2514 	const RequestVector* requests = NULL;
2515 	if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) {
2516 		for (RequestVector::ConstIterator it = requests->Begin();
2517 			 it != requests->End();
2518 			 it++) {
2519 			delete *it;
2520 		}
2521 	}
2522 }
2523 
2524 
2525 // #pragma mark -
2526 
2527 // QueryDomainIntersectsWith
2528 bool
2529 ClientConnection::QueryDomainIntersectsWith(Volume* volume)
2530 {
2531 	// Iterate through the the client volumes and check whether any one contains
2532 	// the supplied volume or its root dir is on the volume. We don't check
2533 	// directory inclusion for the latter, since we don't need to query the
2534 	// volume, if the client volume is located on a volume mounted somewhere
2535 	// under the supplied volume (e.g. the root FS contains everything, but does
2536 	// seldomly need to be queried).
2537 	VolumeManager* volumeManager = VolumeManager::GetDefault();
2538 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
2539 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2540 		ClientVolume* clientVolume = it.Next().value;
2541 		Directory* volumeRoot = volume->GetRootDirectory();
2542 		Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
2543 		if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true)
2544 			|| volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) {
2545 			return true;
2546 		}
2547 	}
2548 
2549 	return false;
2550 }
2551 
2552 // ProcessQueryEvent
2553 void
2554 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event)
2555 {
2556 	dev_t volumeID;
2557 	ino_t directoryID;
2558 	if (event->opcode == B_ENTRY_CREATED) {
2559 		// "entry created" event
2560 		EntryCreatedEvent* createdEvent
2561 			= dynamic_cast<EntryCreatedEvent*>(event);
2562 		if (!createdEvent)
2563 			return;
2564 		volumeID = createdEvent->volumeID;
2565 		directoryID = createdEvent->directoryID;
2566 
2567 	} else if (event->opcode == B_ENTRY_REMOVED) {
2568 		// "entry removed" event
2569 		EntryRemovedEvent* removedEvent
2570 			= dynamic_cast<EntryRemovedEvent*>(event);
2571 		if (!removedEvent)
2572 			return;
2573 		volumeID = removedEvent->volumeID;
2574 		directoryID = removedEvent->directoryID;
2575 
2576 	} else {
2577 		// We only support "entry created" and "entry removed" query events.
2578 		// "entry moved" is split by the volume manager into those.
2579 		ERROR("Ignoring unexpected query event: opcode: 0x%" B_PRIx32 "\n",
2580 			event->opcode);
2581 		return;
2582 	}
2583 	PRINT("ClientConnection::ProcessQueryEvent(): event: %p, type: %s:"
2584 		" directory: (%" B_PRIdDEV ", %" B_PRIdINO ")\n",
2585 		event, typeid(event).name(), volumeID, directoryID);
2586 
2587 	// create an array for the IDs of the client volumes a found entry may
2588 	// reside on
2589 	int32 volumeCount = fVolumes->Size();
2590 	int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2591 	if (!volumeIDs)
2592 		return;
2593 
2594 	ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2595 
2596 	HasQueryPermissionClientVolumeFilter filter;
2597 
2598 	// load the directory the concerned entry belongs/belonged to
2599 	Directory* directory;
2600 	int32 concernedVolumes = 0;
2601 	if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID,
2602 			&directory) == B_OK) {
2603 		// find out, which client volumes the directory is located in
2604 		concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs,
2605 			volumeCount, &filter);
2606 	} else {
2607 		// Failed to load the directory, so maybe it has already been
2608 		// deleted. For "entry removed" events, we consider all client
2609 		// volumes to be notified -- those that don't know the entry will
2610 		// ignore the event.
2611 		if (event->opcode == B_ENTRY_REMOVED) {
2612 			concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount,
2613 				&filter);
2614 		}
2615 	}
2616 
2617 	// now push the event for each concerned client volume
2618 	for (int32 i = 0; i < concernedVolumes; i++)
2619 		_PushNodeMonitoringEvent(volumeIDs[i], event);
2620 	// TODO: More than one volume will usually only be concerned in case of
2621 	// nested client volumes. We could optimize the case by having an array of
2622 	// volume IDs in the respective requests sent over the net (just as in the
2623 	// ReadQueryReply).
2624 }
2625 
2626 
2627 // #pragma mark -
2628 
2629 // _Close
2630 void
2631 ClientConnection::_Close()
2632 {
2633 	// terminate node monitoring processor
2634 	CloseNodeMonitoringEventQueue();
2635 	if (fNodeMonitoringProcessor >= 0
2636 		&& find_thread(NULL) != fNodeMonitoringProcessor) {
2637 		int32 result;
2638 		wait_for_thread(fNodeMonitoringProcessor, &result);
2639 		// The variable is not unset, when this is the node monitoring
2640 		// processor thread -- which is good, since the destructor will
2641 		// wait for the thread in this case.
2642 		fNodeMonitoringProcessor = -1;
2643 	}
2644 	if (fConnection)
2645 		fConnection->Close();
2646 	// notify the listener
2647 	ClientConnectionListener* listener = fListener;
2648 	fListener = NULL;
2649 	if (listener)
2650 		listener->ClientConnectionClosed(this, fError);
2651 }
2652 
2653 // _MarkClosed
2654 void
2655 ClientConnection::_MarkClosed(bool error)
2656 {
2657 	AutoLocker<Locker> _(fLock);
2658 	if (!fClosed) {
2659 		fClosed = true;
2660 		fError = error;
2661 	}
2662 }
2663 
2664 // _GetNodeInfo
2665 void
2666 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info)
2667 {
2668 	if (node && info) {
2669 		info->st = node->GetStat();
2670 		info->revision = VolumeManager::GetDefault()->GetRevision();
2671 	}
2672 }
2673 
2674 // _GetEntryInfo
2675 void
2676 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info)
2677 {
2678 	if (entry && info) {
2679 		info->directoryID.volumeID = entry->GetVolumeID();
2680 		info->directoryID.nodeID = entry->GetDirectoryID();
2681 		info->name.SetTo(entry->GetName());
2682 		_GetNodeInfo(entry->GetNode(), &info->nodeInfo);
2683 	}
2684 }
2685 
2686 // _GetAttrInfo
2687 status_t
2688 ClientConnection::_GetAttrInfo(Request* request, const char* name,
2689 	const attr_info& attrInfo, const void* data, AttributeInfo* info)
2690 {
2691 	if (!request || !name || !info)
2692 		return B_BAD_VALUE;
2693 
2694 	info->name.SetTo(name);
2695 	info->info = attrInfo;
2696 	data = (attrInfo.size > 0 ? data : NULL);
2697 	int32 dataSize = (data ? attrInfo.size : 0);
2698 	info->data.SetTo(data, dataSize);
2699 
2700 	// if the client has inverse endianess, swap the type, if we don't know it
2701 	if (fInverseClientEndianess) {
2702 		if (_KnownAttributeType(info->info.type)) {
2703 			// we need to convert the data, if supplied
2704 			if (data) {
2705 				// allocate a buffer
2706 				RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize);
2707 				if (!requestBuffer)
2708 					return B_NO_MEMORY;
2709 
2710 				// convert the data
2711 				memcpy(requestBuffer->GetData(), data, dataSize);
2712 				_ConvertAttribute(info->info, requestBuffer->GetData());
2713 			}
2714 		} else
2715 			info->info.type = B_SWAP_INT32(info->info.type);
2716 	}
2717 
2718 	return B_OK;
2719 }
2720 
2721 // _GetAttrDirInfo
2722 status_t
2723 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir,
2724 	AttrDirInfo* info)
2725 {
2726 	if (!request || !attrDir || !info || !attrDir->IsAttrDirValid())
2727 		return B_BAD_VALUE;
2728 
2729 	// add the attribute infos
2730 	for (Attribute* attribute = attrDir->GetFirstAttribute();
2731 		 attribute;
2732 		 attribute = attrDir->GetNextAttribute(attribute)) {
2733 		// get the attribute info
2734 		AttributeInfo attrInfo;
2735 		attr_info bAttrInfo;
2736 		attribute->GetInfo(&bAttrInfo);
2737 		status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo,
2738 			attribute->GetData(), &attrInfo);
2739 
2740 		// append it
2741 		if (error == B_OK)
2742 			error = info->attributeInfos.Append(attrInfo);
2743 		if (error != B_OK)
2744 			return error;
2745 	}
2746 
2747 	info->revision = VolumeManager::GetDefault()->GetRevision();
2748 	info->isValid = true;
2749 
2750 	return B_OK;
2751 }
2752 
2753 // _CreateVolume
2754 status_t
2755 ClientConnection::_CreateVolume(ClientVolume** _volume)
2756 {
2757 	// create and init the volume
2758 	ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock,
2759 		this);
2760 	if (!volume)
2761 		return B_NO_MEMORY;
2762 	status_t error = volume->Init();
2763 	if (error != B_OK) {
2764 		delete volume;
2765 		return error;
2766 	}
2767 
2768 	// add it to the volume map
2769 	AutoLocker<VolumeMap> locker(fVolumes);
2770 	error = fVolumes->Put(volume->GetID(), volume);
2771 	locker.Unlock();
2772 
2773 	if (error == B_OK)
2774 		*_volume = volume;
2775 	else
2776 		delete volume;
2777 
2778 	return error;
2779 }
2780 
2781 // _GetVolume
2782 ClientVolume*
2783 ClientConnection::_GetVolume(int32 id)
2784 {
2785 	AutoLocker<VolumeMap> _(fVolumes);
2786 	ClientVolume* volume = fVolumes->Get(id);
2787 	if (!volume || volume->IsRemoved())
2788 		return NULL;
2789 	volume->AcquireReference();
2790 	return volume;
2791 }
2792 
2793 // _PutVolume
2794 //
2795 // The VolumeManager may be locked, but no other lock must be held.
2796 void
2797 ClientConnection::_PutVolume(ClientVolume* volume)
2798 {
2799 	if (!volume)
2800 		return;
2801 
2802 	// decrement reference counter and remove the volume, if 0
2803 	AutoLocker<VolumeMap> locker(fVolumes);
2804 	bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved());
2805 	if (removed)
2806 		fVolumes->Remove(volume->GetID());
2807 	locker.Unlock();
2808 
2809 	if (removed) {
2810 		VolumeManagerLocker managerLocker;
2811 		delete volume;
2812 	}
2813 }
2814 
2815 // _UnmountVolume
2816 //
2817 // The caller must have a reference to the volume.
2818 void
2819 ClientConnection::_UnmountVolume(ClientVolume* volume)
2820 {
2821 	if (!volume)
2822 		return;
2823 	AutoLocker<VolumeMap> locker(fVolumes);
2824 	volume->MarkRemoved();
2825 	locker.Unlock();
2826 
2827 	// push a notification event
2828 	if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) {
2829 		VolumeManagerLocker managerLocker;
2830 
2831 		event->opcode = B_DEVICE_UNMOUNTED;
2832 		_PushNodeMonitoringEvent(volume->GetID(), event);
2833 		event->ReleaseReference();
2834 	}
2835 }
2836 
2837 // _UnmountAllVolumes
2838 void
2839 ClientConnection::_UnmountAllVolumes()
2840 {
2841 	while (true) {
2842 		// To avoid heap allocation (which can fail) we unmount the volumes
2843 		// chunkwise.
2844 		// get the volumes
2845 		const int32 volumeChunkSize = 32;
2846 		ClientVolume* volumes[volumeChunkSize];
2847 		int32 volumeCount = 0;
2848 		AutoLocker<VolumeMap> volumesLocker(fVolumes);
2849 		for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2850 			if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) {
2851 				volumes[volumeCount++] = volume;
2852 			}
2853 			if (volumeCount == volumeChunkSize)
2854 				break;
2855 		}
2856 		volumesLocker.Unlock();
2857 
2858 		// unmount and put the volumes
2859 		for (int32 i = 0; i < volumeCount; i++) {
2860 			ClientVolume* volume = volumes[i];
2861 			_UnmountVolume(volume);
2862 			_PutVolume(volume);
2863 		}
2864 
2865 		if (volumeCount < volumeChunkSize)
2866 			break;
2867 	}
2868 }
2869 
2870 // _NodeMonitoringProcessorEntry
2871 int32
2872 ClientConnection::_NodeMonitoringProcessorEntry(void* data)
2873 {
2874 	return ((ClientConnection*)data)->_NodeMonitoringProcessor();
2875 }
2876 
2877 
2878 // _NodeMonitoringProcessor
2879 int32
2880 ClientConnection::_NodeMonitoringProcessor()
2881 {
2882 	while (!fClosed) {
2883 		// get the next request
2884 		NodeMonitoringRequest* request = NULL;
2885 		status_t error = fNodeMonitoringEvents->Pop(&request);
2886 
2887 		// get a client connection reference
2888 		ConnectionReference connectionReference(this);
2889 		if (!connectionReference.IsValid())
2890 			return B_OK;
2891 
2892 		// No request? Next round...
2893 		if (error != B_OK)
2894 			continue;
2895 		ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2896 
2897 		// send the request
2898 		error = fConnection->SendRequest(request);
2899 		if (error != B_OK) {
2900 			ERROR(("ClientConnection::_NodeMonitoringProcessor(): "
2901 				"Failed to send request.\n"));
2902 		}
2903 	}
2904 	return 0;
2905 }
2906 
2907 
2908 // _PushNodeMonitoringEvent
2909 //
2910 // The caller must have a connection reference. Moreover the VolumeManager
2911 // must be locked.
2912 status_t
2913 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID,
2914 	NodeMonitoringEvent* event)
2915 {
2916 	if (!event)
2917 		return B_BAD_VALUE;
2918 
2919 	// get the volume
2920 	ClientVolume* volume = _GetVolume(volumeID);
2921 	if (!volume && event->opcode != B_DEVICE_UNMOUNTED)
2922 		return B_BAD_VALUE;
2923 	ClientVolumePutter volumePutter(this, volume);
2924 
2925 	// create a node monitoring request
2926 	NodeMonitoringRequest* request = NULL;
2927 	status_t error = B_ERROR;
2928 	switch (event->opcode) {
2929 		case B_ENTRY_CREATED:
2930 			error = _EntryCreated(volume,
2931 				dynamic_cast<EntryCreatedEvent*>(event), request);
2932 			break;
2933 		case B_ENTRY_REMOVED:
2934 			error = _EntryRemoved(volume,
2935 				dynamic_cast<EntryRemovedEvent*>(event), request);
2936 			break;
2937 		case B_ENTRY_MOVED:
2938 			error = _EntryMoved(volume,
2939 				dynamic_cast<EntryMovedEvent*>(event), request);
2940 			break;
2941 		case B_STAT_CHANGED:
2942 			error = _NodeStatChanged(volume,
2943 				dynamic_cast<StatChangedEvent*>(event), request);
2944 			break;
2945 		case B_ATTR_CHANGED:
2946 			error = _NodeAttributeChanged(volume,
2947 				dynamic_cast<AttributeChangedEvent*>(event), request);
2948 			break;
2949 		case B_DEVICE_UNMOUNTED:
2950 			error = B_OK;
2951 			break;
2952 	}
2953 
2954 	// replace all data buffers -- when the request is actually sent, they
2955 	// might no longer exist
2956 	if (error == B_OK)
2957 		error = RequestBufferReplacer().ReplaceBuffer(request);
2958 
2959 	if (error == B_OK) {
2960 		// common initialization
2961 		request->volumeID = volumeID;
2962 		request->opcode = event->opcode;
2963 		request->revision = VolumeManager::GetDefault()->GetRevision();
2964 
2965 		// push the request
2966 		error = fNodeMonitoringEvents->Push(request);
2967 		if (error != B_OK)
2968 			delete request;
2969 	}
2970 
2971 	return error;
2972 }
2973 
2974 // _EntryCreated
2975 status_t
2976 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event,
2977 	NodeMonitoringRequest*& _request)
2978 {
2979 	// allocate the request
2980 	EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest;
2981 	if (!request)
2982 		return B_NO_MEMORY;
2983 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2984 
2985 	// get the name
2986 	const char* name = event->name.GetString();
2987 
2988 	// set the request fields
2989 	request->directoryID = NodeID(event->volumeID, event->directoryID);
2990 	request->nodeID = NodeID(event->volumeID, event->nodeID);
2991 	request->name.SetTo(name);
2992 	if (event->queryHandler) {
2993 		request->port = event->remotePort;
2994 		request->token = event->remoteToken;
2995 		request->queryUpdate = true;
2996 	} else
2997 		request->queryUpdate = false;
2998 
2999 	// try to get an entry info
3000 	Entry* entry;
3001 	if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
3002 			event->directoryID, name, true, &entry) == B_OK
3003 		&& entry->GetNode()->GetVolumeID() == event->volumeID
3004 		&& entry->GetNode()->GetID() == event->nodeID) {
3005 		_GetEntryInfo(entry, &request->entryInfo);
3006 		request->entryInfoValid = true;
3007 	} else
3008 		request->entryInfoValid = false;
3009 
3010 	requestDeleter.Detach();
3011 	_request = request;
3012 	return B_OK;
3013 }
3014 
3015 // _EntryRemoved
3016 status_t
3017 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event,
3018 	NodeMonitoringRequest*& _request)
3019 {
3020 	// special handling, if it is the root node of the client volume that has
3021 	// been removed
3022 	if (!event->queryHandler
3023 		&& NodeRef(event->nodeVolumeID, event->nodeID)
3024 			== volume->GetRootNodeRef()) {
3025 		NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, ".");
3026 		BEntry entry;
3027 		if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists())
3028 			_UnmountVolume(volume);
3029 
3030 		// don't send the "entry removed" event
3031 		return B_ERROR;
3032 	}
3033 
3034 	// allocate the request
3035 	EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest;
3036 	if (!request)
3037 		return B_NO_MEMORY;
3038 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3039 
3040 	// get the name
3041 	const char* name = event->name.GetString();
3042 
3043 	// set the request fields
3044 	request->directoryID = NodeID(event->volumeID, event->directoryID);
3045 	request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3046 	request->name.SetTo(name);
3047 	if (event->queryHandler) {
3048 		request->port = event->remotePort;
3049 		request->token = event->remoteToken;
3050 		request->queryUpdate = true;
3051 	} else
3052 		request->queryUpdate = false;
3053 
3054 	requestDeleter.Detach();
3055 	_request = request;
3056 	return B_OK;
3057 }
3058 
3059 // _EntryMoved
3060 status_t
3061 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event,
3062 	NodeMonitoringRequest*& _request)
3063 {
3064 	// allocate the request
3065 	EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest;
3066 	if (!request)
3067 		return B_NO_MEMORY;
3068 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3069 
3070 	// allocate memory for the names
3071 	int32 fromNameLen = event->fromName.GetLength();
3072 	const char* fromName
3073 		= (fromNameLen > 0 ? event->fromName.GetString() : NULL);
3074 	const char* toName = event->toName.GetString();
3075 
3076 	// set the request fields
3077 	request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID);
3078 	request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID);
3079 	request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3080 	request->fromName.SetTo(fromName);
3081 	request->toName.SetTo(toName);
3082 	request->queryUpdate = false;
3083 
3084 	// try to get an entry info
3085 	Entry* entry;
3086 	if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
3087 			event->toDirectoryID, toName, true, &entry) == B_OK
3088 		&& entry->GetNode()->GetVolumeID() == event->nodeVolumeID
3089 		&& entry->GetNode()->GetID() == event->nodeID) {
3090 		_GetEntryInfo(entry, &request->entryInfo);
3091 		request->entryInfoValid = true;
3092 	} else
3093 		request->entryInfoValid = false;
3094 
3095 	requestDeleter.Detach();
3096 	_request = request;
3097 	return B_OK;
3098 }
3099 
3100 // _NodeStatChanged
3101 status_t
3102 ClientConnection::_NodeStatChanged(ClientVolume* volume,
3103 	StatChangedEvent* event, NodeMonitoringRequest*& _request)
3104 {
3105 	// get the node
3106 	Node* node = volume->GetNode(event->volumeID, event->nodeID);
3107 	if (!node)
3108 		return B_ENTRY_NOT_FOUND;
3109 
3110 	// allocate the request
3111 	StatChangedRequest* request = new(std::nothrow) StatChangedRequest;
3112 	if (!request)
3113 		return B_NO_MEMORY;
3114 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3115 
3116 	// set the request fields
3117 	request->nodeID = NodeID(event->volumeID, event->nodeID);
3118 	_GetNodeInfo(node, &request->nodeInfo);
3119 	request->queryUpdate = false;
3120 
3121 	requestDeleter.Detach();
3122 	_request = request;
3123 	return B_OK;
3124 }
3125 
3126 // _NodeAttributeChanged
3127 status_t
3128 ClientConnection::_NodeAttributeChanged(ClientVolume* volume,
3129 	AttributeChangedEvent* event, NodeMonitoringRequest*& _request)
3130 {
3131 	// get the node
3132 	Node* node = volume->GetNode(event->volumeID, event->nodeID);
3133 	if (!node)
3134 		return B_ENTRY_NOT_FOUND;
3135 
3136 	// update the attribute directory
3137 	bool removed = false;
3138 	bool valid = false;
3139 	attr_info info;
3140 	const void* data = NULL;
3141 	status_t error = node->UpdateAttribute(event->attribute.GetString(),
3142 		&removed, &info, &data);
3143 	valid = (error == B_OK);
3144 
3145 	// allocate the request
3146 	AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest;
3147 	if (!request)
3148 		return B_NO_MEMORY;
3149 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3150 
3151 	// get an attr dir info, if the directory is valid
3152 	if (node->IsAttrDirValid()) {
3153 		status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo);
3154 		if (error != B_OK)
3155 			return error;
3156 	}
3157 
3158 	// get name and the data size
3159 	int32 dataSize = (data ? info.size : 0);
3160 	const char* name = event->attribute.GetString();
3161 
3162 	// set the request fields
3163 	request->nodeID = NodeID(event->volumeID, event->nodeID);
3164 	request->attrInfo.name.SetTo(name);
3165 	request->valid = valid;
3166 	request->removed = removed;
3167 	if (!removed && valid) {
3168 		request->attrInfo.info = info;
3169 		request->attrInfo.data.SetTo(data, dataSize);
3170 	}
3171 	request->queryUpdate = false;
3172 
3173 	requestDeleter.Detach();
3174 	_request = request;
3175 	return B_OK;
3176 }
3177 
3178 // _KnownAttributeType
3179 bool
3180 ClientConnection::_KnownAttributeType(type_code type)
3181 {
3182 	if (!fInverseClientEndianess)
3183 		return false;
3184 
3185 	switch (type) {
3186 		case B_BOOL_TYPE:
3187 		case B_CHAR_TYPE:
3188 		case B_COLOR_8_BIT_TYPE:
3189 		case B_DOUBLE_TYPE:
3190 		case B_FLOAT_TYPE:
3191 		case B_GRAYSCALE_8_BIT_TYPE:
3192 		case B_INT64_TYPE:
3193 		case B_INT32_TYPE:
3194 		case B_INT16_TYPE:
3195 		case B_INT8_TYPE:
3196 		case B_MESSAGE_TYPE:
3197 		case B_MESSENGER_TYPE:
3198 		case B_MIME_TYPE:
3199 		case B_MONOCHROME_1_BIT_TYPE:
3200 		case B_OFF_T_TYPE:
3201 		case B_POINTER_TYPE:
3202 		case B_POINT_TYPE:
3203 		case B_RECT_TYPE:
3204 		case B_REF_TYPE:
3205 		case B_RGB_COLOR_TYPE:
3206 		case B_SIZE_T_TYPE:
3207 		case B_SSIZE_T_TYPE:
3208 		case B_STRING_TYPE:
3209 		case B_TIME_TYPE:
3210 		case B_UINT64_TYPE:
3211 		case B_UINT32_TYPE:
3212 		case B_UINT16_TYPE:
3213 		case B_UINT8_TYPE:
3214 		case B_ASCII_TYPE:
3215 		case B_MIME_STRING_TYPE:
3216 			return true;
3217 
3218 		//B_RGB_32_BIT_TYPE: We could translate it, but it's heavy...
3219 	}
3220 
3221 	return false;
3222 }
3223 
3224 // _ConvertAttribute
3225 void
3226 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer)
3227 {
3228 	swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS);
3229 }
3230 
3231 
3232 // #pragma mark -
3233 
3234 // _OpenQuery
3235 status_t
3236 ClientConnection::_OpenQuery(const char* queryString, uint32 flags,
3237 	port_id remotePort, int32 remoteToken, QueryHandle** _handle)
3238 {
3239 	if (!queryString || !_handle)
3240 		return B_BAD_VALUE;
3241 
3242 	// open query
3243 	QueryHandle* queryHandle;
3244 	status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString,
3245 		flags, remotePort, remoteToken, &queryHandle);
3246 	if (error != B_OK)
3247 		return error;
3248 	BReference<QueryHandle> handleReference(queryHandle, true);
3249 
3250 	// lock the handle
3251 	queryHandle->Lock();
3252 
3253 	// add the handle
3254 	error = fQueryHandles->AddNodeHandle(queryHandle);
3255 	if (error != B_OK)
3256 		return error;
3257 
3258 	handleReference.Detach();
3259 	*_handle = queryHandle;
3260 	return B_OK;
3261 }
3262 
3263 // _CloseQuery
3264 status_t
3265 ClientConnection::_CloseQuery(QueryHandle* handle)
3266 {
3267 	if (!handle || !fQueryHandles->RemoveNodeHandle(handle))
3268 		return B_BAD_VALUE;
3269 
3270 	return B_OK;
3271 }
3272 
3273 // _LockQueryHandle
3274 //
3275 // VolumeManager must NOT be locked.
3276 status_t
3277 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle)
3278 {
3279 	NodeHandle* handle;
3280 	status_t error = fQueryHandles->LockNodeHandle(cookie, &handle);
3281 	if (error == B_OK)
3282 		*_handle = static_cast<QueryHandle*>(handle);
3283 	return error;
3284 }
3285 
3286 // _UnlockQueryHandle
3287 //
3288 // VolumeManager may or may not be locked.
3289 void
3290 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle)
3291 {
3292 	fQueryHandles->UnlockNodeHandle(nodeHandle);
3293 }
3294 
3295 
3296 // #pragma mark -
3297 
3298 // _GetAllClientVolumeIDs
3299 int32
3300 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize,
3301 	ClientVolumeFilter* filter)
3302 {
3303 	int32 count = 0;
3304 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
3305 	for (VolumeMap::Iterator it = fVolumes->GetIterator();
3306 		 it.HasNext() && arraySize > count;) {
3307 		ClientVolume* clientVolume = it.Next().value;
3308 		if (!filter || filter->FilterVolume(this, clientVolume))
3309 			volumeIDs[count++] = clientVolume->GetID();
3310 	}
3311 
3312 	return count;
3313 }
3314 
3315 // _GetContainingClientVolumes
3316 int32
3317 ClientConnection::_GetContainingClientVolumes(Directory* directory,
3318 	int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter)
3319 {
3320 	int32 count = 0;
3321 	VolumeManager* volumeManager = VolumeManager::GetDefault();
3322 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
3323 	for (VolumeMap::Iterator it = fVolumes->GetIterator();
3324 		 it.HasNext() && arraySize > count;) {
3325 		ClientVolume* clientVolume = it.Next().value;
3326 		Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
3327 		if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true)
3328 			&& (!filter || filter->FilterVolume(this, clientVolume))) {
3329 			volumeIDs[count++] = clientVolume->GetID();
3330 		}
3331 	}
3332 
3333 	return count;
3334 }
3335 
3336 
3337 // #pragma mark -
3338 // #pragma mark ----- ClientConnectionListener -----
3339 
3340 // constructor
3341 ClientConnectionListener::ClientConnectionListener()
3342 {
3343 }
3344 
3345 // destructor
3346 ClientConnectionListener::~ClientConnectionListener()
3347 {
3348 }
3349 
3350