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