xref: /haiku/src/build/libbe/storage/File.cpp (revision 837b16251d4b2b6249ebcaa19bb319cbe82c6126)
1 //----------------------------------------------------------------------
2 //  This software is part of the Haiku distribution and is covered
3 //  by the MIT license.
4 //---------------------------------------------------------------------
5 /*!
6 	\file File.cpp
7 	BFile implementation.
8 */
9 
10 #include <fcntl.h>
11 #include <unistd.h>
12 
13 #include <Directory.h>
14 #include <Entry.h>
15 #include <File.h>
16 #include <NodeMonitor.h>
17 
18 #include <syscalls.h>
19 
20 
21 extern mode_t __gUmask;
22 	// declared in sys/umask.c
23 
24 
25 #ifdef USE_OPENBEOS_NAMESPACE
26 namespace OpenBeOS {
27 #endif
28 
29 // constructor
30 //! Creates an uninitialized BFile.
31 BFile::BFile()
32 	 : BNode(),
33 	   BPositionIO(),
34 	   fMode(0)
35 {
36 }
37 
38 // copy constructor
39 //! Creates a copy of the supplied BFile.
40 /*! If \a file is uninitialized, the newly constructed BFile will be, too.
41 	\param file the BFile object to be copied
42 */
43 BFile::BFile(const BFile &file)
44 	 : BNode(),
45 	   BPositionIO(),
46 	   fMode(0)
47 {
48 	*this = file;
49 }
50 
51 // constructor
52 /*! \brief Creates a BFile and initializes it to the file referred to by
53 		   the supplied entry_ref and according to the specified open mode.
54 	\param ref the entry_ref referring to the file
55 	\param openMode the mode in which the file should be opened
56 	\see SetTo() for values for \a openMode
57 */
58 BFile::BFile(const entry_ref *ref, uint32 openMode)
59 	 : BNode(),
60 	   BPositionIO(),
61 	   fMode(0)
62 {
63 	SetTo(ref, openMode);
64 }
65 
66 // constructor
67 /*! \brief Creates a BFile and initializes it to the file referred to by
68 		   the supplied BEntry and according to the specified open mode.
69 	\param entry the BEntry referring to the file
70 	\param openMode the mode in which the file should be opened
71 	\see SetTo() for values for \a openMode
72 */
73 BFile::BFile(const BEntry *entry, uint32 openMode)
74 	 : BNode(),
75 	   BPositionIO(),
76 	   fMode(0)
77 {
78 	SetTo(entry, openMode);
79 }
80 
81 // constructor
82 /*! \brief Creates a BFile and initializes it to the file referred to by
83 		   the supplied path name and according to the specified open mode.
84 	\param path the file's path name
85 	\param openMode the mode in which the file should be opened
86 	\see SetTo() for values for \a openMode
87 */
88 BFile::BFile(const char *path, uint32 openMode)
89 	 : BNode(),
90 	   BPositionIO(),
91 	   fMode(0)
92 {
93 	SetTo(path, openMode);
94 }
95 
96 // constructor
97 /*! \brief Creates a BFile and initializes it to the file referred to by
98 		   the supplied path name relative to the specified BDirectory and
99 		   according to the specified open mode.
100 	\param dir the BDirectory, relative to which the file's path name is
101 		   given
102 	\param path the file's path name relative to \a dir
103 	\param openMode the mode in which the file should be opened
104 	\see SetTo() for values for \a openMode
105 */
106 BFile::BFile(const BDirectory *dir, const char *path, uint32 openMode)
107 	 : BNode(),
108 	   BPositionIO(),
109 	   fMode(0)
110 {
111 	SetTo(dir, path, openMode);
112 }
113 
114 // destructor
115 //! Frees all allocated resources.
116 /*!	If the file is properly initialized, the file's file descriptor is closed.
117 */
118 BFile::~BFile()
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 BFile to the file referred to by the
130 		   supplied entry_ref and according to the specified open mode.
131 	\param ref the entry_ref referring to the file
132 	\param openMode the mode in which the file should be opened
133 	\a openMode must be a bitwise or of exactly one of the flags
134 	- \c B_READ_ONLY: The file is opened read only.
135 	- \c B_WRITE_ONLY: The file is opened write only.
136 	- \c B_READ_WRITE: The file is opened for random read/write access.
137 	and any number of the flags
138 	- \c B_CREATE_FILE: A new file will be created, if it does not already
139 	  exist.
140 	- \c B_FAIL_IF_EXISTS: If the file does already exist and B_CREATE_FILE is
141 	  set, SetTo() fails.
142 	- \c B_ERASE_FILE: An already existing file is truncated to zero size.
143 	- \c B_OPEN_AT_END: Seek() to the end of the file after opening.
144 	\return
145 	- \c B_OK: Everything went fine.
146 	- \c B_BAD_VALUE: \c NULL \a ref or bad \a openMode.
147 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
148 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
149 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
150 	- \c B_NO_MEMORY: Insufficient memory for operation.
151 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
152 	- \c B_BUSY: A node was busy.
153 	- \c B_FILE_ERROR: A general file error.
154 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
155 */
156 status_t
157 BFile::SetTo(const entry_ref *ref, uint32 openMode)
158 {
159 	Unset();
160 
161 	if (!ref)
162 		return (fCStatus = B_BAD_VALUE);
163 
164 	int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
165 		openMode, DEFFILEMODE & ~__gUmask);
166 	if (fd >= 0) {
167 		set_fd(fd);
168 		fMode = openMode;
169 		fCStatus = B_OK;
170 
171 		fcntl(fd, F_SETFD, FD_CLOEXEC);
172 
173 	} else
174 		fCStatus = fd;
175 
176 	return fCStatus;
177 }
178 
179 // SetTo
180 /*! \brief Re-initializes the BFile to the file referred to by the
181 		   supplied BEntry and according to the specified open mode.
182 	\param entry the BEntry referring to the file
183 	\param openMode the mode in which the file should be opened
184 	\return
185 	- \c B_OK: Everything went fine.
186 	- \c B_BAD_VALUE: \c NULL \a entry or bad \a openMode.
187 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
188 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
189 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
190 	- \c B_NO_MEMORY: Insufficient memory for operation.
191 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
192 	- \c B_BUSY: A node was busy.
193 	- \c B_FILE_ERROR: A general file error.
194 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
195 	\todo Implemented using SetTo(entry_ref*, uint32). Check, if necessary
196 		  to reimplement!
197 */
198 status_t
199 BFile::SetTo(const BEntry *entry, uint32 openMode)
200 {
201 	Unset();
202 
203 	if (!entry)
204 		return (fCStatus = B_BAD_VALUE);
205 	if (entry->InitCheck() != B_OK)
206 		return (fCStatus = entry->InitCheck());
207 
208 	int fd = _kern_open(entry->fDirFd, entry->fName, openMode,
209 		DEFFILEMODE & ~__gUmask);
210 	if (fd >= 0) {
211 		set_fd(fd);
212 		fMode = openMode;
213 		fCStatus = B_OK;
214 
215 		fcntl(fd, F_SETFD, FD_CLOEXEC);
216 	} else
217 		fCStatus = fd;
218 
219 	return fCStatus;
220 }
221 
222 // SetTo
223 /*! \brief Re-initializes the BFile to the file referred to by the
224 		   supplied path name and according to the specified open mode.
225 	\param path the file's path name
226 	\param openMode the mode in which the file should be opened
227 	\return
228 	- \c B_OK: Everything went fine.
229 	- \c B_BAD_VALUE: \c NULL \a path or bad \a openMode.
230 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
231 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
232 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
233 	- \c B_NO_MEMORY: Insufficient memory for operation.
234 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
235 	- \c B_BUSY: A node was busy.
236 	- \c B_FILE_ERROR: A general file error.
237 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
238 */
239 status_t
240 BFile::SetTo(const char *path, uint32 openMode)
241 {
242 	Unset();
243 
244 	if (!path)
245 		return (fCStatus = B_BAD_VALUE);
246 
247 	int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask);
248 	if (fd >= 0) {
249 		set_fd(fd);
250 		fMode = openMode;
251 		fCStatus = B_OK;
252 
253 		fcntl(fd, F_SETFD, FD_CLOEXEC);
254 	} else
255 		fCStatus = fd;
256 
257 	return fCStatus;
258 }
259 
260 // SetTo
261 /*! \brief Re-initializes the BFile to the file referred to by the
262 		   supplied path name relative to the specified BDirectory and
263 		   according to the specified open mode.
264 	\param dir the BDirectory, relative to which the file's path name is
265 		   given
266 	\param path the file's path name relative to \a dir
267 	\param openMode the mode in which the file should be opened
268 	- \c B_OK: Everything went fine.
269 	- \c B_BAD_VALUE: \c NULL \a dir or \a path or bad \a openMode.
270 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
271 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
272 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
273 	- \c B_NO_MEMORY: Insufficient memory for operation.
274 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
275 	- \c B_BUSY: A node was busy.
276 	- \c B_FILE_ERROR: A general file error.
277 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
278 	\todo Implemented using SetTo(BEntry*, uint32). Check, if necessary
279 		  to reimplement!
280 */
281 status_t
282 BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode)
283 {
284 	Unset();
285 
286 	if (!dir)
287 		return (fCStatus = B_BAD_VALUE);
288 
289 	int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask);
290 	if (fd >= 0) {
291 		set_fd(fd);
292 		fMode = openMode;
293 		fCStatus = B_OK;
294 
295 		fcntl(fd, F_SETFD, FD_CLOEXEC);
296 	} else
297 		fCStatus = fd;
298 
299 	return fCStatus;
300 }
301 
302 // IsReadable
303 //! Returns whether the file is readable.
304 /*!	\return
305 	- \c true, if the BFile has been initialized properly and the file has
306 	  been been opened for reading,
307 	- \c false, otherwise.
308 */
309 bool
310 BFile::IsReadable() const
311 {
312 	return (InitCheck() == B_OK
313 			&& ((fMode & O_ACCMODE) == O_RDONLY
314 				|| (fMode & O_ACCMODE) == O_RDWR));
315 }
316 
317 // IsWritable
318 //!	Returns whether the file is writable.
319 /*!	\return
320 	- \c true, if the BFile has been initialized properly and the file has
321 	  been opened for writing,
322 	- \c false, otherwise.
323 */
324 bool
325 BFile::IsWritable() const
326 {
327 	return (InitCheck() == B_OK
328 			&& ((fMode & O_ACCMODE) == O_WRONLY
329 				|| (fMode & O_ACCMODE) == O_RDWR));
330 }
331 
332 // Read
333 //!	Reads a number of bytes from the file into a buffer.
334 /*!	\param buffer the buffer the data from the file shall be written to
335 	\param size the number of bytes that shall be read
336 	\return the number of bytes actually read or an error code
337 */
338 ssize_t
339 BFile::Read(void *buffer, size_t size)
340 {
341 	if (InitCheck() != B_OK)
342 		return InitCheck();
343 	return _kern_read(get_fd(), -1, buffer, size);
344 }
345 
346 // ReadAt
347 /*!	\brief Reads a number of bytes from a certain position within the file
348 		   into a buffer.
349 	\param location the position (in bytes) within the file from which the
350 		   data shall be read
351 	\param buffer the buffer the data from the file shall be written to
352 	\param size the number of bytes that shall be read
353 	\return the number of bytes actually read or an error code
354 */
355 ssize_t
356 BFile::ReadAt(off_t location, void *buffer, size_t size)
357 {
358 	if (InitCheck() != B_OK)
359 		return InitCheck();
360 	if (location < 0)
361 		return B_BAD_VALUE;
362 	return _kern_read(get_fd(), location, buffer, size);
363 }
364 
365 // Write
366 //!	Writes a number of bytes from a buffer into the file.
367 /*!	\param buffer the buffer containing the data to be written to the file
368 	\param size the number of bytes that shall be written
369 	\return the number of bytes actually written or an error code
370 */
371 ssize_t
372 BFile::Write(const void *buffer, size_t size)
373 {
374 	if (InitCheck() != B_OK)
375 		return InitCheck();
376 	return _kern_write(get_fd(), -1, buffer, size);
377 }
378 
379 // WriteAt
380 /*!	\brief Writes a number of bytes from a buffer at a certain position
381 		   into the file.
382 	\param location the position (in bytes) within the file at which the data
383 		   shall be written
384 	\param buffer the buffer containing the data to be written to the file
385 	\param size the number of bytes that shall be written
386 	\return the number of bytes actually written or an error code
387 */
388 ssize_t
389 BFile::WriteAt(off_t location, const void *buffer, size_t size)
390 {
391 	if (InitCheck() != B_OK)
392 		return InitCheck();
393 	if (location < 0)
394 		return B_BAD_VALUE;
395 	return _kern_write(get_fd(), location, buffer, size);
396 }
397 
398 // Seek
399 //!	Seeks to another read/write position within the file.
400 /*!	It is allowed to seek past the end of the file. A subsequent call to
401 	Write() will pad the file with undefined data. Seeking before the
402 	beginning of the file will fail and the behavior of subsequent Read()
403 	or Write() invocations will be undefined.
404 	\param offset new read/write position, depending on \a seekMode relative
405 		   to the beginning or the end of the file or the current position
406 	\param seekMode:
407 		- \c SEEK_SET: move relative to the beginning of the file
408 		- \c SEEK_CUR: move relative to the current position
409 		- \c SEEK_END: move relative to the end of the file
410 	\return
411 	- the new read/write position relative to the beginning of the file
412 	- \c B_ERROR when trying to seek before the beginning of the file
413 	- \c B_FILE_ERROR, if the file is not properly initialized
414 */
415 off_t
416 BFile::Seek(off_t offset, uint32 seekMode)
417 {
418 	if (InitCheck() != B_OK)
419 		return B_FILE_ERROR;
420 	return _kern_seek(get_fd(), offset, seekMode);
421 }
422 
423 // Position
424 //!	Returns the current read/write position within the file.
425 /*!	\return
426 	- the current read/write position relative to the beginning of the file
427 	- \c B_ERROR, after a Seek() before the beginning of the file
428 	- \c B_FILE_ERROR, if the file has not been initialized
429 */
430 off_t
431 BFile::Position() const
432 {
433 	if (InitCheck() != B_OK)
434 		return B_FILE_ERROR;
435 	return _kern_seek(get_fd(), 0, SEEK_CUR);
436 }
437 
438 // SetSize
439 //!	Sets the size of the file.
440 /*!	If the file is shorter than \a size bytes it will be padded with
441 	unspecified data to the requested size. If it is larger, it will be
442 	truncated.
443 	Note: There's no problem with setting the size of a BFile opened in
444 	\c B_READ_ONLY mode, unless the file resides on a read only volume.
445 	\param size the new file size
446 	\return
447 	- \c B_OK, if everything went fine
448 	- \c B_NOT_ALLOWED, if trying to set the size of a file on a read only
449 	  volume
450 	- \c B_DEVICE_FULL, if there's not enough space left on the volume
451 */
452 status_t
453 BFile::SetSize(off_t size)
454 {
455 	if (InitCheck() != B_OK)
456 		return InitCheck();
457 	if (size < 0)
458 		return B_BAD_VALUE;
459 	struct stat statData;
460 	statData.st_size = size;
461 	return set_stat(statData, B_STAT_SIZE);
462 }
463 
464 
465 status_t
466 BFile::GetSize(off_t* size) const
467 {
468 	return BStatable::GetSize(size);
469 }
470 
471 
472 // =
473 //!	Assigns another BFile to this BFile.
474 /*!	If the other BFile is uninitialized, this one will be too. Otherwise it
475 	will refer to the same file using the same mode, unless an error occurs.
476 	\param file the original BFile
477 	\return a reference to this BFile
478 */
479 BFile &
480 BFile::operator=(const BFile &file)
481 {
482 	if (&file != this) {	// no need to assign us to ourselves
483 		Unset();
484 		if (file.InitCheck() == B_OK) {
485 			// duplicate the file descriptor
486 			int fd = _kern_dup(file.get_fd());
487 			// set it
488 			if (fd >= 0) {
489 				fFd = fd;
490 				fMode = file.fMode;
491 				fCStatus = B_OK;
492 			} else
493 				fCStatus = fd;
494 		}
495 	}
496 	return *this;
497 }
498 
499 
500 // FBC
501 void BFile::_PhiloFile1() {}
502 void BFile::_PhiloFile2() {}
503 void BFile::_PhiloFile3() {}
504 void BFile::_PhiloFile4() {}
505 void BFile::_PhiloFile5() {}
506 void BFile::_PhiloFile6() {}
507 
508 
509 // get_fd
510 /*!	Returns the file descriptor.
511 	To be used instead of accessing the BNode's private \c fFd member directly.
512 	\return the file descriptor, or -1, if not properly initialized.
513 */
514 int
515 BFile::get_fd() const
516 {
517 	return fFd;
518 }
519 
520 // close_fd
521 /*!	Overrides BNode::close_fd() solely for R5 binary compatibility.
522 */
523 void
524 BFile::close_fd()
525 {
526 	BNode::close_fd();
527 }
528 
529 
530 #ifdef USE_OPENBEOS_NAMESPACE
531 };		// namespace OpenBeOS
532 #endif
533 
534