xref: /haiku/src/kits/storage/Directory.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 Directory.cpp
7 	BDirectory implementation.
8 */
9 
10 #include <fs_info.h>
11 #include <string.h>
12 
13 #include <Directory.h>
14 #include <Entry.h>
15 #include <File.h>
16 #include <Path.h>
17 #include <SymLink.h>
18 #include "storage_support.h"
19 #include "kernel_interface.h"
20 
21 #ifdef USE_OPENBEOS_NAMESPACE
22 namespace OpenBeOS {
23 #endif
24 
25 // constructor
26 //! Creates an uninitialized BDirectory object.
27 BDirectory::BDirectory()
28 		  : BNode(),
29 			BEntryList(),
30 			fDirFd(BPrivate::Storage::NullFd)
31 {
32 }
33 
34 // copy constructor
35 //! Creates a copy of the supplied BDirectory.
36 /*!	\param dir the BDirectory object to be copied
37 */
38 BDirectory::BDirectory(const BDirectory &dir)
39 		  : BNode(),
40 			BEntryList(),
41 			fDirFd(BPrivate::Storage::NullFd)
42 {
43 	*this = dir;
44 }
45 
46 // constructor
47 /*! \brief Creates a BDirectory and initializes it to the directory referred
48 	to by the supplied entry_ref.
49 	\param ref the entry_ref referring to the directory
50 */
51 BDirectory::BDirectory(const entry_ref *ref)
52 		  : BNode(),
53 			BEntryList(),
54 			fDirFd(BPrivate::Storage::NullFd)
55 {
56 	SetTo(ref);
57 }
58 
59 // constructor
60 /*! \brief Creates a BDirectory and initializes it to the directory referred
61 	to by the supplied node_ref.
62 	\param nref the node_ref referring to the directory
63 */
64 BDirectory::BDirectory(const node_ref *nref)
65 		  : BNode(),
66 			BEntryList(),
67 			fDirFd(BPrivate::Storage::NullFd)
68 {
69 	SetTo(nref);
70 }
71 
72 // constructor
73 /*! \brief Creates a BDirectory and initializes it to the directory referred
74 	to by the supplied BEntry.
75 	\param entry the BEntry referring to the directory
76 */
77 BDirectory::BDirectory(const BEntry *entry)
78 		  : BNode(),
79 			BEntryList(),
80 			fDirFd(BPrivate::Storage::NullFd)
81 {
82 	SetTo(entry);
83 }
84 
85 // constructor
86 /*! \brief Creates a BDirectory and initializes it to the directory referred
87 	to by the supplied path name.
88 	\param path the directory's path name
89 */
90 BDirectory::BDirectory(const char *path)
91 		  : BNode(),
92 			BEntryList(),
93 			fDirFd(BPrivate::Storage::NullFd)
94 {
95 	SetTo(path);
96 }
97 
98 // constructor
99 /*! \brief Creates a BDirectory and initializes it to the directory referred
100 	to by the supplied path name relative to the specified BDirectory.
101 	\param dir the BDirectory, relative to which the directory's path name is
102 		   given
103 	\param path the directory's path name relative to \a dir
104 */
105 BDirectory::BDirectory(const BDirectory *dir, const char *path)
106 		  : BNode(),
107 			BEntryList(),
108 			fDirFd(BPrivate::Storage::NullFd)
109 {
110 	SetTo(dir, path);
111 }
112 
113 // destructor
114 //! Frees all allocated resources.
115 /*! If the BDirectory is properly initialized, the directory's file descriptor
116 	is closed.
117 */
118 BDirectory::~BDirectory()
119 {
120 	// Also called by the BNode destructor, but we rather try to avoid
121 	// problems with calling virtual functions in the base class destructor.
122 	// Depending on the compiler implementation an object may be degraded to
123 	// an object of the base class after the destructor of the derived class
124 	// has been executed.
125 	close_fd();
126 }
127 
128 // SetTo
129 /*! \brief Re-initializes the BDirectory to the directory referred to by the
130 	supplied entry_ref.
131 	\param ref the entry_ref referring to the directory
132 	\return
133 	- \c B_OK: Everything went fine.
134 	- \c B_BAD_VALUE: \c NULL \a ref.
135 	- \c B_ENTRY_NOT_FOUND: Directory not found.
136 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
137 	- \c B_NO_MEMORY: Insufficient memory for operation.
138 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
139 	- \c B_BUSY: A node was busy.
140 	- \c B_FILE_ERROR: A general file error.
141 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
142 	\todo Currently implemented using BPrivate::Storage::entry_ref_to_path().
143 		  Reimplement!
144 */
145 status_t
146 BDirectory::SetTo(const entry_ref *ref)
147 {
148 	Unset();
149 	char path[B_PATH_NAME_LENGTH];
150 	status_t error = (ref ? B_OK : B_BAD_VALUE);
151 	if (error == B_OK) {
152 		error = BPrivate::Storage::entry_ref_to_path(ref, path,
153 													 B_PATH_NAME_LENGTH);
154 	}
155 	if (error == B_OK)
156 		error = SetTo(path);
157 	set_status(error);
158 	return error;
159 }
160 
161 // SetTo
162 /*! \brief Re-initializes the BDirectory to the directory referred to by the
163 	supplied node_ref.
164 	\param nref the node_ref referring to the directory
165 	\return
166 	- \c B_OK: Everything went fine.
167 	- \c B_BAD_VALUE: \c NULL \a nref.
168 	- \c B_ENTRY_NOT_FOUND: Directory not found.
169 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
170 	- \c B_NO_MEMORY: Insufficient memory for operation.
171 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
172 	- \c B_BUSY: A node was busy.
173 	- \c B_FILE_ERROR: A general file error.
174 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
175 */
176 status_t
177 BDirectory::SetTo(const node_ref *nref)
178 {
179 	Unset();
180 	status_t error = (nref ? B_OK : B_BAD_VALUE);
181 	if (error == B_OK) {
182 		entry_ref ref(nref->device, nref->node, ".");
183 		error = SetTo(&ref);
184 	}
185 	set_status(error);
186 	return error;
187 }
188 
189 // SetTo
190 /*! \brief Re-initializes the BDirectory to the directory referred to by the
191 	supplied BEntry.
192 	\param entry the BEntry referring to the directory
193 	\return
194 	- \c B_OK: Everything went fine.
195 	- \c B_BAD_VALUE: \c NULL \a entry.
196 	- \c B_ENTRY_NOT_FOUND: Directory not found.
197 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
198 	- \c B_NO_MEMORY: Insufficient memory for operation.
199 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
200 	- \c B_BUSY: A node was busy.
201 	- \c B_FILE_ERROR: A general file error.
202 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
203 	\todo Implemented using SetTo(entry_ref*). Check, if necessary to
204 		  reimplement!
205 */
206 status_t
207 BDirectory::SetTo(const BEntry *entry)
208 {
209 	Unset();
210 	entry_ref ref;
211 	status_t error = (entry ? B_OK : B_BAD_VALUE);
212 	if (error == B_OK && entry->InitCheck() != B_OK)
213 		error = B_BAD_VALUE;
214 	if (error == B_OK)
215 		error = entry->GetRef(&ref);
216 	if (error == B_OK)
217 		error = SetTo(&ref);
218 	set_status(error);
219 	return error;
220 }
221 
222 // SetTo
223 /*! \brief Re-initializes the BDirectory to the directory referred to by the
224 	supplied path name.
225 	\param path the directory's path name
226 	\return
227 	- \c B_OK: Everything went fine.
228 	- \c B_BAD_VALUE: \c NULL \a path.
229 	- \c B_ENTRY_NOT_FOUND: Directory not found.
230 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
231 	- \c B_NO_MEMORY: Insufficient memory for operation.
232 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
233 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
234 	- \c B_BUSY: A node was busy.
235 	- \c B_FILE_ERROR: A general file error.
236 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
237 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
238 */
239 status_t
240 BDirectory::SetTo(const char *path)
241 {
242 	Unset();
243 	status_t result = (path ? B_OK : B_BAD_VALUE);
244 	BPrivate::Storage::FileDescriptor newDirFd = BPrivate::Storage::NullFd;
245 	if (result == B_OK)
246 		result = BPrivate::Storage::open_dir(path, newDirFd);
247 	if (result == B_OK) {
248 		// We have to take care that BNode doesn't stick to a symbolic link.
249 		// open_dir() does always traverse those. Therefore we open the FD for
250 		// BNode (without the O_NOTRAVERSE flag).
251 		BPrivate::Storage::FileDescriptor fd = BPrivate::Storage::NullFd;
252 		result = BPrivate::Storage::open(path, O_RDWR, fd, true);
253 		if (result == B_OK) {
254 			result = set_fd(fd);
255 			if (result != B_OK)
256 				BPrivate::Storage::close(fd);
257 		}
258 		if (result == B_OK)
259 			fDirFd = newDirFd;
260 		else
261 			BPrivate::Storage::close_dir(newDirFd);
262 	}
263 	// finally set the BNode status
264 	set_status(result);
265 	return result;
266 }
267 
268 // SetTo
269 /*! \brief Re-initializes the BDirectory to the directory referred to by the
270 	supplied path name relative to the specified BDirectory.
271 	\param dir the BDirectory, relative to which the directory's path name is
272 		   given
273 	\param path the directory's path name relative to \a dir
274 	\return
275 	- \c B_OK: Everything went fine.
276 	- \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute.
277 	- \c B_ENTRY_NOT_FOUND: Directory not found.
278 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
279 	- \c B_NO_MEMORY: Insufficient memory for operation.
280 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
281 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
282 	- \c B_BUSY: A node was busy.
283 	- \c B_FILE_ERROR: A general file error.
284 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
285 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
286 	\todo Implemented using SetTo(BEntry*). Check, if necessary to reimplement!
287 */
288 status_t
289 BDirectory::SetTo(const BDirectory *dir, const char *path)
290 {
291 	Unset();
292 	status_t error = (dir && path ? B_OK : B_BAD_VALUE);
293 	if (error == B_OK && BPrivate::Storage::is_absolute_path(path))
294 		error = B_BAD_VALUE;
295 	BEntry entry;
296 	if (error == B_OK)
297 		error = entry.SetTo(dir, path);
298 	if (error == B_OK)
299 		error = SetTo(&entry);
300 	set_status(error);
301 	return error;
302 }
303 
304 // GetEntry
305 //! Returns a BEntry referring to the directory represented by this object.
306 /*!	If the initialization of \a entry fails, it is Unset().
307 	\param entry a pointer to the entry that shall be set to refer to the
308 		   directory
309 	\return
310 	- \c B_OK: Everything went fine.
311 	- \c B_BAD_VALUE: \c NULL \a entry.
312 	- \c B_ENTRY_NOT_FOUND: Directory not found.
313 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
314 	- \c B_NO_MEMORY: Insufficient memory for operation.
315 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
316 	- \c B_BUSY: A node was busy.
317 	- \c B_FILE_ERROR: A general file error.
318 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
319 	\todo Implemented using BPrivate::Storage::dir_to_self_entry_ref(). Check, if
320 		  there is a better alternative.
321 */
322 status_t
323 BDirectory::GetEntry(BEntry *entry) const
324 {
325 	status_t error = (entry ? B_OK : B_BAD_VALUE);
326 	if (entry)
327 		entry->Unset();
328 	if (error == B_OK && InitCheck() != B_OK)
329 		error = B_NO_INIT;
330 	entry_ref ref;
331 	if (error == B_OK)
332 		error = BPrivate::Storage::dir_to_self_entry_ref(fDirFd, &ref);
333 	if (error == B_OK)
334 		error = entry->SetTo(&ref);
335 	return error;
336 }
337 
338 // IsRootDirectory
339 /*!	\brief Returns whether the directory represented by this BDirectory is a
340 	root directory of a volume.
341 	\return
342 	- \c true, if the BDirectory is properly initialized and represents a
343 	  root directory of some volume,
344 	- \c false, otherwise.
345 */
346 bool
347 BDirectory::IsRootDirectory() const
348 {
349 	// compare the directory's node ID with the ID of the root node of the FS
350 	bool result = false;
351 	node_ref ref;
352 	fs_info info;
353 	if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0)
354 		result = (ref.node == info.root);
355 	return result;
356 }
357 
358 // FindEntry
359 /*! \brief Finds an entry referred to by a path relative to the directory
360 	represented by this BDirectory.
361 	\a path may be absolute. If the BDirectory is not properly initialized,
362 	the entry is search relative to the current directory.
363 	If the entry couldn't be found, \a entry is Unset().
364 	\param path the entry's path name. May be relative to this directory or
365 		   absolute.
366 	\param entry a pointer to a BEntry to be initialized with the found entry
367 	\param traverse specifies whether to follow it, if the found entry
368 		   is a symbolic link.
369 	\return
370 	- \c B_OK: Everything went fine.
371 	- \c B_BAD_VALUE: \c NULL \a path or \a entry.
372 	- \c B_ENTRY_NOT_FOUND: Entry not found.
373 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
374 	- \c B_NO_MEMORY: Insufficient memory for operation.
375 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
376 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
377 	- \c B_BUSY: A node was busy.
378 	- \c B_FILE_ERROR: A general file error.
379 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
380 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
381 	\note The functionality of this method differs from the one of
382 		  BEntry::SetTo(BDirectory *, const char *, bool) in that the
383 		  latter doesn't require the entry to be existent, whereas this
384 		  function does.
385 */
386 status_t
387 BDirectory::FindEntry(const char *path, BEntry *entry, bool traverse) const
388 {
389 	status_t error = (path && entry ? B_OK : B_BAD_VALUE);
390 	if (entry)
391 		entry->Unset();
392 	if (error == B_OK) {
393 		// init a potentially abstract entry
394 		if (InitCheck() == B_OK)
395 			error = entry->SetTo(this, path, traverse);
396 		else
397 			error = entry->SetTo(path, traverse);
398 		// fail, if entry is abstract
399 		if (error == B_OK && !entry->Exists()) {
400 			error = B_ENTRY_NOT_FOUND;
401 			entry->Unset();
402 		}
403 	}
404 	return error;
405 }
406 
407 // Contains
408 /*!	\brief Returns whether this directory or any of its subdirectories
409 	at any level contain the entry referred to by the supplied path name.
410 	Only entries that match the node flavor specified by \a nodeFlags are
411 	considered.
412 	If the BDirectory is not properly initialized, the method returns \c false.
413 	A non-absolute path is considered relative to the current directory.
414 
415 	\note R5's implementation always returns \c true given an absolute path or
416 	an unitialized directory. This implementation is not compatible with that
417 	behavior. Instead it converts the path into a BEntry and passes it to the
418 	other version of Contains().
419 
420 	\param path the entry's path name. May be relative to this directory or
421 		   absolute.
422 	\param nodeFlags Any of the following:
423 		   - \c B_FILE_NODE: The entry must be a file.
424 		   - \c B_DIRECTORY_NODE: The entry must be a directory.
425 		   - \c B_SYMLINK_NODE: The entry must be a symbolic link.
426 		   - \c B_ANY_NODE: The entry may be of any kind.
427 	\return
428 	- \c true, if the entry exists, its kind does match \nodeFlags and the
429 	  BDirectory is properly initialized and does contain the entry at any
430 	  level,
431 	- \c false, otherwise
432 */
433 bool
434 BDirectory::Contains(const char *path, int32 nodeFlags) const
435 {
436 	// check initialization and parameters
437 	if (InitCheck() != B_OK)
438 		return false;
439 	if (!path)
440 		return true;	// mimic R5 behavior
441 	// turn the path into a BEntry and let the other version do the work
442 	BEntry entry;
443 	if (BPrivate::Storage::is_absolute_path(path))
444 		entry.SetTo(path);
445 	else
446 		entry.SetTo(this, path);
447 	return Contains(&entry, nodeFlags);
448 }
449 
450 // Contains
451 /*!	\brief Returns whether this directory or any of its subdirectories
452 	at any level contain the entry referred to by the supplied BEntry.
453 	Only entries that match the node flavor specified by \a nodeFlags are
454 	considered.
455 	\param entry a BEntry referring to the entry
456 	\param nodeFlags Any of the following:
457 		   - \c B_FILE_NODE: The entry must be a file.
458 		   - \c B_DIRECTORY_NODE: The entry must be a directory.
459 		   - \c B_SYMLINK_NODE: The entry must be a symbolic link.
460 		   - \c B_ANY_NODE: The entry may be of any kind.
461 	\return
462 	- \c true, if the BDirectory is properly initialized and the entry of the
463 	  matching kind could be found,
464 	- \c false, otherwise
465 */
466 bool
467 BDirectory::Contains(const BEntry *entry, int32 nodeFlags) const
468 {
469 	bool result = (entry);
470 	// check, if the entry exists at all
471 	if (result)
472 		result = entry->Exists();
473 	// test the node kind
474 	if (result) {
475 		switch (nodeFlags) {
476 			case B_FILE_NODE:
477 				result = entry->IsFile();
478 				break;
479 			case B_DIRECTORY_NODE:
480 				result = entry->IsDirectory();
481 				break;
482 			case B_SYMLINK_NODE:
483 				result = entry->IsSymLink();
484 				break;
485 			case B_ANY_NODE:
486 				break;
487 			default:
488 				result = false;
489 				break;
490 		}
491 	}
492 	// If the directory is initialized, get the canonical paths of the dir and
493 	// the entry and check, if the latter is a prefix of the first one.
494 	if (result && InitCheck() == B_OK) {
495 		char dirPath[B_PATH_NAME_LENGTH];
496 		char entryPath[B_PATH_NAME_LENGTH];
497 		result = (BPrivate::Storage::dir_to_path(fDirFd, dirPath,
498 												 B_PATH_NAME_LENGTH) == B_OK);
499 		entry_ref ref;
500 		if (result)
501 			result = (entry->GetRef(&ref) == B_OK);
502 		if (result) {
503 			result = (BPrivate::Storage::entry_ref_to_path(&ref, entryPath,
504 														   B_PATH_NAME_LENGTH)
505 					  == B_OK);
506 		}
507 		if (result)
508 			result = !strncmp(dirPath, entryPath, strlen(dirPath));
509 	}
510 	return result;
511 }
512 
513 // GetStatFor
514 /*!	\brief Returns the stat structure of the entry referred to by the supplied
515 	path name.
516 	\param path the entry's path name. May be relative to this directory or
517 		   absolute, or \c NULL to get the directories stat info.
518 	\param st a pointer to the stat structure to be filled in by this function
519 	\return
520 	- \c B_OK: Everything went fine.
521 	- \c B_BAD_VALUE: \c NULL \a st.
522 	- \c B_ENTRY_NOT_FOUND: Entry not found.
523 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
524 	- \c B_NO_MEMORY: Insufficient memory for operation.
525 	- \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long.
526 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
527 	- \c B_BUSY: A node was busy.
528 	- \c B_FILE_ERROR: A general file error.
529 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
530 	- \c B_NOT_A_DIRECTORY: \a path includes a non-directory.
531 */
532 status_t
533 BDirectory::GetStatFor(const char *path, struct stat *st) const
534 {
535 	status_t error = (st ? B_OK : B_BAD_VALUE);
536 	if (error == B_OK && InitCheck() != B_OK)
537 		error = B_NO_INIT;
538 	if (error == B_OK) {
539 		if (path) {
540 			if (strlen(path) == 0)
541 				error = B_ENTRY_NOT_FOUND;
542 			else {
543 				BEntry entry(this, path);
544 				error = entry.InitCheck();
545 				if (error == B_OK)
546 					error = entry.GetStat(st);
547 			}
548 		} else
549 			error = GetStat(st);
550 	}
551 	return error;
552 }
553 
554 // GetNextEntry
555 //! Returns the BDirectory's next entry as a BEntry.
556 /*!	Unlike GetNextDirents() this method ignores the entries "." and "..".
557 	\param entry a pointer to a BEntry to be initialized to the found entry
558 	\param traverse specifies whether to follow it, if the found entry
559 		   is a symbolic link.
560 	\note The iterator used by this method is the same one used by
561 		  GetNextRef(), GetNextDirents(), Rewind() and CountEntries().
562 	\return
563 	- \c B_OK: Everything went fine.
564 	- \c B_BAD_VALUE: \c NULL \a entry.
565 	- \c B_ENTRY_NOT_FOUND: No more entries found.
566 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
567 	- \c B_NO_MEMORY: Insufficient memory for operation.
568 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
569 	- \c B_BUSY: A node was busy.
570 	- \c B_FILE_ERROR: A general file error.
571 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
572 */
573 status_t
574 BDirectory::GetNextEntry(BEntry *entry, bool traverse)
575 {
576 	status_t error = (entry ? B_OK : B_BAD_VALUE);
577 	if (error == B_OK) {
578 		entry_ref ref;
579 		error = GetNextRef(&ref);
580 		if (error == B_OK)
581 			error = entry->SetTo(&ref, traverse);
582 	}
583 	return error;
584 }
585 
586 // GetNextRef
587 //! Returns the BDirectory's next entry as an entry_ref.
588 /*!	Unlike GetNextDirents() this method ignores the entries "." and "..".
589 	\param ref a pointer to an entry_ref to be filled in with the data of the
590 		   found entry
591 	\param traverse specifies whether to follow it, if the found entry
592 		   is a symbolic link.
593 	\note The iterator used be this method is the same one used by
594 		  GetNextEntry(), GetNextDirents(), Rewind() and CountEntries().
595 	\return
596 	- \c B_OK: Everything went fine.
597 	- \c B_BAD_VALUE: \c NULL \a ref.
598 	- \c B_ENTRY_NOT_FOUND: No more entries found.
599 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
600 	- \c B_NO_MEMORY: Insufficient memory for operation.
601 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
602 	- \c B_BUSY: A node was busy.
603 	- \c B_FILE_ERROR: A general file error.
604 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
605 */
606 status_t
607 BDirectory::GetNextRef(entry_ref *ref)
608 {
609 	status_t error = (ref ? B_OK : B_BAD_VALUE);
610 	if (error == B_OK && InitCheck() != B_OK)
611 		error = B_FILE_ERROR;
612 	if (error == B_OK) {
613 		BPrivate::Storage::LongDirEntry entry;
614 		bool next = true;
615 		while (error == B_OK && next) {
616 			if (BPrivate::Storage::read_dir(fDirFd, &entry, sizeof(entry), 1) != 1)
617 				error = B_ENTRY_NOT_FOUND;
618 			if (error == B_OK) {
619 				next = (!strcmp(entry.d_name, ".")
620 						|| !strcmp(entry.d_name, ".."));
621 			}
622 		}
623 		if (error == B_OK)
624 			*ref = entry_ref(entry.d_pdev, entry.d_pino, entry.d_name);
625 	}
626 	return error;
627 }
628 
629 // GetNextDirents
630 //! Returns the BDirectory's next entries as dirent structures.
631 /*!	Unlike GetNextEntry() and GetNextRef(), this method returns also
632 	the entries "." and "..".
633 	\param buf a pointer to a buffer to be filled with dirent structures of
634 		   the found entries
635 	\param count the maximal number of entries to be returned.
636 	\note The iterator used by this method is the same one used by
637 		  GetNextEntry(), GetNextRef(), Rewind() and CountEntries().
638 	\return
639 	- The number of dirent structures stored in the buffer, 0 when there are
640 	  no more entries to be returned.
641 	- \c B_BAD_VALUE: \c NULL \a buf.
642 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
643 	- \c B_NO_MEMORY: Insufficient memory for operation.
644 	- \c B_NAME_TOO_LONG: The entry's name is too long for the buffer.
645 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
646 	- \c B_BUSY: A node was busy.
647 	- \c B_FILE_ERROR: A general file error.
648 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
649 */
650 int32
651 BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count)
652 {
653 	int32 result = (buf ? B_OK : B_BAD_VALUE);
654 	if (result == B_OK && InitCheck() != B_OK)
655 		result = B_FILE_ERROR;
656 	if (result == B_OK)
657 		result = BPrivate::Storage::read_dir(fDirFd, buf, bufSize, count);
658 	return result;
659 }
660 
661 // Rewind
662 //!	Rewinds the directory iterator.
663 /*!	\return
664 	- \c B_OK: Everything went fine.
665 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
666 	- \c B_NO_MEMORY: Insufficient memory for operation.
667 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
668 	- \c B_BUSY: A node was busy.
669 	- \c B_FILE_ERROR: A general file error.
670 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
671 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries()
672 */
673 status_t
674 BDirectory::Rewind()
675 {
676 	status_t error = B_OK;
677 	if (error == B_OK && InitCheck() != B_OK)
678 		error = B_FILE_ERROR;
679 	if (error == B_OK)
680 		error = BPrivate::Storage::rewind_dir(fDirFd);
681 	return error;
682 }
683 
684 // CountEntries
685 //!	Returns the number of entries in this directory.
686 /*!	CountEntries() uses the directory iterator also used by GetNextEntry(),
687 	GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through
688 	the entries and Rewind()s again. The entries "." and ".." are not counted.
689 	\return
690 	- the number of entries in the directory (not counting "." and "..").
691 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
692 	- \c B_NO_MEMORY: Insufficient memory for operation.
693 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
694 	- \c B_BUSY: A node was busy.
695 	- \c B_FILE_ERROR: A general file error.
696 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
697 	\see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind()
698 */
699 int32
700 BDirectory::CountEntries()
701 {
702 	status_t error = Rewind();
703 	int32 count = 0;
704 	if (error == B_OK) {
705 		BPrivate::Storage::LongDirEntry entry;
706 		while (error == B_OK) {
707 			if (BPrivate::Storage::read_dir(fDirFd, &entry, sizeof(entry), 1) != 1)
708 				error = B_ENTRY_NOT_FOUND;
709 			if (error == B_OK
710 				&& strcmp(entry.d_name, ".") && strcmp(entry.d_name, "..")) {
711 				count++;
712 			}
713 		}
714 		if (error == B_ENTRY_NOT_FOUND)
715 			error = B_OK;
716 	}
717 	Rewind();
718 	return (error == B_OK ? count : error);
719 }
720 
721 // CreateDirectory
722 //! Creates a new directory.
723 /*! If an entry with the supplied name does already exist, the method fails.
724 	\param path the new directory's path name. May be relative to this
725 		   directory or absolute.
726 	\param dir a pointer to a BDirectory to be initialized to the newly
727 		   created directory. May be \c NULL.
728 	\return
729 	- \c B_OK: Everything went fine.
730 	- \c B_BAD_VALUE: \c NULL \a path.
731 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
732 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
733 	- \c B_NO_MEMORY: Insufficient memory for operation.
734 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
735 	- \c B_BUSY: A node was busy.
736 	- \c B_FILE_ERROR: A general file error.
737 	- \c B_FILE_EXISTS: An entry with that name does already exist.
738 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
739 */
740 status_t
741 BDirectory::CreateDirectory(const char *path, BDirectory *dir)
742 {
743 	status_t error = (path ? B_OK : B_BAD_VALUE);
744 	if (error == B_OK) {
745 		// get the actual (absolute) path using BEntry's help
746 		BEntry entry;
747 		if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
748 			entry.SetTo(this, path);
749 		else
750 			entry.SetTo(path);
751 		error = entry.InitCheck();
752 		BPath realPath;
753 		if (error == B_OK)
754 			error = entry.GetPath(&realPath);
755 		if (error == B_OK)
756 			error = BPrivate::Storage::create_dir(realPath.Path());
757 		if (error == B_OK && dir)
758 			error = dir->SetTo(realPath.Path());
759 	}
760 	return error;
761 }
762 
763 // CreateFile
764 //! Creates a new file.
765 /*!	If a file with the supplied name does already exist, the method fails,
766 	unless it is passed \c false to \a failIfExists -- in that case the file
767 	is truncated to zero size. The new BFile will operate in \c B_READ_WRITE
768 	mode.
769 	\param path the new file's path name. May be relative to this
770 		   directory or absolute.
771 	\param file a pointer to a BFile to be initialized to the newly
772 		   created file. May be \c NULL.
773 	\param failIfExists \c true, if the method should fail when the file
774 		   already exists, \c false otherwise
775 	\return
776 	- \c B_OK: Everything went fine.
777 	- \c B_BAD_VALUE: \c NULL \a path.
778 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
779 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
780 	- \c B_NO_MEMORY: Insufficient memory for operation.
781 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
782 	- \c B_BUSY: A node was busy.
783 	- \c B_FILE_ERROR: A general file error.
784 	- \c B_FILE_EXISTS: A file with that name does already exist and
785 	  \c true has been passed for \a failIfExists.
786 	- \c B_IS_A_DIRECTORY: A directory with the supplied name does already
787 	  exist.
788 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
789 */
790 status_t
791 BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists)
792 {
793 	status_t error (path ? B_OK : B_BAD_VALUE);
794 	if (error == B_OK) {
795 		// Let BFile do the dirty job.
796 		uint32 openMode = B_READ_WRITE | B_CREATE_FILE
797 						  | (failIfExists ? B_FAIL_IF_EXISTS : 0);
798 		BFile tmpFile;
799 		BFile *realFile = (file ? file : &tmpFile);
800 		if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
801 			error = realFile->SetTo(this, path, openMode);
802 		else
803 			error = realFile->SetTo(path, openMode);
804 		if (error != B_OK)
805 			realFile->Unset();
806 	}
807 	return error;
808 }
809 
810 // CreateSymLink
811 //! Creates a new symbolic link.
812 /*! If an entry with the supplied name does already exist, the method fails.
813 	\param path the new symbolic link's path name. May be relative to this
814 		   directory or absolute.
815 	\param linkToPath the path the symbolic link shall point to.
816 	\param dir a pointer to a BSymLink to be initialized to the newly
817 		   created symbolic link. May be \c NULL.
818 	\return
819 	- \c B_OK: Everything went fine.
820 	- \c B_BAD_VALUE: \c NULL \a path or \a linkToPath.
821 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
822 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
823 	- \c B_NO_MEMORY: Insufficient memory for operation.
824 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
825 	- \c B_BUSY: A node was busy.
826 	- \c B_FILE_ERROR: A general file error.
827 	- \c B_FILE_EXISTS: An entry with that name does already exist.
828 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
829 */
830 status_t
831 BDirectory::CreateSymLink(const char *path, const char *linkToPath,
832 						  BSymLink *link)
833 {
834 	status_t error = (path && linkToPath ? B_OK : B_BAD_VALUE);
835 	if (error == B_OK) {
836 		// get the actual (absolute) path using BEntry's help
837 		BEntry entry;
838 		if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path))
839 			entry.SetTo(this, path);
840 		else
841 			entry.SetTo(path);
842 		error = entry.InitCheck();
843 		BPath realPath;
844 		if (error == B_OK)
845 			error = entry.GetPath(&realPath);
846 		if (error == B_OK)
847 			error = BPrivate::Storage::create_link(realPath.Path(), linkToPath);
848 		if (error == B_OK && link)
849 			error = link->SetTo(realPath.Path());
850 	}
851 	return error;
852 }
853 
854 // =
855 //! Assigns another BDirectory to this BDirectory.
856 /*!	If the other BDirectory is uninitialized, this one will be too. Otherwise
857 	it will refer to the same directory, unless an error occurs.
858 	\param dir the original BDirectory
859 	\return a reference to this BDirectory
860 */
861 BDirectory &
862 BDirectory::operator=(const BDirectory &dir)
863 {
864 	if (&dir != this) {	// no need to assign us to ourselves
865 		Unset();
866 		if (dir.InitCheck() == B_OK) {
867 			*((BNode*)this) = dir;
868 			if (InitCheck() == B_OK) {
869 				// duplicate the file descriptor
870 				status_t status = BPrivate::Storage::dup_dir(dir.fDirFd, fDirFd);
871 				if (status != B_OK)
872 					Unset();
873 				set_status(status);
874 			}
875 		}
876 	}
877 	return *this;
878 }
879 
880 
881 // FBC
882 void BDirectory::_ErectorDirectory1() {}
883 void BDirectory::_ErectorDirectory2() {}
884 void BDirectory::_ErectorDirectory3() {}
885 void BDirectory::_ErectorDirectory4() {}
886 void BDirectory::_ErectorDirectory5() {}
887 void BDirectory::_ErectorDirectory6() {}
888 
889 // close_fd
890 //! Closes the BDirectory's file descriptor.
891 void
892 BDirectory::close_fd()
893 {
894 	if (fDirFd != BPrivate::Storage::NullFd) {
895 		BPrivate::Storage::close_dir(fDirFd);
896 		fDirFd = BPrivate::Storage::NullFd;
897 	}
898 	BNode::close_fd();
899 }
900 
901 //! Returns the BDirectory's file descriptor.
902 /*!	To be used instead of accessing the BDirectory's private \c fDirFd member
903 	directly.
904 	\return the file descriptor, or -1, if not properly initialized.
905 */
906 BPrivate::Storage::FileDescriptor
907 BDirectory::get_fd() const
908 {
909 	return fDirFd;
910 }
911 
912 
913 // C functions
914 
915 // create_directory
916 //! Creates all missing directories along a given path.
917 /*!	\param path the directory path name.
918 	\param mode a permission specification, which shall be used for the
919 		   newly created directories.
920 	\return
921 	- \c B_OK: Everything went fine.
922 	- \c B_BAD_VALUE: \c NULL \a path.
923 	- \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry.
924 	- \c B_PERMISSION_DENIED: Directory permissions didn't allow operation.
925 	- \c B_NO_MEMORY: Insufficient memory for operation.
926 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
927 	- \c B_BUSY: A node was busy.
928 	- \c B_FILE_ERROR: A general file error.
929 	- \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does
930 	  already exist.
931 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
932 	\todo Check for efficency.
933 */
934 status_t
935 create_directory(const char *path, mode_t mode)
936 {
937 	// That's the strategy: We start with the first component of the supplied
938 	// path, create a BPath object from it and successively add the following
939 	// components. Each time we get a new path, we check, if the entry it
940 	// refers to exists and is a directory. If it doesn't exist, then we try
941 	// to create it. This goes on, until we're done with the input path or
942 	// an error occurs.
943 	status_t error = (path ? B_OK : B_BAD_VALUE);
944 	if (error == B_OK) {
945 		BPath dirPath;
946 		char *component;
947 		int32 nextComponent;
948 		do {
949 			// get the next path component
950 			error = BPrivate::Storage::parse_first_path_component(path, component,
951 														   nextComponent);
952 			if (error == B_OK) {
953 				// append it to the BPath
954 				if (dirPath.InitCheck() == B_NO_INIT)	// first component
955 					error = dirPath.SetTo(component);
956 				else
957 					error = dirPath.Append(component);
958 				delete[] component;
959 				path += nextComponent;
960 				// create a BEntry from the BPath
961 				BEntry entry;
962 				if (error == B_OK)
963 					error = entry.SetTo(dirPath.Path(), true);
964 				// check, if it exists
965 				if (error == B_OK) {
966 					if (entry.Exists()) {
967 						// yep, it exists
968 						if (!entry.IsDirectory())	// but is no directory
969 							error = B_NOT_A_DIRECTORY;
970 					} else	// it doesn't exists -- create it
971 						error = BPrivate::Storage::create_dir(dirPath.Path(), mode);
972 				}
973 			}
974 		} while (error == B_OK && nextComponent != 0);
975 	}
976 	return error;
977 }
978 
979 
980 #ifdef USE_OPENBEOS_NAMESPACE
981 };		// namespace OpenBeOS
982 #endif
983 
984 
985 
986