1 /*
2 * Copyright 2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Ingo Weinhold, ingo_weinhold@gmx.de
7 */
8
9
10 #include "VirtualDirectoryManager.h"
11
12 #include <errno.h>
13
14 #include <new>
15
16 #include <Directory.h>
17 #include <File.h>
18 #include <StringList.h>
19
20 #include <AutoDeleter.h>
21 #include <AutoLocker.h>
22 #include <DriverSettings.h>
23 #include <NotOwningEntryRef.h>
24 #include <Uuid.h>
25
26 #include "MimeTypes.h"
27 #include "Model.h"
28
29
30 namespace BPrivate {
31
32 static const size_t kMaxVirtualDirectoryFileSize = 10 * 1024;
33 static const char* const kTemporaryDefinitionFileBaseDirectoryPath
34 = "/tmp/tracker/virtual-directories";
35
36
37 // #pragma mark - VirtualDirectoryManager::Info
38
39
40 class VirtualDirectoryManager::Info {
41 private:
42 typedef BObjectList<Info> InfoList;
43
44 public:
Info(RootInfo * root,Info * parent,const BString & path,const node_ref & definitionFileNodeRef,const entry_ref & definitionFileEntryRef)45 Info(RootInfo* root, Info* parent, const BString& path,
46 const node_ref& definitionFileNodeRef,
47 const entry_ref& definitionFileEntryRef)
48 :
49 fRoot(root),
50 fParent(parent),
51 fPath(path),
52 fDefinitionFileNodeRef(definitionFileNodeRef),
53 fDefinitionFileEntryRef(definitionFileEntryRef),
54 fId(),
55 fChildDefinitionsDirectoryRef(-1, -1),
56 fChildren(10, true)
57 {
58 }
59
~Info()60 ~Info()
61 {
62 }
63
Root() const64 RootInfo* Root() const
65 {
66 return fRoot;
67 }
68
Parent() const69 Info* Parent() const
70 {
71 return fParent;
72 }
73
Name() const74 const char* Name() const
75 {
76 return fDefinitionFileEntryRef.name;
77 }
78
Path() const79 const BString& Path() const
80 {
81 return fPath;
82 }
83
DefinitionFileNodeRef() const84 const node_ref& DefinitionFileNodeRef() const
85 {
86 return fDefinitionFileNodeRef;
87 }
88
DefinitionFileEntryRef() const89 const entry_ref& DefinitionFileEntryRef() const
90 {
91 return fDefinitionFileEntryRef;
92 }
93
Children() const94 const InfoList& Children() const
95 {
96 return fChildren;
97 }
98
Id() const99 const BString& Id() const
100 {
101 return fId;
102 }
103
SetId(const BString & id)104 void SetId(const BString& id)
105 {
106 fId = id;
107 }
108
ChildDefinitionsDirectoryRef() const109 const node_ref& ChildDefinitionsDirectoryRef() const
110 {
111 return fChildDefinitionsDirectoryRef;
112 }
113
SetChildDefinitionsDirectoryRef(const node_ref & ref)114 void SetChildDefinitionsDirectoryRef(const node_ref& ref)
115 {
116 fChildDefinitionsDirectoryRef = ref;
117 }
118
GetChild(const char * name) const119 Info* GetChild(const char* name) const
120 {
121 for (int32 i = 0; Info* child = fChildren.ItemAt(i); i++) {
122 if (strcmp(name, child->Name()) == 0)
123 return child;
124 }
125 return NULL;
126 }
127
CreateChild(const node_ref & definitionFileNodeRef,const entry_ref & definitionFileEntryRef)128 Info* CreateChild(const node_ref& definitionFileNodeRef,
129 const entry_ref& definitionFileEntryRef)
130 {
131 BString path;
132 if (fPath.IsEmpty()) {
133 path = definitionFileEntryRef.name;
134 } else {
135 path.SetToFormat("%s/%s", fPath.String(),
136 definitionFileEntryRef.name);
137 }
138 if (path.IsEmpty())
139 return NULL;
140
141 Info* info = new(std::nothrow) Info(fRoot, this, path,
142 definitionFileNodeRef, definitionFileEntryRef);
143 if (info == NULL || !fChildren.AddItem(info)) {
144 delete info;
145 return NULL;
146 }
147 return info;
148 }
149
DeleteChild(Info * info)150 bool DeleteChild(Info* info)
151 {
152 return fChildren.RemoveItem(info, true);
153 }
154
DeleteChildAt(int32 index)155 void DeleteChildAt(int32 index)
156 {
157 delete fChildren.RemoveItemAt(index);
158 }
159
160 private:
161 RootInfo* fRoot;
162 Info* fParent;
163 BString fPath;
164 node_ref fDefinitionFileNodeRef;
165 entry_ref fDefinitionFileEntryRef;
166 BString fId;
167 node_ref fChildDefinitionsDirectoryRef;
168 InfoList fChildren;
169 };
170
171
172 // #pragma mark - VirtualDirectoryManager::RootInfo
173
174
175 class VirtualDirectoryManager::RootInfo {
176 public:
RootInfo(const node_ref & definitionFileNodeRef,const entry_ref & definitionFileEntryRef)177 RootInfo(const node_ref& definitionFileNodeRef,
178 const entry_ref& definitionFileEntryRef)
179 :
180 fDirectoryPaths(),
181 fInfo(new(std::nothrow) VirtualDirectoryManager::Info(this, NULL,
182 BString(), definitionFileNodeRef, definitionFileEntryRef)),
183 fFileTime(-1),
184 fLastChangeTime(-1)
185 {
186 }
187
~RootInfo()188 ~RootInfo()
189 {
190 delete fInfo;
191 }
192
InitCheck() const193 status_t InitCheck() const
194 {
195 return fInfo != NULL ? B_OK : B_NO_MEMORY;
196 }
197
FileTime() const198 bigtime_t FileTime() const
199 {
200 return fFileTime;
201 }
202
LastChangeTime() const203 bigtime_t LastChangeTime() const
204 {
205 return fLastChangeTime;
206 }
207
DirectoryPaths() const208 const BStringList& DirectoryPaths() const
209 {
210 return fDirectoryPaths;
211 }
212
ReadDefinition(bool * _changed=NULL)213 status_t ReadDefinition(bool* _changed = NULL)
214 {
215 // open the definition file
216 BFile file;
217 status_t error = file.SetTo(&fInfo->DefinitionFileEntryRef(),
218 B_READ_ONLY);
219 if (error != B_OK)
220 return error;
221
222 struct stat st;
223 error = file.GetStat(&st);
224 if (error != B_OK)
225 return error;
226
227 bigtime_t fileTime = st.st_mtim.tv_sec;
228 fileTime *= 1000000;
229 fileTime += st.st_mtim.tv_nsec / 1000;
230 if (fileTime == fFileTime) {
231 if (_changed != NULL)
232 *_changed = false;
233
234 return B_OK;
235 }
236
237 if (node_ref(st.st_dev, st.st_ino) != fInfo->DefinitionFileNodeRef())
238 return B_ENTRY_NOT_FOUND;
239
240 // read the contents
241 off_t fileSize = st.st_size;
242 if (fileSize > (off_t)kMaxVirtualDirectoryFileSize)
243 return B_BAD_VALUE;
244
245 char* buffer = new(std::nothrow) char[fileSize + 1];
246 if (buffer == NULL)
247 return B_NO_MEMORY;
248 ArrayDeleter<char> bufferDeleter(buffer);
249
250 ssize_t bytesRead = file.ReadAt(0, buffer, fileSize);
251 if (bytesRead < 0)
252 return bytesRead;
253
254 buffer[bytesRead] = '\0';
255
256 // parse it
257 BStringList oldDirectoryPaths(fDirectoryPaths);
258 fDirectoryPaths.MakeEmpty();
259
260 BDriverSettings driverSettings;
261 error = driverSettings.SetToString(buffer);
262 if (error != B_OK)
263 return error;
264
265 BDriverParameterIterator it
266 = driverSettings.ParameterIterator("directory");
267 while (it.HasNext()) {
268 BDriverParameter parameter = it.Next();
269 for (int32 i = 0; i < parameter.CountValues(); i++)
270 fDirectoryPaths.Add(parameter.ValueAt(i));
271 }
272
273 // update file time and check whether something has changed
274 fFileTime = fileTime;
275
276 bool changed = fDirectoryPaths != oldDirectoryPaths;
277 if (changed || fLastChangeTime < 0)
278 fLastChangeTime = fFileTime;
279
280 if (_changed != NULL)
281 *_changed = changed;
282
283 return B_OK;
284 }
285
Info() const286 VirtualDirectoryManager::Info* Info() const
287 {
288 return fInfo;
289 }
290
291 private:
292 typedef std::map<BString, VirtualDirectoryManager::Info*> InfoMap;
293
294 private:
295 BStringList fDirectoryPaths;
296 VirtualDirectoryManager::Info* fInfo;
297 bigtime_t fFileTime;
298 // actual file modified time
299 bigtime_t fLastChangeTime;
300 // last time something actually changed
301 };
302
303
304 // #pragma mark - VirtualDirectoryManager
305
306
VirtualDirectoryManager()307 VirtualDirectoryManager::VirtualDirectoryManager()
308 :
309 fLock("virtual directory manager")
310 {
311 }
312
313
314 /*static*/ VirtualDirectoryManager*
Instance()315 VirtualDirectoryManager::Instance()
316 {
317 static VirtualDirectoryManager* manager
318 = new(std::nothrow) VirtualDirectoryManager;
319 return manager;
320 }
321
322
323 status_t
ResolveDirectoryPaths(const node_ref & definitionFileNodeRef,const entry_ref & definitionFileEntryRef,BStringList & _directoryPaths,node_ref * _definitionFileNodeRef,entry_ref * _definitionFileEntryRef)324 VirtualDirectoryManager::ResolveDirectoryPaths(
325 const node_ref& definitionFileNodeRef,
326 const entry_ref& definitionFileEntryRef, BStringList& _directoryPaths,
327 node_ref* _definitionFileNodeRef, entry_ref* _definitionFileEntryRef)
328 {
329 Info* info = _InfoForNodeRef(definitionFileNodeRef);
330 if (info == NULL) {
331 status_t error = _ResolveUnknownDefinitionFile(definitionFileNodeRef,
332 definitionFileEntryRef, info);
333 if (error != B_OK)
334 return error;
335 }
336
337 const BString& subDirectory = info->Path();
338 const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths();
339 if (subDirectory.IsEmpty()) {
340 _directoryPaths = rootDirectoryPaths;
341 } else {
342 _directoryPaths.MakeEmpty();
343 int32 count = rootDirectoryPaths.CountStrings();
344 for (int32 i = 0; i < count; i++) {
345 BString path = rootDirectoryPaths.StringAt(i);
346 _directoryPaths.Add(path << '/' << subDirectory);
347 }
348 }
349
350 if (_definitionFileEntryRef != NULL) {
351 *_definitionFileEntryRef = info->DefinitionFileEntryRef();
352 if (_definitionFileEntryRef->name == NULL)
353 return B_NO_MEMORY;
354 }
355
356 if (_definitionFileNodeRef != NULL)
357 *_definitionFileNodeRef = info->DefinitionFileNodeRef();
358
359 return B_OK;
360 }
361
362
363 bool
GetDefinitionFileChangeTime(const node_ref & definitionFileRef,bigtime_t & _time) const364 VirtualDirectoryManager::GetDefinitionFileChangeTime(
365 const node_ref& definitionFileRef, bigtime_t& _time) const
366 {
367 Info* info = _InfoForNodeRef(definitionFileRef);
368 if (info == NULL)
369 return false;
370
371 _time = info->Root()->LastChangeTime();
372 return true;
373 }
374
375
376 bool
GetRootDefinitionFile(const node_ref & definitionFileRef,node_ref & _rootDefinitionFileRef)377 VirtualDirectoryManager::GetRootDefinitionFile(
378 const node_ref& definitionFileRef, node_ref& _rootDefinitionFileRef)
379 {
380 Info* info = _InfoForNodeRef(definitionFileRef);
381 if (info == NULL)
382 return false;
383
384 _rootDefinitionFileRef = info->Root()->Info()->DefinitionFileNodeRef();
385 return true;
386 }
387
388
389 bool
GetSubDirectoryDefinitionFile(const node_ref & baseDefinitionRef,const char * subDirName,entry_ref & _entryRef,node_ref & _nodeRef)390 VirtualDirectoryManager::GetSubDirectoryDefinitionFile(
391 const node_ref& baseDefinitionRef, const char* subDirName,
392 entry_ref& _entryRef, node_ref& _nodeRef)
393 {
394 Info* parentInfo = _InfoForNodeRef(baseDefinitionRef);
395 if (parentInfo == NULL)
396 return false;
397
398 Info* info = parentInfo->GetChild(subDirName);
399 if (info == NULL)
400 return false;
401
402 _entryRef = info->DefinitionFileEntryRef();
403 _nodeRef = info->DefinitionFileNodeRef();
404 return _entryRef.name != NULL;
405 }
406
407
408 bool
GetParentDirectoryDefinitionFile(const node_ref & subDirDefinitionRef,entry_ref & _entryRef,node_ref & _nodeRef)409 VirtualDirectoryManager::GetParentDirectoryDefinitionFile(
410 const node_ref& subDirDefinitionRef, entry_ref& _entryRef,
411 node_ref& _nodeRef)
412 {
413 Info* info = _InfoForNodeRef(subDirDefinitionRef);
414 if (info == NULL)
415 return false;
416
417 Info* parentInfo = info->Parent();
418 if (parentInfo == NULL)
419 return false;
420
421 _entryRef = parentInfo->DefinitionFileEntryRef();
422 _nodeRef = parentInfo->DefinitionFileNodeRef();
423 return _entryRef.name != NULL;
424 }
425
426
427 status_t
TranslateDirectoryEntry(const node_ref & definitionFileRef,dirent * buffer)428 VirtualDirectoryManager::TranslateDirectoryEntry(
429 const node_ref& definitionFileRef, dirent* buffer)
430 {
431 NotOwningEntryRef entryRef(buffer->d_pdev, buffer->d_pino, buffer->d_name);
432 node_ref nodeRef(buffer->d_dev, buffer->d_ino);
433
434 status_t result = TranslateDirectoryEntry(definitionFileRef, entryRef,
435 nodeRef);
436 if (result != B_OK)
437 return result;
438
439 buffer->d_pdev = entryRef.device;
440 buffer->d_pino = entryRef.directory;
441 buffer->d_dev = nodeRef.device;
442 buffer->d_ino = nodeRef.node;
443
444 return B_OK;
445 }
446
447
448 status_t
TranslateDirectoryEntry(const node_ref & definitionFileRef,entry_ref & _entryRef,node_ref & _nodeRef)449 VirtualDirectoryManager::TranslateDirectoryEntry(
450 const node_ref& definitionFileRef, entry_ref& _entryRef, node_ref& _nodeRef)
451 {
452 Info* parentInfo = _InfoForNodeRef(definitionFileRef);
453 if (parentInfo == NULL)
454 return B_BAD_VALUE;
455
456 // get the info for the entry
457 Info* info = parentInfo->GetChild(_entryRef.name);
458 if (info == NULL) {
459 // If not done yet, create a directory for the parent, where we can
460 // place the new definition file.
461 if (parentInfo->Id().IsEmpty()) {
462 BString id = BUuid().SetToRandom().ToString();
463 if (id.IsEmpty())
464 return B_NO_MEMORY;
465
466 BPath path(kTemporaryDefinitionFileBaseDirectoryPath, id);
467 status_t error = path.InitCheck();
468 if (error != B_OK)
469 return error;
470
471 error = create_directory(path.Path(),
472 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
473 if (error != B_OK)
474 return error;
475
476 struct stat st;
477 if (lstat(path.Path(), &st) != 0)
478 return errno;
479
480 parentInfo->SetId(id);
481 parentInfo->SetChildDefinitionsDirectoryRef(
482 node_ref(st.st_dev, st.st_ino));
483 }
484
485 // create the definition file
486 const node_ref& directoryRef
487 = parentInfo->ChildDefinitionsDirectoryRef();
488 NotOwningEntryRef entryRef(directoryRef, _entryRef.name);
489
490 BFile definitionFile;
491 status_t error = definitionFile.SetTo(&entryRef,
492 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
493 if (error != B_OK)
494 return error;
495
496 node_ref nodeRef;
497 error = definitionFile.GetNodeRef(&nodeRef);
498 if (error != B_OK)
499 return error;
500
501 BNodeInfo nodeInfo(&definitionFile);
502 error = nodeInfo.SetType(kVirtualDirectoryMimeType);
503 if (error != B_OK)
504 return error;
505
506 // create the info
507 info = parentInfo->CreateChild(nodeRef, entryRef);
508 if (info == NULL || !_AddInfo(info))
509 return B_NO_MEMORY;
510
511 // Write some info into the definition file that helps us to find the
512 // root definition file. This is only necessary when definition file
513 // entry refs are transferred between applications. Then the receiving
514 // application may need to find the root definition file and resolve
515 // the subdirectories.
516 const entry_ref& rootEntryRef
517 = parentInfo->Root()->Info()->DefinitionFileEntryRef();
518 BString definitionFileContent;
519 definitionFileContent.SetToFormat(
520 "root {\n"
521 " device %" B_PRIdDEV "\n"
522 " directory %" B_PRIdINO "\n"
523 " name \"%s\"\n"
524 "}\n"
525 "subdir \"%s\"\n",
526 rootEntryRef.device, rootEntryRef.directory, rootEntryRef.name,
527 info->Path().String());
528 // failure is not nice, but not mission critical for this application
529 if (!definitionFileContent.IsEmpty()) {
530 definitionFile.WriteAt(0,
531 definitionFileContent.String(), definitionFileContent.Length());
532 }
533 }
534
535 const entry_ref& entryRef = info->DefinitionFileEntryRef();
536 _nodeRef = info->DefinitionFileNodeRef();
537 _entryRef.device = entryRef.device;
538 _entryRef.directory = entryRef.directory;
539
540 return B_OK;
541 }
542
543
544 bool
DefinitionFileChanged(const node_ref & definitionFileRef)545 VirtualDirectoryManager::DefinitionFileChanged(
546 const node_ref& definitionFileRef)
547 {
548 Info* info = _InfoForNodeRef(definitionFileRef);
549 if (info == NULL)
550 return false;
551
552 _UpdateTree(info->Root());
553
554 return _InfoForNodeRef(definitionFileRef) != NULL;
555 }
556
557
558 status_t
DirectoryRemoved(const node_ref & definitionFileRef)559 VirtualDirectoryManager::DirectoryRemoved(const node_ref& definitionFileRef)
560 {
561 Info* info = _InfoForNodeRef(definitionFileRef);
562 if (info == NULL)
563 return B_ENTRY_NOT_FOUND;
564
565 _RemoveDirectory(info);
566
567 // delete the info
568 if (info->Parent() == NULL)
569 delete info->Root();
570 else
571 info->Parent()->DeleteChild(info);
572
573 return B_OK;
574 }
575
576
577 /*static*/ bool
GetEntry(const BStringList & directoryPaths,const char * name,entry_ref * _ref,struct stat * _st)578 VirtualDirectoryManager::GetEntry(const BStringList& directoryPaths,
579 const char* name, entry_ref* _ref, struct stat* _st)
580 {
581 int32 count = directoryPaths.CountStrings();
582 for (int32 i = 0; i < count; i++) {
583 BPath path;
584 if (path.SetTo(directoryPaths.StringAt(i), name) != B_OK)
585 continue;
586
587 struct stat st;
588 if (lstat(path.Path(), &st) == 0) {
589 if (_ref != NULL) {
590 if (get_ref_for_path(path.Path(), _ref) != B_OK)
591 return false;
592 }
593 if (_st != NULL)
594 *_st = st;
595 return true;
596 }
597 }
598
599 return false;
600 }
601
602
603 VirtualDirectoryManager::Info*
_InfoForNodeRef(const node_ref & nodeRef) const604 VirtualDirectoryManager::_InfoForNodeRef(const node_ref& nodeRef) const
605 {
606 NodeRefInfoMap::const_iterator it = fInfos.find(nodeRef);
607 return it != fInfos.end() ? it->second : NULL;
608 }
609
610
611 bool
_AddInfo(Info * info)612 VirtualDirectoryManager::_AddInfo(Info* info)
613 {
614 try {
615 fInfos[info->DefinitionFileNodeRef()] = info;
616 return true;
617 } catch (...) {
618 return false;
619 }
620 }
621
622
623 void
_RemoveInfo(Info * info)624 VirtualDirectoryManager::_RemoveInfo(Info* info)
625 {
626 NodeRefInfoMap::iterator it = fInfos.find(info->DefinitionFileNodeRef());
627 if (it != fInfos.end())
628 fInfos.erase(it);
629 }
630
631
632 void
_UpdateTree(RootInfo * root)633 VirtualDirectoryManager::_UpdateTree(RootInfo* root)
634 {
635 bool changed = false;
636 status_t result = root->ReadDefinition(&changed);
637 if (result != B_OK) {
638 DirectoryRemoved(root->Info()->DefinitionFileNodeRef());
639 return;
640 }
641
642 if (!changed)
643 return;
644
645 _UpdateTree(root->Info());
646 }
647
648
649 void
_UpdateTree(Info * info)650 VirtualDirectoryManager::_UpdateTree(Info* info)
651 {
652 const BStringList& directoryPaths = info->Root()->DirectoryPaths();
653
654 int32 childCount = info->Children().CountItems();
655 for (int32 i = childCount -1; i >= 0; i--) {
656 Info* childInfo = info->Children().ItemAt(i);
657 struct stat st;
658 if (GetEntry(directoryPaths, childInfo->Path(), NULL, &st)
659 && S_ISDIR(st.st_mode)) {
660 _UpdateTree(childInfo);
661 } else {
662 _RemoveDirectory(childInfo);
663 info->DeleteChildAt(i);
664 }
665 }
666 }
667
668
669 void
_RemoveDirectory(Info * info)670 VirtualDirectoryManager::_RemoveDirectory(Info* info)
671 {
672 // recursively remove the subdirectories
673 for (int32 i = 0; Info* child = info->Children().ItemAt(i); i++)
674 _RemoveDirectory(child);
675
676 // remove the directory for the child definition file
677 if (!info->Id().IsEmpty()) {
678 BPath path(kTemporaryDefinitionFileBaseDirectoryPath, info->Id());
679 if (path.InitCheck() == B_OK)
680 rmdir(path.Path());
681 }
682
683 // unless this is the root directory, remove the definition file
684 if (info != info->Root()->Info())
685 BEntry(&info->DefinitionFileEntryRef()).Remove();
686
687 _RemoveInfo(info);
688 }
689
690
691 status_t
_ResolveUnknownDefinitionFile(const node_ref & definitionFileNodeRef,const entry_ref & definitionFileEntryRef,Info * & _info)692 VirtualDirectoryManager::_ResolveUnknownDefinitionFile(
693 const node_ref& definitionFileNodeRef,
694 const entry_ref& definitionFileEntryRef, Info*& _info)
695 {
696 // This is either a root definition file or a subdir definition file
697 // created by another application. We'll just try to read the info from the
698 // file that a subdir definition file would contain. If that fails, we
699 // assume a root definition file.
700 entry_ref entryRef;
701 BString subDirPath;
702 if (_ReadSubDirectoryDefinitionFileInfo(definitionFileEntryRef, entryRef,
703 subDirPath) != B_OK) {
704 return _CreateRootInfo(definitionFileNodeRef, definitionFileEntryRef,
705 _info);
706 }
707
708 if (subDirPath.IsEmpty())
709 return B_BAD_VALUE;
710
711 // get the root definition file node ref
712 node_ref nodeRef;
713 status_t error = BEntry(&entryRef).GetNodeRef(&nodeRef);
714 if (error != B_OK)
715 return error;
716
717 // resolve/create the root info
718 Info* info = _InfoForNodeRef(nodeRef);
719 if (info == NULL) {
720 error = _CreateRootInfo(nodeRef, entryRef, info);
721 if (error != B_OK)
722 return error;
723 } else if (info->Root()->Info() != info)
724 return B_BAD_VALUE;
725
726 const BStringList& rootDirectoryPaths = info->Root()->DirectoryPaths();
727
728 // now we can traverse the subdir path and resolve all infos along the way
729 int32 nextComponentOffset = 0;
730 while (nextComponentOffset < subDirPath.Length()) {
731 int32 componentEnd = subDirPath.FindFirst('/', nextComponentOffset);
732 if (componentEnd >= 0) {
733 // skip duplicate '/'s
734 if (componentEnd == nextComponentOffset + 1) {
735 nextComponentOffset = componentEnd;
736 continue;
737 }
738 nextComponentOffset = componentEnd + 1;
739 } else {
740 componentEnd = subDirPath.Length();
741 nextComponentOffset = componentEnd;
742 }
743
744 BString entryPath(subDirPath, componentEnd);
745 if (entryPath.IsEmpty())
746 return B_NO_MEMORY;
747
748 struct stat st;
749 if (!GetEntry(rootDirectoryPaths, entryPath, &entryRef, &st))
750 return B_ENTRY_NOT_FOUND;
751
752 if (!S_ISDIR(st.st_mode))
753 return B_BAD_VALUE;
754
755 error = TranslateDirectoryEntry(info->DefinitionFileNodeRef(), entryRef,
756 nodeRef);
757 if (error != B_OK)
758 return error;
759
760 info = _InfoForNodeRef(nodeRef);
761 }
762
763 _info = info;
764
765 return B_OK;
766 }
767
768
769 status_t
_CreateRootInfo(const node_ref & definitionFileNodeRef,const entry_ref & definitionFileEntryRef,Info * & _info)770 VirtualDirectoryManager::_CreateRootInfo(const node_ref& definitionFileNodeRef,
771 const entry_ref& definitionFileEntryRef, Info*& _info)
772 {
773 RootInfo* root = new(std::nothrow) RootInfo(definitionFileNodeRef,
774 definitionFileEntryRef);
775 if (root == NULL || root->InitCheck() != B_OK) {
776 delete root;
777 return B_NO_MEMORY;
778 }
779 ObjectDeleter<RootInfo> rootDeleter(root);
780
781 status_t error = root->ReadDefinition();
782 if (error != B_OK)
783 return error;
784
785 if (!_AddInfo(root->Info()))
786 return B_NO_MEMORY;
787
788 rootDeleter.Detach();
789 _info = root->Info();
790
791 return B_OK;
792 }
793
794
795 status_t
_ReadSubDirectoryDefinitionFileInfo(const entry_ref & entryRef,entry_ref & _rootDefinitionFileEntryRef,BString & _subDirPath)796 VirtualDirectoryManager::_ReadSubDirectoryDefinitionFileInfo(
797 const entry_ref& entryRef, entry_ref& _rootDefinitionFileEntryRef,
798 BString& _subDirPath)
799 {
800 BDriverSettings driverSettings;
801 status_t error = driverSettings.Load(entryRef);
802 if (error != B_OK)
803 return error;
804
805 const char* subDirPath = driverSettings.GetParameterValue("subdir");
806 if (subDirPath == NULL || subDirPath[0] == '\0')
807 return B_BAD_DATA;
808
809 BDriverParameter rootParameter;
810 if (!driverSettings.FindParameter("root", &rootParameter))
811 return B_BAD_DATA;
812
813 const char* name = rootParameter.GetParameterValue("name");
814 dev_t device = rootParameter.GetInt32ParameterValue("device", -1, -1);
815 ino_t directory = rootParameter.GetInt64ParameterValue("directory");
816 if (name == NULL || name[0] == '\0' || device < 0)
817 return B_BAD_DATA;
818
819 _rootDefinitionFileEntryRef = entry_ref(device, directory, name);
820 _subDirPath = subDirPath;
821
822 return !_subDirPath.IsEmpty() && _rootDefinitionFileEntryRef.name != NULL
823 ? B_OK : B_NO_MEMORY;
824 }
825
826 } // namespace BPrivate
827