1 /*
2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Copyright 2017, Jessica Hamilton, jessica.l.hamilton@gmail.com.
5 * Distributed under the terms of the MIT License.
6 */
7
8
9 #include <boot/vfs.h>
10
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <string.h>
14 #include <sys/uio.h>
15 #include <unistd.h>
16
17 #include <StorageDefs.h>
18
19 #include <AutoDeleter.h>
20
21 #include <boot/platform.h>
22 #include <boot/partitions.h>
23 #include <boot/stdio.h>
24 #include <boot/stage2.h>
25 #include <syscall_utils.h>
26
27 #include "package_support.h"
28 #include "RootFileSystem.h"
29 #include "file_systems/packagefs/packagefs.h"
30
31
32 using namespace boot;
33
34 //#define TRACE_VFS
35 #ifdef TRACE_VFS
36 # define TRACE(x) dprintf x
37 #else
38 # define TRACE(x) ;
39 #endif
40
41
42 struct __DIR {
43 Directory* directory;
44 void* cookie;
45
46 char _direntBuffer[sizeof(dirent) + B_FILE_NAME_LENGTH + 1];
entry__DIR47 dirent* entry() { return (dirent*)_direntBuffer; }
48 };
49
50
51 class Descriptor {
52 public:
53 Descriptor(Node *node, void *cookie);
54 ~Descriptor();
55
56 ssize_t ReadAt(off_t pos, void *buffer, size_t bufferSize);
57 ssize_t Read(void *buffer, size_t bufferSize);
58 ssize_t WriteAt(off_t pos, const void *buffer, size_t bufferSize);
59 ssize_t Write(const void *buffer, size_t bufferSize);
60
61 void Stat(struct stat &stat);
62 status_t Seek(off_t position, int mode);
63
Offset() const64 off_t Offset() const { return fOffset; }
RefCount() const65 int32 RefCount() const { return fRefCount; }
66
67 status_t Acquire();
68 status_t Release();
69
GetNode() const70 Node *GetNode() const { return fNode; }
71
72 private:
73 Node *fNode;
74 void *fCookie;
75 off_t fOffset;
76 int32 fRefCount;
77 };
78
79 #define MAX_VFS_DESCRIPTORS 64
80
81 NodeList gBootDevices;
82 NodeList gPartitions;
83 RootFileSystem *gRoot;
84 static Descriptor *sDescriptors[MAX_VFS_DESCRIPTORS];
85 static Node *sBootDevice;
86
87
Node()88 Node::Node()
89 :
90 fRefCount(1)
91 {
92 }
93
94
~Node()95 Node::~Node()
96 {
97 }
98
99
100 status_t
Open(void ** _cookie,int mode)101 Node::Open(void **_cookie, int mode)
102 {
103 TRACE(("%p::Open()\n", this));
104 return Acquire();
105 }
106
107
108 status_t
Close(void * cookie)109 Node::Close(void *cookie)
110 {
111 TRACE(("%p::Close()\n", this));
112 return Release();
113 }
114
115
116 status_t
ReadLink(char * buffer,size_t bufferSize)117 Node::ReadLink(char* buffer, size_t bufferSize)
118 {
119 return B_BAD_VALUE;
120 }
121
122
123 status_t
GetName(char * nameBuffer,size_t bufferSize) const124 Node::GetName(char *nameBuffer, size_t bufferSize) const
125 {
126 return B_ERROR;
127 }
128
129
130 status_t
GetFileMap(struct file_map_run * runs,int32 * count)131 Node::GetFileMap(struct file_map_run *runs, int32 *count)
132 {
133 return B_ERROR;
134 }
135
136
137 int32
Type() const138 Node::Type() const
139 {
140 return 0;
141 }
142
143
144 off_t
Size() const145 Node::Size() const
146 {
147 return 0LL;
148 }
149
150
151 ino_t
Inode() const152 Node::Inode() const
153 {
154 return 0;
155 }
156
157
158 void
Stat(struct stat & stat)159 Node::Stat(struct stat& stat)
160 {
161 stat.st_mode = Type();
162 stat.st_size = Size();
163 stat.st_ino = Inode();
164 }
165
166
167 status_t
Acquire()168 Node::Acquire()
169 {
170 fRefCount++;
171 TRACE(("%p::Acquire(), fRefCount = %" B_PRId32 "\n", this, fRefCount));
172 return B_OK;
173 }
174
175
176 status_t
Release()177 Node::Release()
178 {
179 TRACE(("%p::Release(), fRefCount = %" B_PRId32 "\n", this, fRefCount));
180 if (--fRefCount == 0) {
181 TRACE(("delete node: %p\n", this));
182 delete this;
183 return 1;
184 }
185
186 return B_OK;
187 }
188
189
190 // #pragma mark -
191
192
ConsoleNode()193 ConsoleNode::ConsoleNode()
194 : Node()
195 {
196 }
197
198
199 ssize_t
Read(void * buffer,size_t bufferSize)200 ConsoleNode::Read(void *buffer, size_t bufferSize)
201 {
202 return ReadAt(NULL, -1, buffer, bufferSize);
203 }
204
205
206 ssize_t
Write(const void * buffer,size_t bufferSize)207 ConsoleNode::Write(const void *buffer, size_t bufferSize)
208 {
209 return WriteAt(NULL, -1, buffer, bufferSize);
210 }
211
212
213 // #pragma mark -
214
215
Directory()216 Directory::Directory()
217 : Node()
218 {
219 }
220
221
222 ssize_t
ReadAt(void * cookie,off_t pos,void * buffer,size_t bufferSize)223 Directory::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
224 {
225 return B_ERROR;
226 }
227
228
229 ssize_t
WriteAt(void * cookie,off_t pos,const void * buffer,size_t bufferSize)230 Directory::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
231 {
232 return B_ERROR;
233 }
234
235
236 int32
Type() const237 Directory::Type() const
238 {
239 return S_IFDIR;
240 }
241
242
243 Node*
Lookup(const char * name,bool traverseLinks)244 Directory::Lookup(const char* name, bool traverseLinks)
245 {
246 Node* node = LookupDontTraverse(name);
247 if (node == NULL)
248 return NULL;
249
250 if (!traverseLinks || !S_ISLNK(node->Type()))
251 return node;
252
253 // the node is a symbolic link, so we have to resolve the path
254 char* linkPath = (char*)malloc(B_PATH_NAME_LENGTH);
255 if (linkPath == NULL) {
256 node->Release();
257 return NULL;
258 }
259
260 status_t error = node->ReadLink(linkPath, B_PATH_NAME_LENGTH);
261
262 node->Release();
263 // we don't need this one anymore
264
265 if (error != B_OK) {
266 free(linkPath);
267 return NULL;
268 }
269
270 // let open_from() do the real work
271 int fd = open_from(this, linkPath, O_RDONLY);
272 if (fd < 0) {
273 free(linkPath);
274 return NULL;
275 }
276
277 free(linkPath);
278 node = get_node_from(fd);
279 if (node != NULL)
280 node->Acquire();
281
282 close(fd);
283 return node;
284 }
285
286
287 status_t
CreateFile(const char * name,mode_t permissions,Node ** _node)288 Directory::CreateFile(const char *name, mode_t permissions, Node **_node)
289 {
290 return EROFS;
291 }
292
293
294 // #pragma mark -
295
296
MemoryDisk(const uint8 * data,size_t size,const char * name)297 MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name)
298 : Node(),
299 fData(data),
300 fSize(size)
301 {
302 strlcpy(fName, name, sizeof(fName));
303 }
304
305
306 ssize_t
ReadAt(void * cookie,off_t pos,void * buffer,size_t bufferSize)307 MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize)
308 {
309 if (pos < 0)
310 return B_BAD_VALUE;
311 if ((size_t)pos >= fSize)
312 return 0;
313
314 if (pos + bufferSize > fSize)
315 bufferSize = fSize - pos;
316
317 memcpy(buffer, fData + pos, bufferSize);
318 return bufferSize;
319 }
320
321
322 ssize_t
WriteAt(void * cookie,off_t pos,const void * buffer,size_t bufferSize)323 MemoryDisk::WriteAt(void* cookie, off_t pos, const void* buffer,
324 size_t bufferSize)
325 {
326 return B_NOT_ALLOWED;
327 }
328
329
330 off_t
Size() const331 MemoryDisk::Size() const
332 {
333 return fSize;
334 }
335
336
337 status_t
GetName(char * nameBuffer,size_t bufferSize) const338 MemoryDisk::GetName(char *nameBuffer, size_t bufferSize) const
339 {
340 if (!nameBuffer)
341 return B_BAD_VALUE;
342
343 strlcpy(nameBuffer, fName, bufferSize);
344 return B_OK;
345 }
346
347
348 // #pragma mark -
349
350
Descriptor(Node * node,void * cookie)351 Descriptor::Descriptor(Node *node, void *cookie)
352 :
353 fNode(node),
354 fCookie(cookie),
355 fOffset(0),
356 fRefCount(1)
357 {
358 }
359
360
~Descriptor()361 Descriptor::~Descriptor()
362 {
363 }
364
365
366 ssize_t
Read(void * buffer,size_t bufferSize)367 Descriptor::Read(void *buffer, size_t bufferSize)
368 {
369 ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize);
370 if (bytesRead > B_OK)
371 fOffset += bytesRead;
372
373 return bytesRead;
374 }
375
376
377 ssize_t
ReadAt(off_t pos,void * buffer,size_t bufferSize)378 Descriptor::ReadAt(off_t pos, void *buffer, size_t bufferSize)
379 {
380 return fNode->ReadAt(fCookie, pos, buffer, bufferSize);
381 }
382
383
384 ssize_t
Write(const void * buffer,size_t bufferSize)385 Descriptor::Write(const void *buffer, size_t bufferSize)
386 {
387 ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize);
388 if (bytesWritten > B_OK)
389 fOffset += bytesWritten;
390
391 return bytesWritten;
392 }
393
394
395 ssize_t
WriteAt(off_t pos,const void * buffer,size_t bufferSize)396 Descriptor::WriteAt(off_t pos, const void *buffer, size_t bufferSize)
397 {
398 return fNode->WriteAt(fCookie, pos, buffer, bufferSize);
399 }
400
401
402 void
Stat(struct stat & stat)403 Descriptor::Stat(struct stat &stat)
404 {
405 fNode->Stat(stat);
406 }
407
408
409 status_t
Seek(off_t position,int mode)410 Descriptor::Seek(off_t position, int mode)
411 {
412 off_t newPosition;
413 switch (mode)
414 {
415 case SEEK_SET:
416 newPosition = position;
417 break;
418 case SEEK_CUR:
419 newPosition = fOffset + position;
420 break;
421 case SEEK_END:
422 {
423 struct stat st;
424 Stat(st);
425 newPosition = st.st_size + position;
426 break;
427 }
428 default:
429 return B_BAD_VALUE;
430 }
431
432 if (newPosition < 0)
433 return B_BAD_VALUE;
434
435 fOffset = newPosition;
436 return B_OK;
437 }
438
439
440 status_t
Acquire()441 Descriptor::Acquire()
442 {
443 fRefCount++;
444 return B_OK;
445 }
446
447
448 status_t
Release()449 Descriptor::Release()
450 {
451 if (--fRefCount == 0) {
452 status_t status = fNode->Close(fCookie);
453 if (status != B_OK)
454 return status;
455 }
456
457 return B_OK;
458 }
459
460
461 // #pragma mark -
462
463
BootVolume()464 BootVolume::BootVolume()
465 :
466 fRootDirectory(NULL),
467 fSystemDirectory(NULL),
468 fPackageVolumeInfo(NULL),
469 fPackageVolumeState(NULL)
470 {
471 }
472
473
~BootVolume()474 BootVolume::~BootVolume()
475 {
476 Unset();
477 }
478
479
480 status_t
SetTo(Directory * rootDirectory,PackageVolumeInfo * packageVolumeInfo,PackageVolumeState * packageVolumeState)481 BootVolume::SetTo(Directory* rootDirectory,
482 PackageVolumeInfo* packageVolumeInfo,
483 PackageVolumeState* packageVolumeState)
484 {
485 Unset();
486
487 status_t error = _SetTo(rootDirectory, packageVolumeInfo,
488 packageVolumeState);
489 if (error != B_OK)
490 Unset();
491
492 return error;
493 }
494
495
496 void
Unset()497 BootVolume::Unset()
498 {
499 if (fRootDirectory != NULL) {
500 fRootDirectory->Release();
501 fRootDirectory = NULL;
502 }
503
504 if (fSystemDirectory != NULL) {
505 fSystemDirectory->Release();
506 fSystemDirectory = NULL;
507 }
508
509 if (fPackageVolumeInfo != NULL) {
510 fPackageVolumeInfo->ReleaseReference();
511 fPackageVolumeInfo = NULL;
512 fPackageVolumeState = NULL;
513 }
514 }
515
516
517 status_t
_SetTo(Directory * rootDirectory,PackageVolumeInfo * packageVolumeInfo,PackageVolumeState * packageVolumeState)518 BootVolume::_SetTo(Directory* rootDirectory,
519 PackageVolumeInfo* packageVolumeInfo,
520 PackageVolumeState* packageVolumeState)
521 {
522 Unset();
523
524 if (rootDirectory == NULL)
525 return B_BAD_VALUE;
526
527 fRootDirectory = rootDirectory;
528 fRootDirectory->Acquire();
529
530 // find the system directory
531 Node* systemNode = fRootDirectory->Lookup("system", true);
532 if (systemNode == NULL || !S_ISDIR(systemNode->Type())) {
533 if (systemNode != NULL)
534 systemNode->Release();
535 Unset();
536 return B_ENTRY_NOT_FOUND;
537 }
538
539 fSystemDirectory = static_cast<Directory*>(systemNode);
540
541 if (packageVolumeInfo == NULL) {
542 // get a package volume info
543 BReference<PackageVolumeInfo> packageVolumeInfoReference(
544 new(std::nothrow) PackageVolumeInfo);
545 status_t error = packageVolumeInfoReference->SetTo(fSystemDirectory,
546 "packages");
547 if (error != B_OK) {
548 // apparently not packaged
549 return B_OK;
550 }
551
552 fPackageVolumeInfo = packageVolumeInfoReference.Detach();
553 } else {
554 fPackageVolumeInfo = packageVolumeInfo;
555 fPackageVolumeInfo->AcquireReference();
556 }
557
558 fPackageVolumeState = packageVolumeState != NULL
559 ? packageVolumeState : fPackageVolumeInfo->States().Head();
560
561 // try opening the system package
562 int packageFD = _OpenSystemPackage();
563 if (packageFD < 0)
564 return packageFD;
565
566 // mount packagefs
567 Directory* packageRootDirectory;
568 status_t error = packagefs_mount_file(packageFD, fSystemDirectory,
569 packageRootDirectory);
570 close(packageFD);
571 if (error != B_OK) {
572 Unset();
573 return error;
574 }
575
576 fSystemDirectory->Release();
577 fSystemDirectory = packageRootDirectory;
578
579 return B_OK;
580 }
581
582
583 int
_OpenSystemPackage()584 BootVolume::_OpenSystemPackage()
585 {
586 // open the packages directory
587 Node* packagesNode = fSystemDirectory->Lookup("packages", false);
588 if (packagesNode == NULL)
589 return -1;
590 MethodDeleter<Node, status_t, &Node::Release>
591 packagesNodeReleaser(packagesNode);
592
593 if (!S_ISDIR(packagesNode->Type()))
594 return -1;
595 Directory* packageDirectory = (Directory*)packagesNode;
596
597 // open the system package
598 return open_from(packageDirectory, fPackageVolumeState->SystemPackage(),
599 O_RDONLY);
600 }
601
602
603 // #pragma mark -
604
605
606 status_t
vfs_init(stage2_args * args)607 vfs_init(stage2_args *args)
608 {
609 gRoot = new(nothrow) RootFileSystem();
610 if (gRoot == NULL)
611 return B_NO_MEMORY;
612
613 return B_OK;
614 }
615
616
617 status_t
register_boot_file_system(BootVolume & bootVolume)618 register_boot_file_system(BootVolume& bootVolume)
619 {
620 Directory* rootDirectory = bootVolume.RootDirectory();
621 gRoot->AddLink("boot", rootDirectory);
622
623 Partition *partition;
624 status_t status = gRoot->GetPartitionFor(rootDirectory, &partition);
625 if (status != B_OK) {
626 dprintf("register_boot_file_system(): could not locate boot volume in "
627 "root!\n");
628 return status;
629 }
630
631 gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET,
632 partition->offset);
633
634 if (bootVolume.IsPackaged()) {
635 gBootVolume.SetBool(BOOT_VOLUME_PACKAGED, true);
636 PackageVolumeState* state = bootVolume.GetPackageVolumeState();
637 if (state->Name() != NULL)
638 gBootVolume.AddString(BOOT_VOLUME_PACKAGES_STATE, state->Name());
639 }
640
641 Node *device = get_node_from(partition->FD());
642 if (device == NULL) {
643 dprintf("register_boot_file_system(): could not get boot device!\n");
644 return B_ERROR;
645 }
646
647 return platform_register_boot_device(device);
648 }
649
650
651 /*! Gets the boot device, scans all of its partitions, gets the
652 boot partition, and mounts its file system.
653
654 \param args The stage 2 arguments.
655 \param _bootVolume On success set to the boot volume.
656 \return \c B_OK on success, another error code otherwise.
657 */
658 status_t
get_boot_file_system(stage2_args * args,BootVolume & _bootVolume)659 get_boot_file_system(stage2_args* args, BootVolume& _bootVolume)
660 {
661 status_t error = platform_add_boot_device(args, &gBootDevices);
662 if (error != B_OK)
663 return error;
664
665 NodeIterator iterator = gBootDevices.GetIterator();
666 while (iterator.HasNext()) {
667 Node *device = iterator.Next();
668
669 error = add_partitions_for(device, false, true);
670 if (error != B_OK)
671 continue;
672
673 NodeList bootPartitions;
674 error = platform_get_boot_partitions(args, device, &gPartitions, &bootPartitions);
675 if (error != B_OK)
676 continue;
677
678 NodeIterator partitionIterator = bootPartitions.GetIterator();
679 while (partitionIterator.HasNext()) {
680 Partition *partition = (Partition*)partitionIterator.Next();
681
682 Directory *fileSystem;
683 error = partition->Mount(&fileSystem, true);
684 if (error != B_OK) {
685 // this partition doesn't contain any known file system; we
686 // don't need it anymore
687 gPartitions.Remove(partition);
688 delete partition;
689 continue;
690 }
691
692 // init the BootVolume
693 error = _bootVolume.SetTo(fileSystem);
694 if (error != B_OK)
695 continue;
696
697 sBootDevice = device;
698 return B_OK;
699 }
700 }
701
702 return B_ERROR;
703 }
704
705
706 /** Mounts all file systems recognized on the given device by
707 * calling the add_partitions_for() function on them.
708 */
709
710 status_t
mount_file_systems(stage2_args * args)711 mount_file_systems(stage2_args *args)
712 {
713 // mount other partitions on boot device (if any)
714 NodeIterator iterator = gPartitions.GetIterator();
715
716 Partition *partition = NULL;
717 while ((partition = (Partition *)iterator.Next()) != NULL) {
718 // don't scan known partitions again
719 if (partition->IsFileSystem())
720 continue;
721
722 // remove the partition if it doesn't contain a (known) file system
723 if (partition->Scan(true) != B_OK && !partition->IsFileSystem()) {
724 gPartitions.Remove(partition);
725 delete partition;
726 }
727 }
728
729 // add all block devices the platform has for us
730
731 status_t status = platform_add_block_devices(args, &gBootDevices);
732 if (status < B_OK)
733 return status;
734
735 iterator = gBootDevices.GetIterator();
736 Node *device = NULL, *last = NULL;
737 while ((device = iterator.Next()) != NULL) {
738 // don't scan former boot device again
739 if (device == sBootDevice)
740 continue;
741
742 if (add_partitions_for(device, true) == B_OK) {
743 // ToDo: we can't delete the object here, because it must
744 // be removed from the list before we know that it was
745 // deleted.
746
747 /* // if the Release() deletes the object, we need to skip it
748 if (device->Release() > 0) {
749 list_remove_item(&gBootDevices, device);
750 device = last;
751 }
752 */
753 (void)last;
754 }
755 last = device;
756 }
757
758 if (gPartitions.IsEmpty())
759 return B_ENTRY_NOT_FOUND;
760
761 #if 0
762 void *cookie;
763 if (gRoot->Open(&cookie, O_RDONLY) == B_OK) {
764 Directory *directory;
765 while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) {
766 char name[256];
767 if (directory->GetName(name, sizeof(name)) == B_OK)
768 printf(":: %s (%p)\n", name, directory);
769
770 void *subCookie;
771 if (directory->Open(&subCookie, O_RDONLY) == B_OK) {
772 while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) {
773 printf("\t%s\n", name);
774 }
775 directory->Close(subCookie);
776 }
777 }
778 gRoot->Close(cookie);
779 }
780 #endif
781
782 return B_OK;
783 }
784
785
786 /*! Resolves \a directory + \a path to a node.
787 Note that \a path will be modified by the function.
788 */
789 static status_t
get_node_for_path(Directory * directory,char * path,Node ** _node)790 get_node_for_path(Directory *directory, char *path, Node **_node)
791 {
792 directory->Acquire();
793 // balance Acquire()/Release() calls
794
795 while (true) {
796 Node *nextNode;
797 char *nextPath;
798
799 // walk to find the next path component ("path" will point to a single
800 // path component), and filter out multiple slashes
801 for (nextPath = path + 1; nextPath[0] != '\0' && nextPath[0] != '/'; nextPath++);
802
803 if (*nextPath == '/') {
804 *nextPath = '\0';
805 do
806 nextPath++;
807 while (*nextPath == '/');
808 }
809
810 nextNode = directory->Lookup(path, true);
811 directory->Release();
812
813 if (nextNode == NULL)
814 return B_ENTRY_NOT_FOUND;
815
816 path = nextPath;
817 if (S_ISDIR(nextNode->Type()))
818 directory = (Directory *)nextNode;
819 else if (path[0])
820 return B_NOT_ALLOWED;
821
822 // are we done?
823 if (path[0] == '\0') {
824 *_node = nextNode;
825 return B_OK;
826 }
827 }
828
829 return B_ENTRY_NOT_FOUND;
830 }
831
832
833 /*! Version of get_node_for_path() not modifying \a path.
834 */
835 static status_t
get_node_for_path(Directory * directory,const char * path,Node ** _node)836 get_node_for_path(Directory* directory, const char* path, Node** _node)
837 {
838 char* mutablePath = strdup(path);
839 if (mutablePath == NULL)
840 return B_NO_MEMORY;
841 MemoryDeleter mutablePathDeleter(mutablePath);
842
843 return get_node_for_path(directory, mutablePath, _node);
844 }
845
846 // #pragma mark -
847
848
849 static Descriptor *
get_descriptor(int fd)850 get_descriptor(int fd)
851 {
852 if (fd < 0 || fd >= MAX_VFS_DESCRIPTORS)
853 return NULL;
854
855 return sDescriptors[fd];
856 }
857
858
859 static void
free_descriptor(int fd)860 free_descriptor(int fd)
861 {
862 if (fd >= MAX_VFS_DESCRIPTORS)
863 return;
864
865 delete sDescriptors[fd];
866 sDescriptors[fd] = NULL;
867 }
868
869
870 /** Reserves an entry of the descriptor table and
871 * assigns the given node to it.
872 */
873
874 int
open_node(Node * node,int mode)875 open_node(Node *node, int mode)
876 {
877 if (node == NULL)
878 return B_ERROR;
879
880 // get free descriptor
881
882 int fd = 0;
883 for (; fd < MAX_VFS_DESCRIPTORS; fd++) {
884 if (sDescriptors[fd] == NULL)
885 break;
886 }
887 if (fd == MAX_VFS_DESCRIPTORS)
888 return B_ERROR;
889
890 TRACE(("got descriptor %d for node %p\n", fd, node));
891
892 // we got a free descriptor entry, now try to open the node
893
894 void *cookie;
895 status_t status = node->Open(&cookie, mode);
896 if (status < B_OK)
897 return status;
898
899 TRACE(("could open node at %p\n", node));
900
901 Descriptor *descriptor = new(nothrow) Descriptor(node, cookie);
902 if (descriptor == NULL)
903 return B_NO_MEMORY;
904
905 sDescriptors[fd] = descriptor;
906
907 return fd;
908 }
909
910
911 int
dup(int fd)912 dup(int fd)
913 {
914 Descriptor *descriptor = get_descriptor(fd);
915 if (descriptor == NULL)
916 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
917
918 descriptor->Acquire();
919 RETURN_AND_SET_ERRNO(fd);
920 }
921
922
923 off_t
lseek(int fd,off_t offset,int whence)924 lseek(int fd, off_t offset, int whence)
925 {
926 Descriptor* descriptor = get_descriptor(fd);
927 if (descriptor == NULL)
928 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
929
930 status_t error = descriptor->Seek(offset, whence);
931 if (error != B_OK)
932 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
933
934 return descriptor->Offset();
935 }
936
937
938 int
ftruncate(int fd,off_t newSize)939 ftruncate(int fd, off_t newSize)
940 {
941 dprintf("ftruncate() not implemented!\n");
942 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
943 }
944
945
946 ssize_t
read_pos(int fd,off_t offset,void * buffer,size_t bufferSize)947 read_pos(int fd, off_t offset, void *buffer, size_t bufferSize)
948 {
949 Descriptor *descriptor = get_descriptor(fd);
950 if (descriptor == NULL)
951 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
952
953 RETURN_AND_SET_ERRNO(descriptor->ReadAt(offset, buffer, bufferSize));
954 }
955
956
957 ssize_t
pread(int fd,void * buffer,size_t bufferSize,off_t offset)958 pread(int fd, void* buffer, size_t bufferSize, off_t offset)
959 {
960 return read_pos(fd, offset, buffer, bufferSize);
961 }
962
963
964 ssize_t
read(int fd,void * buffer,size_t bufferSize)965 read(int fd, void *buffer, size_t bufferSize)
966 {
967 Descriptor *descriptor = get_descriptor(fd);
968 if (descriptor == NULL)
969 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
970
971 RETURN_AND_SET_ERRNO(descriptor->Read(buffer, bufferSize));
972 }
973
974
975 ssize_t
write_pos(int fd,off_t offset,const void * buffer,size_t bufferSize)976 write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize)
977 {
978 Descriptor *descriptor = get_descriptor(fd);
979 if (descriptor == NULL)
980 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
981
982 RETURN_AND_SET_ERRNO(descriptor->WriteAt(offset, buffer, bufferSize));
983 }
984
985
986 ssize_t
pwrite(int fd,const void * buffer,size_t bufferSize,off_t offset)987 pwrite(int fd, const void* buffer, size_t bufferSize, off_t offset)
988 {
989 return write_pos(fd, offset, buffer, bufferSize);
990 }
991
992
993 ssize_t
write(int fd,const void * buffer,size_t bufferSize)994 write(int fd, const void *buffer, size_t bufferSize)
995 {
996 Descriptor *descriptor = get_descriptor(fd);
997 if (descriptor == NULL)
998 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
999
1000 RETURN_AND_SET_ERRNO(descriptor->Write(buffer, bufferSize));
1001 }
1002
1003
1004 ssize_t
writev(int fd,const struct iovec * vecs,int count)1005 writev(int fd, const struct iovec* vecs, int count)
1006 {
1007 size_t totalWritten = 0;
1008
1009 if (count < 0)
1010 RETURN_AND_SET_ERRNO(B_BAD_VALUE);
1011
1012 for (int i = 0; i < count; i++) {
1013 ssize_t written = write(fd, vecs[i].iov_base, vecs[i].iov_len);
1014 if (written < 0)
1015 return totalWritten == 0 ? written : totalWritten;
1016
1017 totalWritten += written;
1018
1019 if ((size_t)written != vecs[i].iov_len)
1020 break;
1021 }
1022
1023 return totalWritten;
1024 }
1025
1026
1027 int
open(const char * name,int mode,...)1028 open(const char *name, int mode, ...)
1029 {
1030 mode_t permissions = 0;
1031 if ((mode & O_CREAT) != 0) {
1032 va_list args;
1033 va_start(args, mode);
1034 permissions = va_arg(args, int) /*& ~__gUmask*/;
1035 // adapt the permissions as required by POSIX
1036 va_end(args);
1037 }
1038
1039 // we always start at the top (there is no notion of a current directory (yet?))
1040 RETURN_AND_SET_ERRNO(open_from(gRoot, name, mode, permissions));
1041 }
1042
1043
1044 int
open_from(Directory * directory,const char * name,int mode,mode_t permissions)1045 open_from(Directory *directory, const char *name, int mode, mode_t permissions)
1046 {
1047 if (name[0] == '/') {
1048 // ignore the directory and start from root if we are asked to do that
1049 directory = gRoot;
1050 name++;
1051 }
1052
1053 char* path = (char*)malloc(B_PATH_NAME_LENGTH);
1054 if (path == NULL)
1055 return B_NO_MEMORY;
1056
1057 if (strlcpy(path, name, B_PATH_NAME_LENGTH) >= B_PATH_NAME_LENGTH) {
1058 free(path);
1059 return B_NAME_TOO_LONG;
1060 }
1061
1062 Node *node;
1063 status_t error = get_node_for_path(directory, path, &node);
1064 if (error != B_OK) {
1065 if (error != B_ENTRY_NOT_FOUND) {
1066 free(path);
1067 return error;
1068 }
1069
1070 if ((mode & O_CREAT) == 0) {
1071 free(path);
1072 return B_ENTRY_NOT_FOUND;
1073 }
1074
1075 // try to resolve the parent directory
1076 strlcpy(path, name, B_PATH_NAME_LENGTH);
1077 if (char* lastSlash = strrchr(path, '/')) {
1078 if (lastSlash[1] == '\0') {
1079 free(path);
1080 return B_ENTRY_NOT_FOUND;
1081 }
1082
1083 *lastSlash = '\0';
1084 name = lastSlash + 1;
1085
1086 // resolve the directory
1087 if (get_node_for_path(directory, path, &node) != B_OK) {
1088 free(path);
1089 return B_ENTRY_NOT_FOUND;
1090 }
1091
1092 if (node->Type() != S_IFDIR) {
1093 node->Release();
1094 free(path);
1095 return B_NOT_A_DIRECTORY;
1096 }
1097
1098 directory = static_cast<Directory*>(node);
1099 } else
1100 directory->Acquire();
1101
1102 // create the file
1103 error = directory->CreateFile(name, permissions, &node);
1104 directory->Release();
1105
1106 if (error != B_OK) {
1107 free(path);
1108 return error;
1109 }
1110 } else if ((mode & O_EXCL) != 0) {
1111 node->Release();
1112 free(path);
1113 return B_FILE_EXISTS;
1114 }
1115
1116 int fd = open_node(node, mode);
1117
1118 node->Release();
1119 free(path);
1120 return fd;
1121 }
1122
1123
1124 /** Since we don't have directory functions yet, this
1125 * function is needed to get the contents of a directory.
1126 * It should be removed once readdir() & co. are in place.
1127 */
1128
1129 Node *
get_node_from(int fd)1130 get_node_from(int fd)
1131 {
1132 Descriptor *descriptor = get_descriptor(fd);
1133 if (descriptor == NULL)
1134 return NULL;
1135
1136 return descriptor->GetNode();
1137 }
1138
1139
1140 status_t
get_stat(Directory * directory,const char * path,struct stat & st)1141 get_stat(Directory* directory, const char* path, struct stat& st)
1142 {
1143 Node* node;
1144 status_t error = get_node_for_path(directory, path, &node);
1145 if (error != B_OK)
1146 return error;
1147
1148 node->Stat(st);
1149 node->Release();
1150 return B_OK;
1151 }
1152
1153
1154 Directory*
directory_from(DIR * dir)1155 directory_from(DIR* dir)
1156 {
1157 return dir != NULL ? dir->directory : NULL;
1158 }
1159
1160
1161 int
close(int fd)1162 close(int fd)
1163 {
1164 Descriptor *descriptor = get_descriptor(fd);
1165 if (descriptor == NULL)
1166 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1167
1168 status_t status = descriptor->Release();
1169 if (!descriptor->RefCount())
1170 free_descriptor(fd);
1171
1172 RETURN_AND_SET_ERRNO(status);
1173 }
1174
1175
1176 // ToDo: remove this kludge when possible
1177 int
1178 #if defined(fstat) && !defined(main)
_fstat(int fd,struct stat * stat,size_t)1179 _fstat(int fd, struct stat *stat, size_t /*statSize*/)
1180 #else
1181 fstat(int fd, struct stat *stat)
1182 #endif
1183 {
1184 if (stat == NULL)
1185 RETURN_AND_SET_ERRNO(B_BAD_VALUE);
1186
1187 Descriptor *descriptor = get_descriptor(fd);
1188 if (descriptor == NULL)
1189 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1190
1191 descriptor->Stat(*stat);
1192 return 0;
1193 }
1194
1195
1196 DIR*
open_directory(Directory * baseDirectory,const char * path)1197 open_directory(Directory* baseDirectory, const char* path)
1198 {
1199 DIR* dir = new(std::nothrow) DIR;
1200 if (dir == NULL) {
1201 errno = B_NO_MEMORY;
1202 return NULL;
1203 }
1204 ObjectDeleter<DIR> dirDeleter(dir);
1205
1206 Node* node;
1207 status_t error = get_node_for_path(baseDirectory, path, &node);
1208 if (error != B_OK) {
1209 errno = error;
1210 return NULL;
1211 }
1212 MethodDeleter<Node, status_t, &Node::Release> nodeReleaser(node);
1213
1214 if (!S_ISDIR(node->Type())) {
1215 errno = error;
1216 return NULL;
1217 }
1218
1219 dir->directory = static_cast<Directory*>(node);
1220
1221 error = dir->directory->Open(&dir->cookie, O_RDONLY);
1222 if (error != B_OK) {
1223 errno = error;
1224 return NULL;
1225 }
1226
1227 nodeReleaser.Detach();
1228 return dirDeleter.Detach();
1229 }
1230
1231
1232 DIR*
opendir(const char * dirName)1233 opendir(const char* dirName)
1234 {
1235 return open_directory(gRoot, dirName);
1236 }
1237
1238
1239 int
closedir(DIR * dir)1240 closedir(DIR* dir)
1241 {
1242 if (dir != NULL) {
1243 dir->directory->Close(dir->cookie);
1244 dir->directory->Release();
1245 delete dir;
1246 }
1247
1248 return 0;
1249 }
1250
1251
1252 struct dirent*
readdir(DIR * dir)1253 readdir(DIR* dir)
1254 {
1255 if (dir == NULL) {
1256 errno = B_BAD_VALUE;
1257 return NULL;
1258 }
1259
1260 for (;;) {
1261 status_t error = dir->directory->GetNextEntry(dir->cookie,
1262 dir->entry()->d_name, B_FILE_NAME_LENGTH);
1263 if (error != B_OK) {
1264 errno = error;
1265 return NULL;
1266 }
1267
1268 dir->entry()->d_pdev = 0;
1269 // not supported
1270 dir->entry()->d_pino = dir->directory->Inode();
1271 dir->entry()->d_dev = dir->entry()->d_pdev;
1272 // not supported
1273
1274 if (strcmp(dir->entry()->d_name, ".") == 0
1275 || strcmp(dir->entry()->d_name, "..") == 0) {
1276 // Note: That's obviously not correct for "..", but we can't
1277 // retrieve that information.
1278 dir->entry()->d_ino = dir->entry()->d_pino;
1279 } else {
1280 Node* node = dir->directory->Lookup(dir->entry()->d_name, false);
1281 if (node == NULL)
1282 continue;
1283
1284 dir->entry()->d_ino = node->Inode();
1285 node->Release();
1286 }
1287
1288 return dir->entry();
1289 }
1290 }
1291
1292
1293 void
rewinddir(DIR * dir)1294 rewinddir(DIR* dir)
1295 {
1296 if (dir == NULL) {
1297 errno = B_BAD_VALUE;
1298 return;
1299 }
1300
1301 status_t error = dir->directory->Rewind(dir->cookie);
1302 if (error != B_OK)
1303 errno = error;
1304 }
1305