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