xref: /haiku/src/build/libbe/storage/Node.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 */
34 node_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 */
44 node_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 */
56 bool
57 node_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 */
67 bool
68 node_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 */
78 node_ref&
79 node_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 */
92 BNode::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 */
103 BNode::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 */
115 BNode::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 */
127 BNode::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 */
141 BNode::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 */
152 BNode::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 */
162 BNode::~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 */
172 status_t
173 BNode::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 */
186 status_t
187 BNode::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 */
202 status_t
203 BNode::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 */
216 status_t
217 BNode::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 */
235 status_t
236 BNode::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 */
252 status_t
253 BNode::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 */
264 void
265 BNode::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 */
278 status_t
279 BNode::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 */
292 status_t
293 BNode::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 */
305 status_t
306 BNode::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 */
331 ssize_t
332 BNode::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 */
358 ssize_t
359 BNode::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 */
379 status_t
380 BNode::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 */
397 status_t
398 BNode::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 */
416 status_t
417 BNode::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  */
443 status_t
444 BNode::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 */
470 status_t
471 BNode::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 */
490 status_t
491 BNode::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 */
514 status_t
515 BNode::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 */
549 BNode&
550 BNode::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 */
570 bool
571 BNode::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 */
593 bool
594 BNode::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 */
604 int
605 BNode::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) */
613 void BNode::_RudeNode1() { }
614 void BNode::_RudeNode2() { }
615 void BNode::_RudeNode3() { }
616 void BNode::_RudeNode4() { }
617 void BNode::_RudeNode5() { }
618 void 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 */
631 status_t
632 BNode::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 */
645 void
646 BNode::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 */
665 void
666 BNode::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 */
696 status_t
697 BNode::_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 */
731 status_t
732 BNode::_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 */
760 status_t
761 BNode::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 */
774 status_t
775 BNode::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