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
21using std::nothrow;
22
23static int open_mode_to_access(int openMode);
24
25
26// AttributeCookie
27class BeOSKernelVolume::AttributeCookie {
28public:
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
48inline BeOSKernelFileSystem*
49BeOSKernelVolume::_FileSystem() const
50{
51	return static_cast<BeOSKernelFileSystem*>(fFileSystem);
52}
53
54
55// constructor
56BeOSKernelVolume::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
68BeOSKernelVolume::~BeOSKernelVolume()
69{
70}
71
72// #pragma mark -
73// #pragma mark ----- FS -----
74
75// Mount
76status_t
77BeOSKernelVolume::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
94status_t
95BeOSKernelVolume::Unmount()
96{
97	if (!fFSOps->unmount)
98		return B_BAD_VALUE;
99	return fFSOps->unmount(fVolumeCookie);
100}
101
102// Sync
103status_t
104BeOSKernelVolume::Sync()
105{
106	if (!fFSOps->sync)
107		return B_BAD_VALUE;
108	return fFSOps->sync(fVolumeCookie);
109}
110
111// ReadFSInfo
112status_t
113BeOSKernelVolume::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
123status_t
124BeOSKernelVolume::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
138status_t
139BeOSKernelVolume::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
148status_t
149BeOSKernelVolume::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
178status_t
179BeOSKernelVolume::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
207status_t
208BeOSKernelVolume::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
216status_t
217BeOSKernelVolume::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
229status_t
230BeOSKernelVolume::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
240status_t
241BeOSKernelVolume::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
249status_t
250BeOSKernelVolume::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
261status_t
262BeOSKernelVolume::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
271status_t
272BeOSKernelVolume::FSync(void* node)
273{
274	if (!fFSOps->fsync)
275		return B_BAD_VALUE;
276	return fFSOps->fsync(fVolumeCookie, node);
277}
278
279// ReadSymlink
280status_t
281BeOSKernelVolume::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
291status_t
292BeOSKernelVolume::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
302status_t
303BeOSKernelVolume::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
311status_t
312BeOSKernelVolume::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
320status_t
321BeOSKernelVolume::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
330status_t
331BeOSKernelVolume::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
339status_t
340BeOSKernelVolume::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
351status_t
352BeOSKernelVolume::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
368status_t
369BeOSKernelVolume::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
379status_t
380BeOSKernelVolume::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
388status_t
389BeOSKernelVolume::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
397status_t
398BeOSKernelVolume::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
406status_t
407BeOSKernelVolume::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
417status_t
418BeOSKernelVolume::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
433status_t
434BeOSKernelVolume::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
443status_t
444BeOSKernelVolume::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
452status_t
453BeOSKernelVolume::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
461status_t
462BeOSKernelVolume::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
470status_t
471BeOSKernelVolume::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
479status_t
480BeOSKernelVolume::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
494status_t
495BeOSKernelVolume::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
507status_t
508BeOSKernelVolume::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
516status_t
517BeOSKernelVolume::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
525status_t
526BeOSKernelVolume::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
534status_t
535BeOSKernelVolume::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
549status_t
550BeOSKernelVolume::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
562status_t
563BeOSKernelVolume::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
570status_t
571BeOSKernelVolume::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
578status_t
579BeOSKernelVolume::CloseAttr(void* node, void* cookie)
580{
581	return B_OK;
582}
583
584// FreeAttrCookie
585status_t
586BeOSKernelVolume::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
600status_t
601BeOSKernelVolume::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
620status_t
621BeOSKernelVolume::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
640status_t
641BeOSKernelVolume::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
664status_t
665BeOSKernelVolume::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
677status_t
678BeOSKernelVolume::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
690status_t
691BeOSKernelVolume::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
699status_t
700BeOSKernelVolume::CloseIndexDir(void* cookie)
701{
702	if (!fFSOps->close_indexdir)
703		return B_OK;
704	return fFSOps->close_indexdir(fVolumeCookie, cookie);
705}
706
707// FreeIndexDirCookie
708status_t
709BeOSKernelVolume::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
717status_t
718BeOSKernelVolume::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
732status_t
733BeOSKernelVolume::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
741status_t
742BeOSKernelVolume::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
750status_t
751BeOSKernelVolume::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
759status_t
760BeOSKernelVolume::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
786status_t
787BeOSKernelVolume::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
797status_t
798BeOSKernelVolume::CloseQuery(void* cookie)
799{
800	if (!fFSOps->close_query)
801		return B_OK;
802	return fFSOps->close_query(fVolumeCookie, cookie);
803}
804
805// FreeQueryCookie
806status_t
807BeOSKernelVolume::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
815status_t
816BeOSKernelVolume::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
834status_t
835BeOSKernelVolume::_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
877static int
878open_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