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
35static const uint32 kOptimalIOSize = 64 * 1024;
36
37
38// #pragma mark - helper functions
39
40
41static status_t
42check_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
56static status_t
57packagefs_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
85static status_t
86packagefs_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
99static status_t
100packagefs_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 = 0;
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
120static status_t
121packagefs_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
162static status_t
163packagefs_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
178static status_t
179packagefs_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
208static status_t
209packagefs_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
230static status_t
231packagefs_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
253status_t
254packagefs_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
269static status_t
270packagefs_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
289static status_t
290packagefs_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
304static status_t
305packagefs_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
336struct FileCookie {
337	int	openMode;
338
339	FileCookie(int openMode)
340		:
341		openMode(openMode)
342	{
343	}
344};
345
346
347static status_t
348packagefs_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
382static status_t
383packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
384{
385	return B_OK;
386}
387
388
389static status_t
390packagefs_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
407static status_t
408packagefs_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
430struct 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
512static status_t
513packagefs_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
542static status_t
543packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
544{
545	return B_OK;
546}
547
548
549static status_t
550packagefs_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
568static status_t
569packagefs_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
633static status_t
634packagefs_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
655status_t
656packagefs_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
681status_t
682packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
683{
684	AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
685	return cookie->Close();
686}
687
688
689status_t
690packagefs_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
708status_t
709packagefs_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
725status_t
726packagefs_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
744status_t
745packagefs_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
775status_t
776packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
777{
778	AttributeCookie* cookie = (AttributeCookie*)_cookie;
779	RETURN_ERROR(cookie->Close());
780}
781
782
783status_t
784packagefs_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
801status_t
802packagefs_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
818status_t
819packagefs_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
842status_t
843packagefs_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
859status_t
860packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
861{
862	return B_OK;
863}
864
865
866status_t
867packagefs_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
876status_t
877packagefs_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
913status_t
914packagefs_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
927status_t
928packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
929	uint32 flags)
930{
931	return B_NOT_SUPPORTED;
932}
933
934
935status_t
936packagefs_remove_index(fs_volume* fsVolume, const char* name)
937{
938	return B_NOT_SUPPORTED;
939}
940
941
942status_t
943packagefs_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
971status_t
972packagefs_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
994status_t
995packagefs_close_query(fs_volume* fsVolume, void* cookie)
996{
997	FUNCTION_START();
998	return B_OK;
999}
1000
1001
1002status_t
1003packagefs_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
1018status_t
1019packagefs_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
1041status_t
1042packagefs_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
1058static status_t
1059packagefs_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
1119static 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
1141fs_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
1171fs_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
1247module_info *modules[] = {
1248	(module_info *)&sPackageFSModuleInfo,
1249	NULL,
1250};
1251