xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/ShareVolume.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
1 // ShareVolume.cpp
2 
3 #include "ShareVolume.h"
4 
5 #include <new>
6 #include <unistd.h>
7 
8 #include <AppDefs.h>	// for B_QUERY_UPDATE
9 #include <AutoDeleter.h>
10 #include <AutoLocker.h>
11 #include <HashMap.h>
12 
13 #include "AuthenticationServer.h"
14 #include "Compatibility.h"
15 #include "Connection.h"
16 #include "ConnectionFactory.h"
17 #include "DebugSupport.h"
18 #include "ExtendedServerInfo.h"
19 #include "Permissions.h"
20 #include "Node.h"
21 #include "QueryManager.h"
22 #include "RequestChannel.h"
23 #include "RequestConnection.h"
24 #include "Requests.h"
25 #include "RootVolume.h"
26 #include "SendReceiveRequest.h"
27 #include "ServerConnection.h"
28 #include "ServerConnectionProvider.h"
29 #include "ShareAttrDir.h"
30 #include "ShareAttrDirIterator.h"
31 #include "ShareNode.h"
32 #include "Utils.h"
33 #include "VolumeManager.h"
34 #include "VolumeSupport.h"
35 
36 // TODO: Request timeouts!
37 
38 static const int32 kMaxWriteBufferSize	= 64 * 1024;	// 64 KB
39 static const int32 kUserBufferSize = 256;
40 static const int32 kPasswordBufferSize = 256;
41 
42 // connection states
43 enum {
44 	CONNECTION_NOT_INITIALIZED,
45 	CONNECTION_READY,
46 	CONNECTION_CLOSED,
47 };
48 
49 // NodeMap
50 struct ShareVolume::NodeMap : HashMap<HashKey64<ino_t>, ShareNode*> {
51 };
52 
53 // EntryKey
54 //
55 // NOTE: This class doesn't make a copy of the name string it is constructed
56 // with. So, when entering the key in a map, one must make sure, that the
57 // string stays valid as long as the entry is in the map.
58 struct ShareVolume::EntryKey {
59 	EntryKey() {}
60 
61 	EntryKey(ino_t directoryID, const char* name)
62 		: directoryID(directoryID),
63 		  name(name)
64 	{
65 	}
66 
67 	EntryKey(const EntryKey& other)
68 		: directoryID(other.directoryID),
69 		  name(other.name)
70 	{
71 	}
72 
73 	uint32 GetHashCode() const
74 	{
75 		uint32 hash = (uint32)directoryID;
76 		hash = 31 * hash + (uint32)(directoryID >> 32);
77 		hash = 31 * hash + string_hash(name);
78 		return hash;
79 	}
80 
81 	EntryKey& operator=(const EntryKey& other)
82 	{
83 		directoryID = other.directoryID;
84 		name = other.name;
85 		return *this;
86 	}
87 
88 	bool operator==(const EntryKey& other) const
89 	{
90 		if (directoryID != other.directoryID)
91 			return false;
92 
93 		if (name)
94 			return (other.name && strcmp(name, other.name) == 0);
95 
96 		return !other.name;
97 	}
98 
99 	bool operator!=(const EntryKey& other) const
100 	{
101 		return !(*this == other);
102 	}
103 
104 	ino_t		directoryID;
105 	const char*	name;
106 };
107 
108 // EntryMap
109 struct ShareVolume::EntryMap : HashMap<EntryKey, ShareDirEntry*> {
110 };
111 
112 // LocalNodeIDMap
113 struct ShareVolume::LocalNodeIDMap : HashMap<NodeID, ino_t> {
114 };
115 
116 // RemoteNodeIDMap
117 struct ShareVolume::RemoteNodeIDMap : HashMap<HashKey64<ino_t>, NodeID> {
118 };
119 
120 // DirCookie
121 struct ShareVolume::DirCookie {
122 	ShareDirIterator*	iterator;
123 };
124 
125 // AttrDirCookie
126 struct ShareVolume::AttrDirCookie {
127 	AttrDirCookie()
128 		: iterator(NULL),
129 		  cookie(-1),
130 		  rewind(false)
131 	{
132 	}
133 
134 	ShareAttrDirIterator*	iterator;
135 	int32					cookie;
136 	bool					rewind;
137 };
138 
139 // AttrDirIteratorMap
140 struct ShareVolume::AttrDirIteratorMap
141 	: HashMap<HashKey64<ino_t>, DoublyLinkedList<ShareAttrDirIterator>*> {
142 };
143 
144 
145 // #pragma mark -
146 
147 // constructor
148 ShareVolume::ShareVolume(VolumeManager* volumeManager,
149 	ServerConnectionProvider* connectionProvider,
150 	ExtendedServerInfo* serverInfo, ExtendedShareInfo* shareInfo)
151 	: Volume(volumeManager),
152 	  fID(-1),
153 	  fFlags(0),
154 	  fMountLock("share mount lock"),
155 	  fNodes(NULL),
156 	  fEntries(NULL),
157 	  fAttrDirIterators(NULL),
158 	  fLocalNodeIDs(NULL),
159 	  fRemoteNodeIDs(NULL),
160 	  fServerConnectionProvider(connectionProvider),
161 	  fServerInfo(serverInfo),
162 	  fShareInfo(shareInfo),
163 	  fServerConnection(NULL),
164 	  fConnection(NULL),
165 	  fSharePermissions(0),
166 	  fConnectionState(CONNECTION_NOT_INITIALIZED)
167 {
168 	fFlags = fVolumeManager->GetMountFlags();
169 	if (fServerConnectionProvider)
170 		fServerConnectionProvider->AcquireReference();
171 	if (fServerInfo)
172 		fServerInfo->AcquireReference();
173 	if (fShareInfo)
174 		fShareInfo->AcquireReference();
175 }
176 
177 // destructor
178 ShareVolume::~ShareVolume()
179 {
180 PRINT(("ShareVolume::~ShareVolume()\n"));
181 	// delete the root node
182 	if (fRootNode) {
183 		if (fNodes)
184 			fNodes->Remove(fRootNode->GetID());
185 		delete fRootNode;
186 		fRootNode = NULL;
187 	}
188 
189 	// delete the nodes
190 	if (fNodes) {
191 		// there shouldn't be any more nodes
192 		if (fNodes->Size() > 0) {
193 			WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
194 				"%" B_PRId32 " nodes\n", fNodes->Size());
195 		}
196 		for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();)
197 			delete it.Next().value;
198 		delete fNodes;
199 	}
200 
201 	// delete the entries
202 	if (fEntries) {
203 		// there shouldn't be any more entries
204 		if (fEntries->Size() > 0) {
205 			WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
206 				"%" B_PRId32 " entries\n", fEntries->Size());
207 		}
208 		for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();)
209 			delete it.Next().value;
210 		delete fEntries;
211 	}
212 
213 	delete fLocalNodeIDs;
214 	delete fRemoteNodeIDs;
215 
216 	if (fShareInfo)
217 		fShareInfo->ReleaseReference();
218 	if (fServerInfo)
219 		fServerInfo->ReleaseReference();
220 	if (fServerConnection)
221 		fServerConnection->ReleaseReference();
222 	if (fServerConnectionProvider)
223 		fServerConnectionProvider->ReleaseReference();
224 }
225 
226 // GetID
227 nspace_id
228 ShareVolume::GetID() const
229 {
230 	return fID;
231 }
232 
233 // IsReadOnly
234 bool
235 ShareVolume::IsReadOnly() const
236 {
237 	return (fFlags & B_MOUNT_READ_ONLY);
238 }
239 
240 // SupportsQueries
241 bool
242 ShareVolume::SupportsQueries() const
243 {
244 	return (fSharePermissions & QUERY_SHARE_PERMISSION);
245 }
246 
247 // Init
248 status_t
249 ShareVolume::Init(const char* name)
250 {
251 	status_t error = Volume::Init(name);
252 	if (error != B_OK)
253 		return error;
254 
255 	// create node map
256 	fNodes = new(std::nothrow) NodeMap;
257 	if (!fNodes)
258 		RETURN_ERROR(B_NO_MEMORY);
259 	error = fNodes->InitCheck();
260 	if (error != B_OK)
261 		return error;
262 
263 	// create entry map
264 	fEntries = new(std::nothrow) EntryMap;
265 	if (!fEntries)
266 		RETURN_ERROR(B_NO_MEMORY);
267 	error = fEntries->InitCheck();
268 	if (error != B_OK)
269 		return error;
270 
271 	// create attribute iterator map
272 	fAttrDirIterators = new(std::nothrow) AttrDirIteratorMap;
273 	if (!fAttrDirIterators)
274 		RETURN_ERROR(B_NO_MEMORY);
275 	error = fAttrDirIterators->InitCheck();
276 	if (error != B_OK)
277 		return error;
278 
279 	// create local node ID map
280 	fLocalNodeIDs = new(std::nothrow) LocalNodeIDMap;
281 	if (!fLocalNodeIDs)
282 		RETURN_ERROR(B_NO_MEMORY);
283 	error = fLocalNodeIDs->InitCheck();
284 	if (error != B_OK)
285 		return error;
286 
287 	// create remote node ID map
288 	fRemoteNodeIDs = new(std::nothrow) RemoteNodeIDMap;
289 	if (!fRemoteNodeIDs)
290 		RETURN_ERROR(B_NO_MEMORY);
291 	error = fRemoteNodeIDs->InitCheck();
292 	if (error != B_OK)
293 		return error;
294 
295 	// get a local node ID for our root node
296 	vnode_id localID = fVolumeManager->NewNodeID(this);
297 	if (localID < 0)
298 		return localID;
299 
300 	// create the root node
301 	fRootNode = new(std::nothrow) ShareDir(this, localID, NULL);
302 	if (!fRootNode) {
303 		fVolumeManager->RemoveNodeID(localID);
304 		return B_NO_MEMORY;
305 	}
306 
307 	// add the root node to the node map
308 	error = fNodes->Put(localID, fRootNode);
309 	if (error != B_OK)
310 		return error;
311 
312 	return B_OK;
313 }
314 
315 // Uninit
316 void
317 ShareVolume::Uninit()
318 {
319 	Volume::Uninit();
320 }
321 
322 // GetRootNode
323 Node*
324 ShareVolume::GetRootNode() const
325 {
326 	return fRootNode;
327 }
328 
329 // PrepareToUnmount
330 void
331 ShareVolume::PrepareToUnmount()
332 {
333 PRINT(("ShareVolume::PrepareToUnmount()\n"));
334 	Volume::PrepareToUnmount();
335 
336 	ConnectionClosed();
337 
338 	AutoLocker<Locker> locker(fLock);
339 
340 	// remove all entries and send respective "entry removed" events
341 	for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) {
342 		ShareDirEntry* entry = it.Next().value;
343 
344 		NotifyListener(B_ENTRY_REMOVED, fVolumeManager->GetID(),
345 			entry->GetDirectory()->GetID(), 0, entry->GetNode()->GetID(),
346 			entry->GetName());
347 
348 		it.Remove();
349 		_RemoveEntry(entry);
350 	}
351 
352 	// get all IDs
353 	int32 count = fNodes->Size();
354 	if (count == 0)
355 		return;
356 	PRINT("  %" B_PRId32 " nodes to remove\n", count);
357 	vnode_id* ids = new(std::nothrow) vnode_id[count];
358 	if (!ids) {
359 		ERROR("ShareVolume::PrepareToUnmount(): ERROR: Insufficient memory to "
360 			"allocate the node ID array!\n");
361 		return;
362 	}
363 	ArrayDeleter<vnode_id> _(ids);
364 	count = 0;
365 	for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
366 		ShareNode* node = it.Next().value;
367 		ids[count++] = node->GetID();
368 	}
369 
370 	// Remove all nodes that are not known to the VFS right away.
371 	// If the netfs is already in the process of being unmounted, GetVNode()
372 	// will fail and the GetVNode(), RemoveVNode(), PutVNode() method won't
373 	// work for removing them.
374 	int32 remainingCount = 0;
375 	for (int32 i = 0; i < count; i++) {
376 		if (Node* node = fNodes->Get(ids[i])) {
377 			if (node->IsKnownToVFS()) {
378 				// node is known to VFS; we need to use the GetVNode(),
379 				// RemoveVNode(), PutVNode() method
380 				ids[remainingCount++] = ids[i];
381 			} else {
382 				// node is not known to VFS; just remove and delete it
383 				fNodes->Remove(node->GetID());
384 				_RemoveLocalNodeID(node->GetID());
385 				if (node != fRootNode)
386 					delete node;
387 			}
388 		}
389 	}
390 	count = remainingCount;
391 
392 	locker.Unlock();
393 
394 	// remove the nodes
395 	for (int32 i = 0; i < count; i++) {
396 		Node* node;
397 		if (GetVNode(ids[i], &node) == B_OK) {
398 			PRINT("  removing node %" B_PRIdINO "\n", ids[i]);
399 			Volume::RemoveVNode(ids[i]);
400 			PutVNode(ids[i]);
401 		}
402 	}
403 
404 	// remove ourselves for the server connection
405 	if (fServerConnection)
406 		fServerConnection->RemoveVolume(this);
407 
408 	// delete all entries
409 
410 PRINT(("ShareVolume::PrepareToUnmount() done\n"));
411 }
412 
413 // RemoveChildVolume
414 void
415 ShareVolume::RemoveChildVolume(Volume* volume)
416 {
417 	// should never be called
418 	WARN("WARNING: ShareVolume::RemoveChildVolume(%p) invoked!\n", volume);
419 }
420 
421 
422 // #pragma mark -
423 // #pragma mark ----- FS -----
424 
425 // Unmount
426 status_t
427 ShareVolume::Unmount()
428 {
429 	if (_IsConnected()) {
430 		// send the request
431 		UnmountRequest request;
432 		request.volumeID = fID;
433 		fConnection->SendRequest(&request);
434 	}
435 	return B_OK;
436 }
437 
438 // Sync
439 status_t
440 ShareVolume::Sync()
441 {
442 	// TODO: Implement?
443 	// We can't implement this without risking an endless recursion. The server
444 	// could only invoke sync(), which would sync all FSs, including a NetFS
445 	// which might be connected with a server running alongside this client.
446 	// We could introduce a sync flag to break the recursion. This might be
447 	// risky though.
448 	return B_OK;
449 }
450 
451 
452 // #pragma mark -
453 // #pragma mark ----- vnodes -----
454 
455 // ReadVNode
456 status_t
457 ShareVolume::ReadVNode(vnode_id vnid, char reenter, Node** _node)
458 {
459 	// check the map, maybe it's already loaded
460 	ShareNode* node = NULL;
461 	{
462 		AutoLocker<Locker> _(fLock);
463 		node = _GetNodeByLocalID(vnid);
464 		if (node) {
465 			node->SetKnownToVFS(true);
466 			*_node = node;
467 
468 			// add a volume reference for the node
469 			AcquireReference();
470 
471 			return B_OK;
472 		}
473 	}
474 
475 	// not yet loaded: send a request to the server
476 	if (!_EnsureShareMounted())
477 		return ERROR_NOT_CONNECTED;
478 
479 	// get the remote ID
480 	NodeID remoteID;
481 	status_t error = _GetRemoteNodeID(vnid, &remoteID);
482 	if (error != B_OK)
483 		return error;
484 
485 	// prepare the request
486 	ReadVNodeRequest request;
487 	request.volumeID = fID;
488 	request.nodeID = remoteID;
489 
490 	// send the request
491 	ReadVNodeReply* reply;
492 	error = SendRequest(fConnection, &request, &reply);
493 	if (error != B_OK)
494 		RETURN_ERROR(error);
495 	ObjectDeleter<Request> replyDeleter(reply);
496 	if (reply->error != B_OK)
497 		RETURN_ERROR(reply->error);
498 
499 	// add the node
500 	AutoLocker<Locker> _(fLock);
501 	error = _LoadNode(reply->nodeInfo, &node);
502 	if (error != B_OK)
503 		RETURN_ERROR(error);
504 	node->SetKnownToVFS(true);
505 	*_node = node;
506 
507 	// add a volume reference for the node
508 	AcquireReference();
509 
510 	return B_OK;
511 }
512 
513 // WriteVNode
514 status_t
515 ShareVolume::WriteVNode(Node* node, char reenter)
516 {
517 	AutoLocker<Locker> locker(fLock);
518 	node->SetKnownToVFS(false);
519 
520 	// surrender the node's volume reference
521 	locker.Unlock();
522 	PutVolume();
523 
524 	return B_OK;
525 }
526 
527 // RemoveVNode
528 status_t
529 ShareVolume::RemoveVNode(Node* node, char reenter)
530 {
531 	AutoLocker<Locker> locker(fLock);
532 	node->SetKnownToVFS(false);
533 	fNodes->Remove(node->GetID());
534 	_RemoveLocalNodeID(node->GetID());
535 	if (node != fRootNode)
536 		delete node;
537 
538 	// surrender the node's volume reference
539 	locker.Unlock();
540 	PutVolume();
541 
542 	return B_OK;
543 }
544 
545 
546 // #pragma mark -
547 // #pragma mark ----- nodes -----
548 
549 // FSync
550 status_t
551 ShareVolume::FSync(Node* _node)
552 {
553 	// TODO: Implement!
554 	return B_BAD_VALUE;
555 }
556 
557 // ReadStat
558 status_t
559 ShareVolume::ReadStat(Node* _node, struct stat* st)
560 {
561 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
562 
563 	AutoLocker<Locker> _(fLock);
564 	*st = node->GetNodeInfo().st;
565 	st->st_dev = fVolumeManager->GetID();
566 	st->st_ino = node->GetID();
567 	// we set the UID/GID fields to the one who mounted the FS
568 	st->st_uid = fVolumeManager->GetMountUID();
569 	st->st_gid = fVolumeManager->GetMountGID();
570 	return B_OK;
571 }
572 
573 // WriteStat
574 status_t
575 ShareVolume::WriteStat(Node* _node, struct stat *st, uint32 mask)
576 {
577 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
578 
579 	if (!_EnsureShareMounted())
580 		return ERROR_NOT_CONNECTED;
581 
582 	// check read-only
583 	if (IsReadOnly())
584 		return B_PERMISSION_DENIED;
585 	// prepare the request
586 	WriteStatRequest request;
587 	request.volumeID = fID;
588 	request.nodeID = node->GetRemoteID();
589 	request.nodeInfo.st = *st;
590 	request.mask = mask;
591 	// send the request
592 	WriteStatReply* reply;
593 	status_t error = SendRequest(fConnection, &request, &reply);
594 	if (error != B_OK)
595 		RETURN_ERROR(error);
596 	ObjectDeleter<Request> replyDeleter(reply);
597 	// update the node
598 	if (reply->nodeInfoValid)
599 		_UpdateNode(reply->nodeInfo);
600 	if (reply->error != B_OK)
601 		RETURN_ERROR(reply->error);
602 	return B_OK;
603 }
604 
605 // Access
606 status_t
607 ShareVolume::Access(Node* _node, int mode)
608 {
609 	// TODO: Implement.
610 	return B_OK;
611 }
612 
613 
614 // #pragma mark -
615 // #pragma mark ----- files -----
616 
617 // Create
618 status_t
619 ShareVolume::Create(Node* _dir, const char* name, int openMode, int mode,
620 	vnode_id* vnid, void** cookie)
621 {
622 	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
623 	if (!dir)
624 		return B_BAD_VALUE;
625 
626 	if (!_EnsureShareMounted())
627 		return ERROR_NOT_CONNECTED;
628 
629 	// check permissions
630 	if (IsReadOnly())
631 		return B_PERMISSION_DENIED;
632 	if (IsVNodeRemoved(dir->GetID()) > 0)
633 		RETURN_ERROR(B_NOT_ALLOWED);
634 
635 	// prepare the request
636 	CreateFileRequest request;
637 	request.volumeID = fID;
638 	request.directoryID = dir->GetRemoteID();
639 	request.name.SetTo(name);
640 	request.openMode = openMode;
641 	request.mode = mode;
642 
643 	// send the request
644 	CreateFileReply* reply;
645 	status_t error = SendRequest(fConnection, &request, &reply);
646 	if (error != B_OK)
647 		RETURN_ERROR(error);
648 	ObjectDeleter<Request> replyDeleter(reply);
649 	if (reply->error != B_OK)
650 		RETURN_ERROR(reply->error);
651 
652 	// add/update the entry
653 	vnode_id localID = -1;
654 	EntryInfo* entryInfo = &reply->entryInfo;
655 	while (true) {
656 		// get an up to date entry info
657 		WalkReply* walkReply = NULL;
658 		if (!entryInfo) {
659 			error = _Walk(reply->entryInfo.directoryID,
660 				reply->entryInfo.name.GetString(), false, &walkReply);
661 			if (error != B_OK)
662 				break;
663 
664 			entryInfo = &walkReply->entryInfo;
665 		}
666 		ObjectDeleter<Request> walkReplyDeleter(walkReply);
667 
668 		AutoLocker<Locker> locker(fLock);
669 
670 		// check, if the info is obsolete
671 		if (_IsObsoleteEntryInfo(*entryInfo)) {
672 			entryInfo = NULL;
673 			continue;
674 		}
675 
676 		// load the entry
677 		ShareDirEntry* entry;
678 		error = _LoadEntry(dir, *entryInfo, &entry);
679 		if (error == B_OK)
680 			localID = entry->GetNode()->GetID();
681 
682 		break;
683 	}
684 
685 	if (error == B_OK) {
686 		Node* _node;
687 		error = GetVNode(localID, &_node);
688 	}
689 
690 	// set the results / close the handle on error
691 	if (error == B_OK) {
692 		*vnid = localID;
693 		*cookie = (void*)reply->cookie;
694 	} else
695 		_Close(reply->cookie);
696 
697 	RETURN_ERROR(error);
698 }
699 
700 // Open
701 status_t
702 ShareVolume::Open(Node* _node, int openMode, void** cookie)
703 {
704 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
705 
706 // TODO: Allow opening the root node?
707 	if (!_EnsureShareMounted())
708 		return ERROR_NOT_CONNECTED;
709 
710 	// check the open mode
711 	if (IsReadOnly()) {
712 		if ((openMode & O_RWMASK) == O_WRONLY)
713 			return B_PERMISSION_DENIED;
714 		if (openMode & O_TRUNC)
715 			return B_PERMISSION_DENIED;
716 		if ((openMode & O_RWMASK) == O_RDWR)
717 			openMode = (openMode & ~O_RWMASK) | O_RDONLY;
718 	}
719 	// prepare the request
720 	OpenRequest request;
721 	request.volumeID = fID;
722 	request.nodeID = node->GetRemoteID();
723 	request.openMode = openMode;
724 	// send the request
725 	OpenReply* reply;
726 	status_t error = SendRequest(fConnection, &request, &reply);
727 	if (error != B_OK)
728 		RETURN_ERROR(error);
729 	ObjectDeleter<Request> replyDeleter(reply);
730 	if (reply->error != B_OK)
731 		RETURN_ERROR(reply->error);
732 	// update the node
733 	_UpdateNode(reply->nodeInfo);
734 	*cookie = (void*)reply->cookie;
735 	return B_OK;
736 }
737 
738 // Close
739 status_t
740 ShareVolume::Close(Node* _node, void* cookie)
741 {
742 	// no-op: FreeCookie does the job
743 	return B_OK;
744 }
745 
746 // FreeCookie
747 status_t
748 ShareVolume::FreeCookie(Node* _node, void* cookie)
749 {
750 	return _Close((int32)cookie);
751 }
752 
753 // Read
754 status_t
755 ShareVolume::Read(Node* _node, void* cookie, off_t pos, void* _buffer,
756 	size_t bufferSize, size_t* _bytesRead)
757 {
758 	if (!_EnsureShareMounted())
759 		return ERROR_NOT_CONNECTED;
760 
761 	*_bytesRead = 0;
762 	if (bufferSize == 0)
763 		return B_OK;
764 	uint8* buffer = (uint8*)_buffer;
765 	// prepare the request
766 	ReadRequest request;
767 	request.volumeID = fID;
768 	request.cookie = (int32)cookie;
769 	request.pos = pos;
770 	request.size = bufferSize;
771 
772 	struct ReadRequestHandler : public RequestHandler {
773 		uint8*	buffer;
774 		off_t	pos;
775 		int32	bufferSize;
776 		int32	bytesRead;
777 
778 		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
779 			: buffer(buffer),
780 			  pos(pos),
781 			  bufferSize(bufferSize),
782 			  bytesRead(0)
783 		{
784 		}
785 
786 		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
787 		{
788 			// the passed request is deleted by the request port
789 			ReadReply* reply = dynamic_cast<ReadReply*>(_reply);
790 			if (!reply)
791 				RETURN_ERROR(B_BAD_DATA);
792 			// process the reply
793 			status_t error = ProcessReply(reply);
794 			if (error != B_OK)
795 				return error;
796 			bool moreToCome = reply->moreToCome;
797 			while (moreToCome) {
798 				// receive a reply
799 				error = ReceiveRequest(channel, &reply);
800 				if (error != B_OK)
801 					RETURN_ERROR(error);
802 				moreToCome = reply->moreToCome;
803 				ObjectDeleter<Request> replyDeleter(reply);
804 				// process the reply
805 				error = ProcessReply(reply);
806 				if (error != B_OK)
807 					return error;
808 			}
809 			return B_OK;
810 		}
811 
812 		status_t ProcessReply(ReadReply* reply)
813 		{
814 			if (reply->error != B_OK)
815 				RETURN_ERROR(reply->error);
816 			// check the fields
817 			if (reply->pos != pos)
818 				RETURN_ERROR(B_BAD_DATA);
819 			int32 bytesRead = reply->data.GetSize();
820 			if (bytesRead > (int32)bufferSize)
821 				RETURN_ERROR(B_BAD_DATA);
822 			// copy the data into the buffer
823 			if (bytesRead > 0)
824 				memcpy(buffer, reply->data.GetData(), bytesRead);
825 			pos += bytesRead;
826 			buffer += bytesRead;
827 			bufferSize -= bytesRead;
828 			this->bytesRead += bytesRead;
829 			return B_OK;
830 		}
831 	} requestHandler(buffer, pos, bufferSize);
832 
833 	// send the request
834 	status_t error = fConnection->SendRequest(&request, &requestHandler);
835 	if (error != B_OK)
836 		RETURN_ERROR(error);
837 	*_bytesRead = requestHandler.bytesRead;
838 	return B_OK;
839 }
840 
841 // Write
842 status_t
843 ShareVolume::Write(Node* _node, void* cookie, off_t pos, const void* _buffer,
844 	size_t bufferSize, size_t* bytesWritten)
845 {
846 	if (!_EnsureShareMounted())
847 		return ERROR_NOT_CONNECTED;
848 
849 	// check permissions
850 	if (IsReadOnly())
851 		return B_PERMISSION_DENIED;
852 
853 	*bytesWritten = 0;
854 	off_t bytesLeft = bufferSize;
855 	const char* buffer = (const char*)_buffer;
856 	while (bytesLeft > 0) {
857 		off_t toWrite = bytesLeft;
858 		if (toWrite > kMaxWriteBufferSize)
859 			toWrite = kMaxWriteBufferSize;
860 
861 		// prepare the request
862 		WriteRequest request;
863 		request.volumeID = fID;
864 		request.cookie = (int32)cookie;
865 		request.pos = pos;
866 		request.data.SetTo(buffer, toWrite);
867 
868 		// send the request
869 		WriteReply* reply;
870 		status_t error = SendRequest(fConnection, &request, &reply);
871 		if (error != B_OK)
872 			RETURN_ERROR(error);
873 		ObjectDeleter<Request> replyDeleter(reply);
874 		if (reply->error != B_OK)
875 			RETURN_ERROR(reply->error);
876 
877 		bytesLeft -= toWrite;
878 		pos += toWrite;
879 		buffer += toWrite;
880 
881 // TODO: We should probably add an "up to date" flag for ShareNode (just as
882 // done for ShareAttrDir) and clear it at this point. Currently continuity
883 // inconsistencies could occur (e.g. a stat() after a write() returns
884 // obsolete data), depending on when the node monitoring update arrives.
885 	}
886 
887 	*bytesWritten = bufferSize;
888 	return B_OK;
889 }
890 
891 
892 // #pragma mark -
893 // #pragma mark ----- hard links / symlinks -----
894 
895 // Link
896 status_t
897 ShareVolume::Link(Node* _dir, const char* name, Node* _node)
898 {
899 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
900 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
901 
902 	if (!node || node->GetVolume() != this)
903 		return B_NOT_ALLOWED;
904 
905 	if (!_EnsureShareMounted())
906 		return ERROR_NOT_CONNECTED;
907 
908 	// check permissions
909 	if (IsReadOnly())
910 		return B_PERMISSION_DENIED;
911 	if (IsVNodeRemoved(dir->GetID()) > 0)
912 		RETURN_ERROR(B_NOT_ALLOWED);
913 	if (IsVNodeRemoved(node->GetID()) > 0)
914 		RETURN_ERROR(B_NOT_ALLOWED);
915 	// prepare the request
916 	CreateLinkRequest request;
917 	request.volumeID = fID;
918 	request.directoryID = dir->GetRemoteID();
919 	request.name.SetTo(name);
920 	request.nodeID = node->GetRemoteID();
921 	// send the request
922 	CreateLinkReply* reply;
923 	status_t error = SendRequest(fConnection, &request, &reply);
924 	if (error != B_OK)
925 		RETURN_ERROR(error);
926 	ObjectDeleter<Request> replyDeleter(reply);
927 	RETURN_ERROR(reply->error);
928 }
929 
930 // Unlink
931 status_t
932 ShareVolume::Unlink(Node* _dir, const char* name)
933 {
934 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
935 
936 	if (!_EnsureShareMounted())
937 		return ERROR_NOT_CONNECTED;
938 
939 	// check permissions
940 	if (IsReadOnly())
941 		return B_PERMISSION_DENIED;
942 	// prepare the request
943 	UnlinkRequest request;
944 	request.volumeID = fID;
945 	request.directoryID = dir->GetRemoteID();
946 	request.name.SetTo(name);
947 	// send the request
948 	UnlinkReply* reply;
949 	status_t error = SendRequest(fConnection, &request, &reply);
950 	if (error != B_OK)
951 		RETURN_ERROR(error);
952 	ObjectDeleter<Request> replyDeleter(reply);
953 	RETURN_ERROR(reply->error);
954 }
955 
956 // Symlink
957 status_t
958 ShareVolume::Symlink(Node* _dir, const char* name, const char* target)
959 {
960 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
961 
962 	if (!_EnsureShareMounted())
963 		return ERROR_NOT_CONNECTED;
964 
965 	// check permissions
966 	if (IsReadOnly())
967 		return B_PERMISSION_DENIED;
968 	if (IsVNodeRemoved(dir->GetID()) > 0)
969 		RETURN_ERROR(B_NOT_ALLOWED);
970 	// prepare the request
971 	CreateSymlinkRequest request;
972 	request.volumeID = fID;
973 	request.directoryID = dir->GetRemoteID();
974 	request.name.SetTo(name);
975 	request.target.SetTo(target);
976 	// send the request
977 	CreateSymlinkReply* reply;
978 	status_t error = SendRequest(fConnection, &request, &reply);
979 	if (error != B_OK)
980 		RETURN_ERROR(error);
981 	ObjectDeleter<Request> replyDeleter(reply);
982 	RETURN_ERROR(reply->error);
983 }
984 
985 // ReadLink
986 status_t
987 ShareVolume::ReadLink(Node* _node, char* buffer, size_t bufferSize,
988 	size_t* bytesRead)
989 {
990 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
991 
992 	if (!_EnsureShareMounted())
993 		return ERROR_NOT_CONNECTED;
994 
995 	*bytesRead = 0;
996 	// prepare the request
997 	ReadLinkRequest request;
998 	request.volumeID = fID;
999 	request.nodeID = node->GetRemoteID();
1000 	request.maxSize = bufferSize;
1001 	// send the request
1002 	ReadLinkReply* reply;
1003 	status_t error = SendRequest(fConnection, &request, &reply);
1004 	if (error != B_OK)
1005 		RETURN_ERROR(error);
1006 	ObjectDeleter<Request> replyDeleter(reply);
1007 	if (reply->error != B_OK)
1008 		RETURN_ERROR(reply->error);
1009 	if (reply->data.GetSize() > (int32)bufferSize)
1010 		RETURN_ERROR(B_BAD_DATA);
1011 	*bytesRead = reply->data.GetSize();
1012 	if (*bytesRead > 0)
1013 		memcpy(buffer, reply->data.GetData(), *bytesRead);
1014 	_UpdateNode(reply->nodeInfo);
1015 	return B_OK;
1016 }
1017 
1018 // Rename
1019 status_t
1020 ShareVolume::Rename(Node* _oldDir, const char* oldName, Node* _newDir,
1021 	const char* newName)
1022 {
1023 	ShareNode* oldDir = dynamic_cast<ShareNode*>(_oldDir);
1024 	ShareNode* newDir = dynamic_cast<ShareNode*>(_newDir);
1025 
1026 	if (!newDir || newDir->GetVolume() != this)
1027 		return B_NOT_ALLOWED;
1028 
1029 	if (!_EnsureShareMounted())
1030 		return ERROR_NOT_CONNECTED;
1031 
1032 	// check permissions
1033 	if (IsReadOnly())
1034 		return B_PERMISSION_DENIED;
1035 	if (IsVNodeRemoved(newDir->GetID()) > 0)
1036 		RETURN_ERROR(B_NOT_ALLOWED);
1037 	// prepare the request
1038 	RenameRequest request;
1039 	request.volumeID = fID;
1040 	request.oldDirectoryID = oldDir->GetRemoteID();
1041 	request.oldName.SetTo(oldName);
1042 	request.newDirectoryID = newDir->GetRemoteID();
1043 	request.newName.SetTo(newName);
1044 	// send the request
1045 	RenameReply* reply;
1046 	status_t error = SendRequest(fConnection, &request, &reply);
1047 	if (error != B_OK)
1048 		RETURN_ERROR(error);
1049 	ObjectDeleter<Request> replyDeleter(reply);
1050 	RETURN_ERROR(reply->error);
1051 }
1052 
1053 
1054 // #pragma mark -
1055 // #pragma mark ----- directories -----
1056 
1057 // MkDir
1058 status_t
1059 ShareVolume::MkDir(Node* _dir, const char* name, int mode)
1060 {
1061 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
1062 
1063 	if (!_EnsureShareMounted())
1064 		return ERROR_NOT_CONNECTED;
1065 
1066 	// check permissions
1067 	if (IsReadOnly())
1068 		return B_PERMISSION_DENIED;
1069 	if (IsVNodeRemoved(dir->GetID()) > 0)
1070 		RETURN_ERROR(B_NOT_ALLOWED);
1071 	// prepare the request
1072 	MakeDirRequest request;
1073 	request.volumeID = fID;
1074 	request.directoryID = dir->GetRemoteID();
1075 	request.name.SetTo(name);
1076 	request.mode = mode;
1077 	// send the request
1078 	MakeDirReply* reply;
1079 	status_t error = SendRequest(fConnection, &request, &reply);
1080 	if (error != B_OK)
1081 		RETURN_ERROR(error);
1082 	ObjectDeleter<Request> replyDeleter(reply);
1083 	RETURN_ERROR(reply->error);
1084 }
1085 
1086 // RmDir
1087 status_t
1088 ShareVolume::RmDir(Node* _dir, const char* name)
1089 {
1090 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
1091 
1092 	if (!_EnsureShareMounted())
1093 		return ERROR_NOT_CONNECTED;
1094 
1095 	// check permissions
1096 	if (IsReadOnly())
1097 		return B_PERMISSION_DENIED;
1098 	// prepare the request
1099 	RemoveDirRequest request;
1100 	request.volumeID = fID;
1101 	request.directoryID = dir->GetRemoteID();
1102 	request.name.SetTo(name);
1103 	// send the request
1104 	RemoveDirReply* reply;
1105 	status_t error = SendRequest(fConnection, &request, &reply);
1106 	if (error != B_OK)
1107 		RETURN_ERROR(error);
1108 	ObjectDeleter<Request> replyDeleter(reply);
1109 	RETURN_ERROR(reply->error);
1110 }
1111 
1112 // OpenDir
1113 status_t
1114 ShareVolume::OpenDir(Node* _node, void** _cookie)
1115 {
1116 	// we opendir() only directories
1117 	ShareDir* node = dynamic_cast<ShareDir*>(_node);
1118 	if (!node)
1119 		return B_NOT_ALLOWED;
1120 
1121 // TODO: Allow opening the root node?
1122 	if (!_EnsureShareMounted())
1123 		return ERROR_NOT_CONNECTED;
1124 
1125 	// allocate a dir cookie
1126 	DirCookie* cookie = new(std::nothrow) DirCookie;
1127 	if (!cookie)
1128 		RETURN_ERROR(B_NO_MEMORY);
1129 	ObjectDeleter<DirCookie> cookieDeleter(cookie);
1130 
1131 	// if the directory is fully cached, we allocate a local iterator
1132 	{
1133 		AutoLocker<Locker> locker(fLock);
1134 		if (node->IsComplete()) {
1135 			// create a local dir iterator
1136 			LocalShareDirIterator* iterator
1137 				= new(std::nothrow) LocalShareDirIterator();
1138 			if (!iterator)
1139 				RETURN_ERROR(B_NO_MEMORY);
1140 			iterator->SetDirectory(node);
1141 
1142 			// init the cookie
1143 			cookie->iterator = iterator;
1144 			*_cookie = cookie;
1145 			cookieDeleter.Detach();
1146 			return B_OK;
1147 		}
1148 	}
1149 
1150 	// allocate a remote dir iterator
1151 	RemoteShareDirIterator* iterator = new(std::nothrow) RemoteShareDirIterator;
1152 	if (!iterator)
1153 		RETURN_ERROR(B_NO_MEMORY);
1154 	ObjectDeleter<RemoteShareDirIterator> iteratorDeleter(iterator);
1155 
1156 	// prepare the request
1157 	OpenDirRequest request;
1158 	request.volumeID = fID;
1159 	request.nodeID = node->GetRemoteID();
1160 
1161 	// send the request
1162 	OpenDirReply* reply;
1163 	status_t error = SendRequest(fConnection, &request, &reply);
1164 	if (error != B_OK)
1165 		RETURN_ERROR(error);
1166 	ObjectDeleter<Request> replyDeleter(reply);
1167 	if (reply->error != B_OK)
1168 {
1169 		PRINT("OpenDir() failed: node: %" B_PRIdINO ", remote: (%" B_PRIdDEV
1170 			", %" B_PRIdINO ")\n", node->GetID(), node->GetRemoteID().volumeID,
1171 			node->GetRemoteID().nodeID);
1172 		RETURN_ERROR(reply->error);
1173 }
1174 
1175 	// update the node
1176 	_UpdateNode(reply->nodeInfo);
1177 
1178 	// init the cookie
1179 	iterator->SetCookie(reply->cookie);
1180 	cookie->iterator = iterator;
1181 
1182 	*_cookie = cookie;
1183 	cookieDeleter.Detach();
1184 	iteratorDeleter.Detach();
1185 	return B_OK;
1186 }
1187 
1188 // CloseDir
1189 status_t
1190 ShareVolume::CloseDir(Node* _node, void* cookie)
1191 {
1192 	// no-op: FreeDirCookie does the job
1193 	return B_OK;
1194 }
1195 
1196 // FreeDirCookie
1197 status_t
1198 ShareVolume::FreeDirCookie(Node* _node, void* _cookie)
1199 {
1200 	DirCookie* cookie = (DirCookie*)_cookie;
1201 	ObjectDeleter<DirCookie> _(cookie);
1202 	ShareDirIterator* iterator = cookie->iterator;
1203 
1204 	status_t error = B_OK;
1205 	if (RemoteShareDirIterator* remoteIterator
1206 		= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
1207 		// prepare the request
1208 		CloseRequest request;
1209 		request.volumeID = fID;
1210 		request.cookie = remoteIterator->GetCookie();
1211 
1212 		// send the request
1213 		if (!_EnsureShareMounted())
1214 			error = ERROR_NOT_CONNECTED;
1215 
1216 		if (error == B_OK) {
1217 			CloseReply* reply;
1218 			error = SendRequest(fConnection, &request, &reply);
1219 			if (error == B_OK) {
1220 				error = reply->error;
1221 				delete reply;
1222 			}
1223 		}
1224 	}
1225 
1226 	// delete the iterator
1227 	AutoLocker<Locker> locker(fLock);
1228 	delete iterator;
1229 
1230 	return error;
1231 }
1232 
1233 // ReadDir
1234 status_t
1235 ShareVolume::ReadDir(Node* _dir, void* _cookie, struct dirent* buffer,
1236 	size_t bufferSize, int32 count, int32* countRead)
1237 {
1238 	ShareDir* directory = dynamic_cast<ShareDir*>(_dir);
1239 
1240 	if (!_EnsureShareMounted())
1241 		return ERROR_NOT_CONNECTED;
1242 
1243 	*countRead = 0;
1244 	if (count <= 0)
1245 		return B_OK;
1246 
1247 	DirCookie* cookie = (DirCookie*)_cookie;
1248 	ShareDirIterator* iterator = cookie->iterator;
1249 
1250 	while (true) {
1251 		status_t error;
1252 		AutoLocker<Locker> locker(fLock);
1253 		while (ShareDirEntry* entry = iterator->GetCurrentEntry()) {
1254 			// re-get the entry -- it might already have been removed
1255 			const char* name = entry->GetName();
1256 			entry = _GetEntryByLocalID(directory->GetID(), name);
1257 			if (entry) {
1258 				// set the name: this also checks the size of the buffer
1259 				error = set_dirent_name(buffer, bufferSize, name,
1260 					strlen(name));
1261 				if (error != B_OK) {
1262 					// if something has been read at all, we're content
1263 					if (*countRead > 0)
1264 						return B_OK;
1265 					RETURN_ERROR(error);
1266 				}
1267 
1268 				// fill in the other fields
1269 				buffer->d_pdev = fVolumeManager->GetID();
1270 				buffer->d_pino = directory->GetID();
1271 				buffer->d_dev = fVolumeManager->GetID();
1272 				buffer->d_ino = entry->GetNode()->GetID();
1273 
1274 				// if the entry is the parent of the share root, we need to
1275 				// fix the node ID
1276 				if (directory == fRootNode && strcmp(name, "..") == 0) {
1277 					if (Volume* parentVolume = GetParentVolume())
1278 						buffer->d_ino = parentVolume->GetRootID();
1279 				}
1280 
1281 				iterator->NextEntry();
1282 				(*countRead)++;
1283 				if (*countRead >= count || !next_dirent(buffer, bufferSize))
1284 					return B_OK;
1285 			} else
1286 				iterator->NextEntry();
1287 		}
1288 
1289 		// no more entries: check, if we're completely through
1290 		if (iterator->IsDone())
1291 			return B_OK;
1292 
1293 		// we need to actually get entries from the server
1294 		locker.Unlock();
1295 		if (RemoteShareDirIterator* remoteIterator
1296 				= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
1297 			error = _ReadRemoteDir(directory, remoteIterator);
1298 			if (error != B_OK)
1299 				return error;
1300 		}
1301 	}
1302 }
1303 
1304 // RewindDir
1305 status_t
1306 ShareVolume::RewindDir(Node* _node, void* _cookie)
1307 {
1308 	DirCookie* cookie = (DirCookie*)_cookie;
1309 	ShareDirIterator* iterator = cookie->iterator;
1310 	AutoLocker<Locker> _(fLock);
1311 	iterator->Rewind();
1312 	return B_OK;
1313 }
1314 
1315 // Walk
1316 status_t
1317 ShareVolume::Walk(Node* _dir, const char* entryName, char** resolvedPath,
1318 	vnode_id* vnid)
1319 {
1320 	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
1321 	if (!dir)
1322 		return B_BAD_VALUE;
1323 
1324 	// we always resolve "." and ".." of the root node
1325 	if (dir == fRootNode) {
1326 		if (strcmp(entryName, ".") == 0 || strcmp(entryName, "..") == 0) {
1327 			AutoLocker<Locker> _(fLock);
1328 			if (strcmp(entryName, ".") == 0) {
1329 				*vnid = fRootNode->GetID();
1330 			} else if (Volume* parentVolume = GetParentVolume()) {
1331 				*vnid = parentVolume->GetRootID();
1332 			} else
1333 				*vnid = fRootNode->GetID();
1334 			Node* node;
1335 			return GetVNode(*vnid, &node);
1336 		}
1337 	}
1338 
1339 	if (!_EnsureShareMounted())
1340 		return ERROR_NOT_CONNECTED;
1341 
1342 	// check, if the entry is already known
1343 	{
1344 		AutoLocker<Locker> _(fLock);
1345 		ShareDirEntry* entry = _GetEntryByLocalID(dir->GetID(), entryName);
1346 		if (entry) {
1347 			*vnid = entry->GetNode()->GetID();
1348 			Node* node;
1349 			return GetVNode(*vnid, &node);
1350 		} else if (dir->IsComplete())
1351 			return B_ENTRY_NOT_FOUND;
1352 	}
1353 
1354 	WalkReply* reply;
1355 	while (true) {
1356 		// send the request
1357 		status_t error = _Walk(dir->GetRemoteID(), entryName, resolvedPath,
1358 			&reply);
1359 		if (error != B_OK)
1360 			RETURN_ERROR(error);
1361 		ObjectDeleter<Request> replyDeleter(reply);
1362 
1363 		AutoLocker<Locker> locker(fLock);
1364 
1365 		// check, if the returned info is obsolete
1366 		if (_IsObsoleteEntryInfo(reply->entryInfo))
1367 			continue;
1368 
1369 		// load the entry
1370 		ShareDirEntry* entry;
1371 		error = _LoadEntry(dir, reply->entryInfo, &entry);
1372 		if (error != B_OK)
1373 			RETURN_ERROR(error);
1374 		*vnid = entry->GetNode()->GetID();
1375 
1376 		// deal with symlinks
1377 		if (reply->linkPath.GetString() && resolvedPath) {
1378 			*resolvedPath = strdup(reply->linkPath.GetString());
1379 			if (!*resolvedPath)
1380 				RETURN_ERROR(B_NO_MEMORY);
1381 			return B_OK;
1382 		}
1383 
1384 		break;
1385 	}
1386 
1387 	// no symlink or we shall not resolve it: get the node
1388 	Node* _node;
1389 	RETURN_ERROR(GetVNode(*vnid, &_node));
1390 }
1391 
1392 
1393 // #pragma mark -
1394 // #pragma mark ----- attributes -----
1395 
1396 // OpenAttrDir
1397 status_t
1398 ShareVolume::OpenAttrDir(Node* _node, void** _cookie)
1399 {
1400 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1401 
1402 // TODO: Allow opening the root node?
1403 	if (!_EnsureShareMounted())
1404 		return ERROR_NOT_CONNECTED;
1405 
1406 	// allocate a dir cookie
1407 	AttrDirCookie* cookie = new(std::nothrow) AttrDirCookie;
1408 	if (!cookie)
1409 		RETURN_ERROR(B_NO_MEMORY);
1410 	ObjectDeleter<AttrDirCookie> cookieDeleter(cookie);
1411 
1412 	AutoLocker<Locker> locker(fLock);
1413 
1414 	if (!node->GetAttrDir() || !node->GetAttrDir()->IsUpToDate()) {
1415 		// prepare the request
1416 		OpenAttrDirRequest request;
1417 		request.volumeID = fID;
1418 		request.nodeID = node->GetRemoteID();
1419 
1420 		locker.Unlock();
1421 
1422 		// send the request
1423 		OpenAttrDirReply* reply;
1424 		status_t error = SendRequest(fConnection, &request, &reply);
1425 		if (error != B_OK)
1426 			RETURN_ERROR(error);
1427 		ObjectDeleter<Request> replyDeleter(reply);
1428 		if (reply->error != B_OK)
1429 			RETURN_ERROR(reply->error);
1430 
1431 		// If no AttrDirInfo was supplied, we just save the cookie and be done.
1432 		// This usually happens when the attr dir is too big to be cached.
1433 		if (!reply->attrDirInfo.isValid) {
1434 			cookie->cookie = reply->cookie;
1435 			cookie->rewind = false;
1436 			*_cookie = cookie;
1437 			cookieDeleter.Detach();
1438 			return B_OK;
1439 		}
1440 
1441 		locker.SetTo(fLock, false);
1442 
1443 		// a AttrDirInfo has been supplied: load the attr dir
1444 		error = _LoadAttrDir(node, reply->attrDirInfo);
1445 		if (error != B_OK)
1446 			return error;
1447 	}
1448 
1449 	// we have a valid attr dir: create an attr dir iterator
1450 	ShareAttrDirIterator* iterator = new(std::nothrow) ShareAttrDirIterator;
1451 	if (!iterator)
1452 		return B_NO_MEMORY;
1453 	iterator->SetAttrDir(node->GetAttrDir());
1454 
1455 	// add the iterator
1456 	status_t error = _AddAttrDirIterator(node, iterator);
1457 	if (error != B_OK) {
1458 		delete iterator;
1459 		return error;
1460 	}
1461 
1462 	cookie->iterator = iterator;
1463 	*_cookie = cookie;
1464 	cookieDeleter.Detach();
1465 	return B_OK;
1466 }
1467 
1468 // CloseAttrDir
1469 status_t
1470 ShareVolume::CloseAttrDir(Node* _node, void* cookie)
1471 {
1472 	// no-op: FreeAttrDirCookie does the job
1473 	return B_OK;
1474 }
1475 
1476 // FreeAttrDirCookie
1477 status_t
1478 ShareVolume::FreeAttrDirCookie(Node* _node, void* _cookie)
1479 {
1480 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1481 	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1482 	ObjectDeleter<AttrDirCookie> _(cookie);
1483 
1484 	// if this is a local iterator, we just delete it and be done
1485 	if (cookie->iterator) {
1486 		AutoLocker<Locker> locker(fLock);
1487 
1488 		// remove and delete the iterator
1489 		_RemoveAttrDirIterator(node, cookie->iterator);
1490 		delete cookie->iterator;
1491 
1492 		return B_OK;
1493 	}
1494 
1495 	// prepare the request
1496 	CloseRequest request;
1497 	request.volumeID = fID;
1498 	request.cookie = cookie->cookie;
1499 
1500 	// send the request
1501 	if (!_EnsureShareMounted())
1502 		return ERROR_NOT_CONNECTED;
1503 	CloseReply* reply;
1504 	status_t error = SendRequest(fConnection, &request, &reply);
1505 	if (error != B_OK)
1506 		RETURN_ERROR(error);
1507 	ObjectDeleter<Request> replyDeleter(reply);
1508 	if (reply->error != B_OK)
1509 		RETURN_ERROR(reply->error);
1510 
1511 	return B_OK;
1512 }
1513 
1514 // ReadAttrDir
1515 status_t
1516 ShareVolume::ReadAttrDir(Node* _node, void* _cookie, struct dirent* buffer,
1517 	size_t bufferSize, int32 count, int32* countRead)
1518 {
1519 	if (!_EnsureShareMounted())
1520 		return ERROR_NOT_CONNECTED;
1521 
1522 	*countRead = 0;
1523 	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1524 
1525 	// if we have a local iterator, things are easy
1526 	if (ShareAttrDirIterator* iterator = cookie->iterator) {
1527 		AutoLocker<Locker> locker(fLock);
1528 
1529 		// get the current attribute
1530 		Attribute* attribute = iterator->GetCurrentAttribute();
1531 		if (!attribute)
1532 			return B_OK;
1533 
1534 		// set the name: this also checks the size of the buffer
1535 		const char* name = attribute->GetName();
1536 		status_t error = set_dirent_name(buffer, bufferSize, name,
1537 			strlen(name));
1538 		if (error != B_OK)
1539 			RETURN_ERROR(error);
1540 
1541 		// fill in the other fields
1542 		buffer->d_dev = fVolumeManager->GetID();
1543 		buffer->d_ino = -1;
1544 		*countRead = 1;
1545 
1546 		iterator->NextAttribute();
1547 		return B_OK;
1548 	}
1549 
1550 	// prepare the request
1551 	ReadAttrDirRequest request;
1552 	request.volumeID = fID;
1553 	request.cookie = cookie->cookie;
1554 	request.count = 1;
1555 	request.rewind = cookie->rewind;
1556 
1557 	// send the request
1558 	ReadAttrDirReply* reply;
1559 	status_t error = SendRequest(fConnection, &request, &reply);
1560 	if (error != B_OK)
1561 		RETURN_ERROR(error);
1562 	ObjectDeleter<Request> replyDeleter(reply);
1563 	if (reply->error != B_OK)
1564 		RETURN_ERROR(reply->error);
1565 	cookie->rewind = false;
1566 
1567 	// check, if anything has been read at all
1568 	if (reply->count == 0) {
1569 		*countRead = 0;
1570 		return B_OK;
1571 	}
1572 	const char* name = reply->name.GetString();
1573 	int32 nameLen = reply->name.GetSize();
1574 	if (!name || nameLen < 2)
1575 		return B_BAD_DATA;
1576 
1577 	// set the name: this also checks the size of the buffer
1578 	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
1579 	if (error != B_OK)
1580 		RETURN_ERROR(error);
1581 
1582 	// fill in the other fields
1583 	buffer->d_dev = fVolumeManager->GetID();
1584 	buffer->d_ino = -1;
1585 	*countRead = 1;
1586 	return B_OK;
1587 }
1588 
1589 // RewindAttrDir
1590 status_t
1591 ShareVolume::RewindAttrDir(Node* _node, void* _cookie)
1592 {
1593 	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1594 
1595 	// if we have a local iterator, rewind it
1596 	if (ShareAttrDirIterator* iterator = cookie->iterator) {
1597 		AutoLocker<Locker> locker(fLock);
1598 
1599 		iterator->Rewind();
1600 	} else
1601 		cookie->rewind = true;
1602 
1603 	return B_OK;
1604 }
1605 
1606 // ReadAttr
1607 status_t
1608 ShareVolume::ReadAttr(Node* _node, const char* name, int type, off_t pos,
1609 	void* _buffer, size_t bufferSize, size_t* _bytesRead)
1610 {
1611 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1612 
1613 	if (!_EnsureShareMounted())
1614 		return ERROR_NOT_CONNECTED;
1615 
1616 	*_bytesRead = 0;
1617 	if (bufferSize == 0)
1618 		return B_OK;
1619 	uint8* buffer = (uint8*)_buffer;
1620 
1621 	// if we have the attribute directory cached, we can first check, if the
1622 	// attribute exists at all -- maybe its data are cached, too
1623 	{
1624 		AutoLocker<Locker> locker(fLock);
1625 
1626 		ShareAttrDir* attrDir = node->GetAttrDir();
1627 		if (attrDir && attrDir->IsUpToDate()) {
1628 			// get the attribute
1629 			Attribute* attribute = attrDir->GetAttribute(name);
1630 			if (!attribute)
1631 				return B_ENTRY_NOT_FOUND;
1632 
1633 			// get the data
1634 			if (const void* data = attribute->GetData()) {
1635 				// first check, if we can read anything at all
1636 				if (pos < 0)
1637 					pos = 0;
1638 				int32 size = attribute->GetSize();
1639 				if (pos >= size)
1640 					return B_OK;
1641 
1642 				// get the data
1643 				bufferSize = min(bufferSize, size_t(size - pos));
1644 				memcpy(buffer, data, bufferSize);
1645 				*_bytesRead = bufferSize;
1646 				return B_OK;
1647 			}
1648 		}
1649 	}
1650 
1651 	// prepare the request
1652 	ReadAttrRequest request;
1653 	request.volumeID = fID;
1654 	request.nodeID = node->GetRemoteID();
1655 	request.name.SetTo(name);
1656 	request.type = type;
1657 	request.pos = pos;
1658 	request.size = bufferSize;
1659 
1660 	struct ReadRequestHandler : public RequestHandler {
1661 		uint8*	buffer;
1662 		off_t	pos;
1663 		int32	bufferSize;
1664 		int32	bytesRead;
1665 
1666 		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
1667 			: buffer(buffer),
1668 			  pos(pos),
1669 			  bufferSize(bufferSize),
1670 			  bytesRead(0)
1671 		{
1672 		}
1673 
1674 		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
1675 		{
1676 			// the passed request is deleted by the request port
1677 			ReadAttrReply* reply = dynamic_cast<ReadAttrReply*>(_reply);
1678 			if (!reply)
1679 				RETURN_ERROR(B_BAD_DATA);
1680 			// process the reply
1681 			status_t error = ProcessReply(reply);
1682 			if (error != B_OK)
1683 				return error;
1684 			bool moreToCome = reply->moreToCome;
1685 			while (moreToCome) {
1686 				// receive a reply
1687 				error = ReceiveRequest(channel, &reply);
1688 				if (error != B_OK)
1689 					RETURN_ERROR(error);
1690 				moreToCome = reply->moreToCome;
1691 				ObjectDeleter<Request> replyDeleter(reply);
1692 				// process the reply
1693 				error = ProcessReply(reply);
1694 				if (error != B_OK)
1695 					return error;
1696 			}
1697 			return B_OK;
1698 		}
1699 
1700 		status_t ProcessReply(ReadAttrReply* reply)
1701 		{
1702 			if (reply->error != B_OK)
1703 				RETURN_ERROR(reply->error);
1704 			// check the fields
1705 			if (reply->pos != pos)
1706 				RETURN_ERROR(B_BAD_DATA);
1707 			int32 bytesRead = reply->data.GetSize();
1708 			if (bytesRead > (int32)bufferSize)
1709 				RETURN_ERROR(B_BAD_DATA);
1710 			// copy the data into the buffer
1711 			if (bytesRead > 0)
1712 				memcpy(buffer, reply->data.GetData(), bytesRead);
1713 			pos += bytesRead;
1714 			buffer += bytesRead;
1715 			bufferSize -= bytesRead;
1716 			this->bytesRead += bytesRead;
1717 			return B_OK;
1718 		}
1719 	} requestHandler(buffer, pos, bufferSize);
1720 
1721 	// send the request
1722 	status_t error = fConnection->SendRequest(&request, &requestHandler);
1723 	if (error != B_OK)
1724 		RETURN_ERROR(error);
1725 	*_bytesRead = requestHandler.bytesRead;
1726 	return B_OK;
1727 }
1728 
1729 // WriteAttr
1730 status_t
1731 ShareVolume::WriteAttr(Node* _node, const char* name, int type, off_t pos,
1732 	const void* _buffer, size_t bufferSize, size_t* bytesWritten)
1733 {
1734 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1735 
1736 	if (!_EnsureShareMounted())
1737 		return ERROR_NOT_CONNECTED;
1738 
1739 	// check permissions
1740 	if (IsReadOnly())
1741 		return B_PERMISSION_DENIED;
1742 
1743 	*bytesWritten = 0;
1744 	off_t bytesLeft = bufferSize;
1745 	const char* buffer = (const char*)_buffer;
1746 	while (bytesLeft > 0) {
1747 		// store the current attibute dir revision for reference below
1748 		int64 attrDirRevision = -1;
1749 		{
1750 			AutoLocker<Locker> _(fLock);
1751 			if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1752 				if (attrDir->IsUpToDate())
1753 					attrDirRevision = attrDir->GetRevision();
1754 			}
1755 		}
1756 
1757 		off_t toWrite = bytesLeft;
1758 		if (toWrite > kMaxWriteBufferSize)
1759 			toWrite = kMaxWriteBufferSize;
1760 
1761 		// prepare the request
1762 		WriteAttrRequest request;
1763 		request.volumeID = fID;
1764 		request.nodeID = node->GetRemoteID();
1765 		request.name.SetTo(name);
1766 		request.type = type;
1767 		request.pos = pos;
1768 		request.data.SetTo(buffer, toWrite);
1769 
1770 		// send the request
1771 		WriteAttrReply* reply;
1772 		status_t error = SendRequest(fConnection, &request, &reply);
1773 		if (error != B_OK)
1774 			RETURN_ERROR(error);
1775 
1776 		ObjectDeleter<Request> replyDeleter(reply);
1777 		if (reply->error != B_OK)
1778 			RETURN_ERROR(reply->error);
1779 
1780 		bytesLeft -= toWrite;
1781 		pos += toWrite;
1782 		buffer += toWrite;
1783 
1784 		// If the request was successful, we consider the cached attr dir
1785 		// no longer up to date.
1786 		if (attrDirRevision >= 0) {
1787 			AutoLocker<Locker> _(fLock);
1788 			ShareAttrDir* attrDir = node->GetAttrDir();
1789 			if (attrDir && attrDir->GetRevision() == attrDirRevision)
1790 				attrDir->SetUpToDate(false);
1791 		}
1792 	}
1793 
1794 	*bytesWritten = bufferSize;
1795 	return B_OK;
1796 }
1797 
1798 // RemoveAttr
1799 status_t
1800 ShareVolume::RemoveAttr(Node* _node, const char* name)
1801 {
1802 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1803 
1804 	if (!_EnsureShareMounted())
1805 		return ERROR_NOT_CONNECTED;
1806 
1807 	// check permissions
1808 	if (IsReadOnly())
1809 		return B_PERMISSION_DENIED;
1810 
1811 	// store the current attibute dir revision for reference below
1812 	int64 attrDirRevision = -1;
1813 	{
1814 		AutoLocker<Locker> _(fLock);
1815 		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1816 			if (attrDir->IsUpToDate())
1817 				attrDirRevision = attrDir->GetRevision();
1818 		}
1819 	}
1820 
1821 	// prepare the request
1822 	RemoveAttrRequest request;
1823 	request.volumeID = fID;
1824 	request.nodeID = node->GetRemoteID();
1825 	request.name.SetTo(name);
1826 
1827 	// send the request
1828 	RemoveAttrReply* reply;
1829 	status_t error = SendRequest(fConnection, &request, &reply);
1830 	if (error != B_OK)
1831 		RETURN_ERROR(error);
1832 	ObjectDeleter<Request> replyDeleter(reply);
1833 
1834 	// If the request was successful, we consider the cached attr dir
1835 	// no longer up to date.
1836 	if (reply->error == B_OK && attrDirRevision >= 0) {
1837 		AutoLocker<Locker> _(fLock);
1838 		ShareAttrDir* attrDir = node->GetAttrDir();
1839 		if (attrDir && attrDir->GetRevision() == attrDirRevision)
1840 			attrDir->SetUpToDate(false);
1841 	}
1842 
1843 	RETURN_ERROR(reply->error);
1844 }
1845 
1846 // RenameAttr
1847 status_t
1848 ShareVolume::RenameAttr(Node* _node, const char* oldName, const char* newName)
1849 {
1850 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1851 
1852 	if (!_EnsureShareMounted())
1853 		return ERROR_NOT_CONNECTED;
1854 
1855 	// check permissions
1856 	if (IsReadOnly())
1857 		return B_PERMISSION_DENIED;
1858 
1859 	// store the current attibute dir revision for reference below
1860 	int64 attrDirRevision = -1;
1861 	{
1862 		AutoLocker<Locker> _(fLock);
1863 		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1864 			if (attrDir->IsUpToDate())
1865 				attrDirRevision = attrDir->GetRevision();
1866 		}
1867 	}
1868 
1869 	// prepare the request
1870 	RenameAttrRequest request;
1871 	request.volumeID = fID;
1872 	request.nodeID = node->GetRemoteID();
1873 	request.oldName.SetTo(oldName);
1874 	request.newName.SetTo(newName);
1875 
1876 	// send the request
1877 	RenameAttrReply* reply;
1878 	status_t error = SendRequest(fConnection, &request, &reply);
1879 	if (error != B_OK)
1880 		RETURN_ERROR(error);
1881 	ObjectDeleter<Request> replyDeleter(reply);
1882 
1883 	// If the request was successful, we consider the cached attr dir
1884 	// no longer up to date.
1885 	if (reply->error == B_OK && attrDirRevision >= 0) {
1886 		AutoLocker<Locker> _(fLock);
1887 		ShareAttrDir* attrDir = node->GetAttrDir();
1888 		if (attrDir && attrDir->GetRevision() == attrDirRevision)
1889 			attrDir->SetUpToDate(false);
1890 	}
1891 
1892 	RETURN_ERROR(reply->error);
1893 }
1894 
1895 // StatAttr
1896 status_t
1897 ShareVolume::StatAttr(Node* _node, const char* name, struct attr_info* attrInfo)
1898 {
1899 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1900 
1901 	if (!_EnsureShareMounted())
1902 		return ERROR_NOT_CONNECTED;
1903 
1904 	// if we have the attribute directory cached, get the info from there
1905 	{
1906 		AutoLocker<Locker> locker(fLock);
1907 
1908 		ShareAttrDir* attrDir = node->GetAttrDir();
1909 		if (attrDir && attrDir->IsUpToDate()) {
1910 			// get the attribute
1911 			Attribute* attribute = attrDir->GetAttribute(name);
1912 			if (!attribute)
1913 				return B_ENTRY_NOT_FOUND;
1914 
1915 			attribute->GetInfo(attrInfo);
1916 			return B_OK;
1917 		}
1918 	}
1919 
1920 	// prepare the request
1921 	StatAttrRequest request;
1922 	request.volumeID = fID;
1923 	request.nodeID = node->GetRemoteID();
1924 	request.name.SetTo(name);
1925 
1926 	// send the request
1927 	StatAttrReply* reply;
1928 	status_t error = SendRequest(fConnection, &request, &reply);
1929 	if (error != B_OK)
1930 		RETURN_ERROR(error);
1931 	ObjectDeleter<Request> replyDeleter(reply);
1932 	if (reply->error != B_OK)
1933 		RETURN_ERROR(reply->error);
1934 
1935 	// set the result
1936 	*attrInfo = reply->attrInfo.info;
1937 	return B_OK;
1938 }
1939 
1940 
1941 // #pragma mark -
1942 // #pragma mark ----- queries -----
1943 
1944 // GetQueryEntry
1945 status_t
1946 ShareVolume::GetQueryEntry(const EntryInfo& entryInfo,
1947 	const NodeInfo& dirInfo, struct dirent* buffer, size_t bufferSize,
1948 	int32* countRead)
1949 {
1950 	status_t error = B_OK;
1951 
1952 	const char* name = entryInfo.name.GetString();
1953 	int32 nameLen = entryInfo.name.GetSize();
1954 	if (!name || nameLen < 2)
1955 		RETURN_ERROR(B_BAD_DATA);
1956 
1957 	// load the directory
1958 	vnode_id localDirID = -1;
1959 	{
1960 		AutoLocker<Locker> _(fLock);
1961 		ShareNode* node;
1962 		error = _LoadNode(dirInfo, &node);
1963 		if (error != B_OK)
1964 			RETURN_ERROR(error);
1965 		ShareDir* directory = dynamic_cast<ShareDir*>(node);
1966 		if (!directory)
1967 			RETURN_ERROR(B_ENTRY_NOT_FOUND);
1968 		localDirID = directory->GetID();
1969 	}
1970 
1971 	// add/update the entry
1972 	vnode_id localNodeID = -1;
1973 	const EntryInfo* resolvedEntryInfo = &entryInfo;
1974 	while (error == B_OK) {
1975 		// get an up to date entry info
1976 		WalkReply* walkReply = NULL;
1977 		if (!resolvedEntryInfo) {
1978 			error = _Walk(entryInfo.directoryID, name, false,
1979 				&walkReply);
1980 			if (error != B_OK)
1981 				RETURN_ERROR(error);
1982 
1983 			resolvedEntryInfo = &walkReply->entryInfo;
1984 		}
1985 		ObjectDeleter<Request> walkReplyDeleter(walkReply);
1986 
1987 		AutoLocker<Locker> locker(fLock);
1988 
1989 		// check, if the info is obsolete
1990 		if (_IsObsoleteEntryInfo(*resolvedEntryInfo)) {
1991 			resolvedEntryInfo = NULL;
1992 			continue;
1993 		}
1994 
1995 		// get the directory
1996 		ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByLocalID(localDirID));
1997 		if (!dir)
1998 			RETURN_ERROR(B_ERROR);
1999 
2000 		// load the entry
2001 		ShareDirEntry* entry;
2002 		error = _LoadEntry(dir, *resolvedEntryInfo, &entry);
2003 		if (error == B_OK)
2004 			localNodeID = entry->GetNode()->GetID();
2005 
2006 		break;
2007 	}
2008 
2009 	// set the name: this also checks the size of the buffer
2010 	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
2011 	if (error != B_OK)
2012 		RETURN_ERROR(error);
2013 
2014 	// fill in the other fields
2015 	buffer->d_pdev = fVolumeManager->GetID();
2016 	buffer->d_pino = localDirID;
2017 	buffer->d_dev = fVolumeManager->GetID();
2018 	buffer->d_ino = localNodeID;
2019 
2020 	*countRead = 1;
2021 	PRINT("  entry: d_dev: %" B_PRIdDEV ", d_pdev: %" B_PRIdDEV ", d_ino: %"
2022 		B_PRIdINO ", d_pino: %" B_PRIdINO ", d_reclen: %hu, d_name: `%s'\n",
2023 		buffer->d_dev, buffer->d_pdev, buffer->d_ino, buffer->d_pino,
2024 		buffer->d_reclen, buffer->d_name);
2025 	return B_OK;
2026 }
2027 
2028 
2029 // #pragma mark -
2030 
2031 // ProcessNodeMonitoringRequest
2032 void
2033 ShareVolume::ProcessNodeMonitoringRequest(NodeMonitoringRequest* request)
2034 {
2035 	switch (request->opcode) {
2036 		case B_ENTRY_CREATED:
2037 			_HandleEntryCreatedRequest(
2038 				dynamic_cast<EntryCreatedRequest*>(request));
2039 			break;
2040 		case B_ENTRY_REMOVED:
2041 			_HandleEntryRemovedRequest(
2042 				dynamic_cast<EntryRemovedRequest*>(request));
2043 			break;
2044 		case B_ENTRY_MOVED:
2045 			_HandleEntryMovedRequest(
2046 				dynamic_cast<EntryMovedRequest*>(request));
2047 			break;
2048 		case B_STAT_CHANGED:
2049 			_HandleStatChangedRequest(
2050 				dynamic_cast<StatChangedRequest*>(request));
2051 			break;
2052 		case B_ATTR_CHANGED:
2053 			_HandleAttributeChangedRequest(
2054 				dynamic_cast<AttributeChangedRequest*>(request));
2055 			break;
2056 	}
2057 }
2058 
2059 // ConnectionClosed
2060 void
2061 ShareVolume::ConnectionClosed()
2062 {
2063 	AutoLocker<Locker> _(fMountLock);
2064 	fConnectionState = CONNECTION_CLOSED;
2065 }
2066 
2067 
2068 // #pragma mark -
2069 
2070 // _ReadRemoteDir
2071 status_t
2072 ShareVolume::_ReadRemoteDir(ShareDir* directory,
2073 	RemoteShareDirIterator* iterator)
2074 {
2075 	// prepare the request
2076 	fLock.Lock();
2077 	ReadDirRequest request;
2078 	request.volumeID = fID;
2079 	request.cookie = iterator->GetCookie();
2080 	request.count = iterator->GetCapacity();
2081 	request.rewind = iterator->GetRewind();
2082 	fLock.Unlock();
2083 
2084 	// send the request
2085 	ReadDirReply* reply;
2086 	status_t error = SendRequest(fConnection, &request, &reply);
2087 	if (error != B_OK)
2088 		RETURN_ERROR(error);
2089 	ObjectDeleter<Request> replyDeleter(reply);
2090 	if (reply->error != B_OK)
2091 		RETURN_ERROR(reply->error);
2092 
2093 	RequestMemberArray<EntryInfo>* entryInfos = &reply->entryInfos;
2094 	while (true) {
2095 		// get up to date entry infos
2096 		MultiWalkReply* walkReply = NULL;
2097 		if (!entryInfos) {
2098 			error = _MultiWalk(reply->entryInfos, &walkReply);
2099 			if (error != B_OK)
2100 				RETURN_ERROR(error);
2101 
2102 			entryInfos = &walkReply->entryInfos;
2103 		}
2104 		ObjectDeleter<Request> walkReplyDeleter(walkReply);
2105 
2106 		AutoLocker<Locker> locker(fLock);
2107 
2108 		// check, if any info is obsolete
2109 		int32 count = entryInfos->CountElements();
2110 		for (int32 i = 0; i < count; i++) {
2111 			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
2112 			if (_IsObsoleteEntryInfo(entryInfo)) {
2113 				entryInfos = NULL;
2114 				continue;
2115 			}
2116 		}
2117 
2118 		// init the iterator's revision, if it's new or has been rewinded
2119 		if (request.rewind || iterator->GetRevision() < 0)
2120 			iterator->SetRevision(reply->revision);
2121 
2122 		iterator->Clear();
2123 		iterator->SetDone(reply->done);
2124 
2125 		// iterate through the entries
2126 		for (int32 i = 0; i < count; i++) {
2127 			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
2128 			const char* name = entryInfo.name.GetString();
2129 			int32 nameLen = entryInfo.name.GetSize();
2130 			if (!name || nameLen < 2)
2131 				return B_BAD_DATA;
2132 
2133 			// load the node/entry
2134 			ShareDirEntry* entry;
2135 			error = _LoadEntry(directory, entryInfo, &entry);
2136 			if (error != B_OK)
2137 				RETURN_ERROR(error);
2138 
2139 			// add the entry
2140 			if (!iterator->AddEntry(entry)) {
2141 				ERROR("ShareVolume::_ReadRemoteDir(): ERROR: Failed to add "
2142 					"entry to remote iterator!\n");
2143 			}
2144 		}
2145 
2146 		// directory now complete?
2147 		if (reply->done && directory->GetEntryRemovedEventRevision()
2148 				< iterator->GetRevision()) {
2149 			directory->SetComplete(true);
2150 		}
2151 
2152 		break;
2153 	}
2154 
2155 	return B_OK;
2156 }
2157 
2158 // _HandleEntryCreatedRequest
2159 void
2160 ShareVolume::_HandleEntryCreatedRequest(EntryCreatedRequest* request)
2161 {
2162 	if (!request)
2163 		return;
2164 
2165 	nspace_id nsid = fVolumeManager->GetID();
2166 	const char* name = request->name.GetString();
2167 
2168 	// translate the node IDs
2169 	vnode_id vnida = 0;
2170 	vnode_id vnidb = 0;
2171 	vnode_id vnidc = 0;
2172 	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
2173 	if (error == B_OK)
2174 		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2175 		PRINT("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%" B_PRIx32
2176 			", name: \"%s\", dir: %" B_PRIdINO " (remote: (%" B_PRIdDEV ", %"
2177 			B_PRIdINO ")), node: %" B_PRIdINO " (remote: (%" B_PRIdDEV ", %"
2178 			B_PRIdINO "))\n", error, name, vnida,
2179 			request->directoryID.volumeID, request->directoryID.nodeID, vnidc,
2180 			request->nodeID.volumeID, request->nodeID.nodeID);
2181 
2182 	// send notifications / do additional processing
2183 	if (request->queryUpdate) {
2184 		if (error == B_OK) {
2185 			SendNotification(request->port, request->token,
2186 				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
2187 				vnidc, name);
2188 		}
2189 	} else {
2190 		_EntryCreated(request->directoryID, name,
2191 			(request->entryInfoValid ? &request->entryInfo : NULL),
2192 			request->revision);
2193 		if (error == B_OK)
2194 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2195 	}
2196 }
2197 
2198 // _HandleEntryRemovedRequest
2199 void
2200 ShareVolume::_HandleEntryRemovedRequest(EntryRemovedRequest* request)
2201 {
2202 	if (!request)
2203 		return;
2204 
2205 	nspace_id nsid = fVolumeManager->GetID();
2206 	const char* name = request->name.GetString();
2207 
2208 	// translate the node IDs
2209 	vnode_id vnida = 0;
2210 	vnode_id vnidb = 0;
2211 	vnode_id vnidc = 0;
2212 	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
2213 	if (error == B_OK)
2214 		error = _GetLocalNodeID(request->nodeID, &vnidc, false);
2215 			// TODO: We don't enter a node ID mapping here, which might cause
2216 			// undesired behavior in some cases. Queries should usually be
2217 			// fine, since, if the entry was in the query set, then the
2218 			// respective node ID should definately be known at this point.
2219 			// If an entry is removed and the node monitoring event comes
2220 			// before a live query event for the same entry, the former one
2221 			// will cause the ID to be removed, so that it is already gone
2222 			// when the latter one arrives. I haven't observed this yet,
2223 			// though. The query events always seem to be sent before the
2224 			// node monitoring events (and the server processes them in a
2225 			// single-threaded way). I guess, this is FS implementation
2226 			// dependent, though.
2227 			// A node monitoring event that will always get lost, is when the
2228 			// FS user watches a directory that hasn't been read before. Its
2229 			// entries will not be known yet and thus "entry removed" events
2230 			// will be dropped here. I guess, it's arguable whether this is
2231 			// a practical problem (why should the watcher care that an entry
2232 			// has been removed, when they didn't know what entries were in
2233 			// the directory in the first place?).
2234 			// A possible solution would be to never remove node ID mappings.
2235 			// We would only need to take care that the cached node info is
2236 			// correctly flushed, so that e.g. a subsequent ReadVNode() has to
2237 			// ask the server and doesn't work with obsolete data. We would
2238 			// also enter a yet unknown ID into the node ID map here. The only
2239 			// problem is that the ID maps will keep growing, especially when
2240 			// there's a lot of FS activity on the server.
2241 
2242 	// send notifications / do additional processing
2243 	if (request->queryUpdate) {
2244 		if (error == B_OK) {
2245 			SendNotification(request->port, request->token,
2246 				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
2247 				vnidc, name);
2248 		}
2249 	} else {
2250 		_EntryRemoved(request->directoryID, name, request->revision);
2251 		_NodeRemoved(request->nodeID);
2252 		if (error == B_OK)
2253 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2254 	}
2255 }
2256 
2257 // _HandleEntryMovedRequest
2258 void
2259 ShareVolume::_HandleEntryMovedRequest(EntryMovedRequest* request)
2260 {
2261 	if (!request)
2262 		return;
2263 
2264 	nspace_id nsid = fVolumeManager->GetID();
2265 	const char* oldName = request->fromName.GetString();
2266 	const char* name = request->toName.GetString();
2267 
2268 	// translate the node IDs
2269 	vnode_id vnida = 0;
2270 	vnode_id vnidb = 0;
2271 	vnode_id vnidc = 0;
2272 	status_t error = _GetLocalNodeID(request->fromDirectoryID, &vnida, true);
2273 	if (error == B_OK)
2274 		error = _GetLocalNodeID(request->toDirectoryID, &vnidb, true);
2275 	if (error == B_OK)
2276 		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2277 
2278 	// send notifications / do additional processing
2279 	if (!request->queryUpdate) {
2280 		_EntryMoved(request->fromDirectoryID, oldName, request->toDirectoryID,
2281 			name, (request->entryInfoValid ? &request->entryInfo : NULL),
2282 			request->revision);
2283 		if (error == B_OK)
2284 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2285 	}
2286 }
2287 
2288 // _HandleStatChangedRequest
2289 void
2290 ShareVolume::_HandleStatChangedRequest(StatChangedRequest* request)
2291 {
2292 	if (!request)
2293 		return;
2294 
2295 	nspace_id nsid = fVolumeManager->GetID();
2296 
2297 	// translate the node IDs
2298 	vnode_id vnida = 0;
2299 	vnode_id vnidb = 0;
2300 	vnode_id vnidc = 0;
2301 	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2302 
2303 	// send notifications / do additional processing
2304 	if (!request->queryUpdate) {
2305 		_UpdateNode(request->nodeInfo);
2306 		if (error == B_OK)
2307 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, NULL);
2308 	}
2309 }
2310 
2311 // _HandleAttributeChangedRequest
2312 void
2313 ShareVolume::_HandleAttributeChangedRequest(AttributeChangedRequest* request)
2314 {
2315 	if (!request)
2316 		return;
2317 
2318 	nspace_id nsid = fVolumeManager->GetID();
2319 	const char* name = request->attrInfo.name.GetString();
2320 
2321 	// translate the node IDs
2322 	vnode_id vnida = 0;
2323 	vnode_id vnidb = 0;
2324 	vnode_id vnidc = 0;
2325 	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2326 
2327 	// send notifications / do additional processing
2328 	if (!request->queryUpdate) {
2329 		_UpdateAttrDir(request->nodeID, request->attrDirInfo);
2330 		if (error == B_OK)
2331 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2332 	}
2333 }
2334 
2335 // _GetLocalNodeID
2336 status_t
2337 ShareVolume::_GetLocalNodeID(NodeID remoteID, ino_t* _localID, bool enter)
2338 {
2339 	AutoLocker<Locker> _(fLock);
2340 	// if the ID is already know, just return it
2341 	if (fLocalNodeIDs->ContainsKey(remoteID)) {
2342 		*_localID = fLocalNodeIDs->Get(remoteID);
2343 		return B_OK;
2344 	}
2345 
2346 	// ID not yet known
2347 	// enter it? Do this only, if requested and we're not already unmounting.
2348 	if (!enter)
2349 		return B_ENTRY_NOT_FOUND;
2350 	if (fUnmounting)
2351 		return ERROR_NOT_CONNECTED;
2352 
2353 	// get a fresh ID from the volume manager
2354 	vnode_id localID = fVolumeManager->NewNodeID(this);
2355 	if (localID < 0)
2356 		return localID;
2357 
2358 	// put the IDs into local map
2359 	status_t error = fLocalNodeIDs->Put(remoteID, localID);
2360 	if (error != B_OK) {
2361 		fVolumeManager->RemoveNodeID(localID);
2362 		return error;
2363 	}
2364 
2365 	// put the IDs into remote map
2366 	error = fRemoteNodeIDs->Put(localID, remoteID);
2367 	if (error != B_OK) {
2368 		fLocalNodeIDs->Remove(remoteID);
2369 		fVolumeManager->RemoveNodeID(localID);
2370 		return error;
2371 	}
2372 	PRINT("ShareVolume(%" B_PRId32 "): added node ID mapping: local: %"
2373 		B_PRIdINO " -> remote: (%" B_PRIdDEV ", %" B_PRIdINO ")\n", fID,
2374 		localID, remoteID.volumeID, remoteID.nodeID);
2375 
2376 	*_localID = localID;
2377 	return B_OK;
2378 }
2379 
2380 // _GetRemoteNodeID
2381 status_t
2382 ShareVolume::_GetRemoteNodeID(ino_t localID, NodeID* remoteID)
2383 {
2384 	AutoLocker<Locker> _(fLock);
2385 
2386 	// check, if the ID is known
2387 	if (!fRemoteNodeIDs->ContainsKey(localID))
2388 		return B_ENTRY_NOT_FOUND;
2389 
2390 	*remoteID = fRemoteNodeIDs->Get(localID);
2391 	return B_OK;
2392 }
2393 
2394 // _RemoveLocalNodeID
2395 void
2396 ShareVolume::_RemoveLocalNodeID(ino_t localID)
2397 {
2398 	AutoLocker<Locker> _(fLock);
2399 
2400 	// check, if the ID is known
2401 	if (!fRemoteNodeIDs->ContainsKey(localID))
2402 		return;
2403 
2404 	// remove from ID maps
2405 	NodeID remoteID = fRemoteNodeIDs->Get(localID);
2406 	PRINT("ShareVolume::_RemoveLocalNodeID(%" B_PRIdINO "): remote: (%"
2407 		B_PRIdDEV ", %" B_PRIdINO ")\n", localID, remoteID.volumeID,
2408 		remoteID.nodeID);
2409 	fRemoteNodeIDs->Remove(localID);
2410 	fLocalNodeIDs->Remove(remoteID);
2411 
2412 	// remove from volume manager
2413 	fVolumeManager->RemoveNodeID(localID);
2414 }
2415 
2416 // _GetNodeByLocalID
2417 ShareNode*
2418 ShareVolume::_GetNodeByLocalID(ino_t localID)
2419 {
2420 	AutoLocker<Locker> _(fLock);
2421 	return fNodes->Get(localID);
2422 }
2423 
2424 // _GetNodeByRemoteID
2425 ShareNode*
2426 ShareVolume::_GetNodeByRemoteID(NodeID remoteID)
2427 {
2428 	AutoLocker<Locker> _(fLock);
2429 
2430 	ino_t localID;
2431 	if (_GetLocalNodeID(remoteID, &localID, false) == B_OK)
2432 		return fNodes->Get(localID);
2433 
2434 	return NULL;
2435 }
2436 
2437 // _LoadNode
2438 status_t
2439 ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node)
2440 {
2441 	AutoLocker<Locker> _(fLock);
2442 
2443 	// check, if the node is already known
2444 	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
2445 	if (node) {
2446 		node->Update(nodeInfo);
2447 	} else {
2448 		// don't load the node when already unmounting
2449 		if (fUnmounting)
2450 			return B_ERROR;
2451 
2452 		// get a local node ID
2453 		vnode_id localID;
2454 		status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true);
2455 		if (error != B_OK)
2456 			return error;
2457 
2458 		// create a new node
2459 		if (S_ISDIR(nodeInfo.st.st_mode))
2460 			node = new(std::nothrow) ShareDir(this, localID, &nodeInfo);
2461 		else
2462 			node = new(std::nothrow) ShareNode(this, localID, &nodeInfo);
2463 		if (!node) {
2464 			_RemoveLocalNodeID(localID);
2465 			return B_NO_MEMORY;
2466 		}
2467 
2468 		// add it
2469 		error = fNodes->Put(node->GetID(), node);
2470 		if (error != B_OK) {
2471 			_RemoveLocalNodeID(localID);
2472 			delete node;
2473 			return error;
2474 		}
2475 		PRINT("ShareVolume: added node: %" B_PRIdINO ": remote: (%" B_PRIdDEV
2476 			", %" B_PRIdINO "), localID: %" B_PRIdINO "\n", node->GetID(),
2477 			node->GetRemoteID().volumeID,
2478 			node->GetRemoteID().nodeID, localID);
2479 	}
2480 
2481 	if (_node)
2482 		*_node = node;
2483 	return B_OK;
2484 }
2485 
2486 // _UpdateNode
2487 status_t
2488 ShareVolume::_UpdateNode(const NodeInfo& nodeInfo)
2489 {
2490 	AutoLocker<Locker> _(fLock);
2491 
2492 	if (fUnmounting)
2493 		return ERROR_NOT_CONNECTED;
2494 
2495 	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
2496 	if (node) {
2497 		node->Update(nodeInfo);
2498 		return B_OK;
2499 	}
2500 	return B_ENTRY_NOT_FOUND;
2501 }
2502 
2503 // _GetEntryByLocalID
2504 ShareDirEntry*
2505 ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name)
2506 {
2507 	if (!name)
2508 		return NULL;
2509 
2510 	AutoLocker<Locker> _(fLock);
2511 	return fEntries->Get(EntryKey(localDirID, name));
2512 }
2513 
2514 // _GetEntryByRemoteID
2515 ShareDirEntry*
2516 ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name)
2517 {
2518 	if (!name)
2519 		return NULL;
2520 
2521 	AutoLocker<Locker> _(fLock);
2522 
2523 	ino_t localDirID;
2524 	if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK)
2525 		return fEntries->Get(EntryKey(localDirID, name));
2526 
2527 	return NULL;
2528 }
2529 
2530 // _LoadEntry
2531 //
2532 // If _entry is supplied, fLock should be held, otherwise the returned entry
2533 // might as well be deleted.
2534 status_t
2535 ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo,
2536 	ShareDirEntry** _entry)
2537 {
2538 	const char* name = entryInfo.name.GetString();
2539 	if (!directory || !name)
2540 		return B_BAD_VALUE;
2541 
2542 	AutoLocker<Locker> _(fLock);
2543 
2544 	ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name);
2545 	if (entry) {
2546 		if (entryInfo.nodeInfo.revision > entry->GetRevision()) {
2547 			if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) {
2548 				// The node the existing entry refers to is not the node it
2549 				// should refer to. Remove the old entry and create a new one.
2550 				_EntryRemoved(directory->GetRemoteID(), name,
2551 					entryInfo.nodeInfo.revision);
2552 				_EntryCreated(directory->GetRemoteID(), name, &entryInfo,
2553 					entryInfo.nodeInfo.revision);
2554 
2555 				// re-get the entry and check, if everything is fine
2556 				entry = _GetEntryByLocalID(directory->GetID(), name);
2557 				if (!entry)
2558 					return B_ERROR;
2559 				if (entryInfo.nodeInfo.GetID()
2560 					!= entry->GetNode()->GetRemoteID()) {
2561 					return B_ERROR;
2562 				}
2563 			} else {
2564 				entry->SetRevision(entryInfo.nodeInfo.revision);
2565 				_UpdateNode(entryInfo.nodeInfo);
2566 			}
2567 		}
2568 	} else {
2569 		// entry not known yet: create it
2570 
2571 		// don't load the entry when already unmounting
2572 		if (fUnmounting)
2573 			return B_ERROR;
2574 
2575 		// load the node
2576 		ShareNode* node;
2577 		status_t error = _LoadNode(entryInfo.nodeInfo, &node);
2578 		if (error != B_OK)
2579 			return error;
2580 
2581 		// if the directory or the node are marked remove, we don't create the
2582 		// entry
2583 		if (IsVNodeRemoved(directory->GetID()) > 0
2584 			|| IsVNodeRemoved(node->GetID()) > 0) {
2585 			return B_NOT_ALLOWED;
2586 		}
2587 
2588 		// create the entry
2589 		entry = new(std::nothrow) ShareDirEntry(directory, name, node);
2590 		if (!entry)
2591 			return B_NO_MEMORY;
2592 		ObjectDeleter<ShareDirEntry> entryDeleter(entry);
2593 		error = entry->InitCheck();
2594 		if (error != B_OK)
2595 			return error;
2596 
2597 		// add the entry
2598 		error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()),
2599 			entry);
2600 		if (error != B_OK)
2601 			return error;
2602 
2603 		// set the entry revision
2604 		entry->SetRevision(entryInfo.nodeInfo.revision);
2605 
2606 		// add the entry to the directory and the node
2607 		directory->AddEntry(entry);
2608 		entry->GetNode()->AddReferringEntry(entry);
2609 
2610 		// everything went fine
2611 		entryDeleter.Detach();
2612 	}
2613 
2614 	if (_entry)
2615 		*_entry = entry;
2616 	return B_OK;
2617 }
2618 
2619 // _RemoveEntry
2620 //
2621 // fLock must be held.
2622 void
2623 ShareVolume::_RemoveEntry(ShareDirEntry* entry)
2624 {
2625 	fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(),
2626 		entry->GetName()));
2627 	entry->GetDirectory()->RemoveEntry(entry);
2628 	entry->GetNode()->RemoveReferringEntry(entry);
2629 	entry->ReleaseReference();
2630 }
2631 
2632 // _IsObsoleteEntryInfo
2633 //
2634 // fLock must be held.
2635 bool
2636 ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo)
2637 {
2638 	// get the directory
2639 	ShareDir* dir
2640 		= dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID));
2641 	if (!dir)
2642 		return false;
2643 
2644 	return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision());
2645 }
2646 
2647 // _LoadAttrDir
2648 status_t
2649 ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo)
2650 {
2651 	if (!node || !attrDirInfo.isValid)
2652 		return B_BAD_VALUE;
2653 
2654 	AutoLocker<Locker> _(fLock);
2655 
2656 	if (fUnmounting)
2657 		return ERROR_NOT_CONNECTED;
2658 
2659 	ShareAttrDir* attrDir = node->GetAttrDir();
2660 	if (attrDir) {
2661 		if (attrDir->GetRevision() > attrDirInfo.revision)
2662 			return B_OK;
2663 
2664 		// update the attr dir
2665 		return attrDir->Update(attrDirInfo,
2666 			fAttrDirIterators->Get(node->GetID()));
2667 	} else {
2668 		// no attribute directory yet: create one
2669 		attrDir = new(std::nothrow) ShareAttrDir;
2670 		if (!attrDir)
2671 			return B_NO_MEMORY;
2672 		ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir);
2673 
2674 		// initialize it
2675 		status_t error = attrDir->Init(attrDirInfo);
2676 		if (error != B_OK)
2677 			return error;
2678 
2679 		// set it
2680 		node->SetAttrDir(attrDir);
2681 		attrDirDeleter.Detach();
2682 		return B_OK;
2683 	}
2684 }
2685 
2686 // _UpdateAttrDir
2687 status_t
2688 ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo)
2689 {
2690 	AutoLocker<Locker> _(fLock);
2691 
2692 	// get the node
2693 	ShareNode* node = _GetNodeByRemoteID(remoteID);
2694 	if (!node)
2695 		return B_ENTRY_NOT_FOUND;
2696 
2697 	if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) {
2698 		// updating/creating the attr dir failed; if existing, we mark it
2699 		// obsolete
2700 		if (ShareAttrDir* attrDir = node->GetAttrDir())
2701 			attrDir->SetUpToDate(false);
2702 	}
2703 
2704 	return B_OK;
2705 }
2706 
2707 // _AddAttrDirIterator
2708 status_t
2709 ShareVolume::_AddAttrDirIterator(ShareNode* node,
2710 	ShareAttrDirIterator* iterator)
2711 {
2712 	if (!node || !iterator)
2713 		return B_BAD_VALUE;
2714 
2715 	AutoLocker<Locker> locker(fLock);
2716 
2717 	// get the iterator list
2718 	DoublyLinkedList<ShareAttrDirIterator>* iteratorList
2719 		= fAttrDirIterators->Get(node->GetID());
2720 	if (!iteratorList) {
2721 		// no list for the node yet: create one
2722 		iteratorList = new(std::nothrow) DoublyLinkedList<ShareAttrDirIterator>;
2723 		if (!iteratorList)
2724 			return B_NO_MEMORY;
2725 
2726 		// add it
2727 		status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList);
2728 		if (error != B_OK) {
2729 			delete iteratorList;
2730 			return error;
2731 		}
2732 	}
2733 
2734 	// add the iterator
2735 	iteratorList->Insert(iterator);
2736 
2737 	return B_OK;
2738 }
2739 
2740 // _RemoveAttrDirIterator
2741 void
2742 ShareVolume::_RemoveAttrDirIterator(ShareNode* node,
2743 	ShareAttrDirIterator* iterator)
2744 {
2745 	if (!node || !iterator)
2746 		return;
2747 
2748 	AutoLocker<Locker> locker(fLock);
2749 
2750 	// get the iterator list
2751 	DoublyLinkedList<ShareAttrDirIterator>* iteratorList
2752 		= fAttrDirIterators->Get(node->GetID());
2753 	if (!iteratorList) {
2754 		WARN("ShareVolume::_RemoveAttrDirIterator(): Iterator list not "
2755 			"found: node: %" B_PRIdINO "\n", node->GetID());
2756 		return;
2757 	}
2758 
2759 	// remove the iterator
2760 	iteratorList->Remove(iterator);
2761 
2762 	// if the list is empty now, discard it
2763 	if (!iteratorList->First()) {
2764 		fAttrDirIterators->Remove(node->GetID());
2765 		delete iteratorList;
2766 	}
2767 }
2768 
2769 // _NodeRemoved
2770 void
2771 ShareVolume::_NodeRemoved(NodeID remoteID)
2772 {
2773 	AutoLocker<Locker> locker(fLock);
2774 
2775 	ShareNode* node = _GetNodeByRemoteID(remoteID);
2776 	if (!node)
2777 		return;
2778 
2779 	// if the node still has referring entries, we do nothing
2780 	if (node->GetActualReferringEntry())
2781 		return;
2782 
2783 	// if the node is a directory, we remove its entries first
2784 	if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) {
2785 		while (ShareDirEntry* entry = dir->GetFirstEntry())
2786 			_RemoveEntry(entry);
2787 	}
2788 
2789 	// remove all entries still referring to the node
2790 	while (ShareDirEntry* entry = node->GetFirstReferringEntry())
2791 		_RemoveEntry(entry);
2792 
2793 	ino_t localID = node->GetID();
2794 
2795 	// Remove the node ID in all cases -- even, if the node is still
2796 	// known to the VFS. Otherwise there could be a race condition, that the
2797 	// server re-uses the remote ID and we have it still associated with an
2798 	// obsolete local ID.
2799 	_RemoveLocalNodeID(localID);
2800 
2801 	if (node->IsKnownToVFS()) {
2802 		Node* _node;
2803 		if (GetVNode(localID, &_node) != B_OK)
2804 			return;
2805 		Volume::RemoveVNode(localID);
2806 		locker.Unlock();
2807 		PutVNode(localID);
2808 
2809 	} else {
2810 		fNodes->Remove(localID);
2811 		delete node;
2812 	}
2813 }
2814 
2815 // _EntryCreated
2816 void
2817 ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name,
2818 	const EntryInfo* entryInfo, int64 revision)
2819 {
2820 	if (!name)
2821 		return;
2822 
2823 	AutoLocker<Locker> locker(fLock);
2824 
2825 	// get the directory
2826 	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
2827 	if (!dir)
2828 		return;
2829 
2830 	// load the entry, if possible
2831 	ShareDirEntry* entry;
2832 	bool entryLoaded = false;
2833 	if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK)
2834 		entryLoaded = true;
2835 
2836 	// if the entry could not be loaded, we have to mark the dir incomplete
2837 	// and update its revision counter
2838 	if (!entryLoaded) {
2839 		dir->UpdateEntryCreatedEventRevision(revision);
2840 		dir->SetComplete(false);
2841 	}
2842 }
2843 
2844 // _EntryRemoved
2845 void
2846 ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision)
2847 {
2848 	if (!name)
2849 		return;
2850 
2851 	AutoLocker<Locker> locker(fLock);
2852 
2853 	// get the directory
2854 	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
2855 	if (!dir)
2856 		return;
2857 
2858 	// update the directory's "entry removed" event revision
2859 	dir->UpdateEntryRemovedEventRevision(revision);
2860 
2861 	// get the entry
2862 	ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name);
2863 	if (!entry)
2864 		return;
2865 
2866 	// check the entry revision
2867 	if (entry->GetRevision() > revision)
2868 		return;
2869 
2870 	// remove the entry
2871 	_RemoveEntry(entry);
2872 }
2873 
2874 // _EntryMoved
2875 void
2876 ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName,
2877 	NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo,
2878 	int64 revision)
2879 {
2880 	AutoLocker<Locker> locker(fLock);
2881 
2882 	_EntryRemoved(remoteOldDirID, oldName, revision);
2883 	_EntryCreated(remoteNewDirID, name, entryInfo, revision);
2884 }
2885 
2886 // _Walk
2887 status_t
2888 ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink,
2889 	WalkReply** _reply)
2890 {
2891 	// prepare the request
2892 	WalkRequest request;
2893 	request.volumeID = fID;
2894 	request.nodeID = remoteDirID;
2895 	request.name.SetTo(entryName);
2896 	request.resolveLink = resolveLink;
2897 
2898 	// send the request
2899 	WalkReply* reply;
2900 	status_t error = SendRequest(fConnection, &request, &reply);
2901 	if (error != B_OK)
2902 		RETURN_ERROR(error);
2903 	ObjectDeleter<Request> replyDeleter(reply);
2904 	if (reply->error != B_OK)
2905 		RETURN_ERROR(reply->error);
2906 
2907 	replyDeleter.Detach();
2908 	*_reply = reply;
2909 	return B_OK;
2910 }
2911 
2912 // _MultiWalk
2913 status_t
2914 ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos,
2915 	MultiWalkReply** _reply)
2916 {
2917 	int32 count = _entryInfos.CountElements();
2918 	if (!_reply || count == 0)
2919 		return B_BAD_VALUE;
2920 
2921 	EntryInfo* entryInfos = _entryInfos.GetElements();
2922 
2923 	// prepare the request
2924 	MultiWalkRequest request;
2925 	request.volumeID = fID;
2926 	request.nodeID = entryInfos[0].directoryID;
2927 
2928 	// add the names
2929 	for (int32 i = 0; i < count; i++) {
2930 		StringData name;
2931 		name.SetTo(entryInfos[i].name.GetString());
2932 
2933 		status_t error = request.names.Append(name);
2934 		if (error != B_OK)
2935 			return error;
2936 	}
2937 
2938 	// send the request
2939 	MultiWalkReply* reply;
2940 	status_t error = SendRequest(fConnection, &request, &reply);
2941 	if (error != B_OK)
2942 		RETURN_ERROR(error);
2943 	ObjectDeleter<Request> replyDeleter(reply);
2944 	if (reply->error != B_OK)
2945 		RETURN_ERROR(reply->error);
2946 
2947 	replyDeleter.Detach();
2948 	*_reply = reply;
2949 	return B_OK;
2950 }
2951 
2952 // _Close
2953 status_t
2954 ShareVolume::_Close(int32 cookie)
2955 {
2956 	if (!_EnsureShareMounted())
2957 		return ERROR_NOT_CONNECTED;
2958 
2959 	// prepare the request
2960 	CloseRequest request;
2961 	request.volumeID = fID;
2962 	request.cookie = cookie;
2963 	// send the request
2964 	CloseReply* reply;
2965 	status_t error = SendRequest(fConnection, &request, &reply);
2966 	if (error != B_OK)
2967 		RETURN_ERROR(error);
2968 	ObjectDeleter<Request> replyDeleter(reply);
2969 	if (reply->error != B_OK)
2970 		RETURN_ERROR(reply->error);
2971 	return B_OK;
2972 }
2973 
2974 // _GetConnectionState
2975 //
2976 // Must not be called with fLock being held!
2977 uint32
2978 ShareVolume::_GetConnectionState()
2979 {
2980 	AutoLocker<Locker> _(fMountLock);
2981 	return fConnectionState;
2982 }
2983 
2984 // _IsConnected
2985 //
2986 // Must not be called with fLock being held!
2987 bool
2988 ShareVolume::_IsConnected()
2989 {
2990 	return (_GetConnectionState() == CONNECTION_READY);
2991 }
2992 
2993 // _EnsureShareMounted
2994 //
2995 // Must not be called with fLock being held!
2996 bool
2997 ShareVolume::_EnsureShareMounted()
2998 {
2999 	AutoLocker<Locker> _(fMountLock);
3000 	if (fConnectionState == CONNECTION_NOT_INITIALIZED)
3001 		_MountShare();
3002 
3003 	return (fConnectionState == CONNECTION_READY);
3004 }
3005 
3006 // _MountShare
3007 //
3008 // fMountLock must be held.
3009 status_t
3010 ShareVolume::_MountShare()
3011 {
3012 	// get references to the server and share info
3013 	AutoLocker<Locker> locker(fLock);
3014 	BReference<ExtendedServerInfo> serverInfoReference(fServerInfo);
3015 	BReference<ExtendedShareInfo> shareInfoReference(fShareInfo);
3016 	ExtendedServerInfo* serverInfo = fServerInfo;
3017 	ExtendedShareInfo* shareInfo = fShareInfo;
3018 	locker.Unlock();
3019 
3020 	// get server address as string
3021 	HashString serverAddressString;
3022 	status_t error = serverInfo->GetAddress().GetString(&serverAddressString,
3023 		false);
3024 	if (error != B_OK)
3025 		return error;
3026 	const char* server = serverAddressString.GetString();
3027 
3028 	// get the server name
3029 	const char* serverName = serverInfo->GetServerName();
3030 	if (serverName && strlen(serverName) == 0)
3031 		serverName = NULL;
3032 
3033 	// get the share name
3034 	const char* share = shareInfo->GetShareName();
3035 
3036 	PRINT("ShareVolume::_MountShare(%s, %s)\n", server, share);
3037 	// init a connection to the authentication server
3038 	AuthenticationServer authenticationServer;
3039 	error = authenticationServer.InitCheck();
3040 	if (error != B_OK)
3041 		RETURN_ERROR(error);
3042 
3043 	// get the server connection
3044 	fConnectionState = CONNECTION_CLOSED;
3045 	if (!fServerConnection) {
3046 		status_t error = fServerConnectionProvider->GetServerConnection(
3047 			&fServerConnection);
3048 		if (error != B_OK)
3049 			return error;
3050 		fConnection = fServerConnection->GetRequestConnection();
3051 	}
3052 
3053 	// the mount loop
3054 	bool badPassword = false;
3055 	MountReply* reply = NULL;
3056 	do {
3057 		// get the user and password from the authentication server
3058 		char user[kUserBufferSize];
3059 		char password[kPasswordBufferSize];
3060 		bool cancelled;
3061 		error = authenticationServer.GetAuthentication("netfs",
3062 			(serverName ? serverName : server), share,
3063 			fVolumeManager->GetMountUID(), badPassword,
3064 			&cancelled, user, sizeof(user), password, sizeof(password));
3065 		if (cancelled || error != B_OK)
3066 			RETURN_ERROR(error);
3067 
3068 		// prepare the request
3069 		MountRequest request;
3070 		request.share.SetTo(share);
3071 		request.user.SetTo(user);
3072 		request.password.SetTo(password);
3073 
3074 		// send the request
3075 		error = SendRequest(fConnection, &request, &reply);
3076 		if (error != B_OK)
3077 			RETURN_ERROR(error);
3078 		ObjectDeleter<Request> replyDeleter(reply);
3079 
3080 		// if no permission, try again
3081 		badPassword = reply->noPermission;
3082 		if (!badPassword) {
3083 			if (reply->error != B_OK)
3084 				RETURN_ERROR(reply->error);
3085 			fSharePermissions = reply->sharePermissions;
3086 		}
3087 	} while (badPassword);
3088 
3089 	AutoLocker<Locker> _(fLock);
3090 
3091 	fID = reply->volumeID;
3092 
3093 	// update the root node and enter its ID
3094 	fRootNode->Update(reply->nodeInfo);
3095 
3096 	// put the IDs into local map
3097 	error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID());
3098 	if (error != B_OK)
3099 		RETURN_ERROR(error);
3100 
3101 	// put the IDs into remote map
3102 	error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID());
3103 	if (error != B_OK) {
3104 		fLocalNodeIDs->Remove(fRootNode->GetRemoteID());
3105 		RETURN_ERROR(error);
3106 	}
3107 	PRINT("ShareVolume::_MountShare(): root node: local: %" B_PRIdINO
3108 		", remote: (%" B_PRIdDEV ", %" B_PRIdINO ")\n", fRootNode->GetID(),
3109 		fRootNode->GetRemoteID().volumeID,
3110 		fRootNode->GetRemoteID().nodeID);
3111 
3112 	// Add ourselves to the server connection, so that we can receive
3113 	// node monitoring events. There a race condition: We might already
3114 	// have missed events for the root node.
3115 	error = fServerConnection->AddVolume(this);
3116 	if (error != B_OK) {
3117 		_RemoveLocalNodeID(fRootNode->GetID());
3118 		return error;
3119 	}
3120 
3121 	fConnectionState = CONNECTION_READY;
3122 	return B_OK;
3123 }
3124 
3125