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