vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / file_systems / packagefs / kernel_interface.cpp
blob00f19246c7851d8d858ffea6fe6011e1afa16357
1 /*
2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "kernel_interface.h"
9 #include <dirent.h>
11 #include <new>
13 #include <fs_info.h>
14 #include <fs_interface.h>
15 #include <KernelExport.h>
16 #include <io_requests.h>
18 #include <AutoDeleter.h>
20 #include "AttributeCookie.h"
21 #include "AttributeDirectoryCookie.h"
22 #include "DebugSupport.h"
23 #include "Directory.h"
24 #include "GlobalFactory.h"
25 #include "Query.h"
26 #include "PackageFSRoot.h"
27 #include "StringConstants.h"
28 #include "StringPool.h"
29 #include "Utils.h"
30 #include "Volume.h"
33 static const uint32 kOptimalIOSize = 64 * 1024;
36 // #pragma mark - helper functions
39 static status_t
40 check_access(Node* node, int mode)
42 // write access requested?
43 if (mode & W_OK)
44 return B_READ_ONLY_DEVICE;
46 return check_access_permissions(mode, node->Mode(), node->GroupID(),
47 node->UserID());
51 // #pragma mark - Volume
54 static status_t
55 packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
56 const char* parameters, ino_t* _rootID)
58 FUNCTION("fsVolume: %p, device: \"%s\", flags: %#" B_PRIx32 ", parameters: "
59 "\"%s\"\n", fsVolume, device, flags, parameters);
61 // create a Volume object
62 Volume* volume = new(std::nothrow) Volume(fsVolume);
63 if (volume == NULL)
64 RETURN_ERROR(B_NO_MEMORY);
65 ObjectDeleter<Volume> volumeDeleter(volume);
67 // Initialize the fs_volume now already, so it is mostly usable in during
68 // mounting.
69 fsVolume->private_volume = volumeDeleter.Detach();
70 fsVolume->ops = &gPackageFSVolumeOps;
72 status_t error = volume->Mount(parameters);
73 if (error != B_OK)
74 return error;
76 // set return values
77 *_rootID = volume->RootDirectory()->ID();
79 return B_OK;
83 static status_t
84 packagefs_unmount(fs_volume* fsVolume)
86 Volume* volume = (Volume*)fsVolume->private_volume;
88 FUNCTION("volume: %p\n", volume);
90 volume->Unmount();
91 delete volume;
93 return B_OK;
97 static status_t
98 packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
100 Volume* volume = (Volume*)fsVolume->private_volume;
102 FUNCTION("volume: %p, info: %p\n", volume, info);
104 info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY | B_FS_HAS_MIME
105 | B_FS_HAS_ATTR | B_FS_HAS_QUERY | B_FS_SUPPORTS_NODE_MONITORING;
106 info->block_size = 4096;
107 info->io_size = kOptimalIOSize;
108 info->total_blocks = info->free_blocks = 1;
109 strlcpy(info->volume_name, volume->RootDirectory()->Name(),
110 sizeof(info->volume_name));
111 return B_OK;
115 // #pragma mark - VNodes
118 static status_t
119 packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
120 ino_t* _vnid)
122 Volume* volume = (Volume*)fsVolume->private_volume;
123 Node* dir = (Node*)fsDir->private_node;
125 FUNCTION("volume: %p, dir: %p (%" B_PRId64 "), entry: \"%s\"\n", volume,
126 dir, dir->ID(), entryName);
128 if (!S_ISDIR(dir->Mode()))
129 return B_NOT_A_DIRECTORY;
131 // resolve "."
132 if (strcmp(entryName, ".") == 0) {
133 Node* node;
134 *_vnid = dir->ID();
135 return volume->GetVNode(*_vnid, node);
138 // resolve ".."
139 if (strcmp(entryName, "..") == 0) {
140 Node* node;
141 *_vnid = dir->Parent()->ID();
142 return volume->GetVNode(*_vnid, node);
145 // resolve normal entries -- look up the node
146 NodeReadLocker dirLocker(dir);
147 String entryNameString;
148 Node* node = dynamic_cast<Directory*>(dir)->FindChild(StringKey(entryName));
149 if (node == NULL)
150 return B_ENTRY_NOT_FOUND;
151 BReference<Node> nodeReference(node);
152 dirLocker.Unlock();
154 // get the vnode reference
155 *_vnid = node->ID();
156 RETURN_ERROR(volume->GetVNode(*_vnid, node));
160 static status_t
161 packagefs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
162 size_t bufferSize)
164 Node* node = (Node*)fsNode->private_node;
166 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), %p, %zu\n",
167 fsVolume->private_volume, node, node->ID(), buffer, bufferSize);
169 if (strlcpy(buffer, node->Name(), bufferSize) >= bufferSize)
170 return B_BUFFER_OVERFLOW;
172 return B_OK;
176 static status_t
177 packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
178 int* _type, uint32* _flags, bool reenter)
180 Volume* volume = (Volume*)fsVolume->private_volume;
182 FUNCTION("volume: %p, vnid: %" B_PRId64 "\n", volume, vnid);
184 VolumeReadLocker volumeLocker(volume);
185 Node* node = volume->FindNode(vnid);
186 if (node == NULL)
187 return B_ENTRY_NOT_FOUND;
188 BReference<Node> nodeReference(node);
189 volumeLocker.Unlock();
191 NodeWriteLocker nodeLocker(node);
192 status_t error = node->VFSInit(volume->ID());
193 if (error != B_OK)
194 RETURN_ERROR(error);
195 nodeLocker.Unlock();
197 fsNode->private_node = nodeReference.Detach();
198 fsNode->ops = &gPackageFSVnodeOps;
199 *_type = node->Mode() & S_IFMT;
200 *_flags = 0;
202 return B_OK;
206 static status_t
207 packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
209 Volume* volume = (Volume*)fsVolume->private_volume;
210 Node* node = (Node*)fsNode->private_node;
212 FUNCTION("volume: %p, node: %p\n", volume, node);
213 TOUCH(volume);
215 NodeWriteLocker nodeLocker(node);
216 node->VFSUninit();
217 nodeLocker.Unlock();
219 node->ReleaseReference();
221 return B_OK;
225 // #pragma mark - Request I/O
228 static status_t
229 packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
230 io_request* request)
232 Volume* volume = (Volume*)fsVolume->private_volume;
233 Node* node = (Node*)fsNode->private_node;
235 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, request: %p\n",
236 volume, node, node->ID(), cookie, request);
237 TOUCH(volume);
239 if (io_request_is_write(request))
240 RETURN_ERROR(B_READ_ONLY_DEVICE);
242 status_t error = node->Read(request);
243 notify_io_request(request, error);
244 return error;
248 // #pragma mark - Nodes
251 status_t
252 packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
253 uint32 operation, void* buffer, size_t size)
255 Volume* volume = (Volume*)fsVolume->private_volume;
256 Node* node = (Node*)fsNode->private_node;
258 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, operation: %"
259 B_PRIu32 ", buffer: %p, size: %zu\n", volume, node, node->ID(), cookie,
260 operation, buffer, size);
261 TOUCH(cookie);
263 return volume->IOCtl(node, operation, buffer, size);
267 static status_t
268 packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
269 size_t* _bufferSize)
271 Volume* volume = (Volume*)fsVolume->private_volume;
272 Node* node = (Node*)fsNode->private_node;
274 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
275 node->ID());
276 TOUCH(volume);
278 NodeReadLocker nodeLocker(node);
280 if (!S_ISLNK(node->Mode()))
281 return B_BAD_VALUE;
283 return node->ReadSymlink(buffer, _bufferSize);
287 static status_t
288 packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode)
290 Volume* volume = (Volume*)fsVolume->private_volume;
291 Node* node = (Node*)fsNode->private_node;
293 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
294 node->ID());
295 TOUCH(volume);
297 NodeReadLocker nodeLocker(node);
298 return check_access(node, mode);
302 static status_t
303 packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
305 Volume* volume = (Volume*)fsVolume->private_volume;
306 Node* node = (Node*)fsNode->private_node;
308 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
309 node->ID());
310 TOUCH(volume);
312 NodeReadLocker nodeLocker(node);
314 st->st_mode = node->Mode();
315 st->st_nlink = 1;
316 st->st_uid = node->UserID();
317 st->st_gid = node->GroupID();
318 st->st_size = node->FileSize();
319 st->st_blksize = kOptimalIOSize;
320 st->st_mtim = node->ModifiedTime();
321 st->st_atim = st->st_mtim;
322 st->st_ctim = st->st_mtim;
323 // TODO: Perhaps manage a changed time (particularly for directories)?
324 st->st_crtim = st->st_mtim;
325 st->st_blocks = (st->st_size + 511) / 512;
327 return B_OK;
331 // #pragma mark - Files
334 struct FileCookie {
335 int openMode;
337 FileCookie(int openMode)
339 openMode(openMode)
345 static status_t
346 packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
347 void** _cookie)
349 Volume* volume = (Volume*)fsVolume->private_volume;
350 Node* node = (Node*)fsNode->private_node;
352 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), openMode %#x\n",
353 volume, node, node->ID(), openMode);
354 TOUCH(volume);
356 NodeReadLocker nodeLocker(node);
358 // check the open mode and permissions
359 if (S_ISDIR(node->Mode()) && (openMode & O_RWMASK) != O_RDONLY)
360 return B_IS_A_DIRECTORY;
362 if ((openMode & O_RWMASK) != O_RDONLY)
363 return B_NOT_ALLOWED;
365 status_t error = check_access(node, R_OK);
366 if (error != B_OK)
367 return error;
369 // allocate the cookie
370 FileCookie* cookie = new(std::nothrow) FileCookie(openMode);
371 if (cookie == NULL)
372 RETURN_ERROR(B_NO_MEMORY);
374 *_cookie = cookie;
376 return B_OK;
380 static status_t
381 packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
383 return B_OK;
387 static status_t
388 packagefs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
390 Volume* volume = (Volume*)fsVolume->private_volume;
391 Node* node = (Node*)fsNode->private_node;
392 FileCookie* cookie = (FileCookie*)_cookie;
394 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
395 node->ID(), cookie);
396 TOUCH(volume);
397 TOUCH(node);
399 delete cookie;
401 return B_OK;
405 static status_t
406 packagefs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
407 off_t offset, void* buffer, size_t* bufferSize)
409 Volume* volume = (Volume*)fsVolume->private_volume;
410 Node* node = (Node*)fsNode->private_node;
411 FileCookie* cookie = (FileCookie*)_cookie;
413 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, offset: %"
414 B_PRId64 ", buffer: %p, size: %" B_PRIuSIZE "\n", volume, node,
415 node->ID(), cookie, offset, buffer, *bufferSize);
416 TOUCH(volume);
418 if ((cookie->openMode & O_RWMASK) != O_RDONLY)
419 return EBADF;
421 return node->Read(offset, buffer, bufferSize);
425 // #pragma mark - Directories
428 struct DirectoryCookie : DirectoryIterator {
429 Directory* directory;
430 int32 state;
431 bool registered;
433 DirectoryCookie(Directory* directory)
435 directory(directory),
436 state(0),
437 registered(false)
439 Rewind();
442 ~DirectoryCookie()
444 if (registered)
445 directory->RemoveDirectoryIterator(this);
448 void Rewind()
450 if (registered)
451 directory->RemoveDirectoryIterator(this);
452 registered = false;
454 state = 0;
455 node = directory;
458 Node* Current(const char*& _name) const
460 if (node == NULL)
461 return NULL;
463 if (state == 0)
464 _name = ".";
465 else if (state == 1)
466 _name = "..";
467 else
468 _name = node->Name();
470 return node;
473 Node* Next()
475 if (state == 0) {
476 state = 1;
477 node = directory->Parent();
478 if (node == NULL)
479 node = directory;
480 return node;
483 if (state == 1) {
484 node = directory->FirstChild();
485 state = 2;
486 } else {
487 if (node != NULL)
488 node = directory->NextChild(node);
491 if (node == NULL) {
492 if (registered) {
493 directory->RemoveDirectoryIterator(this);
494 registered = false;
497 return NULL;
500 if (!registered) {
501 directory->AddDirectoryIterator(this);
502 registered = true;
505 return node;
510 static status_t
511 packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
513 Volume* volume = (Volume*)fsVolume->private_volume;
514 Node* node = (Node*)fsNode->private_node;
516 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
517 node->ID());
518 TOUCH(volume);
520 if (!S_ISDIR(node->Mode()))
521 return B_NOT_A_DIRECTORY;
523 Directory* dir = dynamic_cast<Directory*>(node);
525 status_t error = check_access(dir, R_OK);
526 if (error != B_OK)
527 return error;
529 // create a cookie
530 NodeWriteLocker dirLocker(dir);
531 DirectoryCookie* cookie = new(std::nothrow) DirectoryCookie(dir);
532 if (cookie == NULL)
533 RETURN_ERROR(B_NO_MEMORY);
535 *_cookie = cookie;
536 return B_OK;
540 static status_t
541 packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
543 return B_OK;
547 static status_t
548 packagefs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
550 Volume* volume = (Volume*)fsVolume->private_volume;
551 Node* node = (Node*)fsNode->private_node;
552 DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
554 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
555 node->ID(), cookie);
556 TOUCH(volume);
557 TOUCH(node);
559 NodeWriteLocker dirLocker(node);
560 delete cookie;
562 return B_OK;
566 static status_t
567 packagefs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
568 struct dirent* buffer, size_t bufferSize, uint32* _count)
570 Volume* volume = (Volume*)fsVolume->private_volume;
571 Node* node = (Node*)fsNode->private_node;
572 DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
574 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
575 node->ID(), cookie);
576 TOUCH(volume);
577 TOUCH(node);
579 NodeWriteLocker dirLocker(cookie->directory);
581 uint32 maxCount = *_count;
582 uint32 count = 0;
584 dirent* previousEntry = NULL;
586 const char* name;
587 while (Node* child = cookie->Current(name)) {
588 // don't read more entries than requested
589 if (count >= maxCount)
590 break;
592 // align the buffer for subsequent entries
593 if (count > 0) {
594 addr_t offset = (addr_t)buffer % 8;
595 if (offset > 0) {
596 offset = 8 - offset;
597 if (bufferSize <= offset)
598 break;
600 previousEntry->d_reclen += offset;
601 buffer = (dirent*)((addr_t)buffer + offset);
602 bufferSize -= offset;
606 // fill in the entry name -- checks whether the entry fits into the
607 // buffer
608 if (!set_dirent_name(buffer, bufferSize, name)) {
609 if (count == 0)
610 RETURN_ERROR(B_BUFFER_OVERFLOW);
611 break;
614 // fill in the other data
615 buffer->d_dev = volume->ID();
616 buffer->d_ino = child->ID();
618 count++;
619 previousEntry = buffer;
620 bufferSize -= buffer->d_reclen;
621 buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
623 cookie->Next();
626 *_count = count;
627 return B_OK;
631 static status_t
632 packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
634 Volume* volume = (Volume*)fsVolume->private_volume;
635 Node* node = (Node*)fsNode->private_node;
636 DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
638 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
639 node->ID(), cookie);
640 TOUCH(volume);
641 TOUCH(node);
643 NodeWriteLocker dirLocker(node);
644 cookie->Rewind();
646 return B_OK;
650 // #pragma mark - Attribute Directories
653 status_t
654 packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
656 Volume* volume = (Volume*)fsVolume->private_volume;
657 Node* node = (Node*)fsNode->private_node;
659 FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
660 node->ID());
661 TOUCH(volume);
663 status_t error = check_access(node, R_OK);
664 if (error != B_OK)
665 return error;
667 // create a cookie
668 NodeReadLocker nodeLocker(node);
669 AttributeDirectoryCookie* cookie;
670 error = node->OpenAttributeDirectory(cookie);
671 if (error != B_OK)
672 RETURN_ERROR(error);
674 *_cookie = cookie;
675 return B_OK;
679 status_t
680 packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
682 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
683 return cookie->Close();
687 status_t
688 packagefs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
689 void* _cookie)
691 Volume* volume = (Volume*)fsVolume->private_volume;
692 Node* node = (Node*)fsNode->private_node;
693 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
695 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
696 node->ID(), cookie);
697 TOUCH(volume);
698 TOUCH(node);
700 delete cookie;
702 return B_OK;
706 status_t
707 packagefs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
708 struct dirent* buffer, size_t bufferSize, uint32* _count)
710 Volume* volume = (Volume*)fsVolume->private_volume;
711 Node* node = (Node*)fsNode->private_node;
712 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
714 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
715 node->ID(), cookie);
716 TOUCH(volume);
717 TOUCH(node);
719 return cookie->Read(volume->ID(), node->ID(), buffer, bufferSize, _count);
723 status_t
724 packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
726 Volume* volume = (Volume*)fsVolume->private_volume;
727 Node* node = (Node*)fsNode->private_node;
728 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
730 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
731 node->ID(), cookie);
732 TOUCH(volume);
733 TOUCH(node);
735 return cookie->Rewind();
739 // #pragma mark - Attribute Operations
742 status_t
743 packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
744 int openMode, void** _cookie)
746 Volume* volume = (Volume*)fsVolume->private_volume;
747 Node* node = (Node*)fsNode->private_node;
749 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), name: \"%s\", openMode "
750 "%#x\n", volume, node, node->ID(), name, openMode);
751 TOUCH(volume);
753 NodeReadLocker nodeLocker(node);
755 // check the open mode and permissions
756 if ((openMode & O_RWMASK) != O_RDONLY)
757 return B_NOT_ALLOWED;
759 status_t error = check_access(node, R_OK);
760 if (error != B_OK)
761 return error;
763 AttributeCookie* cookie;
764 error = node->OpenAttribute(StringKey(name), openMode, cookie);
765 if (error != B_OK)
766 return error;
768 *_cookie = cookie;
769 return B_OK;
773 status_t
774 packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
776 AttributeCookie* cookie = (AttributeCookie*)_cookie;
777 RETURN_ERROR(cookie->Close());
781 status_t
782 packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
784 Volume* volume = (Volume*)fsVolume->private_volume;
785 Node* node = (Node*)fsNode->private_node;
786 AttributeCookie* cookie = (AttributeCookie*)_cookie;
788 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
789 node->ID(), cookie);
790 TOUCH(volume);
791 TOUCH(node);
793 delete cookie;
795 return B_OK;
799 status_t
800 packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
801 off_t offset, void* buffer, size_t* bufferSize)
803 Volume* volume = (Volume*)fsVolume->private_volume;
804 Node* node = (Node*)fsNode->private_node;
805 AttributeCookie* cookie = (AttributeCookie*)_cookie;
807 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
808 node->ID(), cookie);
809 TOUCH(volume);
810 TOUCH(node);
812 return cookie->ReadAttribute(offset, buffer, bufferSize);
816 status_t
817 packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
818 void* _cookie, struct stat* st)
820 Volume* volume = (Volume*)fsVolume->private_volume;
821 Node* node = (Node*)fsNode->private_node;
822 AttributeCookie* cookie = (AttributeCookie*)_cookie;
824 FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
825 node->ID(), cookie);
826 TOUCH(volume);
827 TOUCH(node);
829 return cookie->ReadAttributeStat(st);
833 // #pragma mark - index directory & index operations
836 // NOTE: We don't do any locking in the index dir hooks, since once mounted
837 // the index directory is immutable.
840 status_t
841 packagefs_open_index_dir(fs_volume* fsVolume, void** _cookie)
843 Volume* volume = (Volume*)fsVolume->private_volume;
845 FUNCTION("volume: %p\n", volume);
847 IndexDirIterator* iterator = new(std::nothrow) IndexDirIterator(
848 volume->GetIndexDirIterator());
849 if (iterator == NULL)
850 return B_NO_MEMORY;
852 *_cookie = iterator;
853 return B_OK;
857 status_t
858 packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
860 return B_OK;
864 status_t
865 packagefs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
867 FUNCTION("volume: %p, cookie: %p\n", fsVolume->private_volume, cookie);
869 delete (IndexDirIterator*)cookie;
870 return B_OK;
874 status_t
875 packagefs_read_index_dir(fs_volume* fsVolume, void* cookie,
876 struct dirent* buffer, size_t bufferSize, uint32* _num)
878 Volume* volume = (Volume*)fsVolume->private_volume;
880 FUNCTION("volume: %p, cookie: %p, buffer: %p, bufferSize: %zu, num: %"
881 B_PRIu32 "\n", volume, cookie, buffer, bufferSize, *_num);
883 IndexDirIterator* iterator = (IndexDirIterator*)cookie;
885 if (*_num == 0)
886 return B_BAD_VALUE;
888 IndexDirIterator previousIterator = *iterator;
890 // get the next index
891 Index* index = iterator->Next();
892 if (index == NULL) {
893 *_num = 0;
894 return B_OK;
897 // fill in the entry
898 if (!set_dirent_name(buffer, bufferSize, index->Name())) {
899 *iterator = previousIterator;
900 return B_BUFFER_OVERFLOW;
903 buffer->d_dev = volume->ID();
904 buffer->d_ino = 0;
906 *_num = 1;
907 return B_OK;
911 status_t
912 packagefs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
914 Volume* volume = (Volume*)fsVolume->private_volume;
916 FUNCTION("volume: %p, cookie: %p\n", volume, cookie);
918 IndexDirIterator* iterator = (IndexDirIterator*)cookie;
919 *iterator = volume->GetIndexDirIterator();
921 return B_OK;
925 status_t
926 packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
927 uint32 flags)
929 return B_NOT_SUPPORTED;
933 status_t
934 packagefs_remove_index(fs_volume* fsVolume, const char* name)
936 return B_NOT_SUPPORTED;
940 status_t
941 packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
942 struct stat* stat)
944 Volume* volume = (Volume*)fsVolume->private_volume;
946 FUNCTION("volume: %p, name: \"%s\", stat: %p\n", volume, name, stat);
948 Index* index = volume->FindIndex(StringKey(name));
949 if (index == NULL)
950 return B_ENTRY_NOT_FOUND;
952 VolumeReadLocker volumeReadLocker(volume);
954 memset(stat, 0, sizeof(*stat));
955 // TODO: st_mtime, st_crtime, st_uid, st_gid are made available to
956 // userland, so we should make an attempt to fill in values that make
957 // sense.
959 stat->st_type = index->Type();
960 stat->st_size = index->CountEntries();
962 return B_OK;
966 // #pragma mark - query operations
969 status_t
970 packagefs_open_query(fs_volume* fsVolume, const char* queryString, uint32 flags,
971 port_id port, uint32 token, void** _cookie)
973 Volume* volume = (Volume*)fsVolume->private_volume;
975 FUNCTION("volume: %p, query: \"%s\", flags: %#" B_PRIx32 ", port: %"
976 B_PRId32 ", token: %" B_PRIu32 "\n", volume, queryString, flags, port,
977 token);
979 VolumeWriteLocker volumeWriteLocker(volume);
981 Query* query;
982 status_t error = Query::Create(volume, queryString, flags, port, token,
983 query);
984 if (error != B_OK)
985 return error;
987 *_cookie = query;
988 return B_OK;
992 status_t
993 packagefs_close_query(fs_volume* fsVolume, void* cookie)
995 FUNCTION_START();
996 return B_OK;
1000 status_t
1001 packagefs_free_query_cookie(fs_volume* fsVolume, void* cookie)
1003 Volume* volume = (Volume*)fsVolume->private_volume;
1004 Query* query = (Query*)cookie;
1006 FUNCTION("volume: %p, query: %p\n", volume, query);
1008 VolumeWriteLocker volumeWriteLocker(volume);
1010 delete query;
1012 return B_OK;
1016 status_t
1017 packagefs_read_query(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
1018 size_t bufferSize, uint32* _num)
1020 Volume* volume = (Volume*)fsVolume->private_volume;
1021 Query* query = (Query*)cookie;
1023 FUNCTION("volume: %p, query: %p\n", volume, query);
1025 VolumeWriteLocker volumeWriteLocker(volume);
1027 status_t error = query->GetNextEntry(buffer, bufferSize);
1028 if (error == B_OK)
1029 *_num = 1;
1030 else if (error == B_ENTRY_NOT_FOUND)
1031 *_num = 0;
1032 else
1033 return error;
1035 return B_OK;
1039 status_t
1040 packagefs_rewind_query(fs_volume* fsVolume, void* cookie)
1042 Volume* volume = (Volume*)fsVolume->private_volume;
1043 Query* query = (Query*)cookie;
1045 FUNCTION("volume: %p, query: %p\n", volume, query);
1047 VolumeWriteLocker volumeWriteLocker(volume);
1049 return query->Rewind();
1053 // #pragma mark - Module Interface
1056 static status_t
1057 packagefs_std_ops(int32 op, ...)
1059 switch (op) {
1060 case B_MODULE_INIT:
1062 init_debugging();
1063 PRINT("package_std_ops(): B_MODULE_INIT\n");
1065 status_t error = StringPool::Init();
1066 if (error != B_OK) {
1067 ERROR("Failed to init StringPool\n");
1068 exit_debugging();
1069 return error;
1072 if (!StringConstants::Init()) {
1073 ERROR("Failed to init string constants\n");
1074 StringPool::Cleanup();
1075 exit_debugging();
1076 return error;
1079 error = GlobalFactory::CreateDefault();
1080 if (error != B_OK) {
1081 ERROR("Failed to init GlobalFactory\n");
1082 StringConstants::Cleanup();
1083 StringPool::Cleanup();
1084 exit_debugging();
1085 return error;
1088 error = PackageFSRoot::GlobalInit();
1089 if (error != B_OK) {
1090 ERROR("Failed to init PackageFSRoot\n");
1091 GlobalFactory::DeleteDefault();
1092 StringConstants::Cleanup();
1093 StringPool::Cleanup();
1094 exit_debugging();
1095 return error;
1098 return B_OK;
1101 case B_MODULE_UNINIT:
1103 PRINT("package_std_ops(): B_MODULE_UNINIT\n");
1104 PackageFSRoot::GlobalUninit();
1105 GlobalFactory::DeleteDefault();
1106 StringConstants::Cleanup();
1107 StringPool::Cleanup();
1108 exit_debugging();
1109 return B_OK;
1112 default:
1113 return B_ERROR;
1118 static file_system_module_info sPackageFSModuleInfo = {
1120 "file_systems/packagefs" B_CURRENT_FS_API_VERSION,
1122 packagefs_std_ops,
1125 "packagefs", // short_name
1126 "Package File System", // pretty_name
1127 0, // DDM flags
1130 // scanning
1131 NULL, // identify_partition,
1132 NULL, // scan_partition,
1133 NULL, // free_identify_partition_cookie,
1134 NULL, // free_partition_content_cookie()
1136 &packagefs_mount
1140 fs_volume_ops gPackageFSVolumeOps = {
1141 &packagefs_unmount,
1142 &packagefs_read_fs_info,
1143 NULL, // write_fs_info,
1144 NULL, // sync,
1146 &packagefs_get_vnode,
1148 // index directory
1149 &packagefs_open_index_dir,
1150 &packagefs_close_index_dir,
1151 &packagefs_free_index_dir_cookie,
1152 &packagefs_read_index_dir,
1153 &packagefs_rewind_index_dir,
1155 &packagefs_create_index,
1156 &packagefs_remove_index,
1157 &packagefs_read_index_stat,
1159 // query operations
1160 &packagefs_open_query,
1161 &packagefs_close_query,
1162 &packagefs_free_query_cookie,
1163 &packagefs_read_query,
1164 &packagefs_rewind_query,
1166 // TODO: FS layer operations
1170 fs_vnode_ops gPackageFSVnodeOps = {
1171 // vnode operations
1172 &packagefs_lookup,
1173 &packagefs_get_vnode_name,
1174 &packagefs_put_vnode,
1175 &packagefs_put_vnode, // remove_vnode -- same as put_vnode
1177 // VM file access
1178 NULL, // can_page,
1179 NULL, // read_pages,
1180 NULL, // write_pages,
1182 &packagefs_io,
1183 NULL, // cancel_io()
1185 NULL, // get_file_map,
1187 &packagefs_ioctl,
1188 NULL, // set_flags,
1189 NULL, // select,
1190 NULL, // deselect,
1191 NULL, // fsync,
1193 &packagefs_read_symlink,
1194 NULL, // create_symlink,
1196 NULL, // link,
1197 NULL, // unlink,
1198 NULL, // rename,
1200 &packagefs_access,
1201 &packagefs_read_stat,
1202 NULL, // write_stat,
1203 NULL, // preallocate,
1205 // file operations
1206 NULL, // create,
1207 &packagefs_open,
1208 &packagefs_close,
1209 &packagefs_free_cookie,
1210 &packagefs_read,
1211 NULL, // write,
1213 // directory operations
1214 NULL, // create_dir,
1215 NULL, // remove_dir,
1216 &packagefs_open_dir,
1217 &packagefs_close_dir,
1218 &packagefs_free_dir_cookie,
1219 &packagefs_read_dir,
1220 &packagefs_rewind_dir,
1222 // attribute directory operations
1223 &packagefs_open_attr_dir,
1224 &packagefs_close_attr_dir,
1225 &packagefs_free_attr_dir_cookie,
1226 &packagefs_read_attr_dir,
1227 &packagefs_rewind_attr_dir,
1229 // attribute operations
1230 NULL, // create_attr,
1231 &packagefs_open_attr,
1232 &packagefs_close_attr,
1233 &packagefs_free_attr_cookie,
1234 &packagefs_read_attr,
1235 NULL, // write_attr,
1237 &packagefs_read_attr_stat,
1238 NULL, // write_attr_stat,
1239 NULL, // rename_attr,
1240 NULL // remove_attr,
1242 // TODO: FS layer operations
1246 module_info *modules[] = {
1247 (module_info *)&sPackageFSModuleInfo,
1248 NULL,