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