1//----------------------------------------------------------------------
2//  This software is part of the Haiku distribution and is covered
3//  by the MIT license.
4//----------------------------------------------------------------------
5/*!
6	\file Node.cpp
7	BNode implementation.
8*/
9
10#include <errno.h>
11#include <fcntl.h>
12#include <fs_attr.h> // for struct attr_info
13#include <new>
14#include <string.h>
15#include <unistd.h>
16
17#include <Directory.h>
18#include <Entry.h>
19#include <Node.h>
20#include <String.h>
21#include <TypeConstants.h>
22
23#include <syscalls.h>
24
25#include "storage_support.h"
26
27//----------------------------------------------------------------------
28// node_ref
29//----------------------------------------------------------------------
30
31// constructor
32/*! \brief Creates an uninitialized node_ref object.
33*/
34node_ref::node_ref()
35		: device((dev_t)-1),
36		  node((ino_t)-1)
37{
38}
39
40// copy constructor
41/*! \brief Creates a copy of the given node_ref object.
42	\param ref the node_ref to be copied
43*/
44node_ref::node_ref(const node_ref &ref)
45		: device((dev_t)-1),
46		  node((ino_t)-1)
47{
48	*this = ref;
49}
50
51// ==
52/*! \brief Tests whether this node_ref and the supplied one are equal.
53	\param ref the node_ref to be compared with
54	\return \c true, if the objects are equal, \c false otherwise
55*/
56bool
57node_ref::operator==(const node_ref &ref) const
58{
59	return (device == ref.device && node == ref.node);
60}
61
62// !=
63/*! \brief Tests whether this node_ref and the supplied one are not equal.
64	\param ref the node_ref to be compared with
65	\return \c false, if the objects are equal, \c true otherwise
66*/
67bool
68node_ref::operator!=(const node_ref &ref) const
69{
70	return !(*this == ref);
71}
72
73// =
74/*! \brief Makes this node ref a copy of the supplied one.
75	\param ref the node_ref to be copied
76	\return a reference to this object
77*/
78node_ref&
79node_ref::operator=(const node_ref &ref)
80{
81	device = ref.device;
82	node = ref.node;
83	return *this;
84}
85
86//----------------------------------------------------------------------
87// BNode
88//----------------------------------------------------------------------
89
90/*!	\brief Creates an uninitialized BNode object
91*/
92BNode::BNode()
93	 : fFd(-1),
94	   fAttrFd(-1),
95	   fCStatus(B_NO_INIT)
96{
97}
98
99/*!	\brief Creates a BNode object and initializes it to the specified
100	entry_ref.
101	\param ref the entry_ref referring to the entry
102*/
103BNode::BNode(const entry_ref *ref)
104	 : fFd(-1),
105	   fAttrFd(-1),
106	   fCStatus(B_NO_INIT)
107{
108	SetTo(ref);
109}
110
111/*!	\brief Creates a BNode object and initializes it to the specified
112	filesystem entry.
113	\param entry the BEntry representing the entry
114*/
115BNode::BNode(const BEntry *entry)
116	 : fFd(-1),
117	   fAttrFd(-1),
118	   fCStatus(B_NO_INIT)
119{
120	SetTo(entry);
121}
122
123/*!	\brief Creates a BNode object and initializes it to the entry referred
124	to by the specified path.
125	\param path the path referring to the entry
126*/
127BNode::BNode(const char *path)
128	 : fFd(-1),
129	   fAttrFd(-1),
130	   fCStatus(B_NO_INIT)
131{
132	SetTo(path);
133}
134
135/*!	\brief Creates a BNode object and initializes it to the entry referred
136	to by the specified path rooted in the specified directory.
137	\param dir the BDirectory, relative to which the entry's path name is
138		   given
139	\param path the entry's path name relative to \a dir
140*/
141BNode::BNode(const BDirectory *dir, const char *path)
142	 : fFd(-1),
143	   fAttrFd(-1),
144	   fCStatus(B_NO_INIT)
145{
146	SetTo(dir, path);
147}
148
149/*! \brief Creates a copy of the given BNode.
150	\param node the BNode to be copied
151*/
152BNode::BNode(const BNode &node)
153	 : fFd(-1),
154	   fAttrFd(-1),
155	   fCStatus(B_NO_INIT)
156{
157	*this = node;
158}
159
160/*!	\brief Frees all resources associated with this BNode.
161*/
162BNode::~BNode()
163{
164	Unset();
165}
166
167/*!	\brief Checks whether the object has been properly initialized or not.
168	\return
169	- \c B_OK, if the object has been properly initialized,
170	- an error code, otherwise.
171*/
172status_t
173BNode::InitCheck() const
174{
175	return fCStatus;
176}
177
178/*! \brief Fills in the given stat structure with \code stat() \endcode
179		   information for this object.
180	\param st a pointer to a stat structure to be filled in
181	\return
182	- \c B_OK: Everything went fine.
183	- \c B_BAD_VALUE: \c NULL \a st.
184	- another error code, e.g., if the object wasn't properly initialized
185*/
186status_t
187BNode::GetStat(struct stat *st) const
188{
189	return (fCStatus != B_OK)
190		? fCStatus
191		: _kern_read_stat(fFd, NULL, false, st, sizeof(struct stat));
192}
193
194/*! \brief Reinitializes the object to the specified entry_ref.
195	\param ref the entry_ref referring to the entry
196	\return
197	- \c B_OK: Everything went fine.
198	- \c B_BAD_VALUE: \c NULL \a ref.
199	- \c B_ENTRY_NOT_FOUND: The entry could not be found.
200	- \c B_BUSY: The entry is locked.
201*/
202status_t
203BNode::SetTo(const entry_ref *ref)
204{
205	return _SetTo(ref, false);
206}
207
208/*!	\brief Reinitializes the object to the specified filesystem entry.
209	\param entry the BEntry representing the entry
210	\return
211	- \c B_OK: Everything went fine.
212	- \c B_BAD_VALUE: \c NULL \a entry.
213	- \c B_ENTRY_NOT_FOUND: The entry could not be found.
214	- \c B_BUSY: The entry is locked.
215*/
216status_t
217BNode::SetTo(const BEntry *entry)
218{
219	if (!entry) {
220		Unset();
221		return (fCStatus = B_BAD_VALUE);
222	}
223	return _SetTo(entry->fDirFd, entry->fName, false);
224}
225
226/*!	\brief Reinitializes the object to the entry referred to by the specified
227		   path.
228	\param path the path referring to the entry
229	\return
230	- \c B_OK: Everything went fine.
231	- \c B_BAD_VALUE: \c NULL \a path.
232	- \c B_ENTRY_NOT_FOUND: The entry could not be found.
233	- \c B_BUSY: The entry is locked.
234*/
235status_t
236BNode::SetTo(const char *path)
237{
238	return _SetTo(-1, path, false);
239}
240
241/*! \brief Reinitializes the object to the entry referred to by the specified
242	path rooted in the specified directory.
243	\param dir the BDirectory, relative to which the entry's path name is
244		   given
245	\param path the entry's path name relative to \a dir
246	\return
247	- \c B_OK: Everything went fine.
248	- \c B_BAD_VALUE: \c NULL \a dir or \a path.
249	- \c B_ENTRY_NOT_FOUND: The entry could not be found.
250	- \c B_BUSY: The entry is locked.
251*/
252status_t
253BNode::SetTo(const BDirectory *dir, const char *path)
254{
255	if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) {
256		Unset();
257		return (fCStatus = B_BAD_VALUE);
258	}
259	return _SetTo(dir->fDirFd, path, false);
260}
261
262/*!	\brief Returns the object to an uninitialized state.
263*/
264void
265BNode::Unset()
266{
267	close_fd();
268	fCStatus = B_NO_INIT;
269}
270
271/*!	\brief Attains an exclusive lock on the data referred to by this node, so
272	that it may not be modified by any other objects or methods.
273	\return
274	- \c B_OK: Everything went fine.
275	- \c B_FILE_ERROR: The object is not initialized.
276	- \c B_BUSY: The node is already locked.
277*/
278status_t
279BNode::Lock()
280{
281	if (fCStatus != B_OK)
282		return fCStatus;
283	return _kern_lock_node(fFd);
284}
285
286/*!	\brief Unlocks the node.
287	\return
288	- \c B_OK: Everything went fine.
289	- \c B_FILE_ERROR: The object is not initialized.
290	- \c B_BAD_VALUE: The node is not locked.
291*/
292status_t
293BNode::Unlock()
294{
295	if (fCStatus != B_OK)
296		return fCStatus;
297	return _kern_unlock_node(fFd);
298}
299
300/*!	\brief Immediately performs any pending disk actions on the node.
301	\return
302	- \c B_OK: Everything went fine.
303	- an error code, if something went wrong.
304*/
305status_t
306BNode::Sync()
307{
308	return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_fsync(fFd);
309}
310
311/*!	\brief Writes data from a buffer to an attribute.
312	Write the \a len bytes of data from \a buffer to
313	the attribute specified by \a name after erasing any data
314	that existed previously. The type specified by \a type \em is
315	remembered, and may be queried with GetAttrInfo(). The value of
316	\a offset is currently ignored.
317	\param attr the name of the attribute
318	\param type the type of the attribute
319	\param offset the index at which to write the data (currently ignored)
320	\param buffer the buffer containing the data to be written
321	\param len the number of bytes to be written
322	\return
323	- the number of bytes actually written
324	- \c B_BAD_VALUE: \c NULL \a attr or \a buffer
325	- \c B_FILE_ERROR: The object is not initialized or the node it refers to
326	  is read only.
327	- \c B_NOT_ALLOWED: The node resides on a read only volume.
328	- \c B_DEVICE_FULL: Insufficient disk space.
329	- \c B_NO_MEMORY: Insufficient memory to complete the operation.
330*/
331ssize_t
332BNode::WriteAttr(const char *attr, type_code type, off_t offset,
333				 const void *buffer, size_t len)
334{
335	if (fCStatus != B_OK)
336		return B_FILE_ERROR;
337	if (!attr || !buffer)
338		return B_BAD_VALUE;
339	ssize_t result = fs_write_attr (fFd, attr, type, offset, buffer, len);
340	return (result < 0 ? errno : result);
341}
342
343/*!	\brief Reads data from an attribute into a buffer.
344	Reads the data of the attribute given by \a name into
345	the buffer specified by \a buffer with length specified
346	by \a len. \a type and \a offset are currently ignored.
347	\param attr the name of the attribute
348	\param type the type of the attribute (currently ignored)
349	\param offset the index from which to read the data (currently ignored)
350	\param buffer the buffer for the data to be read
351	\param len the number of bytes to be read
352	\return
353	- the number of bytes actually read
354	- \c B_BAD_VALUE: \c NULL \a attr or \a buffer
355	- \c B_FILE_ERROR: The object is not initialized.
356	- \c B_ENTRY_NOT_FOUND: The node has no attribute \a attr.
357*/
358ssize_t
359BNode::ReadAttr(const char *attr, type_code type, off_t offset,
360				void *buffer, size_t len) const
361{
362	if (fCStatus != B_OK)
363		return B_FILE_ERROR;
364	if (!attr || !buffer)
365		return B_BAD_VALUE;
366	ssize_t result = fs_read_attr(fFd, attr, type, offset, buffer, len );
367	return (result == -1 ? errno : result);
368}
369
370/*!	\brief Deletes the attribute given by \a name.
371	\param name the name of the attribute
372	- \c B_OK: Everything went fine.
373	- \c B_BAD_VALUE: \c NULL \a name
374	- \c B_FILE_ERROR: The object is not initialized or the node it refers to
375	  is read only.
376	- \c B_ENTRY_NOT_FOUND: The node has no attribute \a name.
377	- \c B_NOT_ALLOWED: The node resides on a read only volume.
378*/
379status_t
380BNode::RemoveAttr(const char *name)
381{
382	return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_remove_attr(fFd, name);
383}
384
385/*!	\brief Moves the attribute given by \a oldname to \a newname.
386	If \a newname already exists, the current data is clobbered.
387	\param oldname the name of the attribute to be renamed
388	\param newname the new name for the attribute
389	\return
390	- \c B_OK: Everything went fine.
391	- \c B_BAD_VALUE: \c NULL \a oldname or \a newname
392	- \c B_FILE_ERROR: The object is not initialized or the node it refers to
393	  is read only.
394	- \c B_ENTRY_NOT_FOUND: The node has no attribute \a oldname.
395	- \c B_NOT_ALLOWED: The node resides on a read only volume.
396*/
397status_t
398BNode::RenameAttr(const char *oldname, const char *newname)
399{
400	if (fCStatus != B_OK)
401		return B_FILE_ERROR;
402	return _kern_rename_attr(fFd, oldname, fFd, newname);
403}
404
405
406/*!	\brief Fills in the pre-allocated attr_info struct pointed to by \a info
407	with useful information about the attribute specified by \a name.
408	\param name the name of the attribute
409	\param info the attr_info structure to be filled in
410	\return
411	- \c B_OK: Everything went fine.
412	- \c B_BAD_VALUE: \c NULL \a name
413	- \c B_FILE_ERROR: The object is not initialized.
414	- \c B_ENTRY_NOT_FOUND: The node has no attribute \a name.
415*/
416status_t
417BNode::GetAttrInfo(const char *name, struct attr_info *info) const
418{
419	if (fCStatus != B_OK)
420		return B_FILE_ERROR;
421	if (!name || !info)
422		return B_BAD_VALUE;
423	return (fs_stat_attr(fFd, name, info) < 0) ? errno : B_OK ;
424}
425
426/*!	\brief Returns the next attribute in the node's list of attributes.
427	Every BNode maintains a pointer to its list of attributes.
428	GetNextAttrName() retrieves the name of the attribute that the pointer is
429	currently pointing to, and then bumps the pointer to the next attribute.
430	The name is copied into the buffer, which should be at least
431	B_ATTR_NAME_LENGTH characters long. The copied name is NULL-terminated.
432	When you've asked for every name in the list, GetNextAttrName()
433	returns \c B_ENTRY_NOT_FOUND.
434	\param buffer the buffer the name of the next attribute shall be stored in
435		   (must be at least \c B_ATTR_NAME_LENGTH bytes long)
436	\return
437	- \c B_OK: Everything went fine.
438	- \c B_BAD_VALUE: \c NULL \a buffer.
439	- \c B_FILE_ERROR: The object is not initialized.
440	- \c B_ENTRY_NOT_FOUND: There are no more attributes, the last attribute
441	  name has already been returned.
442 */
443status_t
444BNode::GetNextAttrName(char *buffer)
445{
446	// We're allowed to assume buffer is at least
447	// B_ATTR_NAME_LENGTH chars long, but NULLs
448	// are not acceptable.
449	if (buffer == NULL)
450		return B_BAD_VALUE;	// /new R5 crashed when passed NULL
451	if (InitAttrDir() != B_OK)
452		return B_FILE_ERROR;
453
454	BPrivate::Storage::LongDirEntry entry;
455	ssize_t result = _kern_read_dir(fAttrFd, &entry, sizeof(entry), 1);
456	if (result < 0)
457		return result;
458	if (result == 0)
459		return B_ENTRY_NOT_FOUND;
460	strlcpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH);
461	return B_OK;
462}
463
464/*! \brief Resets the object's attribute pointer to the first attribute in the
465	list.
466	\return
467	- \c B_OK: Everything went fine.
468	- \c B_FILE_ERROR: Some error occured.
469*/
470status_t
471BNode::RewindAttrs()
472{
473	if (InitAttrDir() != B_OK)
474		return B_FILE_ERROR;
475	return _kern_rewind_dir(fAttrFd);
476}
477
478/*!	Writes the specified string to the specified attribute, clobbering any
479	previous data.
480	\param name the name of the attribute
481	\param data the BString to be written to the attribute
482	- \c B_OK: Everything went fine.
483	- \c B_BAD_VALUE: \c NULL \a name or \a data
484	- \c B_FILE_ERROR: The object is not initialized or the node it refers to
485	  is read only.
486	- \c B_NOT_ALLOWED: The node resides on a read only volume.
487	- \c B_DEVICE_FULL: Insufficient disk space.
488	- \c B_NO_MEMORY: Insufficient memory to complete the operation.
489*/
490status_t
491BNode::WriteAttrString(const char *name, const BString *data)
492{
493	status_t error = (!name || !data)  ? B_BAD_VALUE : B_OK;
494	if (error == B_OK) {
495		int32 len = data->Length() + 1;
496		ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(),
497										len);
498		if (sizeWritten != len)
499			error = sizeWritten;
500	}
501	return error;
502}
503
504/*!	\brief Reads the data of the specified attribute into the pre-allocated
505		   \a result.
506	\param name the name of the attribute
507	\param result the BString to be set to the value of the attribute
508	\return
509	- \c B_OK: Everything went fine.
510	- \c B_BAD_VALUE: \c NULL \a name or \a result
511	- \c B_FILE_ERROR: The object is not initialized.
512	- \c B_ENTRY_NOT_FOUND: The node has no attribute \a attr.
513*/
514status_t
515BNode::ReadAttrString(const char *name, BString *result) const
516{
517	if (!name || !result)
518		return B_BAD_VALUE;
519
520	attr_info info;
521	status_t error;
522
523	error = GetAttrInfo(name, &info);
524	if (error != B_OK)
525		return error;
526	// Lock the string's buffer so we can meddle with it
527	char *data = result->LockBuffer(info.size+1);
528	if (!data)
529		return B_NO_MEMORY;
530	// Read the attribute
531	ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size);
532	// Check for failure
533	if (bytes < 0) {
534		error = bytes;
535		bytes = 0;	// In this instance, we simply clear the string
536	} else
537		error = B_OK;
538	// Null terminate the new string just to be sure (since it *is*
539	// possible to read and write non-NULL-terminated strings)
540	data[bytes] = 0;
541	result->UnlockBuffer();
542	return error;
543}
544
545/*!	\brief Reinitializes the object as a copy of the \a node.
546	\param node the BNode to be copied
547	\return a reference to this BNode object.
548*/
549BNode&
550BNode::operator=(const BNode &node)
551{
552	// No need to do any assignment if already equal
553	if (*this == node)
554		return *this;
555	// Close down out current state
556	Unset();
557	// We have to manually dup the node, because R5::BNode::Dup()
558	// is not declared to be const (which IMO is retarded).
559	fFd = _kern_dup(node.fFd);
560	fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ;
561	return *this;
562}
563
564/*!	Tests whether this and the supplied BNode object are equal.
565	Two BNode objects are said to be equal if they're set to the same node,
566	or if they're both \c B_NO_INIT.
567	\param node the BNode to be compared with
568	\return \c true, if the BNode objects are equal, \c false otherwise
569*/
570bool
571BNode::operator==(const BNode &node) const
572{
573	if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT)
574		return true;
575	if (fCStatus == B_OK && node.InitCheck() == B_OK) {
576		// compare the node_refs
577		node_ref ref1, ref2;
578		if (GetNodeRef(&ref1) != B_OK)
579			return false;
580		if (node.GetNodeRef(&ref2) != B_OK)
581			return false;
582		return (ref1 == ref2);
583	}
584	return false;
585}
586
587/*!	Tests whether this and the supplied BNode object are not equal.
588	Two BNode objects are said to be equal if they're set to the same node,
589	or if they're both \c B_NO_INIT.
590	\param node the BNode to be compared with
591	\return \c false, if the BNode objects are equal, \c true otherwise
592*/
593bool
594BNode::operator!=(const BNode &node) const
595{
596	return !(*this == node);
597}
598
599/*!	\brief Returns a POSIX file descriptor to the node this object refers to.
600	Remember to call close() on the file descriptor when you're through with
601	it.
602	\return a valid file descriptor, or -1, if something went wrong.
603*/
604int
605BNode::Dup()
606{
607	int fd = _kern_dup(fFd);
608	return (fd >= 0 ? fd : -1);	// comply with R5 return value
609}
610
611
612/*! (currently unused) */
613void BNode::_RudeNode1() { }
614void BNode::_RudeNode2() { }
615void BNode::_RudeNode3() { }
616void BNode::_RudeNode4() { }
617void BNode::_RudeNode5() { }
618void BNode::_RudeNode6() { }
619
620/*!	\brief Sets the node's file descriptor.
621	Used by each implementation (i.e. BNode, BFile, BDirectory, etc.) to set
622	the node's file descriptor. This allows each subclass to use the various
623	file-type specific system calls for opening file descriptors.
624	\param fd the file descriptor this BNode should be set to (may be -1)
625	\return \c B_OK, if everything went fine, an error code otherwise.
626	\note This method calls close_fd() to close previously opened FDs. Thus
627		  derived classes should take care to first call set_fd() and set
628		  class specific resources freed in their close_fd() version
629		  thereafter.
630*/
631status_t
632BNode::set_fd(int fd)
633{
634	if (fFd != -1)
635		close_fd();
636	fFd = fd;
637	return B_OK;
638}
639
640/*!	\brief Closes the node's file descriptor(s).
641	To be implemented by subclasses to close the file descriptor using the
642	proper system call for the given file-type. This implementation calls
643	_kern_close(fFd) and also _kern_close(fAttrDir) if necessary.
644*/
645void
646BNode::close_fd()
647{
648	if (fAttrFd >= 0)
649	{
650		_kern_close(fAttrFd);
651		fAttrFd = -1;
652	}
653	if (fFd >= 0) {
654		_kern_close(fFd);
655		fFd = -1;
656	}
657}
658
659// set_status
660/*! \brief Sets the BNode's status.
661	To be used by derived classes instead of accessing the BNode's private
662	\c fCStatus member directly.
663	\param newStatus the new value for the status variable.
664*/
665void
666BNode::set_status(status_t newStatus)
667{
668	fCStatus = newStatus;
669}
670
671// _SetTo
672/*!	\brief Initializes the BNode's file descriptor to the node referred to
673		   by the given FD and path combo.
674
675	\a path must either be \c NULL, an absolute or a relative path.
676	In the first case, \a fd must not be \c NULL; the node it refers to will
677	be opened. If absolute, \a fd is ignored. If relative and \a fd is >= 0,
678	it will be reckoned off the directory identified by \a fd, otherwise off
679	the current working directory.
680
681	The method will first try to open the node with read and write permission.
682	If that fails due to a read-only FS or because the user has no write
683	permission for the node, it will re-try opening the node read-only.
684
685	The \a fCStatus member will be set to the return value of this method.
686
687	\param fd Either a directory FD or a value < 0. In the latter case \a path
688		   must be specified.
689	\param path Either \a NULL in which case \a fd must be given, absolute, or
690		   relative to the directory specified by \a fd (if given) or to the
691		   current working directory.
692	\param traverse If the node identified by \a fd and \a path is a symlink
693		   and \a traverse is \c true, the symlink will be resolved recursively.
694	\return \c B_OK, if everything went fine, another error code otherwise.
695*/
696status_t
697BNode::_SetTo(int fd, const char *path, bool traverse)
698{
699	Unset();
700	status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE);
701	if (error == B_OK) {
702		int traverseFlag = (traverse ? 0 : O_NOTRAVERSE);
703		fFd = _kern_open(fd, path, O_RDWR | traverseFlag, 0);
704		if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) {
705			// opening read-write failed, re-try read-only
706			fFd = _kern_open(fd, path, O_RDONLY | traverseFlag, 0);
707		}
708		if (fFd < 0)
709			error = fFd;
710		else
711			fcntl(fFd, F_SETFD, FD_CLOEXEC);
712	}
713	return fCStatus = error;
714}
715
716// _SetTo
717/*!	\brief Initializes the BNode's file descriptor to the node referred to
718		   by the given entry_ref.
719
720	The method will first try to open the node with read and write permission.
721	If that fails due to a read-only FS or because the user has no write
722	permission for the node, it will re-try opening the node read-only.
723
724	The \a fCStatus member will be set to the return value of this method.
725
726	\param ref An entry_ref identifying the node to be opened.
727	\param traverse If the node identified by \a ref is a symlink
728		   and \a traverse is \c true, the symlink will be resolved recursively.
729	\return \c B_OK, if everything went fine, another error code otherwise.
730*/
731status_t
732BNode::_SetTo(const entry_ref *ref, bool traverse)
733{
734	Unset();
735	status_t error = (ref ? B_OK : B_BAD_VALUE);
736	if (error == B_OK) {
737		int traverseFlag = (traverse ? 0 : O_NOTRAVERSE);
738		fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
739			O_RDWR | traverseFlag, 0);
740		if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) {
741			// opening read-write failed, re-try read-only
742			fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
743				O_RDONLY | traverseFlag, 0);
744		}
745		if (fFd < 0)
746			error = fFd;
747		else
748			fcntl(fFd, F_SETFD, FD_CLOEXEC);
749	}
750	return fCStatus = error;
751}
752
753/*! \brief Modifies a certain setting for this node based on \a what and the
754	corresponding value in \a st.
755	Inherited from and called by BStatable.
756	\param st a stat structure containing the value to be set
757	\param what specifies what setting to be modified
758	\return \c B_OK if everything went fine, an error code otherwise.
759*/
760status_t
761BNode::set_stat(struct stat &st, uint32 what)
762{
763	if (fCStatus != B_OK)
764		return B_FILE_ERROR;
765	return _kern_write_stat(fFd, NULL, false, &st, sizeof(struct stat),
766		what);
767}
768
769/*! \brief Verifies that the BNode has been properly initialized, and then
770	(if necessary) opens the attribute directory on the node's file
771	descriptor, storing it in fAttrDir.
772	\return \c B_OK if everything went fine, an error code otherwise.
773*/
774status_t
775BNode::InitAttrDir()
776{
777	if (fCStatus == B_OK && fAttrFd < 0) {
778		fAttrFd = _kern_open_attr_dir(fFd, NULL);
779		if (fAttrFd < 0)
780			return fAttrFd;
781
782		// set close on exec flag
783		fcntl(fAttrFd, F_SETFD, FD_CLOEXEC);
784	}
785	return fCStatus;
786}
787
788/*!	\var BNode::fFd
789	File descriptor for the given node.
790*/
791
792/*!	\var BNode::fAttrFd
793	File descriptor for the attribute directory of the node. Initialized lazily.
794*/
795
796/*!	\var BNode::fCStatus
797	The object's initialization status.
798*/
799
800