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