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