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