11573Srgrimes/*
21573Srgrimes * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
31573Srgrimes * Distributed under the terms of the MIT License.
41573Srgrimes */
51573Srgrimes
61573Srgrimes
71573Srgrimes#include "kernel_interface.h"
81573Srgrimes
91573Srgrimes#include <dirent.h>
101573Srgrimes
111573Srgrimes#include <new>
121573Srgrimes
131573Srgrimes#include <fs_info.h>
141573Srgrimes#include <fs_interface.h>
151573Srgrimes#include <KernelExport.h>
161573Srgrimes#include <io_requests.h>
171573Srgrimes
181573Srgrimes#include <AutoDeleter.h>
191573Srgrimes
201573Srgrimes#include "AttributeCookie.h"
211573Srgrimes#include "AttributeDirectoryCookie.h"
221573Srgrimes#include "DebugSupport.h"
231573Srgrimes#include "Directory.h"
241573Srgrimes#include "GlobalFactory.h"
251573Srgrimes#include "Query.h"
261573Srgrimes#include "PackageFSRoot.h"
271573Srgrimes#include "Utils.h"
281573Srgrimes#include "Volume.h"
291573Srgrimes
301573Srgrimes
311573Srgrimesstatic const uint32 kOptimalIOSize = 64 * 1024;
321573Srgrimes
331573Srgrimes
3492991Sobrien// #pragma mark - helper functions
351573Srgrimes
361573Srgrimes
371573Srgrimesstatic bool
381573Srgrimesis_user_in_group(gid_t gid)
391573Srgrimes{
401573Srgrimes	gid_t groups[NGROUPS_MAX];
411573Srgrimes	int groupCount = getgroups(NGROUPS_MAX, groups);
4217141Sjkh	for (int i = 0; i < groupCount; i++) {
4317141Sjkh		if (gid == groups[i])
4417141Sjkh			return true;
4517141Sjkh	}
4617141Sjkh
4717141Sjkh	return (gid == getegid());
4817141Sjkh}
4917141Sjkh
5017141Sjkh
5117141Sjkhstatic status_t
5217141Sjkhcheck_access(Node* node, int mode)
5317141Sjkh{
5417141Sjkh	// write access requested?
5517141Sjkh	if (mode & W_OK)
5617141Sjkh		return B_READ_ONLY_DEVICE;
5717141Sjkh
5817141Sjkh	// get node permissions
5917141Sjkh	int userPermissions = (node->Mode() & S_IRWXU) >> 6;
6017141Sjkh	int groupPermissions = (node->Mode() & S_IRWXG) >> 3;
6117141Sjkh	int otherPermissions = node->Mode() & S_IRWXO;
6217141Sjkh
6317141Sjkh	// get the permissions for this uid/gid
6417141Sjkh	int permissions = 0;
6517141Sjkh	uid_t uid = geteuid();
6617141Sjkh
6717141Sjkh	if (uid == 0) {
6817141Sjkh		// user is root
6917141Sjkh		// root has always read/write permission, but at least one of the
7017141Sjkh		// X bits must be set for execute permission
7117141Sjkh		permissions = userPermissions | groupPermissions | otherPermissions
7217141Sjkh			| S_IROTH | S_IWOTH;
7317141Sjkh	} else if (uid == node->UserID()) {
7417141Sjkh		// user is node owner
7517141Sjkh		permissions = userPermissions;
7617141Sjkh	} else if (is_user_in_group(node->GroupID())) {
7717141Sjkh		// user is in owning group
7817141Sjkh		permissions = groupPermissions;
7917141Sjkh	} else {
8017141Sjkh		// user is one of the others
8117141Sjkh		permissions = otherPermissions;
8217141Sjkh	}
8317141Sjkh
8417141Sjkh	return (mode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED;
8517141Sjkh}
8617141Sjkh
8717141Sjkh
8817141Sjkh//	#pragma mark - Volume
8917141Sjkh
9017141Sjkh
9117141Sjkhstatic status_t
9217141Sjkhpackagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
9317141Sjkh	const char* parameters, ino_t* _rootID)
9417141Sjkh{
9517141Sjkh	FUNCTION("fsVolume: %p, device: \"%s\", flags: %#lx, parameters: \"%s\"\n",
9617141Sjkh		fsVolume, device, flags, parameters);
9717141Sjkh
9817141Sjkh	// create a Volume object
9917141Sjkh	Volume* volume = new(std::nothrow) Volume(fsVolume);
10017141Sjkh	if (volume == NULL)
10117141Sjkh		RETURN_ERROR(B_NO_MEMORY);
10217141Sjkh	ObjectDeleter<Volume> volumeDeleter(volume);
10317141Sjkh
10417141Sjkh	// Initialize the fs_volume now already, so it is mostly usable in during
10517141Sjkh	// mounting.
10617141Sjkh	fsVolume->private_volume = volumeDeleter.Detach();
10717141Sjkh	fsVolume->ops = &gPackageFSVolumeOps;
10817141Sjkh
10917141Sjkh	status_t error = volume->Mount(parameters);
11017141Sjkh	if (error != B_OK)
11117141Sjkh		return error;
11217141Sjkh
11317141Sjkh	// set return values
11417141Sjkh	*_rootID = volume->RootDirectory()->ID();
11517141Sjkh
11617141Sjkh	return B_OK;
11717141Sjkh}
11817141Sjkh
11917141Sjkh
12017141Sjkhstatic status_t
12117141Sjkhpackagefs_unmount(fs_volume* fsVolume)
12217141Sjkh{
12317141Sjkh	Volume* volume = (Volume*)fsVolume->private_volume;
12417141Sjkh
12517141Sjkh	FUNCTION("volume: %p\n", volume);
12617141Sjkh
12717141Sjkh	volume->Unmount();
12817141Sjkh	delete volume;
12917141Sjkh
13017141Sjkh	return B_OK;
13117141Sjkh}
13217141Sjkh
13317141Sjkh
13417141Sjkhstatic status_t
13517141Sjkhpackagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
13617141Sjkh{
13717141Sjkh	Volume* volume = (Volume*)fsVolume->private_volume;
1381573Srgrimes
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
155static status_t
156packagefs_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
196static status_t
197packagefs_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
212static status_t
213packagefs_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
242static status_t
243packagefs_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
264static status_t
265packagefs_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
287static status_t
288packagefs_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
306static status_t
307packagefs_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
320static status_t
321packagefs_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
351struct FileCookie {
352	int	openMode;
353
354	FileCookie(int openMode)
355		:
356		openMode(openMode)
357	{
358	}
359};
360
361
362static status_t
363packagefs_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
397static status_t
398packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
399{
400	return B_OK;
401}
402
403
404static status_t
405packagefs_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
422static status_t
423packagefs_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
445struct 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
527static status_t
528packagefs_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
556static status_t
557packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
558{
559	return B_OK;
560}
561
562
563static status_t
564packagefs_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
582static status_t
583packagefs_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
647static status_t
648packagefs_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
669status_t
670packagefs_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
694status_t
695packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
696{
697	AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
698	return cookie->Close();
699}
700
701
702status_t
703packagefs_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
721status_t
722packagefs_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
738status_t
739packagefs_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
757status_t
758packagefs_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
788status_t
789packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
790{
791	AttributeCookie* cookie = (AttributeCookie*)_cookie;
792	RETURN_ERROR(cookie->Close());
793}
794
795
796status_t
797packagefs_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
814status_t
815packagefs_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
831status_t
832packagefs_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
855status_t
856packagefs_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
872status_t
873packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
874{
875	return B_OK;
876}
877
878
879status_t
880packagefs_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
889status_t
890packagefs_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
926status_t
927packagefs_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
940status_t
941packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
942	uint32 flags)
943{
944	return B_NOT_SUPPORTED;
945}
946
947
948status_t
949packagefs_remove_index(fs_volume* fsVolume, const char* name)
950{
951	return B_NOT_SUPPORTED;
952}
953
954
955status_t
956packagefs_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
984status_t
985packagefs_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
1007status_t
1008packagefs_close_query(fs_volume* fsVolume, void* cookie)
1009{
1010	FUNCTION_START();
1011	return B_OK;
1012}
1013
1014
1015status_t
1016packagefs_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
1031status_t
1032packagefs_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
1054status_t
1055packagefs_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
1071static status_t
1072packagefs_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
1113static 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
1135fs_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
1165fs_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
1241module_info *modules[] = {
1242	(module_info *)&sPackageFSModuleInfo,
1243	NULL,
1244};
1245