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