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