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