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 {
EntryKeyShareVolume::EntryKey59 EntryKey() {}
60
EntryKeyShareVolume::EntryKey61 EntryKey(ino_t directoryID, const char* name)
62 : directoryID(directoryID),
63 name(name)
64 {
65 }
66
EntryKeyShareVolume::EntryKey67 EntryKey(const EntryKey& other)
68 : directoryID(other.directoryID),
69 name(other.name)
70 {
71 }
72
GetHashCodeShareVolume::EntryKey73 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
operator =ShareVolume::EntryKey81 EntryKey& operator=(const EntryKey& other)
82 {
83 directoryID = other.directoryID;
84 name = other.name;
85 return *this;
86 }
87
operator ==ShareVolume::EntryKey88 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
operator !=ShareVolume::EntryKey99 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 {
AttrDirCookieShareVolume::AttrDirCookie127 AttrDirCookie()
128 : iterator(NULL),
129 cookie(-1),
130 rewind(false)
131 {
132 }
133
134 ShareAttrDirIterator* iterator;
135 intptr_t 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
ShareVolume(VolumeManager * volumeManager,ServerConnectionProvider * connectionProvider,ExtendedServerInfo * serverInfo,ExtendedShareInfo * shareInfo)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
~ShareVolume()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
GetID() const228 ShareVolume::GetID() const
229 {
230 return fID;
231 }
232
233 // IsReadOnly
234 bool
IsReadOnly() const235 ShareVolume::IsReadOnly() const
236 {
237 return (fFlags & B_MOUNT_READ_ONLY);
238 }
239
240 // SupportsQueries
241 bool
SupportsQueries() const242 ShareVolume::SupportsQueries() const
243 {
244 return (fSharePermissions & QUERY_SHARE_PERMISSION);
245 }
246
247 // Init
248 status_t
Init(const char * name)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
Uninit()317 ShareVolume::Uninit()
318 {
319 Volume::Uninit();
320 }
321
322 // GetRootNode
323 Node*
GetRootNode() const324 ShareVolume::GetRootNode() const
325 {
326 return fRootNode;
327 }
328
329 // PrepareToUnmount
330 void
PrepareToUnmount()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 _RemoveEntry(entry);
349 }
350 fEntries->Clear();
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
RemoveChildVolume(Volume * volume)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
Unmount()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
Sync()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
ReadVNode(vnode_id vnid,char reenter,Node ** _node)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
WriteVNode(Node * node,char reenter)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
RemoveVNode(Node * node,char reenter)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
FSync(Node * _node)551 ShareVolume::FSync(Node* _node)
552 {
553 // TODO: Implement!
554 return B_BAD_VALUE;
555 }
556
557 // ReadStat
558 status_t
ReadStat(Node * _node,struct stat * st)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
WriteStat(Node * _node,struct stat * st,uint32 mask)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
Access(Node * _node,int mode)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
Create(Node * _dir,const char * name,int openMode,int mode,vnode_id * vnid,void ** cookie)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
Open(Node * _node,int openMode,void ** cookie)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
Close(Node * _node,void * cookie)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
FreeCookie(Node * _node,void * cookie)748 ShareVolume::FreeCookie(Node* _node, void* cookie)
749 {
750 return _Close((intptr_t)cookie);
751 }
752
753 // Read
754 status_t
Read(Node * _node,void * cookie,off_t pos,void * _buffer,size_t bufferSize,size_t * _bytesRead)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 = (intptr_t)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
Write(Node * _node,void * cookie,off_t pos,const void * _buffer,size_t bufferSize,size_t * bytesWritten)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 = (intptr_t)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
Link(Node * _dir,const char * name,Node * _node)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
Unlink(Node * _dir,const char * name)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
Symlink(Node * _dir,const char * name,const char * target)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
ReadLink(Node * _node,char * buffer,size_t bufferSize,size_t * bytesRead)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
Rename(Node * _oldDir,const char * oldName,Node * _newDir,const char * newName)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
MkDir(Node * _dir,const char * name,int mode)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
RmDir(Node * _dir,const char * name)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
OpenDir(Node * _node,void ** _cookie)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
CloseDir(Node * _node,void * cookie)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
FreeDirCookie(Node * _node,void * _cookie)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
ReadDir(Node * _dir,void * _cookie,struct dirent * buffer,size_t bufferSize,int32 count,int32 * countRead)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
RewindDir(Node * _node,void * _cookie)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
Walk(Node * _dir,const char * entryName,char ** resolvedPath,vnode_id * vnid)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
OpenAttrDir(Node * _node,void ** _cookie)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
CloseAttrDir(Node * _node,void * cookie)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
FreeAttrDirCookie(Node * _node,void * _cookie)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
ReadAttrDir(Node * _node,void * _cookie,struct dirent * buffer,size_t bufferSize,int32 count,int32 * countRead)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
RewindAttrDir(Node * _node,void * _cookie)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
ReadAttr(Node * _node,const char * name,int type,off_t pos,void * _buffer,size_t bufferSize,size_t * _bytesRead)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
WriteAttr(Node * _node,const char * name,int type,off_t pos,const void * _buffer,size_t bufferSize,size_t * bytesWritten)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
RemoveAttr(Node * _node,const char * name)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
RenameAttr(Node * _node,const char * oldName,const char * newName)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
StatAttr(Node * _node,const char * name,struct attr_info * attrInfo)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
GetQueryEntry(const EntryInfo & entryInfo,const NodeInfo & dirInfo,struct dirent * buffer,size_t bufferSize,int32 * countRead)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
ProcessNodeMonitoringRequest(NodeMonitoringRequest * request)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
ConnectionClosed()2061 ShareVolume::ConnectionClosed()
2062 {
2063 AutoLocker<Locker> _(fMountLock);
2064 fConnectionState = CONNECTION_CLOSED;
2065 }
2066
2067
2068 // #pragma mark -
2069
2070 // _ReadRemoteDir
2071 status_t
_ReadRemoteDir(ShareDir * directory,RemoteShareDirIterator * iterator)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
_HandleEntryCreatedRequest(EntryCreatedRequest * request)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
_HandleEntryRemovedRequest(EntryRemovedRequest * request)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
_HandleEntryMovedRequest(EntryMovedRequest * request)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
_HandleStatChangedRequest(StatChangedRequest * request)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
_HandleAttributeChangedRequest(AttributeChangedRequest * request)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
_GetLocalNodeID(NodeID remoteID,ino_t * _localID,bool enter)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
_GetRemoteNodeID(ino_t localID,NodeID * remoteID)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
_RemoveLocalNodeID(ino_t localID)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*
_GetNodeByLocalID(ino_t localID)2418 ShareVolume::_GetNodeByLocalID(ino_t localID)
2419 {
2420 AutoLocker<Locker> _(fLock);
2421 return fNodes->Get(localID);
2422 }
2423
2424 // _GetNodeByRemoteID
2425 ShareNode*
_GetNodeByRemoteID(NodeID remoteID)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
_LoadNode(const NodeInfo & nodeInfo,ShareNode ** _node)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
_UpdateNode(const NodeInfo & nodeInfo)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*
_GetEntryByLocalID(ino_t localDirID,const char * name)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*
_GetEntryByRemoteID(NodeID remoteDirID,const char * name)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
_LoadEntry(ShareDir * directory,const EntryInfo & entryInfo,ShareDirEntry ** _entry)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
_RemoveEntry(ShareDirEntry * entry)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
_IsObsoleteEntryInfo(const EntryInfo & entryInfo)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
_LoadAttrDir(ShareNode * node,const AttrDirInfo & attrDirInfo)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
_UpdateAttrDir(NodeID remoteID,const AttrDirInfo & attrDirInfo)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
_AddAttrDirIterator(ShareNode * node,ShareAttrDirIterator * iterator)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
_RemoveAttrDirIterator(ShareNode * node,ShareAttrDirIterator * iterator)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
_NodeRemoved(NodeID remoteID)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
_EntryCreated(NodeID remoteDirID,const char * name,const EntryInfo * entryInfo,int64 revision)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
_EntryRemoved(NodeID remoteDirID,const char * name,int64 revision)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
_EntryMoved(NodeID remoteOldDirID,const char * oldName,NodeID remoteNewDirID,const char * name,const EntryInfo * entryInfo,int64 revision)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
_Walk(NodeID remoteDirID,const char * entryName,bool resolveLink,WalkReply ** _reply)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
_MultiWalk(RequestMemberArray<EntryInfo> & _entryInfos,MultiWalkReply ** _reply)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
_Close(intptr_t cookie)2954 ShareVolume::_Close(intptr_t 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
_GetConnectionState()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
_IsConnected()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
_EnsureShareMounted()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
_MountShare()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