xref: /haiku/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp (revision 3369e03d5cde9709c8aa70c99bfe6ce24ba65bf9)
1 /*
2  * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "kernel_interface.h"
8 
9 #include <dirent.h>
10 
11 #include <new>
12 
13 #include <fs_info.h>
14 #include <fs_interface.h>
15 #include <KernelExport.h>
16 #include <io_requests.h>
17 
18 #include <AutoDeleter.h>
19 
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"
31 
32 
33 static const uint32 kOptimalIOSize = 64 * 1024;
34 
35 
36 // #pragma mark - helper functions
37 
38 
39 static status_t
40 check_access(Node* node, int mode)
41 {
42 	// write access requested?
43 	if (mode & W_OK)
44 		return B_READ_ONLY_DEVICE;
45 
46 	return check_access_permissions(mode, node->Mode(), node->GroupID(),
47 		node->UserID());
48 }
49 
50 
51 //	#pragma mark - Volume
52 
53 
54 static status_t
55 packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
56 	const char* parameters, ino_t* _rootID)
57 {
58 	FUNCTION("fsVolume: %p, device: \"%s\", flags: %#" B_PRIx32 ", parameters: "
59 			"\"%s\"\n", fsVolume, device, flags, parameters);
60 
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);
66 
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;
71 
72 	status_t error = volume->Mount(parameters);
73 	if (error != B_OK)
74 		return error;
75 
76 	// set return values
77 	*_rootID = volume->RootDirectory()->ID();
78 
79 	return B_OK;
80 }
81 
82 
83 static status_t
84 packagefs_unmount(fs_volume* fsVolume)
85 {
86 	Volume* volume = (Volume*)fsVolume->private_volume;
87 
88 	FUNCTION("volume: %p\n", volume);
89 
90 	volume->Unmount();
91 	delete volume;
92 
93 	return B_OK;
94 }
95 
96 
97 static status_t
98 packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
99 {
100 	Volume* volume = (Volume*)fsVolume->private_volume;
101 
102 	FUNCTION("volume: %p, info: %p\n", volume, info);
103 
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;
112 }
113 
114 
115 // #pragma mark - VNodes
116 
117 
118 static status_t
119 packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
120 	ino_t* _vnid)
121 {
122 	Volume* volume = (Volume*)fsVolume->private_volume;
123 	Node* dir = (Node*)fsDir->private_node;
124 
125 	FUNCTION("volume: %p, dir: %p (%" B_PRId64 "), entry: \"%s\"\n", volume,
126 		dir, dir->ID(), entryName);
127 
128 	if (!S_ISDIR(dir->Mode()))
129 		return B_NOT_A_DIRECTORY;
130 
131 	// resolve "."
132 	if (strcmp(entryName, ".") == 0) {
133 		Node* node;
134 		*_vnid = dir->ID();
135 		return volume->GetVNode(*_vnid, node);
136 	}
137 
138 	// resolve ".."
139 	if (strcmp(entryName, "..") == 0) {
140 		Node* node;
141 		*_vnid = dir->Parent()->ID();
142 		return volume->GetVNode(*_vnid, node);
143 	}
144 
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();
153 
154 	// get the vnode reference
155 	*_vnid = node->ID();
156 	RETURN_ERROR(volume->GetVNode(*_vnid, node));
157 }
158 
159 
160 static status_t
161 packagefs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
162 	size_t bufferSize)
163 {
164 	Node* node = (Node*)fsNode->private_node;
165 
166 	FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), %p, %zu\n",
167 		fsVolume->private_volume, node, node->ID(), buffer, bufferSize);
168 
169 	if (strlcpy(buffer, node->Name(), bufferSize) >= bufferSize)
170 		return B_BUFFER_OVERFLOW;
171 
172 	return B_OK;
173 }
174 
175 
176 static status_t
177 packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
178 	int* _type, uint32* _flags, bool reenter)
179 {
180 	Volume* volume = (Volume*)fsVolume->private_volume;
181 
182 	FUNCTION("volume: %p, vnid: %" B_PRId64 "\n", volume, vnid);
183 
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();
190 
191 	NodeWriteLocker nodeLocker(node);
192 	status_t error = node->VFSInit(volume->ID());
193 	if (error != B_OK)
194 		RETURN_ERROR(error);
195 	nodeLocker.Unlock();
196 
197 	fsNode->private_node = nodeReference.Detach();
198 	fsNode->ops = &gPackageFSVnodeOps;
199 	*_type = node->Mode() & S_IFMT;
200 	*_flags = 0;
201 
202 	return B_OK;
203 }
204 
205 
206 static status_t
207 packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
208 {
209 	Volume* volume = (Volume*)fsVolume->private_volume;
210 	Node* node = (Node*)fsNode->private_node;
211 
212 	FUNCTION("volume: %p, node: %p\n", volume, node);
213 	TOUCH(volume);
214 
215 	NodeWriteLocker nodeLocker(node);
216 	node->VFSUninit();
217 	nodeLocker.Unlock();
218 
219 	node->ReleaseReference();
220 
221 	return B_OK;
222 }
223 
224 
225 // #pragma mark - Request I/O
226 
227 
228 static status_t
229 packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
230 	io_request* request)
231 {
232 	Volume* volume = (Volume*)fsVolume->private_volume;
233 	Node* node = (Node*)fsNode->private_node;
234 
235 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, request: %p\n",
236 		volume, node, node->ID(), cookie, request);
237 	TOUCH(volume);
238 
239 	if (io_request_is_write(request))
240 		RETURN_ERROR(B_READ_ONLY_DEVICE);
241 
242 	status_t error = node->Read(request);
243 	notify_io_request(request, error);
244 	return error;
245 }
246 
247 
248 // #pragma mark - Nodes
249 
250 
251 status_t
252 packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
253 	uint32 operation, void* buffer, size_t size)
254 {
255 	Volume* volume = (Volume*)fsVolume->private_volume;
256 	Node* node = (Node*)fsNode->private_node;
257 
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);
262 
263 	return volume->IOCtl(node, operation, buffer, size);
264 }
265 
266 
267 static status_t
268 packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
269 	size_t* _bufferSize)
270 {
271 	Volume* volume = (Volume*)fsVolume->private_volume;
272 	Node* node = (Node*)fsNode->private_node;
273 
274 	FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
275 		node->ID());
276 	TOUCH(volume);
277 
278 	NodeReadLocker nodeLocker(node);
279 
280 	if (!S_ISLNK(node->Mode()))
281 		return B_BAD_VALUE;
282 
283 	return node->ReadSymlink(buffer, _bufferSize);
284 }
285 
286 
287 static status_t
288 packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode)
289 {
290 	Volume* volume = (Volume*)fsVolume->private_volume;
291 	Node* node = (Node*)fsNode->private_node;
292 
293 	FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
294 		node->ID());
295 	TOUCH(volume);
296 
297 	NodeReadLocker nodeLocker(node);
298 	return check_access(node, mode);
299 }
300 
301 
302 static status_t
303 packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
304 {
305 	Volume* volume = (Volume*)fsVolume->private_volume;
306 	Node* node = (Node*)fsNode->private_node;
307 
308 	FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
309 		node->ID());
310 	TOUCH(volume);
311 
312 	NodeReadLocker nodeLocker(node);
313 
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;
326 
327 	return B_OK;
328 }
329 
330 
331 // #pragma mark - Files
332 
333 
334 struct FileCookie {
335 	int	openMode;
336 
337 	FileCookie(int openMode)
338 		:
339 		openMode(openMode)
340 	{
341 	}
342 };
343 
344 
345 static status_t
346 packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
347 	void** _cookie)
348 {
349 	Volume* volume = (Volume*)fsVolume->private_volume;
350 	Node* node = (Node*)fsNode->private_node;
351 
352 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), openMode %#x\n",
353 		volume, node, node->ID(), openMode);
354 	TOUCH(volume);
355 
356 	NodeReadLocker nodeLocker(node);
357 
358 	// check the open mode and permissions
359 	if (S_ISDIR(node->Mode()) && (openMode & O_RWMASK) != O_RDONLY)
360 		return B_IS_A_DIRECTORY;
361 
362 	if ((openMode & O_RWMASK) != O_RDONLY)
363 		return B_NOT_ALLOWED;
364 
365 	status_t error = check_access(node, R_OK);
366 	if (error != B_OK)
367 		return error;
368 
369 	// allocate the cookie
370 	FileCookie* cookie = new(std::nothrow) FileCookie(openMode);
371 	if (cookie == NULL)
372 		RETURN_ERROR(B_NO_MEMORY);
373 
374 	*_cookie = cookie;
375 
376 	return B_OK;
377 }
378 
379 
380 static status_t
381 packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
382 {
383 	return B_OK;
384 }
385 
386 
387 static status_t
388 packagefs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
389 {
390 	Volume* volume = (Volume*)fsVolume->private_volume;
391 	Node* node = (Node*)fsNode->private_node;
392 	FileCookie* cookie = (FileCookie*)_cookie;
393 
394 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
395 		node->ID(), cookie);
396 	TOUCH(volume);
397 	TOUCH(node);
398 
399 	delete cookie;
400 
401 	return B_OK;
402 }
403 
404 
405 static status_t
406 packagefs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
407 	off_t offset, void* buffer, size_t* bufferSize)
408 {
409 	Volume* volume = (Volume*)fsVolume->private_volume;
410 	Node* node = (Node*)fsNode->private_node;
411 	FileCookie* cookie = (FileCookie*)_cookie;
412 
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);
417 
418 	if ((cookie->openMode & O_RWMASK) != O_RDONLY)
419 		return EBADF;
420 
421 	return node->Read(offset, buffer, bufferSize);
422 }
423 
424 
425 // #pragma mark - Directories
426 
427 
428 struct DirectoryCookie : DirectoryIterator {
429 	Directory*	directory;
430 	int32		state;
431 	bool		registered;
432 
433 	DirectoryCookie(Directory* directory)
434 		:
435 		directory(directory),
436 		state(0),
437 		registered(false)
438 	{
439 		Rewind();
440 	}
441 
442 	~DirectoryCookie()
443 	{
444 		if (registered)
445 			directory->RemoveDirectoryIterator(this);
446 	}
447 
448 	void Rewind()
449 	{
450 		if (registered)
451 			directory->RemoveDirectoryIterator(this);
452 		registered = false;
453 
454 		state = 0;
455 		node = directory;
456 	}
457 
458 	Node* Current(const char*& _name) const
459 	{
460 		if (node == NULL)
461 			return NULL;
462 
463 		if (state == 0)
464 			_name = ".";
465 		else if (state == 1)
466 			_name = "..";
467 		else
468 			_name = node->Name();
469 
470 		return node;
471 	}
472 
473 	Node* Next()
474 	{
475 		if (state == 0) {
476 			state = 1;
477 			node = directory->Parent();
478 			if (node == NULL)
479 				node = directory;
480 			return node;
481 		}
482 
483 		if (state == 1) {
484 			node = directory->FirstChild();
485 			state = 2;
486 		} else {
487 			if (node != NULL)
488 				node = directory->NextChild(node);
489 		}
490 
491 		if (node == NULL) {
492 			if (registered) {
493 				directory->RemoveDirectoryIterator(this);
494 				registered = false;
495 			}
496 
497 			return NULL;
498 		}
499 
500 		if (!registered) {
501 			directory->AddDirectoryIterator(this);
502 			registered = true;
503 		}
504 
505 		return node;
506 	}
507 };
508 
509 
510 static status_t
511 packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
512 {
513 	Volume* volume = (Volume*)fsVolume->private_volume;
514 	Node* node = (Node*)fsNode->private_node;
515 
516 	FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
517 		node->ID());
518 	TOUCH(volume);
519 
520 	if (!S_ISDIR(node->Mode()))
521 		return B_NOT_A_DIRECTORY;
522 
523 	Directory* dir = dynamic_cast<Directory*>(node);
524 
525 	status_t error = check_access(dir, R_OK);
526 	if (error != B_OK)
527 		return error;
528 
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);
534 
535 	*_cookie = cookie;
536 	return B_OK;
537 }
538 
539 
540 static status_t
541 packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
542 {
543 	return B_OK;
544 }
545 
546 
547 static status_t
548 packagefs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
549 {
550 	Volume* volume = (Volume*)fsVolume->private_volume;
551 	Node* node = (Node*)fsNode->private_node;
552 	DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
553 
554 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
555 		node->ID(), cookie);
556 	TOUCH(volume);
557 	TOUCH(node);
558 
559 	NodeWriteLocker dirLocker(node);
560 	delete cookie;
561 
562 	return B_OK;
563 }
564 
565 
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)
569 {
570 	Volume* volume = (Volume*)fsVolume->private_volume;
571 	Node* node = (Node*)fsNode->private_node;
572 	DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
573 
574 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
575 		node->ID(), cookie);
576 	TOUCH(volume);
577 	TOUCH(node);
578 
579 	NodeWriteLocker dirLocker(cookie->directory);
580 
581 	uint32 maxCount = *_count;
582 	uint32 count = 0;
583 
584 	dirent* previousEntry = NULL;
585 
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;
591 
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;
599 
600 				previousEntry->d_reclen += offset;
601 				buffer = (dirent*)((addr_t)buffer + offset);
602 				bufferSize -= offset;
603 			}
604 		}
605 
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;
612 		}
613 
614 		// fill in the other data
615 		buffer->d_dev = volume->ID();
616 		buffer->d_ino = child->ID();
617 
618 		count++;
619 		previousEntry = buffer;
620 		bufferSize -= buffer->d_reclen;
621 		buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
622 
623 		cookie->Next();
624 	}
625 
626 	*_count = count;
627 	return B_OK;
628 }
629 
630 
631 static status_t
632 packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
633 {
634 	Volume* volume = (Volume*)fsVolume->private_volume;
635 	Node* node = (Node*)fsNode->private_node;
636 	DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
637 
638 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
639 		node->ID(), cookie);
640 	TOUCH(volume);
641 	TOUCH(node);
642 
643 	NodeWriteLocker dirLocker(node);
644 	cookie->Rewind();
645 
646 	return B_OK;
647 }
648 
649 
650 // #pragma mark - Attribute Directories
651 
652 
653 status_t
654 packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
655 {
656 	Volume* volume = (Volume*)fsVolume->private_volume;
657 	Node* node = (Node*)fsNode->private_node;
658 
659 	FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
660 		node->ID());
661 	TOUCH(volume);
662 
663 	status_t error = check_access(node, R_OK);
664 	if (error != B_OK)
665 		return error;
666 
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);
673 
674 	*_cookie = cookie;
675 	return B_OK;
676 }
677 
678 
679 status_t
680 packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
681 {
682 	AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
683 	return cookie->Close();
684 }
685 
686 
687 status_t
688 packagefs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
689 	void* _cookie)
690 {
691 	Volume* volume = (Volume*)fsVolume->private_volume;
692 	Node* node = (Node*)fsNode->private_node;
693 	AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
694 
695 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
696 		node->ID(), cookie);
697 	TOUCH(volume);
698 	TOUCH(node);
699 
700 	delete cookie;
701 
702 	return B_OK;
703 }
704 
705 
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)
709 {
710 	Volume* volume = (Volume*)fsVolume->private_volume;
711 	Node* node = (Node*)fsNode->private_node;
712 	AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
713 
714 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
715 		node->ID(), cookie);
716 	TOUCH(volume);
717 	TOUCH(node);
718 
719 	return cookie->Read(volume->ID(), node->ID(), buffer, bufferSize, _count);
720 }
721 
722 
723 status_t
724 packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
725 {
726 	Volume* volume = (Volume*)fsVolume->private_volume;
727 	Node* node = (Node*)fsNode->private_node;
728 	AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
729 
730 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
731 		node->ID(), cookie);
732 	TOUCH(volume);
733 	TOUCH(node);
734 
735 	return cookie->Rewind();
736 }
737 
738 
739 // #pragma mark - Attribute Operations
740 
741 
742 status_t
743 packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
744 	int openMode, void** _cookie)
745 {
746 	Volume* volume = (Volume*)fsVolume->private_volume;
747 	Node* node = (Node*)fsNode->private_node;
748 
749 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), name: \"%s\", openMode "
750 			"%#x\n", volume, node, node->ID(), name, openMode);
751 	TOUCH(volume);
752 
753 	NodeReadLocker nodeLocker(node);
754 
755 	// check the open mode and permissions
756 	if ((openMode & O_RWMASK) != O_RDONLY)
757 		return B_NOT_ALLOWED;
758 
759 	status_t error = check_access(node, R_OK);
760 	if (error != B_OK)
761 		return error;
762 
763 	AttributeCookie* cookie;
764 	error = node->OpenAttribute(StringKey(name), openMode, cookie);
765 	if (error != B_OK)
766 		return error;
767 
768 	*_cookie = cookie;
769 	return B_OK;
770 }
771 
772 
773 status_t
774 packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
775 {
776 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
777 	RETURN_ERROR(cookie->Close());
778 }
779 
780 
781 status_t
782 packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
783 {
784 	Volume* volume = (Volume*)fsVolume->private_volume;
785 	Node* node = (Node*)fsNode->private_node;
786 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
787 
788 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
789 		node->ID(), cookie);
790 	TOUCH(volume);
791 	TOUCH(node);
792 
793 	delete cookie;
794 
795 	return B_OK;
796 }
797 
798 
799 status_t
800 packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
801 	off_t offset, void* buffer, size_t* bufferSize)
802 {
803 	Volume* volume = (Volume*)fsVolume->private_volume;
804 	Node* node = (Node*)fsNode->private_node;
805 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
806 
807 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
808 		node->ID(), cookie);
809 	TOUCH(volume);
810 	TOUCH(node);
811 
812 	return cookie->ReadAttribute(offset, buffer, bufferSize);
813 }
814 
815 
816 status_t
817 packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
818 	void* _cookie, struct stat* st)
819 {
820 	Volume* volume = (Volume*)fsVolume->private_volume;
821 	Node* node = (Node*)fsNode->private_node;
822 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
823 
824 	FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
825 		node->ID(), cookie);
826 	TOUCH(volume);
827 	TOUCH(node);
828 
829 	return cookie->ReadAttributeStat(st);
830 }
831 
832 
833 // #pragma mark - index directory & index operations
834 
835 
836 // NOTE: We don't do any locking in the index dir hooks, since once mounted
837 // the index directory is immutable.
838 
839 
840 status_t
841 packagefs_open_index_dir(fs_volume* fsVolume, void** _cookie)
842 {
843 	Volume* volume = (Volume*)fsVolume->private_volume;
844 
845 	FUNCTION("volume: %p\n", volume);
846 
847 	IndexDirIterator* iterator = new(std::nothrow) IndexDirIterator(
848 		volume->GetIndexDirIterator());
849 	if (iterator == NULL)
850 		return B_NO_MEMORY;
851 
852 	*_cookie = iterator;
853 	return B_OK;
854 }
855 
856 
857 status_t
858 packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
859 {
860 	return B_OK;
861 }
862 
863 
864 status_t
865 packagefs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
866 {
867 	FUNCTION("volume: %p, cookie: %p\n", fsVolume->private_volume, cookie);
868 
869 	delete (IndexDirIterator*)cookie;
870 	return B_OK;
871 }
872 
873 
874 status_t
875 packagefs_read_index_dir(fs_volume* fsVolume, void* cookie,
876 	struct dirent* buffer, size_t bufferSize, uint32* _num)
877 {
878 	Volume* volume = (Volume*)fsVolume->private_volume;
879 
880 	FUNCTION("volume: %p, cookie: %p, buffer: %p, bufferSize: %zu, num: %"
881 		B_PRIu32 "\n", volume, cookie, buffer, bufferSize, *_num);
882 
883 	IndexDirIterator* iterator = (IndexDirIterator*)cookie;
884 
885 	if (*_num == 0)
886 		return B_BAD_VALUE;
887 
888 	IndexDirIterator previousIterator = *iterator;
889 
890 	// get the next index
891 	Index* index = iterator->Next();
892 	if (index == NULL) {
893 		*_num = 0;
894 		return B_OK;
895 	}
896 
897 	// fill in the entry
898 	if (!set_dirent_name(buffer, bufferSize, index->Name())) {
899 		*iterator = previousIterator;
900 		return B_BUFFER_OVERFLOW;
901 	}
902 
903 	buffer->d_dev = volume->ID();
904 	buffer->d_ino = 0;
905 
906 	*_num = 1;
907 	return B_OK;
908 }
909 
910 
911 status_t
912 packagefs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
913 {
914 	Volume* volume = (Volume*)fsVolume->private_volume;
915 
916 	FUNCTION("volume: %p, cookie: %p\n", volume, cookie);
917 
918 	IndexDirIterator* iterator = (IndexDirIterator*)cookie;
919 	*iterator = volume->GetIndexDirIterator();
920 
921 	return B_OK;
922 }
923 
924 
925 status_t
926 packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
927 	uint32 flags)
928 {
929 	return B_NOT_SUPPORTED;
930 }
931 
932 
933 status_t
934 packagefs_remove_index(fs_volume* fsVolume, const char* name)
935 {
936 	return B_NOT_SUPPORTED;
937 }
938 
939 
940 status_t
941 packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
942 	struct stat* stat)
943 {
944 	Volume* volume = (Volume*)fsVolume->private_volume;
945 
946 	FUNCTION("volume: %p, name: \"%s\", stat: %p\n", volume, name, stat);
947 
948 	Index* index = volume->FindIndex(StringKey(name));
949 	if (index == NULL)
950 		return B_ENTRY_NOT_FOUND;
951 
952 	VolumeReadLocker volumeReadLocker(volume);
953 
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.
958 
959 	stat->st_type = index->Type();
960 	stat->st_size = index->CountEntries();
961 
962 	return B_OK;
963 }
964 
965 
966 // #pragma mark - query operations
967 
968 
969 status_t
970 packagefs_open_query(fs_volume* fsVolume, const char* queryString, uint32 flags,
971 	port_id port, uint32 token, void** _cookie)
972 {
973 	Volume* volume = (Volume*)fsVolume->private_volume;
974 
975 	FUNCTION("volume: %p, query: \"%s\", flags: %#" B_PRIx32 ", port: %"
976 		B_PRId32 ", token: %" B_PRIu32 "\n", volume, queryString, flags, port,
977 		token);
978 
979 	VolumeWriteLocker volumeWriteLocker(volume);
980 
981 	Query* query;
982 	status_t error = Query::Create(volume, queryString, flags, port, token,
983 		query);
984 	if (error != B_OK)
985 		return error;
986 
987 	*_cookie = query;
988 	return B_OK;
989 }
990 
991 
992 status_t
993 packagefs_close_query(fs_volume* fsVolume, void* cookie)
994 {
995 	FUNCTION_START();
996 	return B_OK;
997 }
998 
999 
1000 status_t
1001 packagefs_free_query_cookie(fs_volume* fsVolume, void* cookie)
1002 {
1003 	Volume* volume = (Volume*)fsVolume->private_volume;
1004 	Query* query = (Query*)cookie;
1005 
1006 	FUNCTION("volume: %p, query: %p\n", volume, query);
1007 
1008 	VolumeWriteLocker volumeWriteLocker(volume);
1009 
1010 	delete query;
1011 
1012 	return B_OK;
1013 }
1014 
1015 
1016 status_t
1017 packagefs_read_query(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
1018 	size_t bufferSize, uint32* _num)
1019 {
1020 	Volume* volume = (Volume*)fsVolume->private_volume;
1021 	Query* query = (Query*)cookie;
1022 
1023 	FUNCTION("volume: %p, query: %p\n", volume, query);
1024 
1025 	VolumeWriteLocker volumeWriteLocker(volume);
1026 
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;
1034 
1035 	return B_OK;
1036 }
1037 
1038 
1039 status_t
1040 packagefs_rewind_query(fs_volume* fsVolume, void* cookie)
1041 {
1042 	Volume* volume = (Volume*)fsVolume->private_volume;
1043 	Query* query = (Query*)cookie;
1044 
1045 	FUNCTION("volume: %p, query: %p\n", volume, query);
1046 
1047 	VolumeWriteLocker volumeWriteLocker(volume);
1048 
1049 	return query->Rewind();
1050 }
1051 
1052 
1053 // #pragma mark - Module Interface
1054 
1055 
1056 static status_t
1057 packagefs_std_ops(int32 op, ...)
1058 {
1059 	switch (op) {
1060 		case B_MODULE_INIT:
1061 		{
1062 			init_debugging();
1063 			PRINT("package_std_ops(): B_MODULE_INIT\n");
1064 
1065 			status_t error = StringPool::Init();
1066 			if (error != B_OK) {
1067 				ERROR("Failed to init StringPool\n");
1068 				exit_debugging();
1069 				return error;
1070 			}
1071 
1072 			if (!StringConstants::Init()) {
1073 				ERROR("Failed to init string constants\n");
1074 				StringPool::Cleanup();
1075 				exit_debugging();
1076 				return error;
1077 			}
1078 
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;
1086 			}
1087 
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;
1096 			}
1097 
1098 			return B_OK;
1099 		}
1100 
1101 		case B_MODULE_UNINIT:
1102 		{
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;
1110 		}
1111 
1112 		default:
1113 			return B_ERROR;
1114 	}
1115 }
1116 
1117 
1118 static file_system_module_info sPackageFSModuleInfo = {
1119 	{
1120 		"file_systems/packagefs" B_CURRENT_FS_API_VERSION,
1121 		0,
1122 		packagefs_std_ops,
1123 	},
1124 
1125 	"packagefs",				// short_name
1126 	"Package File System",		// pretty_name
1127 	0,							// DDM flags
1128 
1129 
1130 	// scanning
1131 	NULL,	// identify_partition,
1132 	NULL,	// scan_partition,
1133 	NULL,	// free_identify_partition_cookie,
1134 	NULL,	// free_partition_content_cookie()
1135 
1136 	&packagefs_mount
1137 };
1138 
1139 
1140 fs_volume_ops gPackageFSVolumeOps = {
1141 	&packagefs_unmount,
1142 	&packagefs_read_fs_info,
1143 	NULL,	// write_fs_info,
1144 	NULL,	// sync,
1145 
1146 	&packagefs_get_vnode,
1147 
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,
1154 
1155 	&packagefs_create_index,
1156 	&packagefs_remove_index,
1157 	&packagefs_read_index_stat,
1158 
1159 	// query operations
1160 	&packagefs_open_query,
1161 	&packagefs_close_query,
1162 	&packagefs_free_query_cookie,
1163 	&packagefs_read_query,
1164 	&packagefs_rewind_query,
1165 
1166 	// TODO: FS layer operations
1167 };
1168 
1169 
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
1176 
1177 	// VM file access
1178 	NULL,	// can_page,
1179 	NULL,	// read_pages,
1180 	NULL,	// write_pages,
1181 
1182 	&packagefs_io,
1183 	NULL,	// cancel_io()
1184 
1185 	NULL,	// get_file_map,
1186 
1187 	&packagefs_ioctl,
1188 	NULL,	// set_flags,
1189 	NULL,	// select,
1190 	NULL,	// deselect,
1191 	NULL,	// fsync,
1192 
1193 	&packagefs_read_symlink,
1194 	NULL,	// create_symlink,
1195 
1196 	NULL,	// link,
1197 	NULL,	// unlink,
1198 	NULL,	// rename,
1199 
1200 	&packagefs_access,
1201 	&packagefs_read_stat,
1202 	NULL,	// write_stat,
1203 	NULL,	// preallocate,
1204 
1205 	// file operations
1206 	NULL,	// create,
1207 	&packagefs_open,
1208 	&packagefs_close,
1209 	&packagefs_free_cookie,
1210 	&packagefs_read,
1211 	NULL,	// write,
1212 
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,
1221 
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,
1228 
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,
1236 
1237 	&packagefs_read_attr_stat,
1238 	NULL,	// write_attr_stat,
1239 	NULL,	// rename_attr,
1240 	NULL	// remove_attr,
1241 
1242 	// TODO: FS layer operations
1243 };
1244 
1245 
1246 module_info *modules[] = {
1247 	(module_info *)&sPackageFSModuleInfo,
1248 	NULL,
1249 };
1250