xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/ClientConnection.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 	}
1612 else {
1613 if (directory)
1614 PRINT("OpenDir() failed: client volume: %ld, node: (%ld, %lld)\n",
1615 volume->GetID(), directory->GetVolumeID(), directory->GetID());
1616 }
1617 
1618 	managerLocker.Unlock();
1619 
1620 	// send the reply
1621 	reply.error = result;
1622 	status_t error = GetChannel()->SendRequest(&reply);
1623 
1624 	// close the handle, if a send error occurred
1625 	if (error != B_OK && result == B_OK)
1626 		volume->Close(handle);
1627 
1628 	return error;
1629 }
1630 
1631 // VisitReadDirRequest
1632 status_t
1633 ClientConnection::VisitReadDirRequest(ReadDirRequest* request)
1634 {
1635 	ConnectionReference connectionReference(this);
1636 	if (!connectionReference.IsValid())
1637 		return B_OK;
1638 
1639 	// get the volume
1640 	status_t result = B_OK;
1641 	ClientVolume* volume = _GetVolume(request->volumeID);
1642 	if (!volume)
1643 		result = B_BAD_VALUE;
1644 	ClientVolumePutter volumePutter(this, volume);
1645 
1646 	// get the node handle
1647 	NodeHandle* handle = NULL;
1648 	if (result == B_OK)
1649 		result = volume->LockNodeHandle(request->cookie, &handle);
1650 	NodeHandleUnlocker handleUnlocker(volume, handle);
1651 
1652 	// check if it is a directory iterator
1653 	DirIterator* iterator = NULL;
1654 	if (result == B_OK) {
1655 		iterator = dynamic_cast<DirIterator*>(handle);
1656 		if (!iterator)
1657 			result = B_BAD_VALUE;
1658 	}
1659 
1660 	VolumeManagerLocker managerLocker;
1661 
1662 	// get the directory
1663 	Directory* directory = NULL;
1664 	if (result == B_OK) {
1665 		Node* node = volume->GetNode(iterator->GetNodeRef());
1666 		if (node) {
1667 			directory = dynamic_cast<Directory*>(node);
1668 			if (!directory)
1669 				result = B_NOT_A_DIRECTORY;
1670 		} else
1671 			result = B_ENTRY_NOT_FOUND;
1672 	}
1673 
1674 	// check read permission
1675 	if (result == B_OK) {
1676 		if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission())
1677 			result = B_PERMISSION_DENIED;
1678 	}
1679 
1680 if (result == B_OK) {
1681 	PRINT("ReadDir: (%ld, %lld)\n", request->volumeID, directory->GetID());
1682 }
1683 
1684 	// rewind, if requested
1685 	if (result == B_OK && request->rewind)
1686 		iterator->Rewind();
1687 
1688 	// read the directory
1689 	bool done = false;
1690 	ReadDirReply reply;
1691 	int32 toRead = request->count;
1692 	while (result == B_OK && toRead > 0) {
1693 		// get the next entry
1694 		Entry* entry = iterator->NextEntry();
1695 		if (!entry) {
1696 			done = true;
1697 			break;
1698 		}
1699 
1700 		// get and add an entry info
1701 		EntryInfo entryInfo;
1702 		_GetEntryInfo(entry, &entryInfo);
1703 		result = reply.entryInfos.Append(entryInfo);
1704 
1705 		toRead--;
1706 	}
1707 
1708 	reply.revision = VolumeManager::GetDefault()->GetRevision();
1709 
1710 //PRINT(("ReadDir: (%lld) -> (%lx, %ld, dir: %lld, node: %lld, `%s')\n",
1711 //directoryID, reply.error, reply.entryInfos.CountElements(),
1712 //reply.entryInfo.directoryID,
1713 //reply.entryInfo.nodeID, reply.entryInfo.name.GetString()));
1714 if (directory) {
1715 PRINT("ReadDir done: volume: %ld, (%ld, %lld) -> (%lx, %ld)\n",
1716 volume->GetID(), directory->GetVolumeID(), directory->GetID(), result,
1717 reply.entryInfos.CountElements());
1718 }
1719 
1720 	managerLocker.Unlock();
1721 
1722 	// send the reply
1723 	reply.error = result;
1724 	reply.done = (result != B_OK || done);
1725 	return GetChannel()->SendRequest(&reply);
1726 }
1727 
1728 // VisitWalkRequest
1729 status_t
1730 ClientConnection::VisitWalkRequest(WalkRequest* request)
1731 {
1732 	ConnectionReference connectionReference(this);
1733 	if (!connectionReference.IsValid())
1734 		return B_OK;
1735 
1736 	// get the volume
1737 	status_t result = B_OK;
1738 	ClientVolume* volume = _GetVolume(request->volumeID);
1739 	if (!volume)
1740 		result = B_BAD_VALUE;
1741 	ClientVolumePutter volumePutter(this, volume);
1742 
1743 	VolumeManagerLocker managerLocker;
1744 
1745 	// get the directory
1746 	Directory* directory = NULL;
1747 	if (result == B_OK) {
1748 		Node* node = volume->GetNode(request->nodeID);
1749 		if (node) {
1750 			directory = dynamic_cast<Directory*>(node);
1751 			if (!directory)
1752 				result = B_NOT_A_DIRECTORY;
1753 		} else
1754 			result = B_ENTRY_NOT_FOUND;
1755 	}
1756 
1757 	// check permission
1758 	if (result == B_OK) {
1759 		if (!volume->GetNodePermissions(directory)
1760 				.ImpliesResolveDirEntryPermission()) {
1761 			result = B_PERMISSION_DENIED;
1762 		}
1763 	}
1764 
1765 	WalkReply reply;
1766 	char linkPath[B_PATH_NAME_LENGTH];
1767 	if (result == B_OK) {
1768 		// load the entry
1769 		Entry* entry;
1770 		result = volume->LoadEntry(directory, request->name.GetString(),
1771 			&entry);
1772 
1773 		// fill in the reply
1774 		if (result == B_OK) {
1775 			_GetEntryInfo(entry, &reply.entryInfo);
1776 
1777 			// resolve a symlink, if desired
1778 			Node* node = entry->GetNode();
1779 			if (request->resolveLink && node->IsSymlink()) {
1780 				result = node->ReadSymlink(linkPath, B_PATH_NAME_LENGTH);
1781 				if (result == B_OK)
1782 					reply.linkPath.SetTo(linkPath);
1783 			}
1784 		}
1785 	}
1786 
1787 	managerLocker.Unlock();
1788 
1789 	// send the reply
1790 	reply.error = result;
1791 	PRINT("Walk: (%ld, %lld, `%s') -> (%lx, (%ld, %lld), `%s')\n",
1792 		request->nodeID.volumeID, request->nodeID.nodeID,
1793 		request->name.GetString(), result,
1794 		reply.entryInfo.nodeInfo.st.st_dev,
1795 		reply.entryInfo.nodeInfo.st.st_ino, reply.linkPath.GetString());
1796 	return GetChannel()->SendRequest(&reply);
1797 }
1798 
1799 // VisitMultiWalkRequest
1800 status_t
1801 ClientConnection::VisitMultiWalkRequest(MultiWalkRequest* request)
1802 {
1803 	ConnectionReference connectionReference(this);
1804 	if (!connectionReference.IsValid())
1805 		return B_OK;
1806 
1807 	// get the volume
1808 	status_t result = B_OK;
1809 	ClientVolume* volume = _GetVolume(request->volumeID);
1810 	if (!volume)
1811 		result = B_BAD_VALUE;
1812 	ClientVolumePutter volumePutter(this, volume);
1813 
1814 	VolumeManagerLocker managerLocker;
1815 
1816 	// get the directory
1817 	Directory* directory = NULL;
1818 	if (result == B_OK) {
1819 		Node* node = volume->GetNode(request->nodeID);
1820 		if (node) {
1821 			directory = dynamic_cast<Directory*>(node);
1822 			if (!directory)
1823 				result = B_NOT_A_DIRECTORY;
1824 		} else
1825 			result = B_ENTRY_NOT_FOUND;
1826 	}
1827 
1828 	// check permission
1829 	if (result == B_OK) {
1830 		if (!volume->GetNodePermissions(directory)
1831 				.ImpliesResolveDirEntryPermission()) {
1832 			result = B_PERMISSION_DENIED;
1833 		}
1834 	}
1835 
1836 	MultiWalkReply reply;
1837 	StringData* names = request->names.GetElements();
1838 	int32 count = request->names.CountElements();
1839 	for (int32 i = 0; result == B_OK && i < count; i++) {
1840 		// load the entry
1841 		Entry* entry;
1842 		if (volume->LoadEntry(directory, names[i].GetString(), &entry)
1843 				== B_OK) {
1844 			// add an entry info
1845 			EntryInfo entryInfo;
1846 			_GetEntryInfo(entry, &entryInfo);
1847 
1848 			// append the info
1849 			result = reply.entryInfos.Append(entryInfo);
1850 		}
1851 	}
1852 
1853 	managerLocker.Unlock();
1854 
1855 	// send the reply
1856 	reply.error = result;
1857 	PRINT("MultiWalk: (%ld, %lld, %ld) -> (%lx, %ld)\n",
1858 		request->nodeID.volumeID, request->nodeID.nodeID, count,
1859 		result, reply.entryInfos.CountElements());
1860 	return GetChannel()->SendRequest(&reply);
1861 }
1862 
1863 // VisitOpenAttrDirRequest
1864 status_t
1865 ClientConnection::VisitOpenAttrDirRequest(OpenAttrDirRequest* request)
1866 {
1867 	ConnectionReference connectionReference(this);
1868 	if (!connectionReference.IsValid())
1869 		return B_OK;
1870 
1871 	// get the volume
1872 	status_t result = B_OK;
1873 	ClientVolume* volume = _GetVolume(request->volumeID);
1874 	if (!volume)
1875 		result = B_BAD_VALUE;
1876 	ClientVolumePutter volumePutter(this, volume);
1877 
1878 	VolumeManagerLocker managerLocker;
1879 
1880 	// get the node
1881 	Node* node = NULL;
1882 	if (result == B_OK) {
1883 		node = volume->GetNode(request->nodeID);
1884 		if (!node)
1885 			result = B_ENTRY_NOT_FOUND;
1886 	}
1887 
1888 	// check permission
1889 	if (result == B_OK) {
1890 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1891 			result = B_PERMISSION_DENIED;
1892 	}
1893 
1894 	// load/cache the attribute directory
1895 	bool attrDirCached = (node->LoadAttrDir() == B_OK);
1896 
1897 	// open the attribute directory, if caching it failed
1898 	AttrDirIterator* handle = NULL;
1899 	if (result == B_OK && !attrDirCached)
1900 		result = volume->OpenAttrDir(node, &handle);
1901 	NodeHandleUnlocker handleUnlocker(volume, handle);
1902 
1903 	// prepare the reply
1904 	OpenAttrDirReply reply;
1905 	if (result == B_OK) {
1906 		if (handle) {
1907 			reply.cookie = handle->GetCookie();
1908 		} else {
1909 			// the attribute directory is cached
1910 			reply.cookie = -1;
1911 			result = _GetAttrDirInfo(request, node, &reply.attrDirInfo);
1912 		}
1913 	}
1914 
1915 	managerLocker.Unlock();
1916 
1917 	// send the reply
1918 	reply.error = result;
1919 	status_t error = GetChannel()->SendRequest(&reply);
1920 
1921 	// close the handle, if a send error occurred
1922 	if (error != B_OK && result == B_OK && handle)
1923 		volume->Close(handle);
1924 
1925 	return error;
1926 }
1927 
1928 // VisitReadAttrDirRequest
1929 status_t
1930 ClientConnection::VisitReadAttrDirRequest(ReadAttrDirRequest* request)
1931 {
1932 	ConnectionReference connectionReference(this);
1933 	if (!connectionReference.IsValid())
1934 		return B_OK;
1935 
1936 	// get the volume
1937 	status_t result = B_OK;
1938 	ClientVolume* volume = _GetVolume(request->volumeID);
1939 	if (!volume)
1940 		result = B_BAD_VALUE;
1941 	ClientVolumePutter volumePutter(this, volume);
1942 
1943 	// get the node handle
1944 	NodeHandle* handle = NULL;
1945 	if (result == B_OK)
1946 		result = volume->LockNodeHandle(request->cookie, &handle);
1947 	NodeHandleUnlocker handleUnlocker(volume, handle);
1948 
1949 	// check if it is a attribute directory iterator
1950 	AttrDirIterator* iterator = NULL;
1951 	if (result == B_OK) {
1952 		iterator = dynamic_cast<AttrDirIterator*>(handle);
1953 		if (!iterator)
1954 			result = B_BAD_VALUE;
1955 	}
1956 
1957 	VolumeManagerLocker managerLocker;
1958 
1959 	// get the node
1960 	Node* node = NULL;
1961 	if (result == B_OK) {
1962 		node = volume->GetNode(iterator->GetNodeRef());
1963 		if (!node)
1964 			result = B_ENTRY_NOT_FOUND;
1965 	}
1966 
1967 	// check read permission (we already checked when opening, but anyway...)
1968 	if (result == B_OK) {
1969 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1970 			result = B_PERMISSION_DENIED;
1971 	}
1972 
1973 	managerLocker.Unlock();
1974 
1975 	// read the attribute directory
1976 	uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
1977 	struct dirent* dirEntry = (struct dirent*)buffer;
1978 	int32 countRead = 0;
1979 	bool done = true;
1980 	if (result == B_OK) {
1981 		if (request->rewind)
1982 			result = iterator->RewindDir();
1983 		if (result == B_OK) {
1984 			result = iterator->ReadDir(dirEntry, sizeof(buffer), 1,
1985 				&countRead, &done);
1986 		}
1987 	}
1988 
1989 	// prepare the reply
1990 	ReadAttrDirReply reply;
1991 	reply.name.SetTo(dirEntry->d_name);
1992 
1993 	// send the reply
1994 	reply.error = result;
1995 	reply.count = countRead;
1996 	return GetChannel()->SendRequest(&reply);
1997 }
1998 
1999 // VisitReadAttrRequest
2000 status_t
2001 ClientConnection::VisitReadAttrRequest(ReadAttrRequest* request)
2002 {
2003 	ConnectionReference connectionReference(this);
2004 	if (!connectionReference.IsValid())
2005 		return B_OK;
2006 
2007 	// get the volume
2008 	status_t result = B_OK;
2009 	ClientVolume* volume = _GetVolume(request->volumeID);
2010 	if (!volume)
2011 		result = B_BAD_VALUE;
2012 	ClientVolumePutter volumePutter(this, volume);
2013 
2014 	VolumeManagerLocker managerLocker;
2015 
2016 	// get the node
2017 	Node* node = NULL;
2018 	if (result == B_OK) {
2019 		node = volume->GetNode(request->nodeID);
2020 		if (!node)
2021 			result = B_ENTRY_NOT_FOUND;
2022 	}
2023 
2024 	// check read permission
2025 	if (result == B_OK) {
2026 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2027 			result = B_PERMISSION_DENIED;
2028 	}
2029 
2030 	// open the node
2031 	FileHandle* handle = NULL;
2032 	if (result == B_OK)
2033 		result = volume->Open(node, O_RDONLY, &handle);
2034 	NodeHandleUnlocker handleUnlocker(volume, handle);
2035 
2036 	managerLocker.Unlock();
2037 
2038 	// read the attribute
2039 	if (result == B_OK) {
2040 		// Due to a bug in BFS the `pos' is ignored. This means that the loop
2041 		// below won't work if the attribute is non-empty and the buffer is
2042 		// larger than the attribute, because the we would again and again
2043 		// read the beginning of the attribute until the buffer is full.
2044 		// Hence we first get an attr_info and don't try to read more than
2045 		// the size of the attribute.
2046 		attr_info info;
2047 		result = handle->StatAttr(request->name.GetString(), &info);
2048 		off_t originalPos = max(request->pos, (off_t)0);
2049 		int32 originalSize = max(request->size, (int32)0);
2050 		off_t pos = originalPos;
2051 		int32 size = originalSize;
2052 		type_code type = B_SWAP_INT32(request->type);
2053 		bool convert = false;
2054 
2055 		if (result == B_OK) {
2056 			originalSize = min((off_t)originalSize, max((off_t)0, info.size - pos));
2057 			size = originalSize;
2058 
2059 			// deal with inverse endianess clients
2060 			if (fInverseClientEndianess) {
2061 				convert = _KnownAttributeType(info.type);
2062 				if (convert) {
2063 					// read the whole attribute
2064 					pos = 0;
2065 					size = info.size;
2066 				} else
2067 					type = B_SWAP_INT32(request->type);
2068 			}
2069 		}
2070 		int32 bufferSize = min(size, kMaxReadBufferSize);
2071 
2072 		// allocate a buffer
2073 		uint8* buffer = NULL;
2074 		if (result == B_OK) {
2075 			buffer = (uint8*)malloc(bufferSize);
2076 			if (!buffer)
2077 				result = B_NO_MEMORY;
2078 		}
2079 		MemoryDeleter bufferDeleter(buffer);
2080 
2081 		if (convert) {
2082 			// read the whole attribute and convert it
2083 			if (result == B_OK) {
2084 				// read
2085 				size_t bytesRead = 0;
2086 				result = handle->ReadAttr(request->name.GetString(),
2087 					type, 0, buffer, size, &bytesRead);
2088 				if (result == B_OK && (int32)bytesRead != size)
2089 					result = B_ERROR;
2090 
2091 				// convert
2092 				if (result == B_OK)
2093 					_ConvertAttribute(info, buffer);
2094 			}
2095 
2096 			// prepare the reply
2097 			ReadAttrReply reply;
2098 			if (result == B_OK) {
2099 				reply.pos = originalPos;
2100 				reply.data.SetTo(buffer + originalPos, originalSize);
2101 				reply.moreToCome = false;
2102 			}
2103 
2104 			// send the reply
2105 			reply.error = result;
2106 			status_t error = GetChannel()->SendRequest(&reply);
2107 			if (error != B_OK)
2108 				return error;
2109 		} else {
2110 			// read as long as there are bytes left to read or an error occurs
2111 			bool moreToRead = true;
2112 			do {
2113 				int32 bytesToRead = min(size, bufferSize);
2114 				size_t bytesRead = 0;
2115 				if (result == B_OK) {
2116 					result = handle->ReadAttr(request->name.GetString(),
2117 						request->type, pos, buffer, bytesToRead, &bytesRead);
2118 				}
2119 				moreToRead = (result == B_OK && bytesRead > 0
2120 					&& (int32)bytesRead < size);
2121 
2122 				// prepare the reply
2123 				ReadAttrReply reply;
2124 				if (result == B_OK) {
2125 					reply.pos = pos;
2126 					reply.data.SetTo(buffer, bytesRead);
2127 					reply.moreToCome = moreToRead;
2128 					pos += bytesRead;
2129 					size -= bytesRead;
2130 				}
2131 
2132 				// send the reply
2133 				reply.error = result;
2134 				status_t error = GetChannel()->SendRequest(&reply);
2135 				if (error != B_OK)
2136 					return error;
2137 			} while (moreToRead);
2138 		}
2139 
2140 		// close the handle
2141 		volume->Close(handle);
2142 	} else {
2143 		// opening the node failed (or something even earlier): send an error
2144 		// reply
2145 		ReadAttrReply reply;
2146 		reply.error = result;
2147 		status_t error = GetChannel()->SendRequest(&reply);
2148 		if (error != B_OK)
2149 			return error;
2150 	}
2151 
2152 	return B_OK;
2153 }
2154 
2155 // VisitWriteAttrRequest
2156 status_t
2157 ClientConnection::VisitWriteAttrRequest(WriteAttrRequest* request)
2158 {
2159 	ConnectionReference connectionReference(this);
2160 	if (!connectionReference.IsValid())
2161 		return B_OK;
2162 
2163 	// get the volume
2164 	status_t result = B_OK;
2165 	ClientVolume* volume = _GetVolume(request->volumeID);
2166 	if (!volume)
2167 		result = B_BAD_VALUE;
2168 	ClientVolumePutter volumePutter(this, volume);
2169 
2170 	VolumeManagerLocker managerLocker;
2171 
2172 	// get the node
2173 	Node* node = NULL;
2174 	if (result == B_OK) {
2175 		node = volume->GetNode(request->nodeID);
2176 		if (!node)
2177 			result = B_ENTRY_NOT_FOUND;
2178 	}
2179 
2180 	// check read permission
2181 	if (result == B_OK) {
2182 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2183 			result = B_PERMISSION_DENIED;
2184 	}
2185 
2186 	// open the node
2187 	FileHandle* handle = NULL;
2188 	if (result == B_OK)
2189 		result = volume->Open(node, O_RDWR, &handle);
2190 	NodeHandleUnlocker handleUnlocker(volume, handle);
2191 
2192 	managerLocker.Unlock();
2193 
2194 	if (result == B_OK) {
2195 		off_t pos = max(request->pos, (off_t)0);
2196 		int32 size = request->data.GetSize();
2197 		type_code type = request->type;
2198 		char* buffer = (char*)request->data.GetData();
2199 
2200 		// convert the data, if necessary
2201 		if (fInverseClientEndianess) {
2202 			if (_KnownAttributeType(type)) {
2203 				if (pos != 0) {
2204 					WARN("WriteAttr(): WARNING: Need to convert attribute "
2205 						"endianess, but position is not 0: attribute: %s, "
2206 						"pos: %" B_PRIdOFF ", size: %" B_PRId32 "\n",
2207 						request->name.GetString(), pos, size);
2208 				}
2209 				swap_data(type, buffer, size, B_SWAP_ALWAYS);
2210 			} else
2211 				type = B_SWAP_INT32(type);
2212 		}
2213 
2214 		// write the data
2215 		while (result == B_OK && size > 0) {
2216 			size_t bytesWritten;
2217 			result = handle->WriteAttr(request->name.GetString(),
2218 				type, pos, buffer, size, &bytesWritten);
2219 			if (result == B_OK) {
2220 				pos += bytesWritten;
2221 				buffer += bytesWritten;
2222 				size -= bytesWritten;
2223 			}
2224 		}
2225 
2226 		// close the handle
2227 		volume->Close(handle);
2228 	}
2229 
2230 	// prepare the reply
2231 	WriteAttrReply reply;
2232 	// send the reply
2233 	reply.error = result;
2234 	return GetChannel()->SendRequest(&reply);
2235 }
2236 
2237 // VisitRemoveAttrRequest
2238 status_t
2239 ClientConnection::VisitRemoveAttrRequest(RemoveAttrRequest* request)
2240 {
2241 	ConnectionReference connectionReference(this);
2242 	if (!connectionReference.IsValid())
2243 		return B_OK;
2244 
2245 	// get the volume
2246 	status_t result = B_OK;
2247 	ClientVolume* volume = _GetVolume(request->volumeID);
2248 	if (!volume)
2249 		result = B_BAD_VALUE;
2250 	ClientVolumePutter volumePutter(this, volume);
2251 
2252 	VolumeManagerLocker managerLocker;
2253 
2254 	// get the node
2255 	Node* node = NULL;
2256 	if (result == B_OK) {
2257 		node = volume->GetNode(request->nodeID);
2258 		if (!node)
2259 			result = B_ENTRY_NOT_FOUND;
2260 	}
2261 
2262 	// check read permission
2263 	if (result == B_OK) {
2264 		if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2265 			result = B_PERMISSION_DENIED;
2266 	}
2267 
2268 	// open the node
2269 	FileHandle* handle = NULL;
2270 	if (result == B_OK)
2271 		result = volume->Open(node, O_RDWR, &handle);
2272 	NodeHandleUnlocker handleUnlocker(volume, handle);
2273 
2274 	managerLocker.Unlock();
2275 
2276 	// remove the attribute and close the node
2277 	if (result == B_OK) {
2278 		result = handle->RemoveAttr(request->name.GetString());
2279 		volume->Close(handle);
2280 	}
2281 
2282 	// send the reply
2283 	RemoveAttrReply reply;
2284 	reply.error = result;
2285 	return GetChannel()->SendRequest(&reply);
2286 }
2287 
2288 // VisitRenameAttrRequest
2289 status_t
2290 ClientConnection::VisitRenameAttrRequest(RenameAttrRequest* request)
2291 {
2292 	// Not supported, since there's no API function to rename an attribute.
2293 	// send the reply
2294 	RemoveAttrReply reply;
2295 	reply.error = B_UNSUPPORTED;
2296 	return GetChannel()->SendRequest(&reply);
2297 }
2298 
2299 // VisitStatAttrRequest
2300 status_t
2301 ClientConnection::VisitStatAttrRequest(StatAttrRequest* request)
2302 {
2303 	ConnectionReference connectionReference(this);
2304 	if (!connectionReference.IsValid())
2305 		return B_OK;
2306 
2307 	// get the volume
2308 	status_t result = B_OK;
2309 	ClientVolume* volume = _GetVolume(request->volumeID);
2310 	if (!volume)
2311 		result = B_BAD_VALUE;
2312 	ClientVolumePutter volumePutter(this, volume);
2313 
2314 	VolumeManagerLocker managerLocker;
2315 
2316 	// get the node
2317 	Node* node = NULL;
2318 	if (result == B_OK) {
2319 		node = volume->GetNode(request->nodeID);
2320 		if (!node)
2321 			result = B_ENTRY_NOT_FOUND;
2322 	}
2323 
2324 	// check read permission
2325 	if (result == B_OK) {
2326 		if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2327 			result = B_PERMISSION_DENIED;
2328 	}
2329 
2330 	// open the node
2331 	FileHandle* handle = NULL;
2332 	if (result == B_OK)
2333 		result = volume->Open(node, O_RDONLY, &handle);
2334 	NodeHandleUnlocker handleUnlocker(volume, handle);
2335 
2336 	managerLocker.Unlock();
2337 
2338 	// stat the attribute and close the node
2339 	attr_info attrInfo;
2340 	StatAttrReply reply;
2341 	if (result == B_OK) {
2342 		result = handle->StatAttr(request->name.GetString(), &attrInfo);
2343 		volume->Close(handle);
2344 	}
2345 
2346 	// set the attribute info
2347 	if (result == B_OK) {
2348 		result = _GetAttrInfo(request, request->name.GetString(), attrInfo,
2349 			NULL, &reply.attrInfo);
2350 	}
2351 
2352 	// send the reply
2353 	reply.error = result;
2354 	return GetChannel()->SendRequest(&reply);
2355 }
2356 
2357 // VisitOpenQueryRequest
2358 status_t
2359 ClientConnection::VisitOpenQueryRequest(OpenQueryRequest* request)
2360 {
2361 	ConnectionReference connectionReference(this);
2362 	if (!connectionReference.IsValid())
2363 		return B_OK;
2364 
2365 	VolumeManagerLocker managerLocker;
2366 
2367 	// open the query
2368 	status_t result;
2369 	QueryHandle* handle = NULL;
2370 	result = _OpenQuery(request->queryString.GetString(),
2371 			request->flags, request->port, request->token, &handle);
2372 	QueryHandleUnlocker handleUnlocker(this, handle);
2373 
2374 	// prepare the reply
2375 	OpenQueryReply reply;
2376 	if (result == B_OK)
2377 		reply.cookie = handle->GetCookie();
2378 
2379 	managerLocker.Unlock();
2380 
2381 	// send the reply
2382 	reply.error = result;
2383 	status_t error = GetChannel()->SendRequest(&reply);
2384 
2385 	// close the handle, if a send error occurred
2386 	if (error != B_OK && result == B_OK)
2387 		_CloseQuery(handle);
2388 
2389 	return error;
2390 }
2391 
2392 // VisitReadQueryRequest
2393 status_t
2394 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request)
2395 {
2396 	ConnectionReference connectionReference(this);
2397 	if (!connectionReference.IsValid())
2398 		return B_OK;
2399 
2400 	// create an array for the IDs of the client volumes a found entry may
2401 	// reside on
2402 	status_t result = B_OK;
2403 	int32 volumeCount = fVolumes->Size();
2404 	int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2405 	if (!volumeIDs)
2406 		result = B_NO_MEMORY;
2407 	ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2408 
2409 	// get the query handle
2410 	QueryHandle* handle = NULL;
2411 	if (result == B_OK)
2412 		result = _LockQueryHandle(request->cookie, &handle);
2413 	QueryHandleUnlocker handleUnlocker(this, handle);
2414 
2415 	// check if it is a query handle
2416 	QueryHandle* queryHandle = NULL;
2417 	if (result == B_OK) {
2418 		queryHandle = dynamic_cast<QueryHandle*>(handle);
2419 		if (!queryHandle)
2420 			result = B_BAD_VALUE;
2421 	}
2422 
2423 	// read the query
2424 	ReadQueryReply reply;
2425 	int32 countRead = 0;
2426 	while (result == B_OK) {
2427 		uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
2428 		struct dirent* dirEntry = (struct dirent*)buffer;
2429 
2430 		result = queryHandle->ReadDir(dirEntry, 1, &countRead);
2431 		if (result != B_OK)
2432 			break;
2433 		if (countRead == 0)
2434 			break;
2435 		PRINT("  query entry: %ld, %lld, \"%s\"\n",
2436 			dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name);
2437 
2438 		VolumeManagerLocker managerLocker;
2439 		VolumeManager* volumeManager = VolumeManager::GetDefault();
2440 
2441 		// load the entry
2442 		Entry* entry = NULL;
2443 		result = volumeManager->LoadEntry(dirEntry->d_pdev,
2444 			dirEntry->d_pino, dirEntry->d_name, true, &entry);
2445 
2446 		// if at least one client volume contains the entry, get an entry info
2447 		if (result == B_OK) {
2448 			HasQueryPermissionClientVolumeFilter filter;
2449 			int32 entryVolumeCount = _GetContainingClientVolumes(
2450 				entry->GetDirectory(), volumeIDs, volumeCount, &filter);
2451 			if (entryVolumeCount > 0) {
2452 				// store all the client volume IDs in the reply
2453 				for (int32 i = 0; i < entryVolumeCount; i++) {
2454 					result = reply.clientVolumeIDs.Append(volumeIDs[i]);
2455 					if (result != B_OK)
2456 						break;
2457 				}
2458 
2459 				// get an entry info
2460 				_GetNodeInfo(entry->GetDirectory(), &reply.dirInfo);
2461 				_GetEntryInfo(entry, &reply.entryInfo);
2462 				break;
2463 			}
2464 else
2465 PRINT(("  -> no client volumes\n"));
2466 		}
2467 
2468 		// entry is not in the volume: next round...
2469 		result = B_OK;
2470 	}
2471 
2472 	// send the reply
2473 	reply.error = result;
2474 	reply.count = countRead;
2475 	PRINT("ReadQuery: (%lx, %ld, dir: (%ld, %lld), node: (%ld, %lld, `%s')"
2476 		"\n", reply.error, reply.count,
2477 		reply.entryInfo.directoryID.volumeID,
2478 		reply.entryInfo.directoryID.nodeID,
2479 		reply.entryInfo.nodeInfo.st.st_dev,
2480 		reply.entryInfo.nodeInfo.st.st_ino,
2481 		reply.entryInfo.name.GetString());
2482 	return GetChannel()->SendRequest(&reply);
2483 }
2484 
2485 
2486 // #pragma mark -
2487 
2488 // ProcessNodeMonitoringEvent
2489 void
2490 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID,
2491 	NodeMonitoringEvent* event)
2492 {
2493 	// get a connection reference
2494 	ConnectionReference connectionReference(this);
2495 	if (!connectionReference.IsValid())
2496 		return;
2497 
2498 	_PushNodeMonitoringEvent(volumeID, event);
2499 }
2500 
2501 // CloseNodeMonitoringEventQueue
2502 void
2503 ClientConnection::CloseNodeMonitoringEventQueue()
2504 {
2505 	typedef Vector<NodeMonitoringRequest*> RequestVector;
2506 	const RequestVector* requests = NULL;
2507 	if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) {
2508 		for (RequestVector::ConstIterator it = requests->Begin();
2509 			 it != requests->End();
2510 			 it++) {
2511 			delete *it;
2512 		}
2513 	}
2514 }
2515 
2516 
2517 // #pragma mark -
2518 
2519 // QueryDomainIntersectsWith
2520 bool
2521 ClientConnection::QueryDomainIntersectsWith(Volume* volume)
2522 {
2523 	// Iterate through the the client volumes and check whether any one contains
2524 	// the supplied volume or its root dir is on the volume. We don't check
2525 	// directory inclusion for the latter, since we don't need to query the
2526 	// volume, if the client volume is located on a volume mounted somewhere
2527 	// under the supplied volume (e.g. the root FS contains everything, but does
2528 	// seldomly need to be queried).
2529 	VolumeManager* volumeManager = VolumeManager::GetDefault();
2530 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
2531 	for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2532 		ClientVolume* clientVolume = it.Next().value;
2533 		Directory* volumeRoot = volume->GetRootDirectory();
2534 		Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
2535 		if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true)
2536 			|| volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) {
2537 			return true;
2538 		}
2539 	}
2540 
2541 	return false;
2542 }
2543 
2544 // ProcessQueryEvent
2545 void
2546 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event)
2547 {
2548 	dev_t volumeID;
2549 	ino_t directoryID;
2550 	if (event->opcode == B_ENTRY_CREATED) {
2551 		// "entry created" event
2552 		EntryCreatedEvent* createdEvent
2553 			= dynamic_cast<EntryCreatedEvent*>(event);
2554 		if (!createdEvent)
2555 			return;
2556 		volumeID = createdEvent->volumeID;
2557 		directoryID = createdEvent->directoryID;
2558 
2559 	} else if (event->opcode == B_ENTRY_REMOVED) {
2560 		// "entry removed" event
2561 		EntryRemovedEvent* removedEvent
2562 			= dynamic_cast<EntryRemovedEvent*>(event);
2563 		if (!removedEvent)
2564 			return;
2565 		volumeID = removedEvent->volumeID;
2566 		directoryID = removedEvent->directoryID;
2567 
2568 	} else {
2569 		// We only support "entry created" and "entry removed" query events.
2570 		// "entry moved" is split by the volume manager into those.
2571 		ERROR("Ignoring unexpected query event: opcode: 0x%" B_PRIx32 "\n",
2572 			event->opcode);
2573 		return;
2574 	}
2575 	PRINT("ClientConnection::ProcessQueryEvent(): event: %p, type: %s:"
2576 		" directory: (%ld, %lld)\n", event, typeid(event).name(),
2577 		volumeID, directoryID);
2578 
2579 	// create an array for the IDs of the client volumes a found entry may
2580 	// reside on
2581 	status_t result = B_OK;
2582 	int32 volumeCount = fVolumes->Size();
2583 	int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2584 	if (!volumeIDs)
2585 		result = B_NO_MEMORY;
2586 	ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2587 
2588 	HasQueryPermissionClientVolumeFilter filter;
2589 
2590 	// load the directory the concerned entry belongs/belonged to
2591 	Directory* directory;
2592 	int32 concernedVolumes = 0;
2593 	if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID,
2594 			&directory) == B_OK) {
2595 		// find out, which client volumes the directory is located in
2596 		concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs,
2597 			volumeCount, &filter);
2598 	} else {
2599 		// Failed to load the directory, so maybe it has already been
2600 		// deleted. For "entry removed" events, we consider all client
2601 		// volumes to be notified -- those that don't know the entry will
2602 		// ignore the event.
2603 		if (event->opcode == B_ENTRY_REMOVED) {
2604 			concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount,
2605 				&filter);
2606 		}
2607 	}
2608 
2609 	// now push the event for each concerned client volume
2610 	for (int32 i = 0; i < concernedVolumes; i++)
2611 		_PushNodeMonitoringEvent(volumeIDs[i], event);
2612 	// TODO: More than one volume will usually only be concerned in case of
2613 	// nested client volumes. We could optimize the case by having an array of
2614 	// volume IDs in the respective requests sent over the net (just as in the
2615 	// ReadQueryReply).
2616 }
2617 
2618 
2619 // #pragma mark -
2620 
2621 // _Close
2622 void
2623 ClientConnection::_Close()
2624 {
2625 	// terminate node monitoring processor
2626 	CloseNodeMonitoringEventQueue();
2627 	if (fNodeMonitoringProcessor >= 0
2628 		&& find_thread(NULL) != fNodeMonitoringProcessor) {
2629 		int32 result;
2630 		wait_for_thread(fNodeMonitoringProcessor, &result);
2631 		// The variable is not unset, when this is the node monitoring
2632 		// processor thread -- which is good, since the destructor will
2633 		// wait for the thread in this case.
2634 		fNodeMonitoringProcessor = -1;
2635 	}
2636 	if (fConnection)
2637 		fConnection->Close();
2638 	// notify the listener
2639 	ClientConnectionListener* listener = fListener;
2640 	fListener = NULL;
2641 	if (listener)
2642 		listener->ClientConnectionClosed(this, fError);
2643 }
2644 
2645 // _MarkClosed
2646 void
2647 ClientConnection::_MarkClosed(bool error)
2648 {
2649 	AutoLocker<Locker> _(fLock);
2650 	if (!fClosed) {
2651 		fClosed = true;
2652 		fError = error;
2653 	}
2654 }
2655 
2656 // _GetNodeInfo
2657 void
2658 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info)
2659 {
2660 	if (node && info) {
2661 		info->st = node->GetStat();
2662 		info->revision = VolumeManager::GetDefault()->GetRevision();
2663 	}
2664 }
2665 
2666 // _GetEntryInfo
2667 void
2668 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info)
2669 {
2670 	if (entry && info) {
2671 		info->directoryID.volumeID = entry->GetVolumeID();
2672 		info->directoryID.nodeID = entry->GetDirectoryID();
2673 		info->name.SetTo(entry->GetName());
2674 		_GetNodeInfo(entry->GetNode(), &info->nodeInfo);
2675 	}
2676 }
2677 
2678 // _GetAttrInfo
2679 status_t
2680 ClientConnection::_GetAttrInfo(Request* request, const char* name,
2681 	const attr_info& attrInfo, const void* data, AttributeInfo* info)
2682 {
2683 	if (!request || !name || !info)
2684 		return B_BAD_VALUE;
2685 
2686 	info->name.SetTo(name);
2687 	info->info = attrInfo;
2688 	data = (attrInfo.size > 0 ? data : NULL);
2689 	int32 dataSize = (data ? attrInfo.size : 0);
2690 	info->data.SetTo(data, dataSize);
2691 
2692 	// if the client has inverse endianess, swap the type, if we don't know it
2693 	if (fInverseClientEndianess) {
2694 		if (_KnownAttributeType(info->info.type)) {
2695 			// we need to convert the data, if supplied
2696 			if (data) {
2697 				// allocate a buffer
2698 				RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize);
2699 				if (!requestBuffer)
2700 					return B_NO_MEMORY;
2701 
2702 				// convert the data
2703 				memcpy(requestBuffer->GetData(), data, dataSize);
2704 				_ConvertAttribute(info->info, requestBuffer->GetData());
2705 			}
2706 		} else
2707 			info->info.type = B_SWAP_INT32(info->info.type);
2708 	}
2709 
2710 	return B_OK;
2711 }
2712 
2713 // _GetAttrDirInfo
2714 status_t
2715 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir,
2716 	AttrDirInfo* info)
2717 {
2718 	if (!request || !attrDir || !info || !attrDir->IsAttrDirValid())
2719 		return B_BAD_VALUE;
2720 
2721 	// add the attribute infos
2722 	for (Attribute* attribute = attrDir->GetFirstAttribute();
2723 		 attribute;
2724 		 attribute = attrDir->GetNextAttribute(attribute)) {
2725 		// get the attribute info
2726 		AttributeInfo attrInfo;
2727 		attr_info bAttrInfo;
2728 		attribute->GetInfo(&bAttrInfo);
2729 		status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo,
2730 			attribute->GetData(), &attrInfo);
2731 
2732 		// append it
2733 		if (error == B_OK)
2734 			error = info->attributeInfos.Append(attrInfo);
2735 		if (error != B_OK)
2736 			return error;
2737 	}
2738 
2739 	info->revision = VolumeManager::GetDefault()->GetRevision();
2740 	info->isValid = true;
2741 
2742 	return B_OK;
2743 }
2744 
2745 // _CreateVolume
2746 status_t
2747 ClientConnection::_CreateVolume(ClientVolume** _volume)
2748 {
2749 	// create and init the volume
2750 	ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock,
2751 		this);
2752 	if (!volume)
2753 		return B_NO_MEMORY;
2754 	status_t error = volume->Init();
2755 	if (error != B_OK) {
2756 		delete volume;
2757 		return error;
2758 	}
2759 
2760 	// add it to the volume map
2761 	AutoLocker<VolumeMap> locker(fVolumes);
2762 	error = fVolumes->Put(volume->GetID(), volume);
2763 	locker.Unlock();
2764 
2765 	if (error == B_OK)
2766 		*_volume = volume;
2767 	else
2768 		delete volume;
2769 
2770 	return error;
2771 }
2772 
2773 // _GetVolume
2774 ClientVolume*
2775 ClientConnection::_GetVolume(int32 id)
2776 {
2777 	AutoLocker<VolumeMap> _(fVolumes);
2778 	ClientVolume* volume = fVolumes->Get(id);
2779 	if (!volume || volume->IsRemoved())
2780 		return NULL;
2781 	volume->AcquireReference();
2782 	return volume;
2783 }
2784 
2785 // _PutVolume
2786 //
2787 // The VolumeManager may be locked, but no other lock must be held.
2788 void
2789 ClientConnection::_PutVolume(ClientVolume* volume)
2790 {
2791 	if (!volume)
2792 		return;
2793 
2794 	// decrement reference counter and remove the volume, if 0
2795 	AutoLocker<VolumeMap> locker(fVolumes);
2796 	bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved());
2797 	if (removed)
2798 		fVolumes->Remove(volume->GetID());
2799 	locker.Unlock();
2800 
2801 	if (removed) {
2802 		VolumeManagerLocker managerLocker;
2803 		delete volume;
2804 	}
2805 }
2806 
2807 // _UnmountVolume
2808 //
2809 // The caller must have a reference to the volume.
2810 void
2811 ClientConnection::_UnmountVolume(ClientVolume* volume)
2812 {
2813 	if (!volume)
2814 		return;
2815 	AutoLocker<VolumeMap> locker(fVolumes);
2816 	volume->MarkRemoved();
2817 	locker.Unlock();
2818 
2819 	// push a notification event
2820 	if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) {
2821 		VolumeManagerLocker managerLocker;
2822 
2823 		event->opcode = B_DEVICE_UNMOUNTED;
2824 		_PushNodeMonitoringEvent(volume->GetID(), event);
2825 		event->ReleaseReference();
2826 	}
2827 }
2828 
2829 // _UnmountAllVolumes
2830 void
2831 ClientConnection::_UnmountAllVolumes()
2832 {
2833 	while (true) {
2834 		// To avoid heap allocation (which can fail) we unmount the volumes
2835 		// chunkwise.
2836 		// get the volumes
2837 		const int32 volumeChunkSize = 32;
2838 		ClientVolume* volumes[volumeChunkSize];
2839 		int32 volumeCount = 0;
2840 		AutoLocker<VolumeMap> volumesLocker(fVolumes);
2841 		for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2842 			if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) {
2843 				volumes[volumeCount++] = volume;
2844 			}
2845 			if (volumeCount == volumeChunkSize)
2846 				break;
2847 		}
2848 		volumesLocker.Unlock();
2849 
2850 		// unmount and put the volumes
2851 		for (int32 i = 0; i < volumeCount; i++) {
2852 			ClientVolume* volume = volumes[i];
2853 			_UnmountVolume(volume);
2854 			_PutVolume(volume);
2855 		}
2856 
2857 		if (volumeCount < volumeChunkSize)
2858 			break;
2859 	}
2860 }
2861 
2862 // _NodeMonitoringProcessorEntry
2863 int32
2864 ClientConnection::_NodeMonitoringProcessorEntry(void* data)
2865 {
2866 	return ((ClientConnection*)data)->_NodeMonitoringProcessor();
2867 }
2868 
2869 
2870 // _NodeMonitoringProcessor
2871 int32
2872 ClientConnection::_NodeMonitoringProcessor()
2873 {
2874 	while (!fClosed) {
2875 		// get the next request
2876 		NodeMonitoringRequest* request = NULL;
2877 		status_t error = fNodeMonitoringEvents->Pop(&request);
2878 
2879 		// get a client connection reference
2880 		ConnectionReference connectionReference(this);
2881 		if (!connectionReference.IsValid())
2882 			return B_OK;
2883 
2884 		// No request? Next round...
2885 		if (error != B_OK)
2886 			continue;
2887 		ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2888 
2889 		// send the request
2890 		error = fConnection->SendRequest(request);
2891 		if (error != B_OK) {
2892 			ERROR(("ClientConnection::_NodeMonitoringProcessor(): "
2893 				"Failed to send request.\n"));
2894 		}
2895 	}
2896 	return 0;
2897 }
2898 
2899 
2900 // _PushNodeMonitoringEvent
2901 //
2902 // The caller must have a connection reference. Moreover the VolumeManager
2903 // must be locked.
2904 status_t
2905 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID,
2906 	NodeMonitoringEvent* event)
2907 {
2908 	if (!event)
2909 		return B_BAD_VALUE;
2910 
2911 	// get the volume
2912 	ClientVolume* volume = _GetVolume(volumeID);
2913 	if (!volume && event->opcode != B_DEVICE_UNMOUNTED)
2914 		return B_BAD_VALUE;
2915 	ClientVolumePutter volumePutter(this, volume);
2916 
2917 	// create a node monitoring request
2918 	NodeMonitoringRequest* request = NULL;
2919 	status_t error = B_ERROR;
2920 	switch (event->opcode) {
2921 		case B_ENTRY_CREATED:
2922 			error = _EntryCreated(volume,
2923 				dynamic_cast<EntryCreatedEvent*>(event), request);
2924 			break;
2925 		case B_ENTRY_REMOVED:
2926 			error = _EntryRemoved(volume,
2927 				dynamic_cast<EntryRemovedEvent*>(event), request);
2928 			break;
2929 		case B_ENTRY_MOVED:
2930 			error = _EntryMoved(volume,
2931 				dynamic_cast<EntryMovedEvent*>(event), request);
2932 			break;
2933 		case B_STAT_CHANGED:
2934 			error = _NodeStatChanged(volume,
2935 				dynamic_cast<StatChangedEvent*>(event), request);
2936 			break;
2937 		case B_ATTR_CHANGED:
2938 			error = _NodeAttributeChanged(volume,
2939 				dynamic_cast<AttributeChangedEvent*>(event), request);
2940 			break;
2941 		case B_DEVICE_UNMOUNTED:
2942 			error = B_OK;
2943 			break;
2944 	}
2945 
2946 	// replace all data buffers -- when the request is actually sent, they
2947 	// might no longer exist
2948 	if (error == B_OK)
2949 		error = RequestBufferReplacer().ReplaceBuffer(request);
2950 
2951 	if (error == B_OK) {
2952 		// common initialization
2953 		request->volumeID = volumeID;
2954 		request->opcode = event->opcode;
2955 		request->revision = VolumeManager::GetDefault()->GetRevision();
2956 
2957 		// push the request
2958 		error = fNodeMonitoringEvents->Push(request);
2959 		if (error != B_OK)
2960 			delete request;
2961 	}
2962 
2963 	return error;
2964 }
2965 
2966 // _EntryCreated
2967 status_t
2968 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event,
2969 	NodeMonitoringRequest*& _request)
2970 {
2971 	// allocate the request
2972 	EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest;
2973 	if (!request)
2974 		return B_NO_MEMORY;
2975 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2976 
2977 	// get the name
2978 	const char* name = event->name.GetString();
2979 
2980 	// set the request fields
2981 	request->directoryID = NodeID(event->volumeID, event->directoryID);
2982 	request->nodeID = NodeID(event->volumeID, event->nodeID);
2983 	request->name.SetTo(name);
2984 	if (event->queryHandler) {
2985 		request->port = event->remotePort;
2986 		request->token = event->remoteToken;
2987 		request->queryUpdate = true;
2988 	} else
2989 		request->queryUpdate = false;
2990 
2991 	// try to get an entry info
2992 	Entry* entry;
2993 	if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
2994 			event->directoryID, name, true, &entry) == B_OK
2995 		&& entry->GetNode()->GetVolumeID() == event->volumeID
2996 		&& entry->GetNode()->GetID() == event->nodeID) {
2997 		_GetEntryInfo(entry, &request->entryInfo);
2998 		request->entryInfoValid = true;
2999 	} else
3000 		request->entryInfoValid = false;
3001 
3002 	requestDeleter.Detach();
3003 	_request = request;
3004 	return B_OK;
3005 }
3006 
3007 // _EntryRemoved
3008 status_t
3009 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event,
3010 	NodeMonitoringRequest*& _request)
3011 {
3012 	// special handling, if it is the root node of the client volume that has
3013 	// been removed
3014 	if (!event->queryHandler
3015 		&& NodeRef(event->nodeVolumeID, event->nodeID)
3016 			== volume->GetRootNodeRef()) {
3017 		NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, ".");
3018 		BEntry entry;
3019 		if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists())
3020 			_UnmountVolume(volume);
3021 
3022 		// don't send the "entry removed" event
3023 		return B_ERROR;
3024 	}
3025 
3026 	// allocate the request
3027 	EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest;
3028 	if (!request)
3029 		return B_NO_MEMORY;
3030 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3031 
3032 	// get the name
3033 	const char* name = event->name.GetString();
3034 
3035 	// set the request fields
3036 	request->directoryID = NodeID(event->volumeID, event->directoryID);
3037 	request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3038 	request->name.SetTo(name);
3039 	if (event->queryHandler) {
3040 		request->port = event->remotePort;
3041 		request->token = event->remoteToken;
3042 		request->queryUpdate = true;
3043 	} else
3044 		request->queryUpdate = false;
3045 
3046 	requestDeleter.Detach();
3047 	_request = request;
3048 	return B_OK;
3049 }
3050 
3051 // _EntryMoved
3052 status_t
3053 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event,
3054 	NodeMonitoringRequest*& _request)
3055 {
3056 	// allocate the request
3057 	EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest;
3058 	if (!request)
3059 		return B_NO_MEMORY;
3060 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3061 
3062 	// allocate memory for the names
3063 	int32 fromNameLen = event->fromName.GetLength();
3064 	const char* fromName
3065 		= (fromNameLen > 0 ? event->fromName.GetString() : NULL);
3066 	const char* toName = event->toName.GetString();
3067 
3068 	// set the request fields
3069 	request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID);
3070 	request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID);
3071 	request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3072 	request->fromName.SetTo(fromName);
3073 	request->toName.SetTo(toName);
3074 	request->queryUpdate = false;
3075 
3076 	// try to get an entry info
3077 	Entry* entry;
3078 	if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
3079 			event->toDirectoryID, toName, true, &entry) == B_OK
3080 		&& entry->GetNode()->GetVolumeID() == event->nodeVolumeID
3081 		&& entry->GetNode()->GetID() == event->nodeID) {
3082 		_GetEntryInfo(entry, &request->entryInfo);
3083 		request->entryInfoValid = true;
3084 	} else
3085 		request->entryInfoValid = false;
3086 
3087 	requestDeleter.Detach();
3088 	_request = request;
3089 	return B_OK;
3090 }
3091 
3092 // _NodeStatChanged
3093 status_t
3094 ClientConnection::_NodeStatChanged(ClientVolume* volume,
3095 	StatChangedEvent* event, NodeMonitoringRequest*& _request)
3096 {
3097 	// get the node
3098 	Node* node = volume->GetNode(event->volumeID, event->nodeID);
3099 	if (!node)
3100 		return B_ENTRY_NOT_FOUND;
3101 
3102 	// allocate the request
3103 	StatChangedRequest* request = new(std::nothrow) StatChangedRequest;
3104 	if (!request)
3105 		return B_NO_MEMORY;
3106 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3107 
3108 	// set the request fields
3109 	request->nodeID = NodeID(event->volumeID, event->nodeID);
3110 	_GetNodeInfo(node, &request->nodeInfo);
3111 	request->queryUpdate = false;
3112 
3113 	requestDeleter.Detach();
3114 	_request = request;
3115 	return B_OK;
3116 }
3117 
3118 // _NodeAttributeChanged
3119 status_t
3120 ClientConnection::_NodeAttributeChanged(ClientVolume* volume,
3121 	AttributeChangedEvent* event, NodeMonitoringRequest*& _request)
3122 {
3123 	// get the node
3124 	Node* node = volume->GetNode(event->volumeID, event->nodeID);
3125 	if (!node)
3126 		return B_ENTRY_NOT_FOUND;
3127 
3128 	// update the attribute directory
3129 	bool removed = false;
3130 	bool valid = false;
3131 	attr_info info;
3132 	const void* data = NULL;
3133 	status_t error = node->UpdateAttribute(event->attribute.GetString(),
3134 		&removed, &info, &data);
3135 	valid = (error == B_OK);
3136 
3137 	// allocate the request
3138 	AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest;
3139 	if (!request)
3140 		return B_NO_MEMORY;
3141 	ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3142 
3143 	// get an attr dir info, if the directory is valid
3144 	if (node->IsAttrDirValid()) {
3145 		status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo);
3146 		if (error != B_OK)
3147 			return error;
3148 	}
3149 
3150 	// get name and the data size
3151 	int32 dataSize = (data ? info.size : 0);
3152 	const char* name = event->attribute.GetString();
3153 
3154 	// set the request fields
3155 	request->nodeID = NodeID(event->volumeID, event->nodeID);
3156 	request->attrInfo.name.SetTo(name);
3157 	request->valid = valid;
3158 	request->removed = removed;
3159 	if (!removed && valid) {
3160 		request->attrInfo.info = info;
3161 		request->attrInfo.data.SetTo(data, dataSize);
3162 	}
3163 	request->queryUpdate = false;
3164 
3165 	requestDeleter.Detach();
3166 	_request = request;
3167 	return B_OK;
3168 }
3169 
3170 // _KnownAttributeType
3171 bool
3172 ClientConnection::_KnownAttributeType(type_code type)
3173 {
3174 	if (!fInverseClientEndianess)
3175 		return false;
3176 
3177 	switch (type) {
3178 		case B_BOOL_TYPE:
3179 		case B_CHAR_TYPE:
3180 		case B_COLOR_8_BIT_TYPE:
3181 		case B_DOUBLE_TYPE:
3182 		case B_FLOAT_TYPE:
3183 		case B_GRAYSCALE_8_BIT_TYPE:
3184 		case B_INT64_TYPE:
3185 		case B_INT32_TYPE:
3186 		case B_INT16_TYPE:
3187 		case B_INT8_TYPE:
3188 		case B_MESSAGE_TYPE:
3189 		case B_MESSENGER_TYPE:
3190 		case B_MIME_TYPE:
3191 		case B_MONOCHROME_1_BIT_TYPE:
3192 		case B_OFF_T_TYPE:
3193 		case B_POINTER_TYPE:
3194 		case B_POINT_TYPE:
3195 		case B_RECT_TYPE:
3196 		case B_REF_TYPE:
3197 		case B_RGB_COLOR_TYPE:
3198 		case B_SIZE_T_TYPE:
3199 		case B_SSIZE_T_TYPE:
3200 		case B_STRING_TYPE:
3201 		case B_TIME_TYPE:
3202 		case B_UINT64_TYPE:
3203 		case B_UINT32_TYPE:
3204 		case B_UINT16_TYPE:
3205 		case B_UINT8_TYPE:
3206 		case B_ASCII_TYPE:
3207 		case B_MIME_STRING_TYPE:
3208 			return true;
3209 
3210 		//B_RGB_32_BIT_TYPE: We could translate it, but it's heavy...
3211 	}
3212 
3213 	return false;
3214 }
3215 
3216 // _ConvertAttribute
3217 void
3218 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer)
3219 {
3220 	swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS);
3221 }
3222 
3223 
3224 // #pragma mark -
3225 
3226 // _OpenQuery
3227 status_t
3228 ClientConnection::_OpenQuery(const char* queryString, uint32 flags,
3229 	port_id remotePort, int32 remoteToken, QueryHandle** _handle)
3230 {
3231 	if (!queryString || !_handle)
3232 		return B_BAD_VALUE;
3233 
3234 	// open query
3235 	QueryHandle* queryHandle;
3236 	status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString,
3237 		flags, remotePort, remoteToken, &queryHandle);
3238 	if (error != B_OK)
3239 		return error;
3240 	BReference<QueryHandle> handleReference(queryHandle, true);
3241 
3242 	// lock the handle
3243 	queryHandle->Lock();
3244 
3245 	// add the handle
3246 	error = fQueryHandles->AddNodeHandle(queryHandle);
3247 	if (error != B_OK)
3248 		return error;
3249 
3250 	handleReference.Detach();
3251 	*_handle = queryHandle;
3252 	return B_OK;
3253 }
3254 
3255 // _CloseQuery
3256 status_t
3257 ClientConnection::_CloseQuery(QueryHandle* handle)
3258 {
3259 	if (!handle || !fQueryHandles->RemoveNodeHandle(handle))
3260 		return B_BAD_VALUE;
3261 
3262 	return B_OK;
3263 }
3264 
3265 // _LockQueryHandle
3266 //
3267 // VolumeManager must NOT be locked.
3268 status_t
3269 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle)
3270 {
3271 	NodeHandle* handle;
3272 	status_t error = fQueryHandles->LockNodeHandle(cookie, &handle);
3273 	if (error == B_OK)
3274 		*_handle = static_cast<QueryHandle*>(handle);
3275 	return error;
3276 }
3277 
3278 // _UnlockQueryHandle
3279 //
3280 // VolumeManager may or may not be locked.
3281 void
3282 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle)
3283 {
3284 	fQueryHandles->UnlockNodeHandle(nodeHandle);
3285 }
3286 
3287 
3288 // #pragma mark -
3289 
3290 // _GetAllClientVolumeIDs
3291 int32
3292 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize,
3293 	ClientVolumeFilter* filter)
3294 {
3295 	int32 count = 0;
3296 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
3297 	for (VolumeMap::Iterator it = fVolumes->GetIterator();
3298 		 it.HasNext() && arraySize > count;) {
3299 		ClientVolume* clientVolume = it.Next().value;
3300 		if (!filter || filter->FilterVolume(this, clientVolume))
3301 			volumeIDs[count++] = clientVolume->GetID();
3302 	}
3303 
3304 	return count;
3305 }
3306 
3307 // _GetContainingClientVolumes
3308 int32
3309 ClientConnection::_GetContainingClientVolumes(Directory* directory,
3310 	int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter)
3311 {
3312 	int32 count = 0;
3313 	VolumeManager* volumeManager = VolumeManager::GetDefault();
3314 	AutoLocker<VolumeMap> volumesLocker(fVolumes);
3315 	for (VolumeMap::Iterator it = fVolumes->GetIterator();
3316 		 it.HasNext() && arraySize > count;) {
3317 		ClientVolume* clientVolume = it.Next().value;
3318 		Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
3319 		if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true)
3320 			&& (!filter || filter->FilterVolume(this, clientVolume))) {
3321 			volumeIDs[count++] = clientVolume->GetID();
3322 		}
3323 	}
3324 
3325 	return count;
3326 }
3327 
3328 
3329 // #pragma mark -
3330 // #pragma mark ----- ClientConnectionListener -----
3331 
3332 // constructor
3333 ClientConnectionListener::ClientConnectionListener()
3334 {
3335 }
3336 
3337 // destructor
3338 ClientConnectionListener::~ClientConnectionListener()
3339 {
3340 }
3341 
3342