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