xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelVolume.cpp (revision de48af7a58bf645825ef9734ba3b765590f2d5fa)
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
28 class HaikuKernelVolume::NodeMap
29 	: public SynchronizedHashMap<HashKey64<ino_t>, HaikuKernelNode*, Locker> {
30 };
31 
32 
33 // _FileSystem
34 inline HaikuKernelFileSystem*
_FileSystem() const35 HaikuKernelVolume::_FileSystem() const
36 {
37 	return static_cast<HaikuKernelFileSystem*>(fFileSystem);
38 }
39 
40 
41 // constructor
HaikuKernelVolume(FileSystem * fileSystem,dev_t id,file_system_module_info * fsModule)42 HaikuKernelVolume::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
~HaikuKernelVolume()62 HaikuKernelVolume::~HaikuKernelVolume()
63 {
64 	delete fNodes;
65 }
66 
67 
68 // Init
69 status_t
Init()70 HaikuKernelVolume::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
80 status_t
NewVNode(ino_t vnodeID,void * privateNode,fs_vnode_ops * ops,HaikuKernelNode ** _node)81 HaikuKernelVolume::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
119 status_t
PublishVNode(ino_t vnodeID,void * privateNode,fs_vnode_ops * ops,int type,uint32 flags,HaikuKernelNode ** _node)120 HaikuKernelVolume::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
162 void
UndoNewVNode(HaikuKernelNode * node)163 HaikuKernelVolume::UndoNewVNode(HaikuKernelNode* node)
164 {
165 	fNodes->Remove(node->id);
166 	delete node;
167 }
168 
169 
170 // UndoPublishVNode
171 void
UndoPublishVNode(HaikuKernelNode * node)172 HaikuKernelVolume::UndoPublishVNode(HaikuKernelNode* node)
173 {
174 	fNodes->Remove(node->id);
175 	delete node;
176 }
177 
178 
179 // NodeWithID
180 HaikuKernelNode*
NodeWithID(ino_t vnodeID) const181 HaikuKernelVolume::NodeWithID(ino_t vnodeID) const
182 {
183 	return fNodes->Get(vnodeID);
184 }
185 
186 
187 // #pragma mark -
188 // #pragma mark ----- FS -----
189 
190 // Mount
191 status_t
Mount(const char * device,uint32 flags,const char * parameters,ino_t * rootID)192 HaikuKernelVolume::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
210 status_t
Unmount()211 HaikuKernelVolume::Unmount()
212 {
213 	if (!fVolume.ops->unmount)
214 		return B_BAD_VALUE;
215 
216 	return fVolume.ops->unmount(&fVolume);
217 }
218 
219 // Sync
220 status_t
Sync()221 HaikuKernelVolume::Sync()
222 {
223 	if (!fVolume.ops->sync)
224 		return B_BAD_VALUE;
225 	return fVolume.ops->sync(&fVolume);
226 }
227 
228 // ReadFSInfo
229 status_t
ReadFSInfo(fs_info * info)230 HaikuKernelVolume::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
238 status_t
WriteFSInfo(const struct fs_info * info,uint32 mask)239 HaikuKernelVolume::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
251 status_t
GetFileMap(void * _node,off_t offset,size_t size,struct file_io_vec * vecs,size_t * count)252 HaikuKernelVolume::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
268 status_t
Lookup(void * _dir,const char * entryName,ino_t * vnid)269 HaikuKernelVolume::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
280 status_t
GetVNodeName(void * _node,char * buffer,size_t bufferSize)281 HaikuKernelVolume::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
293 status_t
ReadVNode(ino_t vnid,bool reenter,void ** _node,int * type,uint32 * flags,FSVNodeCapabilities * _capabilities)294 HaikuKernelVolume::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
347 status_t
WriteVNode(void * _node,bool reenter)348 HaikuKernelVolume::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
364 status_t
RemoveVNode(void * _node,bool reenter)365 HaikuKernelVolume::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 
380 status_t
DoIO(void * _node,void * cookie,const IORequestInfo & requestInfo)381 HaikuKernelVolume::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 
417 status_t
CancelIO(void * _node,void * cookie,int32 ioRequestID)418 HaikuKernelVolume::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
443 status_t
IterativeIOGetVecs(void * _cookie,int32 requestID,off_t offset,size_t size,struct file_io_vec * vecs,size_t * _count)444 HaikuKernelVolume::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
467 status_t
IterativeIOFinished(void * _cookie,int32 requestID,status_t status,bool partialTransfer,size_t bytesTransferred)468 HaikuKernelVolume::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
498 status_t
IOCtl(void * _node,void * cookie,uint32 command,void * buffer,size_t size)499 HaikuKernelVolume::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
511 status_t
SetFlags(void * _node,void * cookie,int flags)512 HaikuKernelVolume::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
522 status_t
Select(void * _node,void * cookie,uint8 event,selectsync * sync)523 HaikuKernelVolume::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
536 status_t
Deselect(void * _node,void * cookie,uint8 event,selectsync * sync)537 HaikuKernelVolume::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
548 status_t
FSync(void * _node)549 HaikuKernelVolume::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
559 status_t
ReadSymlink(void * _node,char * buffer,size_t bufferSize,size_t * bytesRead)560 HaikuKernelVolume::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
574 status_t
CreateSymlink(void * _dir,const char * name,const char * target,int mode)575 HaikuKernelVolume::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
586 status_t
Link(void * _dir,const char * name,void * _node)587 HaikuKernelVolume::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
598 status_t
Unlink(void * _dir,const char * name)599 HaikuKernelVolume::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
609 status_t
Rename(void * _oldDir,const char * oldName,void * _newDir,const char * newName)610 HaikuKernelVolume::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
622 status_t
Access(void * _node,int mode)623 HaikuKernelVolume::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
633 status_t
ReadStat(void * _node,struct stat * st)634 HaikuKernelVolume::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
644 status_t
WriteStat(void * _node,const struct stat * st,uint32 mask)645 HaikuKernelVolume::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
659 status_t
Create(void * _dir,const char * name,int openMode,int mode,void ** cookie,ino_t * vnid)660 HaikuKernelVolume::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
672 status_t
Open(void * _node,int openMode,void ** cookie)673 HaikuKernelVolume::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
683 status_t
Close(void * _node,void * cookie)684 HaikuKernelVolume::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
694 status_t
FreeCookie(void * _node,void * cookie)695 HaikuKernelVolume::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
705 status_t
Read(void * _node,void * cookie,off_t pos,void * buffer,size_t bufferSize,size_t * bytesRead)706 HaikuKernelVolume::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
720 status_t
Write(void * _node,void * cookie,off_t pos,const void * buffer,size_t bufferSize,size_t * bytesWritten)721 HaikuKernelVolume::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
740 status_t
CreateDir(void * _dir,const char * name,int mode)741 HaikuKernelVolume::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
751 status_t
RemoveDir(void * _dir,const char * name)752 HaikuKernelVolume::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
762 status_t
OpenDir(void * _node,void ** cookie)763 HaikuKernelVolume::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
773 status_t
CloseDir(void * _node,void * cookie)774 HaikuKernelVolume::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
784 status_t
FreeDirCookie(void * _node,void * cookie)785 HaikuKernelVolume::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
795 status_t
ReadDir(void * _node,void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)796 HaikuKernelVolume::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
811 status_t
RewindDir(void * _node,void * cookie)812 HaikuKernelVolume::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
826 status_t
OpenAttrDir(void * _node,void ** cookie)827 HaikuKernelVolume::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
837 status_t
CloseAttrDir(void * _node,void * cookie)838 HaikuKernelVolume::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
848 status_t
FreeAttrDirCookie(void * _node,void * cookie)849 HaikuKernelVolume::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
859 status_t
ReadAttrDir(void * _node,void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)860 HaikuKernelVolume::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
875 status_t
RewindAttrDir(void * _node,void * cookie)876 HaikuKernelVolume::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
890 status_t
CreateAttr(void * _node,const char * name,uint32 type,int openMode,void ** cookie)891 HaikuKernelVolume::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
903 status_t
OpenAttr(void * _node,const char * name,int openMode,void ** cookie)904 HaikuKernelVolume::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
915 status_t
CloseAttr(void * _node,void * cookie)916 HaikuKernelVolume::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
926 status_t
FreeAttrCookie(void * _node,void * cookie)927 HaikuKernelVolume::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
937 status_t
ReadAttr(void * _node,void * cookie,off_t pos,void * buffer,size_t bufferSize,size_t * bytesRead)938 HaikuKernelVolume::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
953 status_t
WriteAttr(void * _node,void * cookie,off_t pos,const void * buffer,size_t bufferSize,size_t * bytesWritten)954 HaikuKernelVolume::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
969 status_t
ReadAttrStat(void * _node,void * cookie,struct stat * st)970 HaikuKernelVolume::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
981 status_t
WriteAttrStat(void * _node,void * cookie,const struct stat * st,int statMask)982 HaikuKernelVolume::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
994 status_t
RenameAttr(void * _oldNode,const char * oldName,void * _newNode,const char * newName)995 HaikuKernelVolume::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
1008 status_t
RemoveAttr(void * _node,const char * name)1009 HaikuKernelVolume::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
1023 status_t
OpenIndexDir(void ** cookie)1024 HaikuKernelVolume::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
1032 status_t
CloseIndexDir(void * cookie)1033 HaikuKernelVolume::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
1041 status_t
FreeIndexDirCookie(void * cookie)1042 HaikuKernelVolume::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
1050 status_t
ReadIndexDir(void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)1051 HaikuKernelVolume::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
1064 status_t
RewindIndexDir(void * cookie)1065 HaikuKernelVolume::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
1073 status_t
CreateIndex(const char * name,uint32 type,uint32 flags)1074 HaikuKernelVolume::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
1082 status_t
RemoveIndex(const char * name)1083 HaikuKernelVolume::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
1091 status_t
ReadIndexStat(const char * name,struct stat * st)1092 HaikuKernelVolume::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
1104 status_t
OpenQuery(const char * queryString,uint32 flags,port_id port,uint32 token,void ** cookie)1105 HaikuKernelVolume::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
1115 status_t
CloseQuery(void * cookie)1116 HaikuKernelVolume::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
1124 status_t
FreeQueryCookie(void * cookie)1125 HaikuKernelVolume::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
1133 status_t
ReadQuery(void * cookie,void * buffer,size_t bufferSize,uint32 count,uint32 * countRead)1134 HaikuKernelVolume::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
1147 status_t
RewindQuery(void * cookie)1148 HaikuKernelVolume::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
1156 void
_InitCapabilities()1157 HaikuKernelVolume::_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