1/*
2 * Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "HaikuKernelVolume.h"
7
8#include <new>
9
10#include <fcntl.h>
11#include <string.h>
12#include <unistd.h>
13
14#include "AutoDeleter.h"
15#include "AutoLocker.h"
16#include "Debug.h"
17#include "HashMap.h"
18
19#include "../IORequestInfo.h"
20#include "../kernel_emu.h"
21
22#include "HaikuKernelFileSystem.h"
23#include "HaikuKernelIORequest.h"
24#include "HaikuKernelNode.h"
25
26
27// NodeMap
28class HaikuKernelVolume::NodeMap
29	: public SynchronizedHashMap<HashKey64<ino_t>, HaikuKernelNode*, Locker> {
30};
31
32
33// _FileSystem
34inline HaikuKernelFileSystem*
35HaikuKernelVolume::_FileSystem() const
36{
37	return static_cast<HaikuKernelFileSystem*>(fFileSystem);
38}
39
40
41// constructor
42HaikuKernelVolume::HaikuKernelVolume(FileSystem* fileSystem, dev_t id,
43	file_system_module_info* fsModule)
44	:
45	Volume(fileSystem, id),
46	fFSModule(fsModule),
47	fNodes(NULL)
48{
49	fVolume.id = id;
50	fVolume.partition = -1;
51	fVolume.layer = 0;
52	fVolume.private_volume = NULL;		// filled in by the FS
53	fVolume.ops = NULL;					// filled in by the FS
54	fVolume.sub_volume = NULL;
55	fVolume.super_volume = NULL;
56	fVolume.file_system = fFSModule;
57	fVolume.file_system_name = const_cast<char*>(fileSystem->GetName());
58	fVolume.haikuVolume = this;
59}
60
61// destructor
62HaikuKernelVolume::~HaikuKernelVolume()
63{
64	delete fNodes;
65}
66
67
68// Init
69status_t
70HaikuKernelVolume::Init()
71{
72	fNodes = new(std::nothrow) NodeMap;
73	if (fNodes == NULL)
74		return B_NO_MEMORY;
75	return fNodes->InitCheck();
76}
77
78
79// NewVNode
80status_t
81HaikuKernelVolume::NewVNode(ino_t vnodeID, void* privateNode, fs_vnode_ops* ops,
82	HaikuKernelNode** _node)
83{
84	AutoLocker<NodeMap> _(fNodes);
85
86	// check whether we do already know the node
87	HaikuKernelNode* node = fNodes->Get(vnodeID);
88	if (node != NULL)
89		return B_BAD_VALUE;
90
91	// get node capabilities
92	HaikuKernelNode::Capabilities* capabilities
93		= _FileSystem()->GetNodeCapabilities(ops);
94	if (capabilities == NULL)
95		return B_NO_MEMORY;
96
97	// create a new node
98	node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode, ops,
99		capabilities);
100	if (node == NULL) {
101		_FileSystem()->PutNodeCapabilities(capabilities);
102		return B_NO_MEMORY;
103	}
104
105	// add to map
106	status_t error = fNodes->Put(vnodeID, node);
107	if (error != B_OK) {
108		delete node;
109		return error;
110	}
111
112	*_node = node;
113
114	return B_OK;
115}
116
117
118// PublishVNode
119status_t
120HaikuKernelVolume::PublishVNode(ino_t vnodeID, void* privateNode,
121	fs_vnode_ops* ops, int type, uint32 flags, HaikuKernelNode** _node)
122{
123	AutoLocker<NodeMap> _(fNodes);
124
125	// check whether we do already know the node
126	HaikuKernelNode* node = fNodes->Get(vnodeID);
127	if (node != NULL) {
128		if (node->published)
129			return B_BAD_VALUE;
130	} else {
131		// get node capabilities
132		HaikuKernelNode::Capabilities* capabilities
133			= _FileSystem()->GetNodeCapabilities(ops);
134		if (capabilities == NULL)
135			return B_NO_MEMORY;
136
137		// create a new node
138		node = new(std::nothrow) HaikuKernelNode(this, vnodeID, privateNode,
139			ops, capabilities);
140		if (node == NULL) {
141			_FileSystem()->PutNodeCapabilities(capabilities);
142			return B_NO_MEMORY;
143		}
144
145		// add to map
146		status_t error = fNodes->Put(vnodeID, node);
147		if (error != B_OK) {
148			delete node;
149			return error;
150		}
151	}
152
153	node->published = true;
154
155	*_node = node;
156
157	return B_OK;
158}
159
160
161// UndoNewVNode
162void
163HaikuKernelVolume::UndoNewVNode(HaikuKernelNode* node)
164{
165	fNodes->Remove(node->id);
166	delete node;
167}
168
169
170// UndoPublishVNode
171void
172HaikuKernelVolume::UndoPublishVNode(HaikuKernelNode* node)
173{
174	fNodes->Remove(node->id);
175	delete node;
176}
177
178
179// NodeWithID
180HaikuKernelNode*
181HaikuKernelVolume::NodeWithID(ino_t vnodeID) const
182{
183	return fNodes->Get(vnodeID);
184}
185
186
187// #pragma mark -
188// #pragma mark ----- FS -----
189
190// Mount
191status_t
192HaikuKernelVolume::Mount(const char* device, uint32 flags,
193	const char* parameters, ino_t* rootID)
194{
195	if (!fFSModule->mount)
196		return B_BAD_VALUE;
197
198	// mount
199	status_t error = fFSModule->mount(&fVolume, device, flags, parameters,
200		rootID);
201	if (error != B_OK)
202		return error;
203
204	_InitCapabilities();
205
206	return B_OK;
207}
208
209// Unmount
210status_t
211HaikuKernelVolume::Unmount()
212{
213	if (!fVolume.ops->unmount)
214		return B_BAD_VALUE;
215
216	return fVolume.ops->unmount(&fVolume);
217}
218
219// Sync
220status_t
221HaikuKernelVolume::Sync()
222{
223	if (!fVolume.ops->sync)
224		return B_BAD_VALUE;
225	return fVolume.ops->sync(&fVolume);
226}
227
228// ReadFSInfo
229status_t
230HaikuKernelVolume::ReadFSInfo(fs_info* info)
231{
232	if (!fVolume.ops->read_fs_info)
233		return B_BAD_VALUE;
234	return fVolume.ops->read_fs_info(&fVolume, info);
235}
236
237// WriteFSInfo
238status_t
239HaikuKernelVolume::WriteFSInfo(const struct fs_info* info, uint32 mask)
240{
241	if (!fVolume.ops->write_fs_info)
242		return B_BAD_VALUE;
243	return fVolume.ops->write_fs_info(&fVolume, info, mask);
244}
245
246
247// #pragma mark - file cache
248
249
250// GetFileMap
251status_t
252HaikuKernelVolume::GetFileMap(void* _node, off_t offset, size_t size,
253	struct file_io_vec* vecs, size_t* count)
254{
255	HaikuKernelNode* node = (HaikuKernelNode*)_node;
256
257	if (!node->ops->get_file_map)
258		return B_BAD_VALUE;
259	return node->ops->get_file_map(&fVolume, node, offset, size, vecs,
260		count);
261}
262
263
264// #pragma mark - vnodes
265
266
267// Lookup
268status_t
269HaikuKernelVolume::Lookup(void* _dir, const char* entryName, ino_t* vnid)
270{
271	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
272
273	if (!dir->ops->lookup)
274		return B_BAD_VALUE;
275	return dir->ops->lookup(&fVolume, dir, entryName, vnid);
276
277}
278
279// GetVNodeName
280status_t
281HaikuKernelVolume::GetVNodeName(void* _node, char* buffer, size_t bufferSize)
282{
283	HaikuKernelNode* node = (HaikuKernelNode*)_node;
284
285	// If not implemented by the client file system, we invoke our super class
286	// version, which emulates the functionality.
287	if (!node->ops->get_vnode_name)
288		return Volume::GetVNodeName(_node, buffer, bufferSize);
289	return node->ops->get_vnode_name(&fVolume, node, buffer, bufferSize);
290}
291
292// ReadVNode
293status_t
294HaikuKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** _node, int* type,
295	uint32* flags, FSVNodeCapabilities* _capabilities)
296{
297	if (!fVolume.ops->get_vnode)
298		return B_BAD_VALUE;
299
300	// create a new wrapper node and add it to the map
301	HaikuKernelNode* node = new(std::nothrow) HaikuKernelNode(this, vnid, NULL,
302		NULL, NULL);
303	if (node == NULL)
304		return B_NO_MEMORY;
305	ObjectDeleter<HaikuKernelNode> nodeDeleter(node);
306
307	AutoLocker<NodeMap> locker(fNodes);
308	if (fNodes->Get(vnid) != NULL)
309		return B_BAD_VALUE;
310
311	status_t error = fNodes->Put(vnid, node);
312	if (error != B_OK)
313		return error;
314
315	locker.Unlock();
316
317	// get the node
318	error = fVolume.ops->get_vnode(&fVolume, vnid, node, type, flags, reenter);
319	if (error != B_OK) {
320		locker.Lock();
321		fNodes->Remove(vnid);
322		return error;
323	}
324
325	// get node capabilities
326	HaikuKernelNode::Capabilities* capabilities
327		= _FileSystem()->GetNodeCapabilities(node->ops);
328	if (capabilities == NULL) {
329		node->ops->put_vnode(&fVolume, node, reenter);
330		locker.Lock();
331		fNodes->Remove(vnid);
332		return B_NO_MEMORY;
333	}
334
335	locker.Lock();
336	node->capabilities = capabilities;
337	node->published = true;
338	nodeDeleter.Detach();
339
340	*_node = node;
341	*_capabilities = capabilities->capabilities;
342
343	return B_OK;
344}
345
346// WriteVNode
347status_t
348HaikuKernelVolume::WriteVNode(void* _node, bool reenter)
349{
350	HaikuKernelNode* node = (HaikuKernelNode*)_node;
351
352	fNodes->Remove(node->id);
353
354	if (!node->ops->put_vnode)
355		return B_BAD_VALUE;
356	status_t error = node->ops->put_vnode(&fVolume, node, reenter);
357
358	delete node;
359
360	return error;
361}
362
363// RemoveVNode
364status_t
365HaikuKernelVolume::RemoveVNode(void* _node, bool reenter)
366{
367	HaikuKernelNode* node = (HaikuKernelNode*)_node;
368
369	fNodes->Remove(node->id);
370
371	if (!node->ops->remove_vnode)
372		return B_BAD_VALUE;
373	return node->ops->remove_vnode(&fVolume, node, reenter);
374}
375
376
377// #pragma mark - asynchronous I/O
378
379
380status_t
381HaikuKernelVolume::DoIO(void* _node, void* cookie,
382	const IORequestInfo& requestInfo)
383{
384	HaikuKernelNode* node = (HaikuKernelNode*)_node;
385
386	if (!node->ops->io)
387		return B_BAD_VALUE;
388
389	// create a request object
390	HaikuKernelIORequest* request
391		= new(std::nothrow) HaikuKernelIORequest(this, requestInfo);
392	if (request == NULL)
393		RETURN_ERROR(B_NO_MEMORY);
394
395	status_t error = _FileSystem()->AddIORequest(request);
396	if (error != B_OK) {
397		delete request;
398		RETURN_ERROR(error);
399	}
400
401	// call the hook
402	error = node->ops->io(&fVolume, node, cookie, (io_request*)request);
403
404	// directly put our reference to the request, if the call failed
405	if (error != B_OK) {
406		_FileSystem()->PutIORequest(request);
407		RETURN_ERROR(error);
408	}
409
410	// TODO: ATM we don't release our reference when the request is finished
411	// normally!
412
413	return B_OK;
414}
415
416
417status_t
418HaikuKernelVolume::CancelIO(void* _node, void* cookie, int32 ioRequestID)
419{
420	HaikuKernelNode* node = (HaikuKernelNode*)_node;
421
422	if (!node->ops->cancel_io)
423		return B_BAD_VALUE;
424
425	// get the request
426	HaikuKernelIORequest* request = _FileSystem()->GetIORequest(ioRequestID);
427	if (request == NULL)
428		RETURN_ERROR(B_BAD_VALUE);
429
430	// call the hook
431	status_t error = node->ops->cancel_io(&fVolume, node, cookie,
432		(io_request*)request);
433
434	// put the request -- once for the reference we got above, once for the
435	// reference we've got in DoIO()
436	_FileSystem()->PutIORequest(request, 2);
437
438	return error;
439}
440
441
442// IterativeIOGetVecs
443status_t
444HaikuKernelVolume::IterativeIOGetVecs(void* _cookie, int32 requestID,
445	off_t offset, size_t size, struct file_io_vec* vecs, size_t* _count)
446{
447	HaikuKernelIterativeFDIOCookie* cookie
448		= (HaikuKernelIterativeFDIOCookie*)_cookie;
449
450	// get the request
451	HaikuKernelIORequest* request = _FileSystem()->GetIORequest(requestID);
452	if (request == NULL)
453		RETURN_ERROR(B_BAD_VALUE);
454
455	// call the callback
456	status_t error = cookie->getVecs(cookie->cookie, (io_request*)request,
457		offset, size, vecs, _count);
458
459	// put the reference we got above
460	_FileSystem()->PutIORequest(request, 1);
461
462	return error;
463}
464
465
466// IterativeIOFinished
467status_t
468HaikuKernelVolume::IterativeIOFinished(void* _cookie, int32 requestID,
469	status_t status, bool partialTransfer, size_t bytesTransferred)
470{
471	HaikuKernelIterativeFDIOCookie* cookie
472		= (HaikuKernelIterativeFDIOCookie*)_cookie;
473
474	// we're definitely done with the cookie, now
475	ObjectDeleter<HaikuKernelIterativeFDIOCookie> _(cookie);
476
477	// get the request
478	HaikuKernelIORequest* request = _FileSystem()->GetIORequest(requestID);
479	if (request == NULL)
480		RETURN_ERROR(B_BAD_VALUE);
481
482	// call the callback
483	status_t error = cookie->finished(cookie->cookie, (io_request*)request,
484		status, partialTransfer, bytesTransferred);
485
486	// We're done with the request, too, so put the reference we got above and
487	// the one added by DoIO().
488	_FileSystem()->PutIORequest(request, 2);
489
490	return error;
491}
492
493
494// #pragma mark - nodes
495
496
497// IOCtl
498status_t
499HaikuKernelVolume::IOCtl(void* _node, void* cookie, uint32 command,
500	void* buffer, size_t size)
501{
502	HaikuKernelNode* node = (HaikuKernelNode*)_node;
503
504	if (!node->ops->ioctl)
505		return B_BAD_VALUE;
506	return node->ops->ioctl(&fVolume, node, cookie, command, buffer,
507		size);
508}
509
510// SetFlags
511status_t
512HaikuKernelVolume::SetFlags(void* _node, void* cookie, int flags)
513{
514	HaikuKernelNode* node = (HaikuKernelNode*)_node;
515
516	if (!node->ops->set_flags)
517		return B_BAD_VALUE;
518	return node->ops->set_flags(&fVolume, node, cookie, flags);
519}
520
521// Select
522status_t
523HaikuKernelVolume::Select(void* _node, void* cookie, uint8 event,
524	selectsync* sync)
525{
526	HaikuKernelNode* node = (HaikuKernelNode*)_node;
527
528	if (!node->ops->select) {
529		UserlandFS::KernelEmu::notify_select_event(sync, event, false);
530		return B_OK;
531	}
532	return node->ops->select(&fVolume, node, cookie, event, sync);
533}
534
535// Deselect
536status_t
537HaikuKernelVolume::Deselect(void* _node, void* cookie, uint8 event,
538	selectsync* sync)
539{
540	HaikuKernelNode* node = (HaikuKernelNode*)_node;
541
542	if (!node->ops->select || !node->ops->deselect)
543		return B_OK;
544	return node->ops->deselect(&fVolume, node, cookie, event, sync);
545}
546
547// FSync
548status_t
549HaikuKernelVolume::FSync(void* _node)
550{
551	HaikuKernelNode* node = (HaikuKernelNode*)_node;
552
553	if (!node->ops->fsync)
554		return B_BAD_VALUE;
555	return node->ops->fsync(&fVolume, node);
556}
557
558// ReadSymlink
559status_t
560HaikuKernelVolume::ReadSymlink(void* _node, char* buffer, size_t bufferSize,
561	size_t* bytesRead)
562{
563	HaikuKernelNode* node = (HaikuKernelNode*)_node;
564
565	if (!node->ops->read_symlink)
566		return B_BAD_VALUE;
567
568	*bytesRead = bufferSize;
569
570	return node->ops->read_symlink(&fVolume, node, buffer, bytesRead);
571}
572
573// CreateSymlink
574status_t
575HaikuKernelVolume::CreateSymlink(void* _dir, const char* name,
576	const char* target, int mode)
577{
578	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
579
580	if (!dir->ops->create_symlink)
581		return B_BAD_VALUE;
582	return dir->ops->create_symlink(&fVolume, dir, name, target, mode);
583}
584
585// Link
586status_t
587HaikuKernelVolume::Link(void* _dir, const char* name, void* _node)
588{
589	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
590	HaikuKernelNode* node = (HaikuKernelNode*)_node;
591
592	if (!dir->ops->link)
593		return B_BAD_VALUE;
594	return dir->ops->link(&fVolume, dir, name, node);
595}
596
597// Unlink
598status_t
599HaikuKernelVolume::Unlink(void* _dir, const char* name)
600{
601	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
602
603	if (!dir->ops->unlink)
604		return B_BAD_VALUE;
605	return dir->ops->unlink(&fVolume, dir, name);
606}
607
608// Rename
609status_t
610HaikuKernelVolume::Rename(void* _oldDir, const char* oldName, void* _newDir,
611	const char* newName)
612{
613	HaikuKernelNode* oldDir = (HaikuKernelNode*)_oldDir;
614	HaikuKernelNode* newDir = (HaikuKernelNode*)_newDir;
615
616	if (!oldDir->ops->rename)
617		return B_BAD_VALUE;
618	return oldDir->ops->rename(&fVolume, oldDir, oldName, newDir, newName);
619}
620
621// Access
622status_t
623HaikuKernelVolume::Access(void* _node, int mode)
624{
625	HaikuKernelNode* node = (HaikuKernelNode*)_node;
626
627	if (!node->ops->access)
628		return B_OK;
629	return node->ops->access(&fVolume, node, mode);
630}
631
632// ReadStat
633status_t
634HaikuKernelVolume::ReadStat(void* _node, struct stat* st)
635{
636	HaikuKernelNode* node = (HaikuKernelNode*)_node;
637
638	if (!node->ops->read_stat)
639		return B_BAD_VALUE;
640	return node->ops->read_stat(&fVolume, node, st);
641}
642
643// WriteStat
644status_t
645HaikuKernelVolume::WriteStat(void* _node, const struct stat *st, uint32 mask)
646{
647	HaikuKernelNode* node = (HaikuKernelNode*)_node;
648
649	if (!node->ops->write_stat)
650		return B_BAD_VALUE;
651	return node->ops->write_stat(&fVolume, node, st, mask);
652}
653
654
655// #pragma mark - files
656
657
658// Create
659status_t
660HaikuKernelVolume::Create(void* _dir, const char* name, int openMode, int mode,
661	void** cookie, ino_t* vnid)
662{
663	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
664
665	if (!dir->ops->create)
666		return B_BAD_VALUE;
667	return dir->ops->create(&fVolume, dir, name, openMode, mode, cookie,
668		vnid);
669}
670
671// Open
672status_t
673HaikuKernelVolume::Open(void* _node, int openMode, void** cookie)
674{
675	HaikuKernelNode* node = (HaikuKernelNode*)_node;
676
677	if (!node->ops->open)
678		return B_BAD_VALUE;
679	return node->ops->open(&fVolume, node, openMode, cookie);
680}
681
682// Close
683status_t
684HaikuKernelVolume::Close(void* _node, void* cookie)
685{
686	HaikuKernelNode* node = (HaikuKernelNode*)_node;
687
688	if (!node->ops->close)
689		return B_OK;
690	return node->ops->close(&fVolume, node, cookie);
691}
692
693// FreeCookie
694status_t
695HaikuKernelVolume::FreeCookie(void* _node, void* cookie)
696{
697	HaikuKernelNode* node = (HaikuKernelNode*)_node;
698
699	if (!node->ops->free_cookie)
700		return B_OK;
701	return node->ops->free_cookie(&fVolume, node, cookie);
702}
703
704// Read
705status_t
706HaikuKernelVolume::Read(void* _node, void* cookie, off_t pos, void* buffer,
707	size_t bufferSize, size_t* bytesRead)
708{
709	HaikuKernelNode* node = (HaikuKernelNode*)_node;
710
711	if (!node->ops->read)
712		return B_BAD_VALUE;
713
714	*bytesRead = bufferSize;
715
716	return node->ops->read(&fVolume, node, cookie, pos, buffer, bytesRead);
717}
718
719// Write
720status_t
721HaikuKernelVolume::Write(void* _node, void* cookie, off_t pos,
722	const void* buffer, size_t bufferSize, size_t* bytesWritten)
723{
724	HaikuKernelNode* node = (HaikuKernelNode*)_node;
725
726	if (!node->ops->write)
727		return B_BAD_VALUE;
728
729	*bytesWritten = bufferSize;
730
731	return node->ops->write(&fVolume, node, cookie, pos, buffer,
732		bytesWritten);
733}
734
735
736// #pragma mark -  directories
737
738
739// CreateDir
740status_t
741HaikuKernelVolume::CreateDir(void* _dir, const char* name, int mode)
742{
743	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
744
745	if (!dir->ops->create_dir)
746		return B_BAD_VALUE;
747	return dir->ops->create_dir(&fVolume, dir, name, mode);
748}
749
750// RemoveDir
751status_t
752HaikuKernelVolume::RemoveDir(void* _dir, const char* name)
753{
754	HaikuKernelNode* dir = (HaikuKernelNode*)_dir;
755
756	if (!dir->ops->remove_dir)
757		return B_BAD_VALUE;
758	return dir->ops->remove_dir(&fVolume, dir, name);
759}
760
761// OpenDir
762status_t
763HaikuKernelVolume::OpenDir(void* _node, void** cookie)
764{
765	HaikuKernelNode* node = (HaikuKernelNode*)_node;
766
767	if (!node->ops->open_dir)
768		return B_BAD_VALUE;
769	return node->ops->open_dir(&fVolume, node, cookie);
770}
771
772// CloseDir
773status_t
774HaikuKernelVolume::CloseDir(void* _node, void* cookie)
775{
776	HaikuKernelNode* node = (HaikuKernelNode*)_node;
777
778	if (!node->ops->close_dir)
779		return B_OK;
780	return node->ops->close_dir(&fVolume, node, cookie);
781}
782
783// FreeDirCookie
784status_t
785HaikuKernelVolume::FreeDirCookie(void* _node, void* cookie)
786{
787	HaikuKernelNode* node = (HaikuKernelNode*)_node;
788
789	if (!node->ops->free_dir_cookie)
790		return B_OK;
791	return node->ops->free_dir_cookie(&fVolume, node, cookie);
792}
793
794// ReadDir
795status_t
796HaikuKernelVolume::ReadDir(void* _node, void* cookie, void* buffer,
797	size_t bufferSize, uint32 count, uint32* countRead)
798{
799	HaikuKernelNode* node = (HaikuKernelNode*)_node;
800
801	if (!node->ops->read_dir)
802		return B_BAD_VALUE;
803
804	*countRead = count;
805
806	return node->ops->read_dir(&fVolume, node, cookie,
807		(struct dirent*)buffer, bufferSize, countRead);
808}
809
810// RewindDir
811status_t
812HaikuKernelVolume::RewindDir(void* _node, void* cookie)
813{
814	HaikuKernelNode* node = (HaikuKernelNode*)_node;
815
816	if (!node->ops->rewind_dir)
817		return B_BAD_VALUE;
818	return node->ops->rewind_dir(&fVolume, node, cookie);
819}
820
821
822// #pragma mark - attribute directories
823
824
825// OpenAttrDir
826status_t
827HaikuKernelVolume::OpenAttrDir(void* _node, void** cookie)
828{
829	HaikuKernelNode* node = (HaikuKernelNode*)_node;
830
831	if (!node->ops->open_attr_dir)
832		return B_BAD_VALUE;
833	return node->ops->open_attr_dir(&fVolume, node, cookie);
834}
835
836// CloseAttrDir
837status_t
838HaikuKernelVolume::CloseAttrDir(void* _node, void* cookie)
839{
840	HaikuKernelNode* node = (HaikuKernelNode*)_node;
841
842	if (!node->ops->close_attr_dir)
843		return B_OK;
844	return node->ops->close_attr_dir(&fVolume, node, cookie);
845}
846
847// FreeAttrDirCookie
848status_t
849HaikuKernelVolume::FreeAttrDirCookie(void* _node, void* cookie)
850{
851	HaikuKernelNode* node = (HaikuKernelNode*)_node;
852
853	if (!node->ops->free_attr_dir_cookie)
854		return B_OK;
855	return node->ops->free_attr_dir_cookie(&fVolume, node, cookie);
856}
857
858// ReadAttrDir
859status_t
860HaikuKernelVolume::ReadAttrDir(void* _node, void* cookie, void* buffer,
861	size_t bufferSize, uint32 count, uint32* countRead)
862{
863	HaikuKernelNode* node = (HaikuKernelNode*)_node;
864
865	if (!node->ops->read_attr_dir)
866		return B_BAD_VALUE;
867
868	*countRead = count;
869
870	return node->ops->read_attr_dir(&fVolume, node, cookie,
871		(struct dirent*)buffer, bufferSize, countRead);
872}
873
874// RewindAttrDir
875status_t
876HaikuKernelVolume::RewindAttrDir(void* _node, void* cookie)
877{
878	HaikuKernelNode* node = (HaikuKernelNode*)_node;
879
880	if (!node->ops->rewind_attr_dir)
881		return B_BAD_VALUE;
882	return node->ops->rewind_attr_dir(&fVolume, node, cookie);
883}
884
885
886// #pragma mark - attributes
887
888
889// CreateAttr
890status_t
891HaikuKernelVolume::CreateAttr(void* _node, const char* name, uint32 type,
892	int openMode, void** cookie)
893{
894	HaikuKernelNode* node = (HaikuKernelNode*)_node;
895
896	if (!node->ops->create_attr)
897		return B_BAD_VALUE;
898	return node->ops->create_attr(&fVolume, node, name, type, openMode,
899		cookie);
900}
901
902// OpenAttr
903status_t
904HaikuKernelVolume::OpenAttr(void* _node, const char* name, int openMode,
905	void** cookie)
906{
907	HaikuKernelNode* node = (HaikuKernelNode*)_node;
908
909	if (!node->ops->open_attr)
910		return B_BAD_VALUE;
911	return node->ops->open_attr(&fVolume, node, name, openMode, cookie);
912}
913
914// CloseAttr
915status_t
916HaikuKernelVolume::CloseAttr(void* _node, void* cookie)
917{
918	HaikuKernelNode* node = (HaikuKernelNode*)_node;
919
920	if (!node->ops->close_attr)
921		return B_OK;
922	return node->ops->close_attr(&fVolume, node, cookie);
923}
924
925// FreeAttrCookie
926status_t
927HaikuKernelVolume::FreeAttrCookie(void* _node, void* cookie)
928{
929	HaikuKernelNode* node = (HaikuKernelNode*)_node;
930
931	if (!node->ops->free_attr_cookie)
932		return B_OK;
933	return node->ops->free_attr_cookie(&fVolume, node, cookie);
934}
935
936// ReadAttr
937status_t
938HaikuKernelVolume::ReadAttr(void* _node, void* cookie, off_t pos,
939	void* buffer, size_t bufferSize, size_t* bytesRead)
940{
941	HaikuKernelNode* node = (HaikuKernelNode*)_node;
942
943	if (!node->ops->read_attr)
944		return B_BAD_VALUE;
945
946	*bytesRead = bufferSize;
947
948	return node->ops->read_attr(&fVolume, node, cookie, pos, buffer,
949		bytesRead);
950}
951
952// WriteAttr
953status_t
954HaikuKernelVolume::WriteAttr(void* _node, void* cookie, off_t pos,
955	const void* buffer, size_t bufferSize, size_t* bytesWritten)
956{
957	HaikuKernelNode* node = (HaikuKernelNode*)_node;
958
959	if (!node->ops->write_attr)
960		return B_BAD_VALUE;
961
962	*bytesWritten = bufferSize;
963
964	return node->ops->write_attr(&fVolume, node, cookie, pos, buffer,
965		bytesWritten);
966}
967
968// ReadAttrStat
969status_t
970HaikuKernelVolume::ReadAttrStat(void* _node, void* cookie,
971	struct stat *st)
972{
973	HaikuKernelNode* node = (HaikuKernelNode*)_node;
974
975	if (!node->ops->read_attr_stat)
976		return B_BAD_VALUE;
977	return node->ops->read_attr_stat(&fVolume, node, cookie, st);
978}
979
980// WriteAttrStat
981status_t
982HaikuKernelVolume::WriteAttrStat(void* _node, void* cookie,
983	const struct stat* st, int statMask)
984{
985	HaikuKernelNode* node = (HaikuKernelNode*)_node;
986
987	if (!node->ops->write_attr_stat)
988		return B_BAD_VALUE;
989	return node->ops->write_attr_stat(&fVolume, node, cookie, st,
990		statMask);
991}
992
993// RenameAttr
994status_t
995HaikuKernelVolume::RenameAttr(void* _oldNode, const char* oldName,
996	void* _newNode, const char* newName)
997{
998	HaikuKernelNode* oldNode = (HaikuKernelNode*)_oldNode;
999	HaikuKernelNode* newNode = (HaikuKernelNode*)_newNode;
1000
1001	if (!oldNode->ops->rename_attr)
1002		return B_BAD_VALUE;
1003	return oldNode->ops->rename_attr(&fVolume, oldNode, oldName, newNode,
1004		newName);
1005}
1006
1007// RemoveAttr
1008status_t
1009HaikuKernelVolume::RemoveAttr(void* _node, const char* name)
1010{
1011	HaikuKernelNode* node = (HaikuKernelNode*)_node;
1012
1013	if (!node->ops->remove_attr)
1014		return B_BAD_VALUE;
1015	return node->ops->remove_attr(&fVolume, node, name);
1016}
1017
1018
1019// #pragma mark - indices
1020
1021
1022// OpenIndexDir
1023status_t
1024HaikuKernelVolume::OpenIndexDir(void** cookie)
1025{
1026	if (!fVolume.ops->open_index_dir)
1027		return B_BAD_VALUE;
1028	return fVolume.ops->open_index_dir(&fVolume, cookie);
1029}
1030
1031// CloseIndexDir
1032status_t
1033HaikuKernelVolume::CloseIndexDir(void* cookie)
1034{
1035	if (!fVolume.ops->close_index_dir)
1036		return B_OK;
1037	return fVolume.ops->close_index_dir(&fVolume, cookie);
1038}
1039
1040// FreeIndexDirCookie
1041status_t
1042HaikuKernelVolume::FreeIndexDirCookie(void* cookie)
1043{
1044	if (!fVolume.ops->free_index_dir_cookie)
1045		return B_OK;
1046	return fVolume.ops->free_index_dir_cookie(&fVolume, cookie);
1047}
1048
1049// ReadIndexDir
1050status_t
1051HaikuKernelVolume::ReadIndexDir(void* cookie, void* buffer,
1052	size_t bufferSize, uint32 count, uint32* countRead)
1053{
1054	if (!fVolume.ops->read_index_dir)
1055		return B_BAD_VALUE;
1056
1057	*countRead = count;
1058
1059	return fVolume.ops->read_index_dir(&fVolume, cookie,
1060		(struct dirent*)buffer, bufferSize, countRead);
1061}
1062
1063// RewindIndexDir
1064status_t
1065HaikuKernelVolume::RewindIndexDir(void* cookie)
1066{
1067	if (!fVolume.ops->rewind_index_dir)
1068		return B_BAD_VALUE;
1069	return fVolume.ops->rewind_index_dir(&fVolume, cookie);
1070}
1071
1072// CreateIndex
1073status_t
1074HaikuKernelVolume::CreateIndex(const char* name, uint32 type, uint32 flags)
1075{
1076	if (!fVolume.ops->create_index)
1077		return B_BAD_VALUE;
1078	return fVolume.ops->create_index(&fVolume, name, type, flags);
1079}
1080
1081// RemoveIndex
1082status_t
1083HaikuKernelVolume::RemoveIndex(const char* name)
1084{
1085	if (!fVolume.ops->remove_index)
1086		return B_BAD_VALUE;
1087	return fVolume.ops->remove_index(&fVolume, name);
1088}
1089
1090// StatIndex
1091status_t
1092HaikuKernelVolume::ReadIndexStat(const char *name, struct stat *st)
1093{
1094	if (!fVolume.ops->read_index_stat)
1095		return B_BAD_VALUE;
1096	return fVolume.ops->read_index_stat(&fVolume, name, st);
1097}
1098
1099
1100// #pragma mark - queries
1101
1102
1103// OpenQuery
1104status_t
1105HaikuKernelVolume::OpenQuery(const char* queryString, uint32 flags,
1106	port_id port, uint32 token, void** cookie)
1107{
1108	if (!fVolume.ops->open_query)
1109		return B_BAD_VALUE;
1110	return fVolume.ops->open_query(&fVolume, queryString, flags, port,
1111		token, cookie);
1112}
1113
1114// CloseQuery
1115status_t
1116HaikuKernelVolume::CloseQuery(void* cookie)
1117{
1118	if (!fVolume.ops->close_query)
1119		return B_OK;
1120	return fVolume.ops->close_query(&fVolume, cookie);
1121}
1122
1123// FreeQueryCookie
1124status_t
1125HaikuKernelVolume::FreeQueryCookie(void* cookie)
1126{
1127	if (!fVolume.ops->free_query_cookie)
1128		return B_OK;
1129	return fVolume.ops->free_query_cookie(&fVolume, cookie);
1130}
1131
1132// ReadQuery
1133status_t
1134HaikuKernelVolume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
1135	uint32 count, uint32* countRead)
1136{
1137	if (!fVolume.ops->read_query)
1138		return B_BAD_VALUE;
1139
1140	*countRead = count;
1141
1142	return fVolume.ops->read_query(&fVolume, cookie, (struct dirent*)buffer,
1143		bufferSize, countRead);
1144}
1145
1146// RewindQuery
1147status_t
1148HaikuKernelVolume::RewindQuery(void* cookie)
1149{
1150	if (!fVolume.ops->rewind_query)
1151		return B_BAD_VALUE;
1152	return fVolume.ops->rewind_query(&fVolume, cookie);
1153}
1154
1155// _InitCapabilities
1156void
1157HaikuKernelVolume::_InitCapabilities()
1158{
1159	fCapabilities.ClearAll();
1160
1161	// FS operations
1162	fCapabilities.Set(FS_VOLUME_CAPABILITY_UNMOUNT, fVolume.ops->unmount);
1163
1164	fCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO,
1165		fVolume.ops->read_fs_info);
1166	fCapabilities.Set(FS_VOLUME_CAPABILITY_WRITE_FS_INFO,
1167		fVolume.ops->write_fs_info);
1168	fCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fVolume.ops->sync);
1169
1170	// vnode operations
1171	fCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, fVolume.ops->get_vnode);
1172
1173	// index directory & index operations
1174	fCapabilities.Set(FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR,
1175		fVolume.ops->open_index_dir);
1176	fCapabilities.Set(FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR,
1177		fVolume.ops->close_index_dir);
1178	fCapabilities.Set(FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE,
1179		fVolume.ops->free_index_dir_cookie);
1180	fCapabilities.Set(FS_VOLUME_CAPABILITY_READ_INDEX_DIR,
1181		fVolume.ops->read_index_dir);
1182	fCapabilities.Set(FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR,
1183		fVolume.ops->rewind_index_dir);
1184
1185	fCapabilities.Set(FS_VOLUME_CAPABILITY_CREATE_INDEX,
1186		fVolume.ops->create_index);
1187	fCapabilities.Set(FS_VOLUME_CAPABILITY_REMOVE_INDEX,
1188		fVolume.ops->remove_index);
1189	fCapabilities.Set(FS_VOLUME_CAPABILITY_READ_INDEX_STAT,
1190		fVolume.ops->read_index_stat);
1191
1192	// query operations
1193	fCapabilities.Set(FS_VOLUME_CAPABILITY_OPEN_QUERY, fVolume.ops->open_query);
1194	fCapabilities.Set(FS_VOLUME_CAPABILITY_CLOSE_QUERY,
1195		fVolume.ops->close_query);
1196	fCapabilities.Set(FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE,
1197		fVolume.ops->free_query_cookie);
1198	fCapabilities.Set(FS_VOLUME_CAPABILITY_READ_QUERY, fVolume.ops->read_query);
1199	fCapabilities.Set(FS_VOLUME_CAPABILITY_REWIND_QUERY,
1200		fVolume.ops->rewind_query);
1201}
1202