xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/beos/BeOSKernelVolume.cpp (revision 97dfeb96704e5dbc5bec32ad7b21379d0125e031)
1 /*
2  * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "BeOSKernelVolume.h"
7 
8 #include <new>
9 
10 #include <fcntl.h>
11 #include <unistd.h>
12 
13 #include "Debug.h"
14 
15 #include "../kernel_emu.h"
16 
17 #include "BeOSKernelFileSystem.h"
18 #include "fs_interface.h"
19 
20 
21 using std::nothrow;
22 
23 static int open_mode_to_access(int openMode);
24 
25 
26 // AttributeCookie
27 class BeOSKernelVolume::AttributeCookie {
28 public:
29 	AttributeCookie(const char* name, uint32 type, int openMode, bool exists,
30 		bool create)
31 		: fType(type),
32 		  fOpenMode(openMode),
33 		  fExists(exists),
34 		  fCreate(create)
35 	{
36 		strcpy(fName, name);
37 	}
38 
39 	char	fName[B_ATTR_NAME_LENGTH];
40 	uint32	fType;
41 	int		fOpenMode;
42 	bool	fExists;
43 	bool	fCreate;
44 };
45 
46 
47 // _FileSystem
48 inline BeOSKernelFileSystem*
49 BeOSKernelVolume::_FileSystem() const
50 {
51 	return static_cast<BeOSKernelFileSystem*>(fFileSystem);
52 }
53 
54 
55 // constructor
56 BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id,
57 	beos_vnode_ops* fsOps, const FSVolumeCapabilities& capabilities)
58 	:
59 	Volume(fileSystem, id),
60 	fFSOps(fsOps),
61 	fVolumeCookie(NULL),
62 	fMounted(false)
63 {
64 	fCapabilities = capabilities;
65 }
66 
67 // destructor
68 BeOSKernelVolume::~BeOSKernelVolume()
69 {
70 }
71 
72 // #pragma mark -
73 // #pragma mark ----- FS -----
74 
75 // Mount
76 status_t
77 BeOSKernelVolume::Mount(const char* device, uint32 flags,
78 	const char* parameters, ino_t* rootID)
79 {
80 	if (!fFSOps->mount)
81 		return B_BAD_VALUE;
82 
83 	size_t len = (parameters ? strlen(parameters) : 0);
84 	status_t error = fFSOps->mount(GetID(), device, flags, (void*)parameters,
85 		len, &fVolumeCookie, rootID);
86 	if (error != B_OK)
87 		return error;
88 
89 	fMounted = true;
90 	return B_OK;
91 }
92 
93 // Unmount
94 status_t
95 BeOSKernelVolume::Unmount()
96 {
97 	if (!fFSOps->unmount)
98 		return B_BAD_VALUE;
99 	return fFSOps->unmount(fVolumeCookie);
100 }
101 
102 // Sync
103 status_t
104 BeOSKernelVolume::Sync()
105 {
106 	if (!fFSOps->sync)
107 		return B_BAD_VALUE;
108 	return fFSOps->sync(fVolumeCookie);
109 }
110 
111 // ReadFSInfo
112 status_t
113 BeOSKernelVolume::ReadFSInfo(fs_info* info)
114 {
115 	if (!fFSOps->rfsstat)
116 		return B_BAD_VALUE;
117 
118 	// Haiku's fs_info equals BeOS's version
119 	return fFSOps->rfsstat(fVolumeCookie, (beos_fs_info*)info);
120 }
121 
122 // WriteFSInfo
123 status_t
124 BeOSKernelVolume::WriteFSInfo(const struct fs_info* info, uint32 mask)
125 {
126 	if (!fFSOps->wfsstat)
127 		return B_BAD_VALUE;
128 
129 	// Haiku's fs_info equals BeOS's version
130 	return fFSOps->wfsstat(fVolumeCookie, (beos_fs_info*)info, (long)mask);
131 }
132 
133 
134 // #pragma mark - vnodes
135 
136 
137 // Lookup
138 status_t
139 BeOSKernelVolume::Lookup(void* dir, const char* entryName, ino_t* vnid)
140 {
141 	if (!fFSOps->walk)
142 		return B_BAD_VALUE;
143 	return fFSOps->walk(fVolumeCookie, dir, entryName, NULL, vnid);
144 }
145 
146 
147 // GetVNodeType
148 status_t
149 BeOSKernelVolume::GetVNodeType(void* node, int* type)
150 {
151 	if (fMounted) {
152 		// The volume is mounted. We can stat() the node to get its type.
153 		struct stat st;
154 		status_t error = ReadStat(node, &st);
155 		if (error != B_OK)
156 			return error;
157 
158 		*type = st.st_mode & S_IFMT;
159 	} else {
160 		// Not mounted yet. That particularly means we don't have a volume
161 		// cookie yet and cannot use calls into the FS to get the node type.
162 		// Just assume the node is a directory. That definitely is the case for
163 		// the root node and shouldn't do harm for the index directory or
164 		// indices, which could get published while mounting as well.
165 		*type = S_IFDIR;
166 			// TODO: Store the concerned nodes and check their type as soon as
167 			// possible (at the end of Mount()). The incorrect ones could be
168 			// corrected in the kernel: remove_vnode(), x*put_vnode() (catching
169 			// the "remove_vnode()" callback), publish_vnode(),
170 			// (x-1)*get_vnode().
171 	}
172 
173 	return B_OK;
174 }
175 
176 
177 // ReadVNode
178 status_t
179 BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type,
180 	uint32* flags, FSVNodeCapabilities* _capabilities)
181 {
182 	if (!fFSOps->read_vnode)
183 		return B_BAD_VALUE;
184 
185 	// get the node
186 	status_t error = fFSOps->read_vnode(fVolumeCookie, vnid, (char)reenter,
187 		node);
188 	if (error != B_OK)
189 		return error;
190 
191 	// stat it -- we need to get the node type
192 	struct stat st;
193 	error = ReadStat(*node, &st);
194 	if (error != B_OK) {
195 		WriteVNode(*node, reenter);
196 		return error;
197 	}
198 
199 	*type = (st.st_mode & S_IFMT);
200 	*flags = 0;
201 	_FileSystem()->GetNodeCapabilities(*_capabilities);
202 
203 	return B_OK;
204 }
205 
206 // WriteVNode
207 status_t
208 BeOSKernelVolume::WriteVNode(void* node, bool reenter)
209 {
210 	if (!fFSOps->write_vnode)
211 		return B_BAD_VALUE;
212 	return fFSOps->write_vnode(fVolumeCookie, node, (char)reenter);
213 }
214 
215 // RemoveVNode
216 status_t
217 BeOSKernelVolume::RemoveVNode(void* node, bool reenter)
218 {
219 	if (!fFSOps->remove_vnode)
220 		return B_BAD_VALUE;
221 	return fFSOps->remove_vnode(fVolumeCookie, node, (char)reenter);
222 }
223 
224 
225 // #pragma mark - nodes
226 
227 
228 // IOCtl
229 status_t
230 BeOSKernelVolume::IOCtl(void* node, void* cookie, uint32 command,
231 	void* buffer, size_t size)
232 {
233 	if (!fFSOps->ioctl)
234 		return B_BAD_VALUE;
235 	return fFSOps->ioctl(fVolumeCookie, node, cookie, (int)command, buffer,
236 		size);
237 }
238 
239 // SetFlags
240 status_t
241 BeOSKernelVolume::SetFlags(void* node, void* cookie, int flags)
242 {
243 	if (!fFSOps->setflags)
244 		return B_BAD_VALUE;
245 	return fFSOps->setflags(fVolumeCookie, node, cookie, flags);
246 }
247 
248 // Select
249 status_t
250 BeOSKernelVolume::Select(void* node, void* cookie, uint8 event,
251 	selectsync* sync)
252 {
253 	if (!fFSOps->select) {
254 		UserlandFS::KernelEmu::notify_select_event(sync, event, false);
255 		return B_OK;
256 	}
257 	return fFSOps->select(fVolumeCookie, node, cookie, event, 0, sync);
258 }
259 
260 // Deselect
261 status_t
262 BeOSKernelVolume::Deselect(void* node, void* cookie, uint8 event,
263 	selectsync* sync)
264 {
265 	if (!fFSOps->select || !fFSOps->deselect)
266 		return B_OK;
267 	return fFSOps->deselect(fVolumeCookie, node, cookie, event, sync);
268 }
269 
270 // FSync
271 status_t
272 BeOSKernelVolume::FSync(void* node)
273 {
274 	if (!fFSOps->fsync)
275 		return B_BAD_VALUE;
276 	return fFSOps->fsync(fVolumeCookie, node);
277 }
278 
279 // ReadSymlink
280 status_t
281 BeOSKernelVolume::ReadSymlink(void* node, char* buffer, size_t bufferSize,
282 	size_t* bytesRead)
283 {
284 	if (!fFSOps->readlink)
285 		return B_BAD_VALUE;
286 	*bytesRead = bufferSize;
287 	return fFSOps->readlink(fVolumeCookie, node, buffer, bytesRead);
288 }
289 
290 // CreateSymlink
291 status_t
292 BeOSKernelVolume::CreateSymlink(void* dir, const char* name,
293 	const char* target, int mode)
294 {
295 	if (!fFSOps->symlink)
296 		return B_BAD_VALUE;
297 // TODO: Don't ignore mode?
298 	return fFSOps->symlink(fVolumeCookie, dir, name, target);
299 }
300 
301 // Link
302 status_t
303 BeOSKernelVolume::Link(void* dir, const char* name, void* node)
304 {
305 	if (!fFSOps->link)
306 		return B_BAD_VALUE;
307 	return fFSOps->link(fVolumeCookie, dir, name, node);
308 }
309 
310 // Unlink
311 status_t
312 BeOSKernelVolume::Unlink(void* dir, const char* name)
313 {
314 	if (!fFSOps->unlink)
315 		return B_BAD_VALUE;
316 	return fFSOps->unlink(fVolumeCookie, dir, name);
317 }
318 
319 // Rename
320 status_t
321 BeOSKernelVolume::Rename(void* oldDir, const char* oldName, void* newDir,
322 	const char* newName)
323 {
324 	if (!fFSOps->rename)
325 		return B_BAD_VALUE;
326 	return fFSOps->rename(fVolumeCookie, oldDir, oldName, newDir, newName);
327 }
328 
329 // Access
330 status_t
331 BeOSKernelVolume::Access(void* node, int mode)
332 {
333 	if (!fFSOps->access)
334 		return B_OK;
335 	return fFSOps->access(fVolumeCookie, node, mode);
336 }
337 
338 // ReadStat
339 status_t
340 BeOSKernelVolume::ReadStat(void* node, struct stat* st)
341 {
342 	if (!fFSOps->rstat)
343 		return B_BAD_VALUE;
344 
345 	// Haiku's struct stat has an additional st_type field (for an attribute
346 	// type), but that doesn't matter here
347 	return fFSOps->rstat(fVolumeCookie, node, (struct beos_stat*)st);
348 }
349 
350 // WriteStat
351 status_t
352 BeOSKernelVolume::WriteStat(void* node, const struct stat *st, uint32 mask)
353 {
354 	if (!fFSOps->wstat)
355 		return B_BAD_VALUE;
356 
357 	// Haiku's struct stat has an additional st_type field (for an attribute
358 	// type), but that doesn't matter here
359 	return fFSOps->wstat(fVolumeCookie, node, (struct beos_stat*)st,
360 		(long)mask);
361 }
362 
363 
364 // #pragma mark - files
365 
366 
367 // Create
368 status_t
369 BeOSKernelVolume::Create(void* dir, const char* name, int openMode, int mode,
370 	void** cookie, ino_t* vnid)
371 {
372 	if (!fFSOps->create)
373 		return B_BAD_VALUE;
374 	return fFSOps->create(fVolumeCookie, dir, name, openMode, mode, vnid,
375 		cookie);
376 }
377 
378 // Open
379 status_t
380 BeOSKernelVolume::Open(void* node, int openMode, void** cookie)
381 {
382 	if (!fFSOps->open)
383 		return B_BAD_VALUE;
384 	return fFSOps->open(fVolumeCookie, node, openMode, cookie);
385 }
386 
387 // Close
388 status_t
389 BeOSKernelVolume::Close(void* node, void* cookie)
390 {
391 	if (!fFSOps->close)
392 		return B_OK;
393 	return fFSOps->close(fVolumeCookie, node, cookie);
394 }
395 
396 // FreeCookie
397 status_t
398 BeOSKernelVolume::FreeCookie(void* node, void* cookie)
399 {
400 	if (!fFSOps->free_cookie)
401 		return B_OK;
402 	return fFSOps->free_cookie(fVolumeCookie, node, cookie);
403 }
404 
405 // Read
406 status_t
407 BeOSKernelVolume::Read(void* node, void* cookie, off_t pos, void* buffer,
408 	size_t bufferSize, size_t* bytesRead)
409 {
410 	if (!fFSOps->read)
411 		return B_BAD_VALUE;
412 	*bytesRead = bufferSize;
413 	return fFSOps->read(fVolumeCookie, node, cookie, pos, buffer, bytesRead);
414 }
415 
416 // Write
417 status_t
418 BeOSKernelVolume::Write(void* node, void* cookie, off_t pos,
419 	const void* buffer, size_t bufferSize, size_t* bytesWritten)
420 {
421 	if (!fFSOps->write)
422 		return B_BAD_VALUE;
423 	*bytesWritten = bufferSize;
424 	return fFSOps->write(fVolumeCookie, node, cookie, pos, buffer,
425 		bytesWritten);
426 }
427 
428 
429 // #pragma mark -  directories
430 
431 
432 // CreateDir
433 status_t
434 BeOSKernelVolume::CreateDir(void* dir, const char* name, int mode)
435 {
436 	if (!fFSOps->mkdir)
437 		return B_BAD_VALUE;
438 
439 	return fFSOps->mkdir(fVolumeCookie, dir, name, mode);
440 }
441 
442 // RemoveDir
443 status_t
444 BeOSKernelVolume::RemoveDir(void* dir, const char* name)
445 {
446 	if (!fFSOps->rmdir)
447 		return B_BAD_VALUE;
448 	return fFSOps->rmdir(fVolumeCookie, dir, name);
449 }
450 
451 // OpenDir
452 status_t
453 BeOSKernelVolume::OpenDir(void* node, void** cookie)
454 {
455 	if (!fFSOps->opendir)
456 		return B_BAD_VALUE;
457 	return fFSOps->opendir(fVolumeCookie, node, cookie);
458 }
459 
460 // CloseDir
461 status_t
462 BeOSKernelVolume::CloseDir(void* node, void* cookie)
463 {
464 	if (!fFSOps->closedir)
465 		return B_OK;
466 	return fFSOps->closedir(fVolumeCookie, node, cookie);
467 }
468 
469 // FreeDirCookie
470 status_t
471 BeOSKernelVolume::FreeDirCookie(void* node, void* cookie)
472 {
473 	if (!fFSOps->free_dircookie)
474 		return B_OK;
475 	return fFSOps->free_dircookie(fVolumeCookie, node, cookie);
476 }
477 
478 // ReadDir
479 status_t
480 BeOSKernelVolume::ReadDir(void* node, void* cookie, void* buffer,
481 	size_t bufferSize, uint32 count, uint32* countRead)
482 {
483 	if (!fFSOps->readdir)
484 		return B_BAD_VALUE;
485 
486 	*countRead = count;
487 
488 	// Haiku's struct dirent equals BeOS's version
489 	return fFSOps->readdir(fVolumeCookie, node, cookie, (long*)countRead,
490 		(beos_dirent*)buffer, bufferSize);
491 }
492 
493 // RewindDir
494 status_t
495 BeOSKernelVolume::RewindDir(void* node, void* cookie)
496 {
497 	if (!fFSOps->rewinddir)
498 		return B_BAD_VALUE;
499 	return fFSOps->rewinddir(fVolumeCookie, node, cookie);
500 }
501 
502 
503 // #pragma mark - attribute directories
504 
505 
506 // OpenAttrDir
507 status_t
508 BeOSKernelVolume::OpenAttrDir(void* node, void** cookie)
509 {
510 	if (!fFSOps->open_attrdir)
511 		return B_BAD_VALUE;
512 	return fFSOps->open_attrdir(fVolumeCookie, node, cookie);
513 }
514 
515 // CloseAttrDir
516 status_t
517 BeOSKernelVolume::CloseAttrDir(void* node, void* cookie)
518 {
519 	if (!fFSOps->close_attrdir)
520 		return B_OK;
521 	return fFSOps->close_attrdir(fVolumeCookie, node, cookie);
522 }
523 
524 // FreeAttrDirCookie
525 status_t
526 BeOSKernelVolume::FreeAttrDirCookie(void* node, void* cookie)
527 {
528 	if (!fFSOps->free_attrdircookie)
529 		return B_OK;
530 	return fFSOps->free_attrdircookie(fVolumeCookie, node, cookie);
531 }
532 
533 // ReadAttrDir
534 status_t
535 BeOSKernelVolume::ReadAttrDir(void* node, void* cookie, void* buffer,
536 	size_t bufferSize, uint32 count, uint32* countRead)
537 {
538 	if (!fFSOps->read_attrdir)
539 		return B_BAD_VALUE;
540 
541 	*countRead = count;
542 
543 	// Haiku's struct dirent equals BeOS's version
544 	return fFSOps->read_attrdir(fVolumeCookie, node, cookie, (long*)countRead,
545 		(struct beos_dirent*)buffer, bufferSize);
546 }
547 
548 // RewindAttrDir
549 status_t
550 BeOSKernelVolume::RewindAttrDir(void* node, void* cookie)
551 {
552 	if (!fFSOps->rewind_attrdir)
553 		return B_BAD_VALUE;
554 	return fFSOps->rewind_attrdir(fVolumeCookie, node, cookie);
555 }
556 
557 
558 // #pragma mark - attributes
559 
560 
561 // CreateAttr
562 status_t
563 BeOSKernelVolume::CreateAttr(void* node, const char* name, uint32 type,
564 	int openMode, void** cookie)
565 {
566 	return _OpenAttr(node, name, type, openMode, true, cookie);
567 }
568 
569 // OpenAttr
570 status_t
571 BeOSKernelVolume::OpenAttr(void* node, const char* name, int openMode,
572 	void** cookie)
573 {
574 	return _OpenAttr(node, name, 0, openMode, false, cookie);
575 }
576 
577 // CloseAttr
578 status_t
579 BeOSKernelVolume::CloseAttr(void* node, void* cookie)
580 {
581 	return B_OK;
582 }
583 
584 // FreeAttrCookie
585 status_t
586 BeOSKernelVolume::FreeAttrCookie(void* node, void* _cookie)
587 {
588 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
589 
590 	// If the attribute doesn't exist yet and it was opened with
591 	// CreateAttr(), we could create it now. We have a race condition here
592 	// though, since someone else could have created it in the meantime.
593 
594 	delete cookie;
595 
596 	return B_OK;
597 }
598 
599 // ReadAttr
600 status_t
601 BeOSKernelVolume::ReadAttr(void* node, void* _cookie, off_t pos,
602 	void* buffer, size_t bufferSize, size_t* bytesRead)
603 {
604 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
605 
606 	// check, if open mode allows reading
607 	if ((open_mode_to_access(cookie->fOpenMode) & R_OK) == 0)
608 		return B_FILE_ERROR;
609 
610 	// read
611 	if (!fFSOps->read_attr)
612 		return B_BAD_VALUE;
613 
614 	*bytesRead = bufferSize;
615 	return fFSOps->read_attr(fVolumeCookie, node, cookie->fName, cookie->fType,
616 		buffer, bytesRead, pos);
617 }
618 
619 // WriteAttr
620 status_t
621 BeOSKernelVolume::WriteAttr(void* node, void* _cookie, off_t pos,
622 	const void* buffer, size_t bufferSize, size_t* bytesWritten)
623 {
624 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
625 
626 	// check, if open mode allows writing
627 	if ((open_mode_to_access(cookie->fOpenMode) & W_OK) == 0)
628 		return B_FILE_ERROR;
629 
630 	// write
631 	if (!fFSOps->write_attr)
632 		return B_BAD_VALUE;
633 
634 	*bytesWritten = bufferSize;
635 	return fFSOps->write_attr(fVolumeCookie, node, cookie->fName, cookie->fType,
636 		buffer, bytesWritten, pos);
637 }
638 
639 // ReadAttrStat
640 status_t
641 BeOSKernelVolume::ReadAttrStat(void* node, void* _cookie,
642 	struct stat *st)
643 {
644 	AttributeCookie* cookie = (AttributeCookie*)_cookie;
645 
646 	// get the stats
647 	beos_attr_info attrInfo;
648 	if (!fFSOps->stat_attr)
649 		return B_BAD_VALUE;
650 
651 	status_t error = fFSOps->stat_attr(fVolumeCookie, node, cookie->fName,
652 		&attrInfo);
653 	if (error != B_OK)
654 		return error;
655 
656 	// translate to struct stat
657 	st->st_size = attrInfo.size;
658 	st->st_type = attrInfo.type;
659 
660 	return B_OK;
661 }
662 
663 // RenameAttr
664 status_t
665 BeOSKernelVolume::RenameAttr(void* oldNode, const char* oldName,
666 	void* newNode, const char* newName)
667 {
668 	if (!fFSOps->rename_attr)
669 		return B_BAD_VALUE;
670 	if (oldNode != newNode)
671 		return B_BAD_VALUE;
672 
673 	return fFSOps->rename_attr(fVolumeCookie, oldNode, oldName, newName);
674 }
675 
676 // RemoveAttr
677 status_t
678 BeOSKernelVolume::RemoveAttr(void* node, const char* name)
679 {
680 	if (!fFSOps->remove_attr)
681 		return B_BAD_VALUE;
682 	return fFSOps->remove_attr(fVolumeCookie, node, name);
683 }
684 
685 
686 // #pragma mark - indices
687 
688 
689 // OpenIndexDir
690 status_t
691 BeOSKernelVolume::OpenIndexDir(void** cookie)
692 {
693 	if (!fFSOps->open_indexdir)
694 		return B_BAD_VALUE;
695 	return fFSOps->open_indexdir(fVolumeCookie, cookie);
696 }
697 
698 // CloseIndexDir
699 status_t
700 BeOSKernelVolume::CloseIndexDir(void* cookie)
701 {
702 	if (!fFSOps->close_indexdir)
703 		return B_OK;
704 	return fFSOps->close_indexdir(fVolumeCookie, cookie);
705 }
706 
707 // FreeIndexDirCookie
708 status_t
709 BeOSKernelVolume::FreeIndexDirCookie(void* cookie)
710 {
711 	if (!fFSOps->free_indexdircookie)
712 		return B_OK;
713 	return fFSOps->free_indexdircookie(fVolumeCookie, NULL, cookie);
714 }
715 
716 // ReadIndexDir
717 status_t
718 BeOSKernelVolume::ReadIndexDir(void* cookie, void* buffer,
719 	size_t bufferSize, uint32 count, uint32* countRead)
720 {
721 	if (!fFSOps->read_indexdir)
722 		return B_BAD_VALUE;
723 
724 	*countRead = count;
725 
726 	// Haiku's struct dirent equals BeOS's version
727 	return fFSOps->read_indexdir(fVolumeCookie, cookie, (long*)countRead,
728 		(struct beos_dirent*)buffer, bufferSize);
729 }
730 
731 // RewindIndexDir
732 status_t
733 BeOSKernelVolume::RewindIndexDir(void* cookie)
734 {
735 	if (!fFSOps->rewind_indexdir)
736 		return B_BAD_VALUE;
737 	return fFSOps->rewind_indexdir(fVolumeCookie, cookie);
738 }
739 
740 // CreateIndex
741 status_t
742 BeOSKernelVolume::CreateIndex(const char* name, uint32 type, uint32 flags)
743 {
744 	if (!fFSOps->create_index)
745 		return B_BAD_VALUE;
746 	return fFSOps->create_index(fVolumeCookie, name, (int)type, (int)flags);
747 }
748 
749 // RemoveIndex
750 status_t
751 BeOSKernelVolume::RemoveIndex(const char* name)
752 {
753 	if (!fFSOps->remove_index)
754 		return B_BAD_VALUE;
755 	return fFSOps->remove_index(fVolumeCookie, name);
756 }
757 
758 // StatIndex
759 status_t
760 BeOSKernelVolume::ReadIndexStat(const char *name, struct stat *st)
761 {
762 	if (!fFSOps->stat_index)
763 		return B_BAD_VALUE;
764 
765 	beos_index_info indexInfo;
766 	status_t error = fFSOps->stat_index(fVolumeCookie, name, &indexInfo);
767 	if (error != B_OK)
768 		return error;
769 
770 	// translate index_info into struct stat
771 	st->st_type = indexInfo.type;
772 	st->st_size = indexInfo.size;
773 	st->st_mtime = indexInfo.modification_time;
774 	st->st_crtime = indexInfo.creation_time;
775 	st->st_uid = indexInfo.uid;
776 	st->st_gid = indexInfo.gid;
777 
778 	return B_OK;
779 }
780 
781 
782 // #pragma mark - queries
783 
784 
785 // OpenQuery
786 status_t
787 BeOSKernelVolume::OpenQuery(const char* queryString, uint32 flags, port_id port,
788 	uint32 token, void** cookie)
789 {
790 	if (!fFSOps->open_query)
791 		return B_BAD_VALUE;
792 	return fFSOps->open_query(fVolumeCookie, queryString, flags, port,
793 		(long)token, cookie);
794 }
795 
796 // CloseQuery
797 status_t
798 BeOSKernelVolume::CloseQuery(void* cookie)
799 {
800 	if (!fFSOps->close_query)
801 		return B_OK;
802 	return fFSOps->close_query(fVolumeCookie, cookie);
803 }
804 
805 // FreeQueryCookie
806 status_t
807 BeOSKernelVolume::FreeQueryCookie(void* cookie)
808 {
809 	if (!fFSOps->free_querycookie)
810 		return B_OK;
811 	return fFSOps->free_querycookie(fVolumeCookie, NULL, cookie);
812 }
813 
814 // ReadQuery
815 status_t
816 BeOSKernelVolume::ReadQuery(void* cookie, void* buffer, size_t bufferSize,
817 	uint32 count, uint32* countRead)
818 {
819 	if (!fFSOps->read_query)
820 		return B_BAD_VALUE;
821 
822 	*countRead = count;
823 
824 	// Haiku's struct dirent equals BeOS's version
825 	return fFSOps->read_query(fVolumeCookie, cookie, (long*)countRead,
826 		(struct beos_dirent*)buffer, bufferSize);
827 }
828 
829 
830 // #pragma mark - Private
831 
832 
833 // _OpenAttr
834 status_t
835 BeOSKernelVolume::_OpenAttr(void* node, const char* name, uint32 type,
836 	int openMode, bool create, void** _cookie)
837 {
838 	// check permissions first
839 	int accessMode = open_mode_to_access(openMode) | (create ? W_OK : 0);
840 	status_t error = Access(node, accessMode);
841 	if (error != B_OK)
842 		return error;
843 
844 	// check whether the attribute already exists
845 	beos_attr_info attrInfo;
846 	if (!fFSOps->stat_attr)
847 		return B_BAD_VALUE;
848 	bool exists
849 		= (fFSOps->stat_attr(fVolumeCookie, node, name, &attrInfo) == B_OK);
850 
851 	if (create) {
852 		// create: fail, if attribute exists and non-existence was required
853 		if (exists && (openMode & O_EXCL))
854 			return B_FILE_EXISTS;
855 	} else {
856 		// open: fail, if attribute doesn't exist
857 		if (!exists)
858 			return B_ENTRY_NOT_FOUND;
859 
860 		// keep the attribute type
861 		type = attrInfo.type;
862 	}
863 
864 	// create an attribute cookie
865 	AttributeCookie* cookie = new(nothrow) AttributeCookie(name, type,
866 		openMode, exists, create);
867 	if (!cookie)
868 		return B_NO_MEMORY;
869 
870 	// TODO: If we want to support O_TRUNC, we should do that here.
871 
872 	*_cookie = cookie;
873 	return B_OK;
874 }
875 
876 // open_mode_to_access
877 static int
878 open_mode_to_access(int openMode)
879 {
880  	switch (openMode & O_RWMASK) {
881 		case O_RDONLY:
882 			return R_OK;
883 		case O_WRONLY:
884 			return W_OK;
885 		case O_RDWR:
886 		default:
887 			return W_OK | R_OK;
888  	}
889 }
890 
891