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