1 // ClientConnection.cpp
2
3 #include "ClientConnection.h"
4
5 #include <new>
6 #include <typeinfo>
7
8 #include <dirent.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <utime.h>
14
15 #include <AutoDeleter.h>
16 #include <AutoLocker.h>
17 #include <Entry.h>
18 #include <fs_query.h>
19 #include <GraphicsDefs.h>
20 #include <HashMap.h>
21 #include <NodeMonitor.h>
22 #include <Path.h>
23 #include <Rect.h>
24 #include <Mime.h>
25
26 #include <fsproto.h>
27
28 #include "Compatibility.h"
29 #include "Connection.h"
30 #include "DebugSupport.h"
31 #include "Directory.h"
32 #include "Entry.h"
33 #include "FDManager.h"
34 #include "NodeHandle.h"
35 #include "NodeHandleMap.h"
36 #include "NodeMonitoringEvent.h"
37 #include "Path.h"
38 #include "RequestBufferReplacer.h"
39 #include "RequestChannel.h"
40 #include "RequestConnection.h"
41 #include "RequestDumper.h"
42 #include "RequestFlattener.h"
43 #include "Requests.h"
44 #include "SecurityContext.h"
45 #include "ServerNodeID.h"
46 #include "UserSecurityContext.h"
47 #include "Utils.h"
48 #include "Volume.h"
49 #include "VolumeManager.h"
50
51 static const int32 kMaxSaneReadLinkSize = 10240; // 10 KB
52 static const int32 kMaxReadBufferSize = 10240; // 10 KB
53 static const int32 kMaxReadDirBufferSize = 10240;
54
55 // Locking:
56 //
57 // fLock: Guards fReferenceCount and fClosed.
58 // fSecurityContextLock: Guards fSecurityContext.
59 // fVolumes: Guards the map itself.
60
61
62 // #pragma mark -
63 // #pragma mark ----- ClientConnection -----
64
65 // ConnectionReference
66 class ClientConnection::ConnectionReference {
67 public:
ConnectionReference(ClientConnection * connection)68 ConnectionReference(ClientConnection* connection)
69 : fConnection(connection)
70 {
71 if (!fConnection || !fConnection->GetReference())
72 fConnection = NULL;
73 }
74
~ConnectionReference()75 ~ConnectionReference()
76 {
77 if (fConnection)
78 fConnection->PutReference();
79 }
80
IsValid() const81 bool IsValid() const
82 {
83 return fConnection;
84 }
85
86 private:
87 ClientConnection* fConnection;
88 };
89
90 // VolumeMap
91 struct ClientConnection::VolumeMap
92 : public SynchronizedHashMap<HashKey32<int32>, ClientVolume*> {
93 };
94
95 // ClientVolumePutter
96 class ClientConnection::ClientVolumePutter {
97 public:
ClientVolumePutter(ClientConnection * connection,ClientVolume * volume)98 ClientVolumePutter(ClientConnection* connection, ClientVolume* volume)
99 : fConnection(connection),
100 fVolume(volume)
101 {
102 }
103
~ClientVolumePutter()104 ~ClientVolumePutter()
105 {
106 if (fConnection && fVolume)
107 fConnection->_PutVolume(fVolume);
108 }
109
Detach()110 void Detach()
111 {
112 fConnection = NULL;
113 fVolume = NULL;
114 }
115
116 private:
117 ClientConnection* fConnection;
118 ClientVolume* fVolume;
119 };
120
121 // VolumeNodeMonitoringEvent
122 struct ClientConnection::VolumeNodeMonitoringEvent {
VolumeNodeMonitoringEventClientConnection::VolumeNodeMonitoringEvent123 VolumeNodeMonitoringEvent(int32 volumeID, NodeMonitoringEvent* event)
124 : volumeID(volumeID),
125 event(event)
126 {
127 if (event)
128 event->AcquireReference();
129 }
130
~VolumeNodeMonitoringEventClientConnection::VolumeNodeMonitoringEvent131 ~VolumeNodeMonitoringEvent()
132 {
133 if (event)
134 event->ReleaseReference();
135 }
136
137 int32 volumeID;
138 NodeMonitoringEvent* event;
139 };
140
141 // NodeMonitoringEventQueue
142 struct ClientConnection::NodeMonitoringEventQueue
143 : BlockingQueue<NodeMonitoringRequest> {
NodeMonitoringEventQueueClientConnection::NodeMonitoringEventQueue144 NodeMonitoringEventQueue()
145 : BlockingQueue<NodeMonitoringRequest>("client NM requests")
146 {
147 }
148 };
149
150 // QueryHandleUnlocker
151 struct ClientConnection::QueryHandleUnlocker {
QueryHandleUnlockerClientConnection::QueryHandleUnlocker152 QueryHandleUnlocker(ClientConnection* connection, NodeHandle* nodeHandle)
153 : fConnection(connection),
154 fHandle(nodeHandle)
155 {
156 }
157
~QueryHandleUnlockerClientConnection::QueryHandleUnlocker158 ~QueryHandleUnlocker()
159 {
160 if (fConnection && fHandle) {
161 fConnection->_UnlockQueryHandle(fHandle);
162 fConnection = NULL;
163 fHandle = NULL;
164 }
165 }
166
167 private:
168 ClientConnection* fConnection;
169 NodeHandle* fHandle;
170 };
171
172 // ClientVolumeFilter
173 struct ClientConnection::ClientVolumeFilter {
~ClientVolumeFilterClientConnection::ClientVolumeFilter174 virtual ~ClientVolumeFilter() {}
175
176 virtual bool FilterVolume(ClientConnection* connection,
177 ClientVolume* volume) = 0;
178 };
179
180 // HasQueryPermissionClientVolumeFilter
181 struct ClientConnection::HasQueryPermissionClientVolumeFilter
182 : ClientConnection::ClientVolumeFilter {
FilterVolumeClientConnection::HasQueryPermissionClientVolumeFilter183 virtual bool FilterVolume(ClientConnection* connection,
184 ClientVolume* volume)
185 {
186 return volume->GetSharePermissions().ImpliesQuerySharePermission();
187 }
188 };
189
190
191 // #pragma mark -
192
193 // constructor
ClientConnection(Connection * connection,SecurityContext * securityContext,User * user,ClientConnectionListener * listener)194 ClientConnection::ClientConnection(Connection* connection,
195 SecurityContext* securityContext, User* user,
196 ClientConnectionListener* listener)
197 : RequestHandler(),
198 ClientVolume::NodeMonitoringProcessor(),
199 fConnection(NULL),
200 fSecurityContext(securityContext),
201 fSecurityContextLock("security context lock"),
202 fUser(user),
203 fVolumes(NULL),
204 fQueryHandles(NULL),
205 fListener(listener),
206 fNodeMonitoringEvents(NULL),
207 fNodeMonitoringProcessor(-1),
208 fLock("client connection locker"),
209 fReferenceCount(0),
210 fInitialized(0),
211 fClosed(false),
212 fError(false),
213 fInverseClientEndianess(false)
214 {
215 fConnection = new(std::nothrow) RequestConnection(connection, this);
216 if (!fConnection)
217 delete connection;
218 }
219
220 // destructor
~ClientConnection()221 ClientConnection::~ClientConnection()
222 {
223 _Close();
224 delete fConnection;
225
226 // delete all volumes
227 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();)
228 delete it.Next().value;
229 delete fVolumes;
230
231 delete fQueryHandles;
232 delete fNodeMonitoringEvents;
233 }
234
235 // Init
236 status_t
Init()237 ClientConnection::Init()
238 {
239 // create a client volume map
240 fVolumes = new(std::nothrow) VolumeMap;
241 if (!fVolumes)
242 return B_NO_MEMORY;
243 status_t error = fVolumes->InitCheck();
244 if (error != B_OK)
245 return error;
246
247 // create the query handle map
248 fQueryHandles = new(std::nothrow) NodeHandleMap("query handles");
249 if (!fQueryHandles)
250 return B_NO_MEMORY;
251 error = fQueryHandles->Init();
252 if (error != B_OK)
253 return error;
254
255 // create the node monitoring event queue
256 fNodeMonitoringEvents = new(std::nothrow) NodeMonitoringEventQueue;
257 if (!fNodeMonitoringEvents)
258 return B_NO_MEMORY;
259 error = fNodeMonitoringEvents->InitCheck();
260 if (error != B_OK)
261 return error;
262
263 // initialize the connection
264 error = fConnection->Init();
265 if (error != B_OK)
266 return error;
267
268 // start the node monitoring processor
269 fNodeMonitoringProcessor = spawn_thread(_NodeMonitoringProcessorEntry,
270 "client connection NM processor", B_NORMAL_PRIORITY, this);
271 if (fNodeMonitoringProcessor < 0) {
272 _Close();
273 return fNodeMonitoringProcessor;
274 }
275 resume_thread(fNodeMonitoringProcessor);
276 return B_OK;
277 }
278
279 // Close
280 /*!
281 Called by the NetFSServer. Not for internal use. Waits for the connection
282 to be closed (at least for the node monitoring thread to be gone).
283 */
284 void
Close()285 ClientConnection::Close()
286 {
287 {
288 ConnectionReference connectionReference(this);
289 if (connectionReference.IsValid())
290 _MarkClosed(false);
291 fListener = NULL;
292 }
293
294 // Wait at least for the node monitoring processor; this is not perfect,
295 // but not too bad either.
296 if (fNodeMonitoringProcessor >= 0
297 && find_thread(NULL) != fNodeMonitoringProcessor) {
298 int32 result;
299 wait_for_thread(fNodeMonitoringProcessor, &result);
300 }
301 }
302
303 // GetReference
304 bool
GetReference()305 ClientConnection::GetReference()
306 {
307 AutoLocker<Locker> _(fLock);
308 if (fClosed || !atomic_or(&fInitialized, 0))
309 return false;
310 fReferenceCount++;
311 return true;
312 }
313
314 // PutReference
315 void
PutReference()316 ClientConnection::PutReference()
317 {
318 bool close = false;
319 {
320 AutoLocker<Locker> _(fLock);
321 --fReferenceCount;
322 if (fClosed)
323 close = (fReferenceCount == 0);
324 }
325 if (close)
326 _Close();
327 }
328
329 // UserRemoved
330 void
UserRemoved(User * user)331 ClientConnection::UserRemoved(User* user)
332 {
333 // get all volumes
334 ClientVolume** volumes = NULL;
335 int32 volumeCount = 0;
336 AutoLocker<VolumeMap> volumesLocker(fVolumes);
337 volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()];
338 if (!volumes) {
339 ERROR(("ClientConnection::UserRemoved(): ERROR: Failed to "
340 "allocate memory for volume array.\n"));
341 volumesLocker.Unlock();
342 _UnmountAllVolumes();
343 return;
344 }
345 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
346 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID()))
347 volumes[volumeCount++] = volume;
348 }
349 volumesLocker.Unlock();
350
351 // unmount the concerned volumes
352 for (int32 i = 0; i < volumeCount; i++) {
353 ClientVolume* volume = volumes[i];
354
355 fSecurityContextLock.Lock();
356 bool unmount = (volume->GetSecurityContext()->GetUser() == user);
357 fSecurityContextLock.Unlock();
358
359 if (unmount)
360 _UnmountVolume(volume);
361 }
362
363 // put the volumes
364 for (int32 i = 0; i < volumeCount; i++)
365 _PutVolume(volumes[i]);
366 delete[] volumes;
367 }
368
369 // ShareRemoved
370 void
ShareRemoved(Share * share)371 ClientConnection::ShareRemoved(Share* share)
372 {
373 // get all volumes
374 ClientVolume** volumes = NULL;
375 int32 volumeCount = 0;
376 AutoLocker<VolumeMap> volumesLocker(fVolumes);
377 volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()];
378 if (!volumes) {
379 ERROR(("ClientConnection::ShareRemoved(): ERROR: Failed to "
380 "allocate memory for volume array.\n"));
381 volumesLocker.Unlock();
382 _UnmountAllVolumes();
383 return;
384 }
385 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
386 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID()))
387 volumes[volumeCount++] = volume;
388 }
389 volumesLocker.Unlock();
390
391 // unmount the concerned volumes
392 for (int32 i = 0; i < volumeCount; i++) {
393 ClientVolume* volume = volumes[i];
394
395 fSecurityContextLock.Lock();
396 bool unmount = (volume->GetShare() == share);
397 fSecurityContextLock.Unlock();
398
399 if (unmount)
400 _UnmountVolume(volume);
401 }
402
403 // put the volumes
404 for (int32 i = 0; i < volumeCount; i++)
405 _PutVolume(volumes[i]);
406 delete[] volumes;
407 }
408
409 // UserPermissionsChanged
410 void
UserPermissionsChanged(Share * share,User * user,Permissions permissions)411 ClientConnection::UserPermissionsChanged(Share* share, User* user,
412 Permissions permissions)
413 {
414 bool unmountAll = (!permissions.ImpliesMountSharePermission());
415
416 // get all volumes
417 ClientVolume** volumes = NULL;
418 int32 volumeCount = 0;
419 AutoLocker<VolumeMap> volumesLocker(fVolumes);
420 volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()];
421 if (!volumes) {
422 ERROR(("ClientConnection::ShareRemoved(): ERROR: Failed to "
423 "allocate memory for volume array.\n"));
424 volumesLocker.Unlock();
425 _UnmountAllVolumes();
426 return;
427 }
428 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
429 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID()))
430 volumes[volumeCount++] = volume;
431 }
432 volumesLocker.Unlock();
433
434 // update the concerned volumes
435 for (int32 i = 0; i < volumeCount; i++) {
436 ClientVolume* volume = volumes[i];
437
438 fSecurityContextLock.Lock();
439 bool concerned = (volume->GetShare() == share
440 && volume->GetSecurityContext()->GetUser() == user);
441 fSecurityContextLock.Unlock();
442
443 if (concerned) {
444 // create a new user security context for the volume
445 status_t error = B_OK;
446
447 if (unmountAll) {
448 _UnmountVolume(volume);
449 } else {
450 // create a new user security context
451 AutoLocker<Locker> securityContextLocker(fSecurityContextLock);
452 UserSecurityContext* userSecurityContext
453 = new(std::nothrow) UserSecurityContext;
454
455 // init it
456 if (userSecurityContext) {
457 error = fSecurityContext->GetUserSecurityContext(user,
458 userSecurityContext);
459 } else
460 error = B_NO_MEMORY;
461 if (error != B_OK) {
462 delete userSecurityContext;
463 securityContextLocker.Unlock();
464 _UnmountVolume(volume);
465 continue;
466 }
467
468 // set the volume's new user security context
469 securityContextLocker.Unlock();
470 volume->SetSecurityContext(userSecurityContext);
471 }
472 }
473 }
474
475 // put the volumes
476 for (int32 i = 0; i < volumeCount; i++)
477 _PutVolume(volumes[i]);
478 delete[] volumes;
479 }
480
481
482 // #pragma mark -
483
484 // VisitConnectionBrokenRequest
485 status_t
VisitConnectionBrokenRequest(ConnectionBrokenRequest * request)486 ClientConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request)
487 {
488 ConnectionReference connectionReference(this);
489 if (!connectionReference.IsValid())
490 return B_OK;
491
492 _MarkClosed(true);
493 return B_OK;
494 }
495
496 // VisitInitConnectionRequest
497 status_t
VisitInitConnectionRequest(InitConnectionRequest * request)498 ClientConnection::VisitInitConnectionRequest(InitConnectionRequest* request)
499 {
500 bool alreadyInitialized = atomic_or(&fInitialized, ~0);
501
502 ConnectionReference connectionReference(this);
503 if (!connectionReference.IsValid())
504 return B_OK;
505
506 if (!alreadyInitialized)
507 fInverseClientEndianess = (request->bigEndian != B_HOST_IS_BENDIAN);
508
509 // prepare the reply
510 InitConnectionReply reply;
511
512 // send the reply
513 reply.error = (alreadyInitialized ? B_BAD_VALUE : B_OK);
514 status_t error = GetChannel()->SendRequest(&reply);
515
516 // on error just close
517 if (error != B_OK)
518 _MarkClosed(true);
519 return B_OK;
520 }
521
522 // VisitMountRequest
523 status_t
VisitMountRequest(MountRequest * request)524 ClientConnection::VisitMountRequest(MountRequest* request)
525 {
526 ConnectionReference connectionReference(this);
527 if (!connectionReference.IsValid())
528 return B_OK;
529
530 status_t result = B_OK;
531 const char* shareName = request->share.GetString();
532 if (!shareName)
533 SET_ERROR(result, B_BAD_DATA);
534
535 // create a volume
536 ClientVolume* volume = NULL;
537 if (result == B_OK)
538 result = _CreateVolume(&volume);
539 ClientVolumePutter volumePutter(this, volume);
540
541 // if we haven't been supplied with a user yet, use the info from the
542 // mount request for authentication
543 VolumeManagerLocker managerLocker;
544 AutoLocker<Locker> securityContextLocker(fSecurityContextLock);
545 const char* userName = request->user.GetString();
546 User* user = fUser;
547 BReference<User> userReference(user);
548 bool noPermission = false;
549 if (result == B_OK && !user) {
550 if (userName) {
551 SET_ERROR(result, fSecurityContext->AuthenticateUser(userName,
552 request->password.GetString(), &user));
553 if (result == B_OK)
554 userReference.SetTo(user, true);
555 } else
556 result = B_PERMISSION_DENIED;
557 if (result == B_PERMISSION_DENIED)
558 noPermission = true;
559 }
560
561 // create a user security context
562 UserSecurityContext* securityContext = NULL;
563 if (result == B_OK) {
564 securityContext = new(std::nothrow) UserSecurityContext;
565 if (securityContext) {
566 SET_ERROR(result, fSecurityContext->GetUserSecurityContext(user,
567 securityContext));
568 } else
569 SET_ERROR(result, B_NO_MEMORY);
570 }
571 ObjectDeleter<UserSecurityContext> securityContextDeleter(securityContext);
572
573 // get the share
574 Share* share = NULL;
575 Permissions sharePermissions;
576 node_ref mountPoint;
577 if (result == B_OK) {
578 AutoLocker<SecurityContext> _(fSecurityContext);
579 share = fSecurityContext->FindShare(shareName);
580 if (share) {
581 mountPoint = share->GetNodeRef();
582 sharePermissions = securityContext->GetNodePermissions(
583 mountPoint);
584 if (!sharePermissions.ImpliesMountSharePermission()) {
585 SET_ERROR(result, B_PERMISSION_DENIED);
586 noPermission = true;
587 }
588 } else
589 SET_ERROR(result, B_ENTRY_NOT_FOUND);
590 }
591 BReference<Share> shareReference(share, true);
592
593 // mount the volume
594 MountReply reply;
595 if (result == B_OK) {
596 SET_ERROR(result, volume->Mount(securityContext, share));
597 securityContextDeleter.Detach();
598 }
599 if (result == B_OK) {
600 _GetNodeInfo(volume->GetRootDirectory(), &reply.nodeInfo);
601 reply.sharePermissions = sharePermissions.GetPermissions();
602 reply.volumeID = volume->GetID();
603 }
604
605 // make sure, the volume is removed on error
606 if (result != B_OK && volume) {
607 AutoLocker<VolumeMap> volumeMapLocker(fVolumes);
608 volume->MarkRemoved();
609 }
610
611 securityContextLocker.Unlock();
612 managerLocker.Unlock();
613
614 // send the reply
615 reply.error = result;
616 reply.noPermission = noPermission;
617 return GetChannel()->SendRequest(&reply);
618 }
619
620 // VisitUnmountRequest
621 status_t
VisitUnmountRequest(UnmountRequest * request)622 ClientConnection::VisitUnmountRequest(UnmountRequest* request)
623 {
624 ConnectionReference connectionReference(this);
625 if (!connectionReference.IsValid())
626 return B_OK;
627
628 if (ClientVolume* volume = _GetVolume(request->volumeID)) {
629 _UnmountVolume(volume);
630 _PutVolume(volume);
631 }
632
633 return B_OK;
634 }
635
636 // VisitReadVNodeRequest
637 status_t
VisitReadVNodeRequest(ReadVNodeRequest * request)638 ClientConnection::VisitReadVNodeRequest(ReadVNodeRequest* request)
639 {
640 ConnectionReference connectionReference(this);
641 if (!connectionReference.IsValid())
642 return B_OK;
643
644 // get the volume
645 status_t result = B_OK;
646 ClientVolume* volume = _GetVolume(request->volumeID);
647 if (!volume)
648 result = B_BAD_VALUE;
649 ClientVolumePutter volumePutter(this, volume);
650
651 VolumeManagerLocker managerLocker;
652
653 // get the node
654 Node* node = NULL;
655 if (result == B_OK) {
656 node = volume->GetNode(request->nodeID);
657 if (!node)
658 result = B_ENTRY_NOT_FOUND;
659 }
660
661 // prepare the reply
662 ReadVNodeReply reply;
663 if (result == B_OK)
664 _GetNodeInfo(node, &reply.nodeInfo);
665
666 managerLocker.Unlock();
667
668 // send the reply
669 reply.error = result;
670 return GetChannel()->SendRequest(&reply);
671 }
672
673 // VisitWriteStatRequest
674 status_t
VisitWriteStatRequest(WriteStatRequest * request)675 ClientConnection::VisitWriteStatRequest(WriteStatRequest* request)
676 {
677 ConnectionReference connectionReference(this);
678 if (!connectionReference.IsValid())
679 return B_OK;
680
681 // get the volume
682 status_t result = B_OK;
683 ClientVolume* volume = _GetVolume(request->volumeID);
684 if (!volume)
685 result = B_BAD_VALUE;
686 ClientVolumePutter volumePutter(this, volume);
687
688 VolumeManagerLocker managerLocker;
689
690 // get the node
691 Node* node = NULL;
692 if (result == B_OK) {
693 node = volume->GetNode(request->nodeID);
694 if (!node)
695 result = B_ENTRY_NOT_FOUND;
696 }
697
698 // check permissions
699 if (result == B_OK) {
700 if (!volume->GetNodePermissions(node).ImpliesWritePermission())
701 result = B_PERMISSION_DENIED;
702 }
703
704 // get the path
705 Path path;
706 if (result == B_OK)
707 result = node->GetPath(&path);
708
709 // write the stat
710 uint32 mask = request->mask;
711 // size
712 if (result == B_OK && (mask & WSTAT_SIZE)) {
713 if (truncate(path.GetPath(), request->nodeInfo.st.st_size) < 0)
714 result = errno;
715 }
716 // mode
717 if (result == B_OK && (mask & WSTAT_MODE)) {
718 if (chmod(path.GetPath(), request->nodeInfo.st.st_mode) < 0)
719 result = errno;
720 }
721 // mtime
722 if (result == B_OK && (mask & (WSTAT_ATIME | WSTAT_MTIME))) {
723 utimbuf buffer;
724 buffer.actime = (mask & WSTAT_ATIME)
725 ? request->nodeInfo.st.st_atime
726 : node->GetStat().st_atime;
727 buffer.modtime = (mask & WSTAT_MTIME)
728 ? request->nodeInfo.st.st_mtime
729 : node->GetStat().st_mtime;
730 if (utime(path.GetPath(), &buffer) < 0)
731 result = errno;
732 }
733 // ignore WSTAT_CRTIME, WSTAT_UID, WSTAT_GID for the time being
734
735 // prepare the reply
736 WriteStatReply reply;
737 // update the node stat
738 reply.nodeInfoValid = false;
739 if (node) {
740 if (node->UpdateStat() == B_OK) {
741 _GetNodeInfo(node, &reply.nodeInfo);
742 reply.nodeInfoValid = true;
743 }
744 }
745
746 managerLocker.Unlock();
747
748 // send the reply
749 reply.error = result;
750 return GetChannel()->SendRequest(&reply);
751 }
752
753 // VisitCreateFileRequest
754 status_t
VisitCreateFileRequest(CreateFileRequest * request)755 ClientConnection::VisitCreateFileRequest(CreateFileRequest* request)
756 {
757 ConnectionReference connectionReference(this);
758 if (!connectionReference.IsValid())
759 return B_OK;
760
761 // get the volume
762 status_t result = B_OK;
763 ClientVolume* volume = _GetVolume(request->volumeID);
764 if (!volume)
765 result = B_BAD_VALUE;
766 ClientVolumePutter volumePutter(this, volume);
767
768 VolumeManagerLocker managerLocker;
769
770 // get the directory
771 Directory* directory = NULL;
772 if (result == B_OK) {
773 Node* node = volume->GetNode(request->directoryID);
774 if (node) {
775 directory = dynamic_cast<Directory*>(node);
776 if (!directory)
777 result = B_NOT_A_DIRECTORY;
778 } else
779 result = B_ENTRY_NOT_FOUND;
780 }
781
782 // check permissions
783 int openMode = request->openMode;
784 if (result == B_OK) {
785 if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
786 result = B_PERMISSION_DENIED;
787 }
788
789 // get the path
790 Path path;
791 if (result == B_OK) {
792 result = directory->GetPath(&path);
793 if (result == B_OK)
794 result = path.Append(request->name.GetString());
795 }
796
797 // create the file
798 if (result == B_OK) {
799 int fd = -1;
800 result = FDManager::Open(path.GetPath(),
801 openMode | O_CREAT | O_NOTRAVERSE, request->mode, fd);
802 if (result == B_OK)
803 close(fd);
804 }
805
806 // load the new entry
807 Entry* entry = NULL;
808 if (result == B_OK) {
809 VolumeManager* volumeManager = VolumeManager::GetDefault();
810
811 // if there existed an entry before, we need to delete it, to avoid that
812 // we open the wrong node
813 entry = volumeManager->GetEntry(directory->GetVolumeID(),
814 directory->GetID(), request->name.GetString());
815 if (entry)
816 volumeManager->DeleteEntry(entry, false);
817
818 // load the new entry
819 entry = NULL;
820 result = volume->LoadEntry(directory, request->name.GetString(),
821 &entry);
822 }
823
824 // open the node
825 FileHandle* handle = NULL;
826 if (result == B_OK) {
827 openMode &= ~(O_CREAT | O_EXCL | O_TRUNC);
828 result = volume->Open(entry->GetNode(), openMode, &handle);
829 }
830 NodeHandleUnlocker handleUnlocker(volume, handle);
831
832 // prepare the reply
833 CreateFileReply reply;
834 if (result == B_OK) {
835 _GetEntryInfo(entry, &reply.entryInfo);
836 reply.cookie = handle->GetCookie();
837 }
838
839 managerLocker.Unlock();
840
841 // send the reply
842 reply.error = result;
843 status_t error = GetChannel()->SendRequest(&reply);
844
845 // close the handle, if a send error occurred
846 if (error != B_OK && result == B_OK)
847 volume->Close(handle);
848
849 return error;
850 }
851
852 // VisitOpenRequest
853 status_t
VisitOpenRequest(OpenRequest * request)854 ClientConnection::VisitOpenRequest(OpenRequest* request)
855 {
856 ConnectionReference connectionReference(this);
857 if (!connectionReference.IsValid())
858 return B_OK;
859
860 // get the volume
861 status_t result = B_OK;
862 ClientVolume* volume = _GetVolume(request->volumeID);
863 if (!volume)
864 result = B_BAD_VALUE;
865 ClientVolumePutter volumePutter(this, volume);
866
867 VolumeManagerLocker managerLocker;
868
869 // get the node
870 Node* node = NULL;
871 if (result == B_OK) {
872 node = volume->GetNode(request->nodeID);
873 if (!node)
874 result = B_ENTRY_NOT_FOUND;
875 }
876
877 // check permissions
878 int openMode = request->openMode;
879 if (result == B_OK) {
880 Permissions permissions = volume->GetNodePermissions(node);
881 if ((openMode & O_RWMASK) == O_RDWR) {
882 // read+write: fall back to read/write only, if the other permission
883 // is missing
884 if (!permissions.ImpliesReadPermission())
885 openMode = (openMode & ~O_RWMASK) | O_WRONLY;
886 else if (!permissions.ImpliesWritePermission())
887 openMode = (openMode & ~O_RWMASK) | O_RDONLY;
888 }
889 if ((openMode & O_RWMASK) == O_RDONLY) {
890 if (!permissions.ImpliesReadPermission())
891 result = B_PERMISSION_DENIED;
892 } else if ((openMode & O_RWMASK) == O_WRONLY) {
893 if (!permissions.ImpliesWritePermission())
894 result = B_PERMISSION_DENIED;
895 }
896 }
897
898 // open the node
899 FileHandle* handle = NULL;
900 if (result == B_OK)
901 result = volume->Open(node, openMode, &handle);
902 NodeHandleUnlocker handleUnlocker(volume, handle);
903
904 // prepare the reply
905 OpenReply reply;
906 if (result == B_OK) {
907 _GetNodeInfo(node, &reply.nodeInfo);
908 reply.cookie = handle->GetCookie();
909 }
910
911 managerLocker.Unlock();
912
913 // send the reply
914 reply.error = result;
915 status_t error = GetChannel()->SendRequest(&reply);
916
917 // close the handle, if a send error occurred
918 if (error != B_OK && result == B_OK)
919 volume->Close(handle);
920
921 return error;
922 }
923
924 // VisitCloseRequest
925 status_t
VisitCloseRequest(CloseRequest * request)926 ClientConnection::VisitCloseRequest(CloseRequest* request)
927 {
928 ConnectionReference connectionReference(this);
929 if (!connectionReference.IsValid())
930 return B_OK;
931
932 status_t result = B_OK;
933
934 if (request->volumeID >= 0) {
935 // get the volume
936 ClientVolume* volume = _GetVolume(request->volumeID);
937 if (!volume)
938 SET_ERROR(result, B_BAD_VALUE);
939 ClientVolumePutter volumePutter(this, volume);
940
941 // get the node handle
942 NodeHandle* handle = NULL;
943 if (result == B_OK)
944 SET_ERROR(result, volume->LockNodeHandle(request->cookie, &handle));
945 NodeHandleUnlocker handleUnlocker(volume, handle);
946
947 VolumeManagerLocker managerLocker;
948
949 // close it
950 if (result == B_OK)
951 SET_ERROR(result, volume->Close(handle));
952
953 managerLocker.Unlock();
954 } else {
955 // no volume ID given, so this is a query handle
956 // lock the handle
957 QueryHandle* handle = NULL;
958 SET_ERROR(result, _LockQueryHandle(request->cookie, &handle));
959 QueryHandleUnlocker handleUnlocker(this, handle);
960
961 // close it
962 if (result == B_OK)
963 SET_ERROR(result, _CloseQuery(handle));
964 }
965
966 // send the reply
967 CloseReply reply;
968 reply.error = result;
969 return GetChannel()->SendRequest(&reply);
970 }
971
972 // VisitReadRequest
973 status_t
VisitReadRequest(ReadRequest * request)974 ClientConnection::VisitReadRequest(ReadRequest* request)
975 {
976 ConnectionReference connectionReference(this);
977 if (!connectionReference.IsValid())
978 return B_OK;
979
980 // get the volume
981 status_t result = B_OK;
982 ClientVolume* volume = _GetVolume(request->volumeID);
983 if (!volume)
984 result = B_BAD_VALUE;
985 ClientVolumePutter volumePutter(this, volume);
986
987 // get the node handle
988 NodeHandle* handle = NULL;
989 if (result == B_OK)
990 result = volume->LockNodeHandle(request->cookie, &handle);
991 NodeHandleUnlocker handleUnlocker(volume, handle);
992
993 // check if it is a file handle
994 FileHandle* fileHandle = NULL;
995 if (result == B_OK) {
996 fileHandle = dynamic_cast<FileHandle*>(handle);
997 if (!fileHandle)
998 result = B_BAD_VALUE;
999 }
1000
1001 VolumeManagerLocker managerLocker;
1002
1003 // check read permission
1004 if (result == B_OK) {
1005 Node* node = volume->GetNode(fileHandle->GetNodeRef());
1006 if (!node || !volume->GetNodePermissions(node).ImpliesReadPermission())
1007 result = B_PERMISSION_DENIED;
1008 }
1009
1010 managerLocker.Unlock();
1011
1012 off_t pos = request->pos;
1013 int32 size = request->size;
1014 int32 bufferSize = min(size, kMaxReadBufferSize);
1015 // allocate a buffer
1016 uint8* buffer = NULL;
1017 if (result == B_OK) {
1018 buffer = (uint8*)malloc(bufferSize);
1019 if (!buffer)
1020 result = B_NO_MEMORY;
1021 }
1022 MemoryDeleter bufferDeleter(buffer);
1023
1024 // read as long as there are bytes left to read or an error occurs
1025 bool moreToRead = true;
1026 do {
1027 int32 bytesToRead = min(size, bufferSize);
1028 size_t bytesRead = 0;
1029 if (result == B_OK)
1030 result = fileHandle->Read(pos, buffer, bytesToRead, &bytesRead);
1031 moreToRead = (result == B_OK && bytesRead > 0
1032 && (int32)bytesRead < size);
1033
1034 // prepare the reply
1035 ReadReply reply;
1036 if (result == B_OK) {
1037 reply.pos = pos;
1038 reply.data.SetTo(buffer, bytesRead);
1039 reply.moreToCome = moreToRead;
1040 pos += bytesRead;
1041 size -= bytesRead;
1042 }
1043
1044 // send the reply
1045 reply.error = result;
1046 status_t error = GetChannel()->SendRequest(&reply);
1047 if (error != B_OK)
1048 return error;
1049 } while (moreToRead);
1050
1051 return B_OK;
1052 }
1053
1054 // VisitWriteRequest
1055 status_t
VisitWriteRequest(WriteRequest * request)1056 ClientConnection::VisitWriteRequest(WriteRequest* request)
1057 {
1058 ConnectionReference connectionReference(this);
1059 if (!connectionReference.IsValid())
1060 return B_OK;
1061
1062 // get the volume
1063 status_t result = B_OK;
1064 ClientVolume* volume = _GetVolume(request->volumeID);
1065 if (!volume)
1066 result = B_BAD_VALUE;
1067 ClientVolumePutter volumePutter(this, volume);
1068
1069 // get the node handle
1070 NodeHandle* handle = NULL;
1071 if (result == B_OK)
1072 result = volume->LockNodeHandle(request->cookie, &handle);
1073 NodeHandleUnlocker handleUnlocker(volume, handle);
1074
1075 // check if it is a file handle
1076 FileHandle* fileHandle = NULL;
1077 if (result == B_OK) {
1078 fileHandle = dynamic_cast<FileHandle*>(handle);
1079 if (!fileHandle)
1080 result = B_BAD_VALUE;
1081 }
1082
1083 VolumeManagerLocker managerLocker;
1084
1085 // check read permission
1086 if (result == B_OK) {
1087 Node* node = volume->GetNode(fileHandle->GetNodeRef());
1088 if (!node || !volume->GetNodePermissions(node).ImpliesWritePermission())
1089 result = B_PERMISSION_DENIED;
1090 }
1091
1092 managerLocker.Unlock();
1093
1094 // write until all has been written or an error occurs
1095 off_t pos = request->pos;
1096 int32 size = request->data.GetSize();
1097 const char* buffer = (const char*)request->data.GetData();
1098 while (result == B_OK && size > 0) {
1099 size_t bytesWritten;
1100 result = fileHandle->Write(pos, buffer, size, &bytesWritten);
1101 if (result == B_OK) {
1102 pos += bytesWritten;
1103 buffer += bytesWritten;
1104 size -= bytesWritten;
1105 }
1106 }
1107
1108 // prepare the reply
1109 WriteReply reply;
1110 // send the reply
1111 reply.error = result;
1112 return GetChannel()->SendRequest(&reply);
1113 }
1114
1115 // VisitCreateLinkRequest
1116 status_t
VisitCreateLinkRequest(CreateLinkRequest * request)1117 ClientConnection::VisitCreateLinkRequest(CreateLinkRequest* request)
1118 {
1119 ConnectionReference connectionReference(this);
1120 if (!connectionReference.IsValid())
1121 return B_OK;
1122
1123 // get the volume
1124 status_t result = B_OK;
1125 ClientVolume* volume = _GetVolume(request->volumeID);
1126 if (!volume)
1127 result = B_BAD_VALUE;
1128 ClientVolumePutter volumePutter(this, volume);
1129
1130 VolumeManagerLocker managerLocker;
1131
1132 // get the target node
1133 Node* node = NULL;
1134 if (result == B_OK) {
1135 node = volume->GetNode(request->nodeID);
1136 if (!node)
1137 result = B_ENTRY_NOT_FOUND;
1138 }
1139
1140 // get the target node path
1141 Path targetPath;
1142 if (result == B_OK)
1143 result = node->GetPath(&targetPath);
1144
1145 // get the directory
1146 Directory* directory = NULL;
1147 if (result == B_OK) {
1148 Node* node = volume->GetNode(request->directoryID);
1149 if (node) {
1150 directory = dynamic_cast<Directory*>(node);
1151 if (!directory)
1152 result = B_NOT_A_DIRECTORY;
1153 } else
1154 result = B_ENTRY_NOT_FOUND;
1155 }
1156
1157 // check permissions
1158 if (result == B_OK) {
1159 if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1160 result = B_PERMISSION_DENIED;
1161 }
1162
1163 // get the new entry's path
1164 Path path;
1165 if (result == B_OK) {
1166 result = directory->GetPath(&path);
1167 if (result == B_OK)
1168 result = path.Append(request->name.GetString());
1169 }
1170
1171 managerLocker.Unlock();
1172
1173 // create the link
1174 if (result == B_OK) {
1175 if (link(targetPath.GetPath(), path.GetPath()) < 0)
1176 result = errno;
1177 }
1178
1179 // prepare the reply
1180 CreateSymlinkReply reply;
1181 // send the reply
1182 reply.error = result;
1183 return GetChannel()->SendRequest(&reply);
1184 }
1185
1186 // VisitUnlinkRequest
1187 status_t
VisitUnlinkRequest(UnlinkRequest * request)1188 ClientConnection::VisitUnlinkRequest(UnlinkRequest* request)
1189 {
1190 ConnectionReference connectionReference(this);
1191 if (!connectionReference.IsValid())
1192 return B_OK;
1193
1194 // get the volume
1195 status_t result = B_OK;
1196 ClientVolume* volume = _GetVolume(request->volumeID);
1197 if (!volume)
1198 result = B_BAD_VALUE;
1199 ClientVolumePutter volumePutter(this, volume);
1200
1201 VolumeManagerLocker managerLocker;
1202
1203 // get the directory
1204 Directory* directory = NULL;
1205 if (result == B_OK) {
1206 Node* node = volume->GetNode(request->directoryID);
1207 if (node) {
1208 directory = dynamic_cast<Directory*>(node);
1209 if (!directory)
1210 result = B_NOT_A_DIRECTORY;
1211 } else
1212 result = B_ENTRY_NOT_FOUND;
1213 }
1214
1215 // check permissions
1216 if (result == B_OK) {
1217 if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1218 result = B_PERMISSION_DENIED;
1219 }
1220
1221 // get the entry's path
1222 Path path;
1223 if (result == B_OK) {
1224 result = directory->GetPath(&path);
1225 if (result == B_OK)
1226 result = path.Append(request->name.GetString());
1227 }
1228
1229 managerLocker.Unlock();
1230
1231 // remove the entry
1232 if (result == B_OK) {
1233 if (unlink(path.GetPath()) < 0)
1234 result = errno;
1235 }
1236
1237 // prepare the reply
1238 UnlinkReply reply;
1239 // send the reply
1240 reply.error = result;
1241 return GetChannel()->SendRequest(&reply);
1242 }
1243
1244 // VisitCreateSymlinkRequest
1245 status_t
VisitCreateSymlinkRequest(CreateSymlinkRequest * request)1246 ClientConnection::VisitCreateSymlinkRequest(CreateSymlinkRequest* request)
1247 {
1248 ConnectionReference connectionReference(this);
1249 if (!connectionReference.IsValid())
1250 return B_OK;
1251
1252 // get the volume
1253 status_t result = B_OK;
1254 ClientVolume* volume = _GetVolume(request->volumeID);
1255 if (!volume)
1256 result = B_BAD_VALUE;
1257 ClientVolumePutter volumePutter(this, volume);
1258
1259 VolumeManagerLocker managerLocker;
1260
1261 // get the directory
1262 Directory* directory = NULL;
1263 if (result == B_OK) {
1264 Node* node = volume->GetNode(request->directoryID);
1265 if (node) {
1266 directory = dynamic_cast<Directory*>(node);
1267 if (!directory)
1268 result = B_NOT_A_DIRECTORY;
1269 } else
1270 result = B_ENTRY_NOT_FOUND;
1271 }
1272
1273 // check permissions
1274 if (result == B_OK) {
1275 if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1276 result = B_PERMISSION_DENIED;
1277 }
1278
1279 // get the new entry's path
1280 Path path;
1281 if (result == B_OK) {
1282 result = directory->GetPath(&path);
1283 if (result == B_OK)
1284 result = path.Append(request->name.GetString());
1285 }
1286
1287 managerLocker.Unlock();
1288
1289 // create the symlink
1290 if (result == B_OK) {
1291 if (symlink(request->target.GetString(), path.GetPath()) < 0)
1292 result = errno;
1293 }
1294
1295 // prepare the reply
1296 CreateSymlinkReply reply;
1297 // send the reply
1298 reply.error = result;
1299 return GetChannel()->SendRequest(&reply);
1300 }
1301
1302 // VisitReadLinkRequest
1303 status_t
VisitReadLinkRequest(ReadLinkRequest * request)1304 ClientConnection::VisitReadLinkRequest(ReadLinkRequest* request)
1305 {
1306 ConnectionReference connectionReference(this);
1307 if (!connectionReference.IsValid())
1308 return B_OK;
1309
1310 // get the volume
1311 status_t result = B_OK;
1312 ClientVolume* volume = _GetVolume(request->volumeID);
1313 if (!volume)
1314 result = B_BAD_VALUE;
1315 ClientVolumePutter volumePutter(this, volume);
1316
1317 VolumeManagerLocker managerLocker;
1318
1319 // get the node
1320 Node* node = NULL;
1321 if (result == B_OK) {
1322 node = volume->GetNode(request->nodeID);
1323 if (!node)
1324 result = B_ENTRY_NOT_FOUND;
1325 }
1326
1327 int32 bufferSize = request->maxSize;
1328
1329 // check read permission
1330 if (result == B_OK) {
1331 if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1332 result = B_PERMISSION_DENIED;
1333 }
1334
1335 // allocate a buffer
1336 void* buffer = NULL;
1337 if (result == B_OK) {
1338 if (bufferSize < 0 || bufferSize > kMaxSaneReadLinkSize)
1339 result = B_BAD_DATA;
1340 }
1341 if (result == B_OK) {
1342 buffer = malloc(bufferSize);
1343 if (!buffer)
1344 result = B_NO_MEMORY;
1345 }
1346 MemoryDeleter bufferDeleter(buffer);
1347
1348 // read the link and prepare the reply
1349 ReadLinkReply reply;
1350 int32 bytesRead = 0;
1351 if (result == B_OK)
1352 result = node->ReadSymlink((char*)buffer, bufferSize, &bytesRead);
1353 if (result == B_OK) {
1354 reply.data.SetTo(buffer, bytesRead);
1355 _GetNodeInfo(node, &reply.nodeInfo);
1356 }
1357
1358 managerLocker.Unlock();
1359
1360 // send the reply
1361 reply.error = result;
1362 return GetChannel()->SendRequest(&reply);
1363 }
1364
1365 // VisitRenameRequest
1366 status_t
VisitRenameRequest(RenameRequest * request)1367 ClientConnection::VisitRenameRequest(RenameRequest* request)
1368 {
1369 ConnectionReference connectionReference(this);
1370 if (!connectionReference.IsValid())
1371 return B_OK;
1372
1373 // get the volume
1374 status_t result = B_OK;
1375 ClientVolume* volume = _GetVolume(request->volumeID);
1376 if (!volume)
1377 result = B_BAD_VALUE;
1378 ClientVolumePutter volumePutter(this, volume);
1379
1380 VolumeManagerLocker managerLocker;
1381
1382 // get the new directory
1383 Directory* newDirectory = NULL;
1384 if (result == B_OK) {
1385 Node* node = volume->GetNode(request->newDirectoryID);
1386 if (node) {
1387 newDirectory = dynamic_cast<Directory*>(node);
1388 if (!newDirectory)
1389 result = B_NOT_A_DIRECTORY;
1390 } else
1391 result = B_ENTRY_NOT_FOUND;
1392 }
1393
1394 // check permissions
1395 if (result == B_OK) {
1396 if (!volume->GetNodePermissions(newDirectory).ImpliesWritePermission())
1397 result = B_PERMISSION_DENIED;
1398 }
1399
1400 // get the new path
1401 Path newPath;
1402 if (result == B_OK) {
1403 result = newDirectory->GetPath(&newPath);
1404 if (result == B_OK)
1405 result = newPath.Append(request->newName.GetString());
1406 }
1407
1408 // get the old directory
1409 Directory* oldDirectory = NULL;
1410 if (result == B_OK) {
1411 Node* node = volume->GetNode(request->oldDirectoryID);
1412 if (node) {
1413 oldDirectory = dynamic_cast<Directory*>(node);
1414 if (!oldDirectory)
1415 result = B_NOT_A_DIRECTORY;
1416 } else
1417 result = B_ENTRY_NOT_FOUND;
1418 }
1419
1420 // check permissions
1421 if (result == B_OK) {
1422 if (!volume->GetNodePermissions(oldDirectory).ImpliesWritePermission())
1423 result = B_PERMISSION_DENIED;
1424 }
1425
1426 // get the new path
1427 Path oldPath;
1428 if (result == B_OK) {
1429 result = oldDirectory->GetPath(&oldPath);
1430 if (result == B_OK)
1431 result = oldPath.Append(request->oldName.GetString());
1432 }
1433
1434 managerLocker.Unlock();
1435
1436 // rename the entry
1437 if (result == B_OK) {
1438 if (rename(oldPath.GetPath(), newPath.GetPath()) < 0)
1439 result = errno;
1440 }
1441
1442 // prepare the reply
1443 RenameReply reply;
1444 // send the reply
1445 reply.error = result;
1446 return GetChannel()->SendRequest(&reply);
1447 }
1448
1449 // VisitMakeDirRequest
1450 status_t
VisitMakeDirRequest(MakeDirRequest * request)1451 ClientConnection::VisitMakeDirRequest(MakeDirRequest* request)
1452 {
1453 ConnectionReference connectionReference(this);
1454 if (!connectionReference.IsValid())
1455 return B_OK;
1456
1457 // get the volume
1458 status_t result = B_OK;
1459 ClientVolume* volume = _GetVolume(request->volumeID);
1460 if (!volume)
1461 result = B_BAD_VALUE;
1462 ClientVolumePutter volumePutter(this, volume);
1463
1464 VolumeManagerLocker managerLocker;
1465
1466 // get the directory
1467 Directory* directory = NULL;
1468 if (result == B_OK) {
1469 Node* node = volume->GetNode(request->directoryID);
1470 if (node) {
1471 directory = dynamic_cast<Directory*>(node);
1472 if (!directory)
1473 result = B_NOT_A_DIRECTORY;
1474 } else
1475 result = B_ENTRY_NOT_FOUND;
1476 }
1477
1478 // check permissions
1479 if (result == B_OK) {
1480 if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1481 result = B_PERMISSION_DENIED;
1482 }
1483
1484 // get the path
1485 Path path;
1486 if (result == B_OK) {
1487 result = directory->GetPath(&path);
1488 if (result == B_OK)
1489 result = path.Append(request->name.GetString());
1490 }
1491
1492 managerLocker.Unlock();
1493
1494 // create the directory
1495 if (result == B_OK) {
1496 if (mkdir(path.GetPath(), request->mode) < 0)
1497 result = errno;
1498 }
1499
1500 // prepare the reply
1501 MakeDirReply reply;
1502 // send the reply
1503 reply.error = result;
1504 return GetChannel()->SendRequest(&reply);
1505 }
1506
1507 // VisitRemoveDirRequest
1508 status_t
VisitRemoveDirRequest(RemoveDirRequest * request)1509 ClientConnection::VisitRemoveDirRequest(RemoveDirRequest* request)
1510 {
1511 ConnectionReference connectionReference(this);
1512 if (!connectionReference.IsValid())
1513 return B_OK;
1514
1515 // get the volume
1516 status_t result = B_OK;
1517 ClientVolume* volume = _GetVolume(request->volumeID);
1518 if (!volume)
1519 result = B_BAD_VALUE;
1520 ClientVolumePutter volumePutter(this, volume);
1521
1522 VolumeManagerLocker managerLocker;
1523
1524 // get the directory
1525 Directory* directory = NULL;
1526 if (result == B_OK) {
1527 Node* node = volume->GetNode(request->directoryID);
1528 if (node) {
1529 directory = dynamic_cast<Directory*>(node);
1530 if (!directory)
1531 result = B_NOT_A_DIRECTORY;
1532 } else
1533 result = B_ENTRY_NOT_FOUND;
1534 }
1535
1536 // check permissions
1537 if (result == B_OK) {
1538 if (!volume->GetNodePermissions(directory).ImpliesWritePermission())
1539 result = B_PERMISSION_DENIED;
1540 }
1541
1542 // get the path
1543 Path path;
1544 if (result == B_OK) {
1545 result = directory->GetPath(&path);
1546 if (result == B_OK)
1547 result = path.Append(request->name.GetString());
1548 }
1549
1550 managerLocker.Unlock();
1551
1552 // remove the directory
1553 if (result == B_OK) {
1554 if (rmdir(path.GetPath()) < 0)
1555 result = errno;
1556 }
1557
1558 // prepare the reply
1559 RemoveDirReply reply;
1560 // send the reply
1561 reply.error = result;
1562 return GetChannel()->SendRequest(&reply);
1563 }
1564
1565 // VisitOpenDirRequest
1566 status_t
VisitOpenDirRequest(OpenDirRequest * request)1567 ClientConnection::VisitOpenDirRequest(OpenDirRequest* request)
1568 {
1569 ConnectionReference connectionReference(this);
1570 if (!connectionReference.IsValid())
1571 return B_OK;
1572
1573 // get the volume
1574 status_t result = B_OK;
1575 ClientVolume* volume = _GetVolume(request->volumeID);
1576 if (!volume)
1577 result = B_BAD_VALUE;
1578 ClientVolumePutter volumePutter(this, volume);
1579
1580 VolumeManagerLocker managerLocker;
1581
1582 // get the directory
1583 Directory* directory = NULL;
1584 if (result == B_OK) {
1585 Node* node = volume->GetNode(request->nodeID);
1586 if (node) {
1587 directory = dynamic_cast<Directory*>(node);
1588 if (!directory)
1589 result = B_NOT_A_DIRECTORY;
1590 } else
1591 result = B_ENTRY_NOT_FOUND;
1592 }
1593
1594 // check permission
1595 if (result == B_OK) {
1596 if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission())
1597 result = B_PERMISSION_DENIED;
1598 }
1599
1600 // open the directory
1601 DirIterator* handle = NULL;
1602 if (result == B_OK)
1603 result = volume->OpenDir(directory, &handle);
1604 NodeHandleUnlocker handleUnlocker(volume, handle);
1605
1606 // prepare the reply
1607 OpenDirReply reply;
1608 if (result == B_OK) {
1609 _GetNodeInfo(directory, &reply.nodeInfo);
1610 reply.cookie = handle->GetCookie();
1611 } else {
1612 if (directory != NULL) {
1613 PRINT("OpenDir() failed: client volume: %" B_PRId32 ", "
1614 "node: (%" B_PRIdDEV ", %" B_PRIdINO ")\n",
1615 volume->GetID(), directory->GetVolumeID(), directory->GetID());
1616 }
1617 }
1618
1619 managerLocker.Unlock();
1620
1621 // send the reply
1622 reply.error = result;
1623 status_t error = GetChannel()->SendRequest(&reply);
1624
1625 // close the handle, if a send error occurred
1626 if (error != B_OK && result == B_OK)
1627 volume->Close(handle);
1628
1629 return error;
1630 }
1631
1632 // VisitReadDirRequest
1633 status_t
VisitReadDirRequest(ReadDirRequest * request)1634 ClientConnection::VisitReadDirRequest(ReadDirRequest* request)
1635 {
1636 ConnectionReference connectionReference(this);
1637 if (!connectionReference.IsValid())
1638 return B_OK;
1639
1640 // get the volume
1641 status_t result = B_OK;
1642 ClientVolume* volume = _GetVolume(request->volumeID);
1643 if (!volume)
1644 result = B_BAD_VALUE;
1645 ClientVolumePutter volumePutter(this, volume);
1646
1647 // get the node handle
1648 NodeHandle* handle = NULL;
1649 if (result == B_OK)
1650 result = volume->LockNodeHandle(request->cookie, &handle);
1651 NodeHandleUnlocker handleUnlocker(volume, handle);
1652
1653 // check if it is a directory iterator
1654 DirIterator* iterator = NULL;
1655 if (result == B_OK) {
1656 iterator = dynamic_cast<DirIterator*>(handle);
1657 if (!iterator)
1658 result = B_BAD_VALUE;
1659 }
1660
1661 VolumeManagerLocker managerLocker;
1662
1663 // get the directory
1664 Directory* directory = NULL;
1665 if (result == B_OK) {
1666 Node* node = volume->GetNode(iterator->GetNodeRef());
1667 if (node) {
1668 directory = dynamic_cast<Directory*>(node);
1669 if (!directory)
1670 result = B_NOT_A_DIRECTORY;
1671 } else
1672 result = B_ENTRY_NOT_FOUND;
1673 }
1674
1675 // check read permission
1676 if (result == B_OK) {
1677 if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission())
1678 result = B_PERMISSION_DENIED;
1679 }
1680
1681 if (result == B_OK) {
1682 PRINT("ReadDir: (%" B_PRId32 ", %" B_PRIdINO ")\n", request->volumeID,
1683 directory->GetID());
1684 }
1685
1686 // rewind, if requested
1687 if (result == B_OK && request->rewind)
1688 iterator->Rewind();
1689
1690 // read the directory
1691 bool done = false;
1692 ReadDirReply reply;
1693 int32 toRead = request->count;
1694 while (result == B_OK && toRead > 0) {
1695 // get the next entry
1696 Entry* entry = iterator->NextEntry();
1697 if (!entry) {
1698 done = true;
1699 break;
1700 }
1701
1702 // get and add an entry info
1703 EntryInfo entryInfo;
1704 _GetEntryInfo(entry, &entryInfo);
1705 result = reply.entryInfos.Append(entryInfo);
1706
1707 toRead--;
1708 }
1709
1710 reply.revision = VolumeManager::GetDefault()->GetRevision();
1711
1712 //PRINT(("ReadDir: (%lld) -> (%lx, %ld, dir: %lld, node: %lld, `%s')\n",
1713 //directoryID, reply.error, reply.entryInfos.CountElements(),
1714 //reply.entryInfo.directoryID,
1715 //reply.entryInfo.nodeID, reply.entryInfo.name.GetString()));
1716 if (directory != NULL) {
1717 PRINT("ReadDir done: volume: %" B_PRId32 ", "
1718 "(%" B_PRIdDEV ", %" B_PRIdINO ") -> "
1719 "(%" B_PRIx32 ", %" B_PRId32 ")\n",
1720 volume->GetID(), directory->GetVolumeID(), directory->GetID(),
1721 result, reply.entryInfos.CountElements());
1722 }
1723
1724 managerLocker.Unlock();
1725
1726 // send the reply
1727 reply.error = result;
1728 reply.done = (result != B_OK || done);
1729 return GetChannel()->SendRequest(&reply);
1730 }
1731
1732 // VisitWalkRequest
1733 status_t
VisitWalkRequest(WalkRequest * request)1734 ClientConnection::VisitWalkRequest(WalkRequest* request)
1735 {
1736 ConnectionReference connectionReference(this);
1737 if (!connectionReference.IsValid())
1738 return B_OK;
1739
1740 // get the volume
1741 status_t result = B_OK;
1742 ClientVolume* volume = _GetVolume(request->volumeID);
1743 if (!volume)
1744 result = B_BAD_VALUE;
1745 ClientVolumePutter volumePutter(this, volume);
1746
1747 VolumeManagerLocker managerLocker;
1748
1749 // get the directory
1750 Directory* directory = NULL;
1751 if (result == B_OK) {
1752 Node* node = volume->GetNode(request->nodeID);
1753 if (node) {
1754 directory = dynamic_cast<Directory*>(node);
1755 if (!directory)
1756 result = B_NOT_A_DIRECTORY;
1757 } else
1758 result = B_ENTRY_NOT_FOUND;
1759 }
1760
1761 // check permission
1762 if (result == B_OK) {
1763 if (!volume->GetNodePermissions(directory)
1764 .ImpliesResolveDirEntryPermission()) {
1765 result = B_PERMISSION_DENIED;
1766 }
1767 }
1768
1769 WalkReply reply;
1770 char linkPath[B_PATH_NAME_LENGTH];
1771 if (result == B_OK) {
1772 // load the entry
1773 Entry* entry;
1774 result = volume->LoadEntry(directory, request->name.GetString(),
1775 &entry);
1776
1777 // fill in the reply
1778 if (result == B_OK) {
1779 _GetEntryInfo(entry, &reply.entryInfo);
1780
1781 // resolve a symlink, if desired
1782 Node* node = entry->GetNode();
1783 if (request->resolveLink && node->IsSymlink()) {
1784 result = node->ReadSymlink(linkPath, B_PATH_NAME_LENGTH);
1785 if (result == B_OK)
1786 reply.linkPath.SetTo(linkPath);
1787 }
1788 }
1789 }
1790
1791 managerLocker.Unlock();
1792
1793 // send the reply
1794 reply.error = result;
1795 PRINT("Walk: (%" B_PRIdDEV ", %" B_PRIdINO ", `%s') -> "
1796 "(%" B_PRIx32 ", (%" B_PRIdDEV ", %" B_PRIdINO "), `%s')\n",
1797 request->nodeID.volumeID, request->nodeID.nodeID,
1798 request->name.GetString(), result,
1799 reply.entryInfo.nodeInfo.st.st_dev,
1800 reply.entryInfo.nodeInfo.st.st_ino, reply.linkPath.GetString());
1801 return GetChannel()->SendRequest(&reply);
1802 }
1803
1804 // VisitMultiWalkRequest
1805 status_t
VisitMultiWalkRequest(MultiWalkRequest * request)1806 ClientConnection::VisitMultiWalkRequest(MultiWalkRequest* request)
1807 {
1808 ConnectionReference connectionReference(this);
1809 if (!connectionReference.IsValid())
1810 return B_OK;
1811
1812 // get the volume
1813 status_t result = B_OK;
1814 ClientVolume* volume = _GetVolume(request->volumeID);
1815 if (!volume)
1816 result = B_BAD_VALUE;
1817 ClientVolumePutter volumePutter(this, volume);
1818
1819 VolumeManagerLocker managerLocker;
1820
1821 // get the directory
1822 Directory* directory = NULL;
1823 if (result == B_OK) {
1824 Node* node = volume->GetNode(request->nodeID);
1825 if (node) {
1826 directory = dynamic_cast<Directory*>(node);
1827 if (!directory)
1828 result = B_NOT_A_DIRECTORY;
1829 } else
1830 result = B_ENTRY_NOT_FOUND;
1831 }
1832
1833 // check permission
1834 if (result == B_OK) {
1835 if (!volume->GetNodePermissions(directory)
1836 .ImpliesResolveDirEntryPermission()) {
1837 result = B_PERMISSION_DENIED;
1838 }
1839 }
1840
1841 MultiWalkReply reply;
1842 StringData* names = request->names.GetElements();
1843 int32 count = request->names.CountElements();
1844 for (int32 i = 0; result == B_OK && i < count; i++) {
1845 // load the entry
1846 Entry* entry;
1847 if (volume->LoadEntry(directory, names[i].GetString(), &entry)
1848 == B_OK) {
1849 // add an entry info
1850 EntryInfo entryInfo;
1851 _GetEntryInfo(entry, &entryInfo);
1852
1853 // append the info
1854 result = reply.entryInfos.Append(entryInfo);
1855 }
1856 }
1857
1858 managerLocker.Unlock();
1859
1860 // send the reply
1861 reply.error = result;
1862 PRINT("MultiWalk: (%" B_PRIdDEV ", %" B_PRIdINO ", %" B_PRId32 ") -> "
1863 "(%" B_PRIx32 ", %" B_PRId32 ")\n",
1864 request->nodeID.volumeID, request->nodeID.nodeID, count,
1865 result, reply.entryInfos.CountElements());
1866 return GetChannel()->SendRequest(&reply);
1867 }
1868
1869 // VisitOpenAttrDirRequest
1870 status_t
VisitOpenAttrDirRequest(OpenAttrDirRequest * request)1871 ClientConnection::VisitOpenAttrDirRequest(OpenAttrDirRequest* request)
1872 {
1873 ConnectionReference connectionReference(this);
1874 if (!connectionReference.IsValid())
1875 return B_OK;
1876
1877 // get the volume
1878 status_t result = B_OK;
1879 ClientVolume* volume = _GetVolume(request->volumeID);
1880 if (!volume)
1881 result = B_BAD_VALUE;
1882 ClientVolumePutter volumePutter(this, volume);
1883
1884 VolumeManagerLocker managerLocker;
1885
1886 // get the node
1887 Node* node = NULL;
1888 if (result == B_OK) {
1889 node = volume->GetNode(request->nodeID);
1890 if (!node)
1891 result = B_ENTRY_NOT_FOUND;
1892 }
1893
1894 // check permission
1895 if (result == B_OK) {
1896 if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1897 result = B_PERMISSION_DENIED;
1898 }
1899
1900 // load/cache the attribute directory
1901 bool attrDirCached = (node->LoadAttrDir() == B_OK);
1902
1903 // open the attribute directory, if caching it failed
1904 AttrDirIterator* handle = NULL;
1905 if (result == B_OK && !attrDirCached)
1906 result = volume->OpenAttrDir(node, &handle);
1907 NodeHandleUnlocker handleUnlocker(volume, handle);
1908
1909 // prepare the reply
1910 OpenAttrDirReply reply;
1911 if (result == B_OK) {
1912 if (handle) {
1913 reply.cookie = handle->GetCookie();
1914 } else {
1915 // the attribute directory is cached
1916 reply.cookie = -1;
1917 result = _GetAttrDirInfo(request, node, &reply.attrDirInfo);
1918 }
1919 }
1920
1921 managerLocker.Unlock();
1922
1923 // send the reply
1924 reply.error = result;
1925 status_t error = GetChannel()->SendRequest(&reply);
1926
1927 // close the handle, if a send error occurred
1928 if (error != B_OK && result == B_OK && handle)
1929 volume->Close(handle);
1930
1931 return error;
1932 }
1933
1934 // VisitReadAttrDirRequest
1935 status_t
VisitReadAttrDirRequest(ReadAttrDirRequest * request)1936 ClientConnection::VisitReadAttrDirRequest(ReadAttrDirRequest* request)
1937 {
1938 ConnectionReference connectionReference(this);
1939 if (!connectionReference.IsValid())
1940 return B_OK;
1941
1942 // get the volume
1943 status_t result = B_OK;
1944 ClientVolume* volume = _GetVolume(request->volumeID);
1945 if (!volume)
1946 result = B_BAD_VALUE;
1947 ClientVolumePutter volumePutter(this, volume);
1948
1949 // get the node handle
1950 NodeHandle* handle = NULL;
1951 if (result == B_OK)
1952 result = volume->LockNodeHandle(request->cookie, &handle);
1953 NodeHandleUnlocker handleUnlocker(volume, handle);
1954
1955 // check if it is a attribute directory iterator
1956 AttrDirIterator* iterator = NULL;
1957 if (result == B_OK) {
1958 iterator = dynamic_cast<AttrDirIterator*>(handle);
1959 if (!iterator)
1960 result = B_BAD_VALUE;
1961 }
1962
1963 VolumeManagerLocker managerLocker;
1964
1965 // get the node
1966 Node* node = NULL;
1967 if (result == B_OK) {
1968 node = volume->GetNode(iterator->GetNodeRef());
1969 if (!node)
1970 result = B_ENTRY_NOT_FOUND;
1971 }
1972
1973 // check read permission (we already checked when opening, but anyway...)
1974 if (result == B_OK) {
1975 if (!volume->GetNodePermissions(node).ImpliesReadPermission())
1976 result = B_PERMISSION_DENIED;
1977 }
1978
1979 managerLocker.Unlock();
1980
1981 // read the attribute directory
1982 uint8 buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH];
1983 struct dirent* dirEntry = (struct dirent*)buffer;
1984 int32 countRead = 0;
1985 bool done = true;
1986 if (result == B_OK) {
1987 if (request->rewind)
1988 result = iterator->RewindDir();
1989 if (result == B_OK) {
1990 result = iterator->ReadDir(dirEntry, sizeof(buffer), 1,
1991 &countRead, &done);
1992 }
1993 }
1994
1995 // prepare the reply
1996 ReadAttrDirReply reply;
1997 reply.name.SetTo(dirEntry->d_name);
1998
1999 // send the reply
2000 reply.error = result;
2001 reply.count = countRead;
2002 return GetChannel()->SendRequest(&reply);
2003 }
2004
2005 // VisitReadAttrRequest
2006 status_t
VisitReadAttrRequest(ReadAttrRequest * request)2007 ClientConnection::VisitReadAttrRequest(ReadAttrRequest* request)
2008 {
2009 ConnectionReference connectionReference(this);
2010 if (!connectionReference.IsValid())
2011 return B_OK;
2012
2013 // get the volume
2014 status_t result = B_OK;
2015 ClientVolume* volume = _GetVolume(request->volumeID);
2016 if (!volume)
2017 result = B_BAD_VALUE;
2018 ClientVolumePutter volumePutter(this, volume);
2019
2020 VolumeManagerLocker managerLocker;
2021
2022 // get the node
2023 Node* node = NULL;
2024 if (result == B_OK) {
2025 node = volume->GetNode(request->nodeID);
2026 if (!node)
2027 result = B_ENTRY_NOT_FOUND;
2028 }
2029
2030 // check read permission
2031 if (result == B_OK) {
2032 if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2033 result = B_PERMISSION_DENIED;
2034 }
2035
2036 // open the node
2037 FileHandle* handle = NULL;
2038 if (result == B_OK)
2039 result = volume->Open(node, O_RDONLY, &handle);
2040 NodeHandleUnlocker handleUnlocker(volume, handle);
2041
2042 managerLocker.Unlock();
2043
2044 // read the attribute
2045 if (result == B_OK) {
2046 // Due to a bug in BFS the `pos' is ignored. This means that the loop
2047 // below won't work if the attribute is non-empty and the buffer is
2048 // larger than the attribute, because the we would again and again
2049 // read the beginning of the attribute until the buffer is full.
2050 // Hence we first get an attr_info and don't try to read more than
2051 // the size of the attribute.
2052 attr_info info;
2053 result = handle->StatAttr(request->name.GetString(), &info);
2054 off_t originalPos = max(request->pos, (off_t)0);
2055 int32 originalSize = max(request->size, (int32)0);
2056 off_t pos = originalPos;
2057 int32 size = originalSize;
2058 type_code type = B_SWAP_INT32(request->type);
2059 bool convert = false;
2060
2061 if (result == B_OK) {
2062 originalSize = min((off_t)originalSize, max((off_t)0, info.size - pos));
2063 size = originalSize;
2064
2065 // deal with inverse endianess clients
2066 if (fInverseClientEndianess) {
2067 convert = _KnownAttributeType(info.type);
2068 if (convert) {
2069 // read the whole attribute
2070 pos = 0;
2071 size = info.size;
2072 } else
2073 type = B_SWAP_INT32(request->type);
2074 }
2075 }
2076 int32 bufferSize = min(size, kMaxReadBufferSize);
2077
2078 // allocate a buffer
2079 uint8* buffer = NULL;
2080 if (result == B_OK) {
2081 buffer = (uint8*)malloc(bufferSize);
2082 if (!buffer)
2083 result = B_NO_MEMORY;
2084 }
2085 MemoryDeleter bufferDeleter(buffer);
2086
2087 if (convert) {
2088 // read the whole attribute and convert it
2089 if (result == B_OK) {
2090 // read
2091 size_t bytesRead = 0;
2092 result = handle->ReadAttr(request->name.GetString(),
2093 type, 0, buffer, size, &bytesRead);
2094 if (result == B_OK && (int32)bytesRead != size)
2095 result = B_ERROR;
2096
2097 // convert
2098 if (result == B_OK)
2099 _ConvertAttribute(info, buffer);
2100 }
2101
2102 // prepare the reply
2103 ReadAttrReply reply;
2104 if (result == B_OK) {
2105 reply.pos = originalPos;
2106 reply.data.SetTo(buffer + originalPos, originalSize);
2107 reply.moreToCome = false;
2108 }
2109
2110 // send the reply
2111 reply.error = result;
2112 status_t error = GetChannel()->SendRequest(&reply);
2113 if (error != B_OK)
2114 return error;
2115 } else {
2116 // read as long as there are bytes left to read or an error occurs
2117 bool moreToRead = true;
2118 do {
2119 int32 bytesToRead = min(size, bufferSize);
2120 size_t bytesRead = 0;
2121 if (result == B_OK) {
2122 result = handle->ReadAttr(request->name.GetString(),
2123 request->type, pos, buffer, bytesToRead, &bytesRead);
2124 }
2125 moreToRead = (result == B_OK && bytesRead > 0
2126 && (int32)bytesRead < size);
2127
2128 // prepare the reply
2129 ReadAttrReply reply;
2130 if (result == B_OK) {
2131 reply.pos = pos;
2132 reply.data.SetTo(buffer, bytesRead);
2133 reply.moreToCome = moreToRead;
2134 pos += bytesRead;
2135 size -= bytesRead;
2136 }
2137
2138 // send the reply
2139 reply.error = result;
2140 status_t error = GetChannel()->SendRequest(&reply);
2141 if (error != B_OK)
2142 return error;
2143 } while (moreToRead);
2144 }
2145
2146 // close the handle
2147 volume->Close(handle);
2148 } else {
2149 // opening the node failed (or something even earlier): send an error
2150 // reply
2151 ReadAttrReply reply;
2152 reply.error = result;
2153 status_t error = GetChannel()->SendRequest(&reply);
2154 if (error != B_OK)
2155 return error;
2156 }
2157
2158 return B_OK;
2159 }
2160
2161 // VisitWriteAttrRequest
2162 status_t
VisitWriteAttrRequest(WriteAttrRequest * request)2163 ClientConnection::VisitWriteAttrRequest(WriteAttrRequest* request)
2164 {
2165 ConnectionReference connectionReference(this);
2166 if (!connectionReference.IsValid())
2167 return B_OK;
2168
2169 // get the volume
2170 status_t result = B_OK;
2171 ClientVolume* volume = _GetVolume(request->volumeID);
2172 if (!volume)
2173 result = B_BAD_VALUE;
2174 ClientVolumePutter volumePutter(this, volume);
2175
2176 VolumeManagerLocker managerLocker;
2177
2178 // get the node
2179 Node* node = NULL;
2180 if (result == B_OK) {
2181 node = volume->GetNode(request->nodeID);
2182 if (!node)
2183 result = B_ENTRY_NOT_FOUND;
2184 }
2185
2186 // check read permission
2187 if (result == B_OK) {
2188 if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2189 result = B_PERMISSION_DENIED;
2190 }
2191
2192 // open the node
2193 FileHandle* handle = NULL;
2194 if (result == B_OK)
2195 result = volume->Open(node, O_RDWR, &handle);
2196 NodeHandleUnlocker handleUnlocker(volume, handle);
2197
2198 managerLocker.Unlock();
2199
2200 if (result == B_OK) {
2201 off_t pos = max(request->pos, (off_t)0);
2202 int32 size = request->data.GetSize();
2203 type_code type = request->type;
2204 char* buffer = (char*)request->data.GetData();
2205
2206 // convert the data, if necessary
2207 if (fInverseClientEndianess) {
2208 if (_KnownAttributeType(type)) {
2209 if (pos != 0) {
2210 WARN("WriteAttr(): WARNING: Need to convert attribute "
2211 "endianess, but position is not 0: attribute: %s, "
2212 "pos: %" B_PRIdOFF ", size: %" B_PRId32 "\n",
2213 request->name.GetString(), pos, size);
2214 }
2215 swap_data(type, buffer, size, B_SWAP_ALWAYS);
2216 } else
2217 type = B_SWAP_INT32(type);
2218 }
2219
2220 // write the data
2221 while (result == B_OK && size > 0) {
2222 size_t bytesWritten;
2223 result = handle->WriteAttr(request->name.GetString(),
2224 type, pos, buffer, size, &bytesWritten);
2225 if (result == B_OK) {
2226 pos += bytesWritten;
2227 buffer += bytesWritten;
2228 size -= bytesWritten;
2229 }
2230 }
2231
2232 // close the handle
2233 volume->Close(handle);
2234 }
2235
2236 // prepare the reply
2237 WriteAttrReply reply;
2238 // send the reply
2239 reply.error = result;
2240 return GetChannel()->SendRequest(&reply);
2241 }
2242
2243 // VisitRemoveAttrRequest
2244 status_t
VisitRemoveAttrRequest(RemoveAttrRequest * request)2245 ClientConnection::VisitRemoveAttrRequest(RemoveAttrRequest* request)
2246 {
2247 ConnectionReference connectionReference(this);
2248 if (!connectionReference.IsValid())
2249 return B_OK;
2250
2251 // get the volume
2252 status_t result = B_OK;
2253 ClientVolume* volume = _GetVolume(request->volumeID);
2254 if (!volume)
2255 result = B_BAD_VALUE;
2256 ClientVolumePutter volumePutter(this, volume);
2257
2258 VolumeManagerLocker managerLocker;
2259
2260 // get the node
2261 Node* node = NULL;
2262 if (result == B_OK) {
2263 node = volume->GetNode(request->nodeID);
2264 if (!node)
2265 result = B_ENTRY_NOT_FOUND;
2266 }
2267
2268 // check read permission
2269 if (result == B_OK) {
2270 if (!volume->GetNodePermissions(node).ImpliesWritePermission())
2271 result = B_PERMISSION_DENIED;
2272 }
2273
2274 // open the node
2275 FileHandle* handle = NULL;
2276 if (result == B_OK)
2277 result = volume->Open(node, O_RDWR, &handle);
2278 NodeHandleUnlocker handleUnlocker(volume, handle);
2279
2280 managerLocker.Unlock();
2281
2282 // remove the attribute and close the node
2283 if (result == B_OK) {
2284 result = handle->RemoveAttr(request->name.GetString());
2285 volume->Close(handle);
2286 }
2287
2288 // send the reply
2289 RemoveAttrReply reply;
2290 reply.error = result;
2291 return GetChannel()->SendRequest(&reply);
2292 }
2293
2294 // VisitRenameAttrRequest
2295 status_t
VisitRenameAttrRequest(RenameAttrRequest * request)2296 ClientConnection::VisitRenameAttrRequest(RenameAttrRequest* request)
2297 {
2298 // Not supported, since there's no API function to rename an attribute.
2299 // send the reply
2300 RemoveAttrReply reply;
2301 reply.error = B_UNSUPPORTED;
2302 return GetChannel()->SendRequest(&reply);
2303 }
2304
2305 // VisitStatAttrRequest
2306 status_t
VisitStatAttrRequest(StatAttrRequest * request)2307 ClientConnection::VisitStatAttrRequest(StatAttrRequest* request)
2308 {
2309 ConnectionReference connectionReference(this);
2310 if (!connectionReference.IsValid())
2311 return B_OK;
2312
2313 // get the volume
2314 status_t result = B_OK;
2315 ClientVolume* volume = _GetVolume(request->volumeID);
2316 if (!volume)
2317 result = B_BAD_VALUE;
2318 ClientVolumePutter volumePutter(this, volume);
2319
2320 VolumeManagerLocker managerLocker;
2321
2322 // get the node
2323 Node* node = NULL;
2324 if (result == B_OK) {
2325 node = volume->GetNode(request->nodeID);
2326 if (!node)
2327 result = B_ENTRY_NOT_FOUND;
2328 }
2329
2330 // check read permission
2331 if (result == B_OK) {
2332 if (!volume->GetNodePermissions(node).ImpliesReadPermission())
2333 result = B_PERMISSION_DENIED;
2334 }
2335
2336 // open the node
2337 FileHandle* handle = NULL;
2338 if (result == B_OK)
2339 result = volume->Open(node, O_RDONLY, &handle);
2340 NodeHandleUnlocker handleUnlocker(volume, handle);
2341
2342 managerLocker.Unlock();
2343
2344 // stat the attribute and close the node
2345 attr_info attrInfo;
2346 StatAttrReply reply;
2347 if (result == B_OK) {
2348 result = handle->StatAttr(request->name.GetString(), &attrInfo);
2349 volume->Close(handle);
2350 }
2351
2352 // set the attribute info
2353 if (result == B_OK) {
2354 result = _GetAttrInfo(request, request->name.GetString(), attrInfo,
2355 NULL, &reply.attrInfo);
2356 }
2357
2358 // send the reply
2359 reply.error = result;
2360 return GetChannel()->SendRequest(&reply);
2361 }
2362
2363 // VisitOpenQueryRequest
2364 status_t
VisitOpenQueryRequest(OpenQueryRequest * request)2365 ClientConnection::VisitOpenQueryRequest(OpenQueryRequest* request)
2366 {
2367 ConnectionReference connectionReference(this);
2368 if (!connectionReference.IsValid())
2369 return B_OK;
2370
2371 VolumeManagerLocker managerLocker;
2372
2373 // open the query
2374 status_t result;
2375 QueryHandle* handle = NULL;
2376 result = _OpenQuery(request->queryString.GetString(),
2377 request->flags, request->port, request->token, &handle);
2378 QueryHandleUnlocker handleUnlocker(this, handle);
2379
2380 // prepare the reply
2381 OpenQueryReply reply;
2382 if (result == B_OK)
2383 reply.cookie = handle->GetCookie();
2384
2385 managerLocker.Unlock();
2386
2387 // send the reply
2388 reply.error = result;
2389 status_t error = GetChannel()->SendRequest(&reply);
2390
2391 // close the handle, if a send error occurred
2392 if (error != B_OK && result == B_OK)
2393 _CloseQuery(handle);
2394
2395 return error;
2396 }
2397
2398 // VisitReadQueryRequest
2399 status_t
VisitReadQueryRequest(ReadQueryRequest * request)2400 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request)
2401 {
2402 ConnectionReference connectionReference(this);
2403 if (!connectionReference.IsValid())
2404 return B_OK;
2405
2406 // create an array for the IDs of the client volumes a found entry may
2407 // reside on
2408 status_t result = B_OK;
2409 int32 volumeCount = fVolumes->Size();
2410 int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2411 if (!volumeIDs)
2412 result = B_NO_MEMORY;
2413
2414 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2415
2416 // get the query handle
2417 QueryHandle* handle = NULL;
2418 if (result == B_OK)
2419 result = _LockQueryHandle(request->cookie, &handle);
2420 QueryHandleUnlocker handleUnlocker(this, handle);
2421
2422 // check if it is a query handle
2423 QueryHandle* queryHandle = NULL;
2424 if (result == B_OK) {
2425 queryHandle = dynamic_cast<QueryHandle*>(handle);
2426 if (!queryHandle)
2427 result = B_BAD_VALUE;
2428 }
2429
2430 // read the query
2431 ReadQueryReply reply;
2432 int32 countRead = 0;
2433 while (result == B_OK) {
2434 uint8 buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH];
2435 struct dirent* dirEntry = (struct dirent*)buffer;
2436
2437 result = queryHandle->ReadDir(dirEntry, 1, &countRead);
2438 if (result != B_OK)
2439 break;
2440 if (countRead == 0)
2441 break;
2442 PRINT(" query entry: %" B_PRIdDEV ", %" B_PRIdINO ", \"%s\"\n",
2443 dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name);
2444
2445 VolumeManagerLocker managerLocker;
2446 VolumeManager* volumeManager = VolumeManager::GetDefault();
2447
2448 // load the entry
2449 Entry* entry = NULL;
2450 result = volumeManager->LoadEntry(dirEntry->d_pdev,
2451 dirEntry->d_pino, dirEntry->d_name, true, &entry);
2452
2453 // if at least one client volume contains the entry, get an entry info
2454 if (result == B_OK) {
2455 HasQueryPermissionClientVolumeFilter filter;
2456 int32 entryVolumeCount = _GetContainingClientVolumes(
2457 entry->GetDirectory(), volumeIDs, volumeCount, &filter);
2458 if (entryVolumeCount > 0) {
2459 // store all the client volume IDs in the reply
2460 for (int32 i = 0; i < entryVolumeCount; i++) {
2461 result = reply.clientVolumeIDs.Append(volumeIDs[i]);
2462 if (result != B_OK)
2463 break;
2464 }
2465
2466 // get an entry info
2467 _GetNodeInfo(entry->GetDirectory(), &reply.dirInfo);
2468 _GetEntryInfo(entry, &reply.entryInfo);
2469 break;
2470 } else
2471 PRINT((" -> no client volumes\n"));
2472 }
2473
2474 // entry is not in the volume: next round...
2475 result = B_OK;
2476 }
2477
2478 // send the reply
2479 reply.error = result;
2480 reply.count = countRead;
2481 PRINT("ReadQuery: (%" B_PRIx32 ", %" B_PRId32 ", "
2482 "dir: (%" B_PRIdDEV ", %" B_PRIdINO "), "
2483 "node: (%" B_PRIdDEV ", %" B_PRIdINO ", `%s')\n",
2484 reply.error, reply.count,
2485 reply.entryInfo.directoryID.volumeID,
2486 reply.entryInfo.directoryID.nodeID,
2487 reply.entryInfo.nodeInfo.st.st_dev,
2488 reply.entryInfo.nodeInfo.st.st_ino,
2489 reply.entryInfo.name.GetString());
2490 return GetChannel()->SendRequest(&reply);
2491 }
2492
2493
2494 // #pragma mark -
2495
2496 // ProcessNodeMonitoringEvent
2497 void
ProcessNodeMonitoringEvent(int32 volumeID,NodeMonitoringEvent * event)2498 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID,
2499 NodeMonitoringEvent* event)
2500 {
2501 // get a connection reference
2502 ConnectionReference connectionReference(this);
2503 if (!connectionReference.IsValid())
2504 return;
2505
2506 _PushNodeMonitoringEvent(volumeID, event);
2507 }
2508
2509 // CloseNodeMonitoringEventQueue
2510 void
CloseNodeMonitoringEventQueue()2511 ClientConnection::CloseNodeMonitoringEventQueue()
2512 {
2513 typedef Vector<NodeMonitoringRequest*> RequestVector;
2514 const RequestVector* requests = NULL;
2515 if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) {
2516 for (RequestVector::ConstIterator it = requests->Begin();
2517 it != requests->End();
2518 it++) {
2519 delete *it;
2520 }
2521 }
2522 }
2523
2524
2525 // #pragma mark -
2526
2527 // QueryDomainIntersectsWith
2528 bool
QueryDomainIntersectsWith(Volume * volume)2529 ClientConnection::QueryDomainIntersectsWith(Volume* volume)
2530 {
2531 // Iterate through the the client volumes and check whether any one contains
2532 // the supplied volume or its root dir is on the volume. We don't check
2533 // directory inclusion for the latter, since we don't need to query the
2534 // volume, if the client volume is located on a volume mounted somewhere
2535 // under the supplied volume (e.g. the root FS contains everything, but does
2536 // seldomly need to be queried).
2537 VolumeManager* volumeManager = VolumeManager::GetDefault();
2538 AutoLocker<VolumeMap> volumesLocker(fVolumes);
2539 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2540 ClientVolume* clientVolume = it.Next().value;
2541 Directory* volumeRoot = volume->GetRootDirectory();
2542 Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
2543 if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true)
2544 || volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) {
2545 return true;
2546 }
2547 }
2548
2549 return false;
2550 }
2551
2552 // ProcessQueryEvent
2553 void
ProcessQueryEvent(NodeMonitoringEvent * event)2554 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event)
2555 {
2556 dev_t volumeID;
2557 ino_t directoryID;
2558 if (event->opcode == B_ENTRY_CREATED) {
2559 // "entry created" event
2560 EntryCreatedEvent* createdEvent
2561 = dynamic_cast<EntryCreatedEvent*>(event);
2562 if (!createdEvent)
2563 return;
2564 volumeID = createdEvent->volumeID;
2565 directoryID = createdEvent->directoryID;
2566
2567 } else if (event->opcode == B_ENTRY_REMOVED) {
2568 // "entry removed" event
2569 EntryRemovedEvent* removedEvent
2570 = dynamic_cast<EntryRemovedEvent*>(event);
2571 if (!removedEvent)
2572 return;
2573 volumeID = removedEvent->volumeID;
2574 directoryID = removedEvent->directoryID;
2575
2576 } else {
2577 // We only support "entry created" and "entry removed" query events.
2578 // "entry moved" is split by the volume manager into those.
2579 ERROR("Ignoring unexpected query event: opcode: 0x%" B_PRIx32 "\n",
2580 event->opcode);
2581 return;
2582 }
2583 PRINT("ClientConnection::ProcessQueryEvent(): event: %p, type: %s:"
2584 " directory: (%" B_PRIdDEV ", %" B_PRIdINO ")\n",
2585 event, typeid(event).name(), volumeID, directoryID);
2586
2587 // create an array for the IDs of the client volumes a found entry may
2588 // reside on
2589 int32 volumeCount = fVolumes->Size();
2590 int32* volumeIDs = new(std::nothrow) int32[volumeCount];
2591 if (!volumeIDs)
2592 return;
2593
2594 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs);
2595
2596 HasQueryPermissionClientVolumeFilter filter;
2597
2598 // load the directory the concerned entry belongs/belonged to
2599 Directory* directory;
2600 int32 concernedVolumes = 0;
2601 if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID,
2602 &directory) == B_OK) {
2603 // find out, which client volumes the directory is located in
2604 concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs,
2605 volumeCount, &filter);
2606 } else {
2607 // Failed to load the directory, so maybe it has already been
2608 // deleted. For "entry removed" events, we consider all client
2609 // volumes to be notified -- those that don't know the entry will
2610 // ignore the event.
2611 if (event->opcode == B_ENTRY_REMOVED) {
2612 concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount,
2613 &filter);
2614 }
2615 }
2616
2617 // now push the event for each concerned client volume
2618 for (int32 i = 0; i < concernedVolumes; i++)
2619 _PushNodeMonitoringEvent(volumeIDs[i], event);
2620 // TODO: More than one volume will usually only be concerned in case of
2621 // nested client volumes. We could optimize the case by having an array of
2622 // volume IDs in the respective requests sent over the net (just as in the
2623 // ReadQueryReply).
2624 }
2625
2626
2627 // #pragma mark -
2628
2629 // _Close
2630 void
_Close()2631 ClientConnection::_Close()
2632 {
2633 // terminate node monitoring processor
2634 CloseNodeMonitoringEventQueue();
2635 if (fNodeMonitoringProcessor >= 0
2636 && find_thread(NULL) != fNodeMonitoringProcessor) {
2637 int32 result;
2638 wait_for_thread(fNodeMonitoringProcessor, &result);
2639 // The variable is not unset, when this is the node monitoring
2640 // processor thread -- which is good, since the destructor will
2641 // wait for the thread in this case.
2642 fNodeMonitoringProcessor = -1;
2643 }
2644 if (fConnection)
2645 fConnection->Close();
2646 // notify the listener
2647 ClientConnectionListener* listener = fListener;
2648 fListener = NULL;
2649 if (listener)
2650 listener->ClientConnectionClosed(this, fError);
2651 }
2652
2653 // _MarkClosed
2654 void
_MarkClosed(bool error)2655 ClientConnection::_MarkClosed(bool error)
2656 {
2657 AutoLocker<Locker> _(fLock);
2658 if (!fClosed) {
2659 fClosed = true;
2660 fError = error;
2661 }
2662 }
2663
2664 // _GetNodeInfo
2665 void
_GetNodeInfo(Node * node,NodeInfo * info)2666 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info)
2667 {
2668 if (node && info) {
2669 info->st = node->GetStat();
2670 info->revision = VolumeManager::GetDefault()->GetRevision();
2671 }
2672 }
2673
2674 // _GetEntryInfo
2675 void
_GetEntryInfo(Entry * entry,EntryInfo * info)2676 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info)
2677 {
2678 if (entry && info) {
2679 info->directoryID.volumeID = entry->GetVolumeID();
2680 info->directoryID.nodeID = entry->GetDirectoryID();
2681 info->name.SetTo(entry->GetName());
2682 _GetNodeInfo(entry->GetNode(), &info->nodeInfo);
2683 }
2684 }
2685
2686 // _GetAttrInfo
2687 status_t
_GetAttrInfo(Request * request,const char * name,const attr_info & attrInfo,const void * data,AttributeInfo * info)2688 ClientConnection::_GetAttrInfo(Request* request, const char* name,
2689 const attr_info& attrInfo, const void* data, AttributeInfo* info)
2690 {
2691 if (!request || !name || !info)
2692 return B_BAD_VALUE;
2693
2694 info->name.SetTo(name);
2695 info->info = attrInfo;
2696 data = (attrInfo.size > 0 ? data : NULL);
2697 int32 dataSize = (data ? attrInfo.size : 0);
2698 info->data.SetTo(data, dataSize);
2699
2700 // if the client has inverse endianess, swap the type, if we don't know it
2701 if (fInverseClientEndianess) {
2702 if (_KnownAttributeType(info->info.type)) {
2703 // we need to convert the data, if supplied
2704 if (data) {
2705 // allocate a buffer
2706 RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize);
2707 if (!requestBuffer)
2708 return B_NO_MEMORY;
2709
2710 // convert the data
2711 memcpy(requestBuffer->GetData(), data, dataSize);
2712 _ConvertAttribute(info->info, requestBuffer->GetData());
2713 }
2714 } else
2715 info->info.type = B_SWAP_INT32(info->info.type);
2716 }
2717
2718 return B_OK;
2719 }
2720
2721 // _GetAttrDirInfo
2722 status_t
_GetAttrDirInfo(Request * request,AttributeDirectory * attrDir,AttrDirInfo * info)2723 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir,
2724 AttrDirInfo* info)
2725 {
2726 if (!request || !attrDir || !info || !attrDir->IsAttrDirValid())
2727 return B_BAD_VALUE;
2728
2729 // add the attribute infos
2730 for (Attribute* attribute = attrDir->GetFirstAttribute();
2731 attribute;
2732 attribute = attrDir->GetNextAttribute(attribute)) {
2733 // get the attribute info
2734 AttributeInfo attrInfo;
2735 attr_info bAttrInfo;
2736 attribute->GetInfo(&bAttrInfo);
2737 status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo,
2738 attribute->GetData(), &attrInfo);
2739
2740 // append it
2741 if (error == B_OK)
2742 error = info->attributeInfos.Append(attrInfo);
2743 if (error != B_OK)
2744 return error;
2745 }
2746
2747 info->revision = VolumeManager::GetDefault()->GetRevision();
2748 info->isValid = true;
2749
2750 return B_OK;
2751 }
2752
2753 // _CreateVolume
2754 status_t
_CreateVolume(ClientVolume ** _volume)2755 ClientConnection::_CreateVolume(ClientVolume** _volume)
2756 {
2757 // create and init the volume
2758 ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock,
2759 this);
2760 if (!volume)
2761 return B_NO_MEMORY;
2762 status_t error = volume->Init();
2763 if (error != B_OK) {
2764 delete volume;
2765 return error;
2766 }
2767
2768 // add it to the volume map
2769 AutoLocker<VolumeMap> locker(fVolumes);
2770 error = fVolumes->Put(volume->GetID(), volume);
2771 locker.Unlock();
2772
2773 if (error == B_OK)
2774 *_volume = volume;
2775 else
2776 delete volume;
2777
2778 return error;
2779 }
2780
2781 // _GetVolume
2782 ClientVolume*
_GetVolume(int32 id)2783 ClientConnection::_GetVolume(int32 id)
2784 {
2785 AutoLocker<VolumeMap> _(fVolumes);
2786 ClientVolume* volume = fVolumes->Get(id);
2787 if (!volume || volume->IsRemoved())
2788 return NULL;
2789 volume->AcquireReference();
2790 return volume;
2791 }
2792
2793 // _PutVolume
2794 //
2795 // The VolumeManager may be locked, but no other lock must be held.
2796 void
_PutVolume(ClientVolume * volume)2797 ClientConnection::_PutVolume(ClientVolume* volume)
2798 {
2799 if (!volume)
2800 return;
2801
2802 // decrement reference counter and remove the volume, if 0
2803 AutoLocker<VolumeMap> locker(fVolumes);
2804 bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved());
2805 if (removed)
2806 fVolumes->Remove(volume->GetID());
2807 locker.Unlock();
2808
2809 if (removed) {
2810 VolumeManagerLocker managerLocker;
2811 delete volume;
2812 }
2813 }
2814
2815 // _UnmountVolume
2816 //
2817 // The caller must have a reference to the volume.
2818 void
_UnmountVolume(ClientVolume * volume)2819 ClientConnection::_UnmountVolume(ClientVolume* volume)
2820 {
2821 if (!volume)
2822 return;
2823 AutoLocker<VolumeMap> locker(fVolumes);
2824 volume->MarkRemoved();
2825 locker.Unlock();
2826
2827 // push a notification event
2828 if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) {
2829 VolumeManagerLocker managerLocker;
2830
2831 event->opcode = B_DEVICE_UNMOUNTED;
2832 _PushNodeMonitoringEvent(volume->GetID(), event);
2833 event->ReleaseReference();
2834 }
2835 }
2836
2837 // _UnmountAllVolumes
2838 void
_UnmountAllVolumes()2839 ClientConnection::_UnmountAllVolumes()
2840 {
2841 while (true) {
2842 // To avoid heap allocation (which can fail) we unmount the volumes
2843 // chunkwise.
2844 // get the volumes
2845 const int32 volumeChunkSize = 32;
2846 ClientVolume* volumes[volumeChunkSize];
2847 int32 volumeCount = 0;
2848 AutoLocker<VolumeMap> volumesLocker(fVolumes);
2849 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2850 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) {
2851 volumes[volumeCount++] = volume;
2852 }
2853 if (volumeCount == volumeChunkSize)
2854 break;
2855 }
2856 volumesLocker.Unlock();
2857
2858 // unmount and put the volumes
2859 for (int32 i = 0; i < volumeCount; i++) {
2860 ClientVolume* volume = volumes[i];
2861 _UnmountVolume(volume);
2862 _PutVolume(volume);
2863 }
2864
2865 if (volumeCount < volumeChunkSize)
2866 break;
2867 }
2868 }
2869
2870 // _NodeMonitoringProcessorEntry
2871 int32
_NodeMonitoringProcessorEntry(void * data)2872 ClientConnection::_NodeMonitoringProcessorEntry(void* data)
2873 {
2874 return ((ClientConnection*)data)->_NodeMonitoringProcessor();
2875 }
2876
2877
2878 // _NodeMonitoringProcessor
2879 int32
_NodeMonitoringProcessor()2880 ClientConnection::_NodeMonitoringProcessor()
2881 {
2882 while (!fClosed) {
2883 // get the next request
2884 NodeMonitoringRequest* request = NULL;
2885 status_t error = fNodeMonitoringEvents->Pop(&request);
2886
2887 // get a client connection reference
2888 ConnectionReference connectionReference(this);
2889 if (!connectionReference.IsValid())
2890 return B_OK;
2891
2892 // No request? Next round...
2893 if (error != B_OK)
2894 continue;
2895 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2896
2897 // send the request
2898 error = fConnection->SendRequest(request);
2899 if (error != B_OK) {
2900 ERROR(("ClientConnection::_NodeMonitoringProcessor(): "
2901 "Failed to send request.\n"));
2902 }
2903 }
2904 return 0;
2905 }
2906
2907
2908 // _PushNodeMonitoringEvent
2909 //
2910 // The caller must have a connection reference. Moreover the VolumeManager
2911 // must be locked.
2912 status_t
_PushNodeMonitoringEvent(int32 volumeID,NodeMonitoringEvent * event)2913 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID,
2914 NodeMonitoringEvent* event)
2915 {
2916 if (!event)
2917 return B_BAD_VALUE;
2918
2919 // get the volume
2920 ClientVolume* volume = _GetVolume(volumeID);
2921 if (!volume && event->opcode != B_DEVICE_UNMOUNTED)
2922 return B_BAD_VALUE;
2923 ClientVolumePutter volumePutter(this, volume);
2924
2925 // create a node monitoring request
2926 NodeMonitoringRequest* request = NULL;
2927 status_t error = B_ERROR;
2928 switch (event->opcode) {
2929 case B_ENTRY_CREATED:
2930 error = _EntryCreated(volume,
2931 dynamic_cast<EntryCreatedEvent*>(event), request);
2932 break;
2933 case B_ENTRY_REMOVED:
2934 error = _EntryRemoved(volume,
2935 dynamic_cast<EntryRemovedEvent*>(event), request);
2936 break;
2937 case B_ENTRY_MOVED:
2938 error = _EntryMoved(volume,
2939 dynamic_cast<EntryMovedEvent*>(event), request);
2940 break;
2941 case B_STAT_CHANGED:
2942 error = _NodeStatChanged(volume,
2943 dynamic_cast<StatChangedEvent*>(event), request);
2944 break;
2945 case B_ATTR_CHANGED:
2946 error = _NodeAttributeChanged(volume,
2947 dynamic_cast<AttributeChangedEvent*>(event), request);
2948 break;
2949 case B_DEVICE_UNMOUNTED:
2950 error = B_OK;
2951 break;
2952 }
2953
2954 // replace all data buffers -- when the request is actually sent, they
2955 // might no longer exist
2956 if (error == B_OK)
2957 error = RequestBufferReplacer().ReplaceBuffer(request);
2958
2959 if (error == B_OK) {
2960 // common initialization
2961 request->volumeID = volumeID;
2962 request->opcode = event->opcode;
2963 request->revision = VolumeManager::GetDefault()->GetRevision();
2964
2965 // push the request
2966 error = fNodeMonitoringEvents->Push(request);
2967 if (error != B_OK)
2968 delete request;
2969 }
2970
2971 return error;
2972 }
2973
2974 // _EntryCreated
2975 status_t
_EntryCreated(ClientVolume * volume,EntryCreatedEvent * event,NodeMonitoringRequest * & _request)2976 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event,
2977 NodeMonitoringRequest*& _request)
2978 {
2979 // allocate the request
2980 EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest;
2981 if (!request)
2982 return B_NO_MEMORY;
2983 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
2984
2985 // get the name
2986 const char* name = event->name.GetString();
2987
2988 // set the request fields
2989 request->directoryID = NodeID(event->volumeID, event->directoryID);
2990 request->nodeID = NodeID(event->volumeID, event->nodeID);
2991 request->name.SetTo(name);
2992 if (event->queryHandler) {
2993 request->port = event->remotePort;
2994 request->token = event->remoteToken;
2995 request->queryUpdate = true;
2996 } else
2997 request->queryUpdate = false;
2998
2999 // try to get an entry info
3000 Entry* entry;
3001 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
3002 event->directoryID, name, true, &entry) == B_OK
3003 && entry->GetNode()->GetVolumeID() == event->volumeID
3004 && entry->GetNode()->GetID() == event->nodeID) {
3005 _GetEntryInfo(entry, &request->entryInfo);
3006 request->entryInfoValid = true;
3007 } else
3008 request->entryInfoValid = false;
3009
3010 requestDeleter.Detach();
3011 _request = request;
3012 return B_OK;
3013 }
3014
3015 // _EntryRemoved
3016 status_t
_EntryRemoved(ClientVolume * volume,EntryRemovedEvent * event,NodeMonitoringRequest * & _request)3017 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event,
3018 NodeMonitoringRequest*& _request)
3019 {
3020 // special handling, if it is the root node of the client volume that has
3021 // been removed
3022 if (!event->queryHandler
3023 && NodeRef(event->nodeVolumeID, event->nodeID)
3024 == volume->GetRootNodeRef()) {
3025 NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, ".");
3026 BEntry entry;
3027 if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists())
3028 _UnmountVolume(volume);
3029
3030 // don't send the "entry removed" event
3031 return B_ERROR;
3032 }
3033
3034 // allocate the request
3035 EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest;
3036 if (!request)
3037 return B_NO_MEMORY;
3038 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3039
3040 // get the name
3041 const char* name = event->name.GetString();
3042
3043 // set the request fields
3044 request->directoryID = NodeID(event->volumeID, event->directoryID);
3045 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3046 request->name.SetTo(name);
3047 if (event->queryHandler) {
3048 request->port = event->remotePort;
3049 request->token = event->remoteToken;
3050 request->queryUpdate = true;
3051 } else
3052 request->queryUpdate = false;
3053
3054 requestDeleter.Detach();
3055 _request = request;
3056 return B_OK;
3057 }
3058
3059 // _EntryMoved
3060 status_t
_EntryMoved(ClientVolume * volume,EntryMovedEvent * event,NodeMonitoringRequest * & _request)3061 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event,
3062 NodeMonitoringRequest*& _request)
3063 {
3064 // allocate the request
3065 EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest;
3066 if (!request)
3067 return B_NO_MEMORY;
3068 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3069
3070 // allocate memory for the names
3071 int32 fromNameLen = event->fromName.GetLength();
3072 const char* fromName
3073 = (fromNameLen > 0 ? event->fromName.GetString() : NULL);
3074 const char* toName = event->toName.GetString();
3075
3076 // set the request fields
3077 request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID);
3078 request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID);
3079 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID);
3080 request->fromName.SetTo(fromName);
3081 request->toName.SetTo(toName);
3082 request->queryUpdate = false;
3083
3084 // try to get an entry info
3085 Entry* entry;
3086 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID,
3087 event->toDirectoryID, toName, true, &entry) == B_OK
3088 && entry->GetNode()->GetVolumeID() == event->nodeVolumeID
3089 && entry->GetNode()->GetID() == event->nodeID) {
3090 _GetEntryInfo(entry, &request->entryInfo);
3091 request->entryInfoValid = true;
3092 } else
3093 request->entryInfoValid = false;
3094
3095 requestDeleter.Detach();
3096 _request = request;
3097 return B_OK;
3098 }
3099
3100 // _NodeStatChanged
3101 status_t
_NodeStatChanged(ClientVolume * volume,StatChangedEvent * event,NodeMonitoringRequest * & _request)3102 ClientConnection::_NodeStatChanged(ClientVolume* volume,
3103 StatChangedEvent* event, NodeMonitoringRequest*& _request)
3104 {
3105 // get the node
3106 Node* node = volume->GetNode(event->volumeID, event->nodeID);
3107 if (!node)
3108 return B_ENTRY_NOT_FOUND;
3109
3110 // allocate the request
3111 StatChangedRequest* request = new(std::nothrow) StatChangedRequest;
3112 if (!request)
3113 return B_NO_MEMORY;
3114 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3115
3116 // set the request fields
3117 request->nodeID = NodeID(event->volumeID, event->nodeID);
3118 _GetNodeInfo(node, &request->nodeInfo);
3119 request->queryUpdate = false;
3120
3121 requestDeleter.Detach();
3122 _request = request;
3123 return B_OK;
3124 }
3125
3126 // _NodeAttributeChanged
3127 status_t
_NodeAttributeChanged(ClientVolume * volume,AttributeChangedEvent * event,NodeMonitoringRequest * & _request)3128 ClientConnection::_NodeAttributeChanged(ClientVolume* volume,
3129 AttributeChangedEvent* event, NodeMonitoringRequest*& _request)
3130 {
3131 // get the node
3132 Node* node = volume->GetNode(event->volumeID, event->nodeID);
3133 if (!node)
3134 return B_ENTRY_NOT_FOUND;
3135
3136 // update the attribute directory
3137 bool removed = false;
3138 bool valid = false;
3139 attr_info info;
3140 const void* data = NULL;
3141 status_t error = node->UpdateAttribute(event->attribute.GetString(),
3142 &removed, &info, &data);
3143 valid = (error == B_OK);
3144
3145 // allocate the request
3146 AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest;
3147 if (!request)
3148 return B_NO_MEMORY;
3149 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request);
3150
3151 // get an attr dir info, if the directory is valid
3152 if (node->IsAttrDirValid()) {
3153 status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo);
3154 if (error != B_OK)
3155 return error;
3156 }
3157
3158 // get name and the data size
3159 int32 dataSize = (data ? info.size : 0);
3160 const char* name = event->attribute.GetString();
3161
3162 // set the request fields
3163 request->nodeID = NodeID(event->volumeID, event->nodeID);
3164 request->attrInfo.name.SetTo(name);
3165 request->valid = valid;
3166 request->removed = removed;
3167 if (!removed && valid) {
3168 request->attrInfo.info = info;
3169 request->attrInfo.data.SetTo(data, dataSize);
3170 }
3171 request->queryUpdate = false;
3172
3173 requestDeleter.Detach();
3174 _request = request;
3175 return B_OK;
3176 }
3177
3178 // _KnownAttributeType
3179 bool
_KnownAttributeType(type_code type)3180 ClientConnection::_KnownAttributeType(type_code type)
3181 {
3182 if (!fInverseClientEndianess)
3183 return false;
3184
3185 switch (type) {
3186 case B_BOOL_TYPE:
3187 case B_CHAR_TYPE:
3188 case B_COLOR_8_BIT_TYPE:
3189 case B_DOUBLE_TYPE:
3190 case B_FLOAT_TYPE:
3191 case B_GRAYSCALE_8_BIT_TYPE:
3192 case B_INT64_TYPE:
3193 case B_INT32_TYPE:
3194 case B_INT16_TYPE:
3195 case B_INT8_TYPE:
3196 case B_MESSAGE_TYPE:
3197 case B_MESSENGER_TYPE:
3198 case B_MIME_TYPE:
3199 case B_MONOCHROME_1_BIT_TYPE:
3200 case B_OFF_T_TYPE:
3201 case B_POINTER_TYPE:
3202 case B_POINT_TYPE:
3203 case B_RECT_TYPE:
3204 case B_REF_TYPE:
3205 case B_RGB_COLOR_TYPE:
3206 case B_SIZE_T_TYPE:
3207 case B_SSIZE_T_TYPE:
3208 case B_STRING_TYPE:
3209 case B_TIME_TYPE:
3210 case B_UINT64_TYPE:
3211 case B_UINT32_TYPE:
3212 case B_UINT16_TYPE:
3213 case B_UINT8_TYPE:
3214 case B_ASCII_TYPE:
3215 case B_MIME_STRING_TYPE:
3216 return true;
3217
3218 //B_RGB_32_BIT_TYPE: We could translate it, but it's heavy...
3219 }
3220
3221 return false;
3222 }
3223
3224 // _ConvertAttribute
3225 void
_ConvertAttribute(const attr_info & info,void * buffer)3226 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer)
3227 {
3228 swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS);
3229 }
3230
3231
3232 // #pragma mark -
3233
3234 // _OpenQuery
3235 status_t
_OpenQuery(const char * queryString,uint32 flags,port_id remotePort,int32 remoteToken,QueryHandle ** _handle)3236 ClientConnection::_OpenQuery(const char* queryString, uint32 flags,
3237 port_id remotePort, int32 remoteToken, QueryHandle** _handle)
3238 {
3239 if (!queryString || !_handle)
3240 return B_BAD_VALUE;
3241
3242 // open query
3243 QueryHandle* queryHandle;
3244 status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString,
3245 flags, remotePort, remoteToken, &queryHandle);
3246 if (error != B_OK)
3247 return error;
3248 BReference<QueryHandle> handleReference(queryHandle, true);
3249
3250 // lock the handle
3251 queryHandle->Lock();
3252
3253 // add the handle
3254 error = fQueryHandles->AddNodeHandle(queryHandle);
3255 if (error != B_OK)
3256 return error;
3257
3258 handleReference.Detach();
3259 *_handle = queryHandle;
3260 return B_OK;
3261 }
3262
3263 // _CloseQuery
3264 status_t
_CloseQuery(QueryHandle * handle)3265 ClientConnection::_CloseQuery(QueryHandle* handle)
3266 {
3267 if (!handle || !fQueryHandles->RemoveNodeHandle(handle))
3268 return B_BAD_VALUE;
3269
3270 return B_OK;
3271 }
3272
3273 // _LockQueryHandle
3274 //
3275 // VolumeManager must NOT be locked.
3276 status_t
_LockQueryHandle(int32 cookie,QueryHandle ** _handle)3277 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle)
3278 {
3279 NodeHandle* handle;
3280 status_t error = fQueryHandles->LockNodeHandle(cookie, &handle);
3281 if (error == B_OK)
3282 *_handle = static_cast<QueryHandle*>(handle);
3283 return error;
3284 }
3285
3286 // _UnlockQueryHandle
3287 //
3288 // VolumeManager may or may not be locked.
3289 void
_UnlockQueryHandle(NodeHandle * nodeHandle)3290 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle)
3291 {
3292 fQueryHandles->UnlockNodeHandle(nodeHandle);
3293 }
3294
3295
3296 // #pragma mark -
3297
3298 // _GetAllClientVolumeIDs
3299 int32
_GetAllClientVolumeIDs(int32 * volumeIDs,int32 arraySize,ClientVolumeFilter * filter)3300 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize,
3301 ClientVolumeFilter* filter)
3302 {
3303 int32 count = 0;
3304 AutoLocker<VolumeMap> volumesLocker(fVolumes);
3305 for (VolumeMap::Iterator it = fVolumes->GetIterator();
3306 it.HasNext() && arraySize > count;) {
3307 ClientVolume* clientVolume = it.Next().value;
3308 if (!filter || filter->FilterVolume(this, clientVolume))
3309 volumeIDs[count++] = clientVolume->GetID();
3310 }
3311
3312 return count;
3313 }
3314
3315 // _GetContainingClientVolumes
3316 int32
_GetContainingClientVolumes(Directory * directory,int32 * volumeIDs,int32 arraySize,ClientVolumeFilter * filter)3317 ClientConnection::_GetContainingClientVolumes(Directory* directory,
3318 int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter)
3319 {
3320 int32 count = 0;
3321 VolumeManager* volumeManager = VolumeManager::GetDefault();
3322 AutoLocker<VolumeMap> volumesLocker(fVolumes);
3323 for (VolumeMap::Iterator it = fVolumes->GetIterator();
3324 it.HasNext() && arraySize > count;) {
3325 ClientVolume* clientVolume = it.Next().value;
3326 Directory* clientVolumeRoot = clientVolume->GetRootDirectory();
3327 if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true)
3328 && (!filter || filter->FilterVolume(this, clientVolume))) {
3329 volumeIDs[count++] = clientVolume->GetID();
3330 }
3331 }
3332
3333 return count;
3334 }
3335
3336
3337 // #pragma mark -
3338 // #pragma mark ----- ClientConnectionListener -----
3339
3340 // constructor
ClientConnectionListener()3341 ClientConnectionListener::ClientConnectionListener()
3342 {
3343 }
3344
3345 // destructor
~ClientConnectionListener()3346 ClientConnectionListener::~ClientConnectionListener()
3347 {
3348 }
3349
3350