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