xref: /haiku/src/kits/storage/File.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
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 	openMode |= O_CLOEXEC;
165 
166 	int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
167 		openMode, DEFFILEMODE & ~__gUmask);
168 	if (fd >= 0) {
169 		set_fd(fd);
170 		fMode = openMode;
171 		fCStatus = B_OK;
172 	} else
173 		fCStatus = fd;
174 
175 	return fCStatus;
176 }
177 
178 // SetTo
179 /*! \brief Re-initializes the BFile to the file referred to by the
180 		   supplied BEntry and according to the specified open mode.
181 	\param entry the BEntry referring to the file
182 	\param openMode the mode in which the file should be opened
183 	\return
184 	- \c B_OK: Everything went fine.
185 	- \c B_BAD_VALUE: \c NULL \a entry or bad \a openMode.
186 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
187 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
188 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
189 	- \c B_NO_MEMORY: Insufficient memory for operation.
190 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
191 	- \c B_BUSY: A node was busy.
192 	- \c B_FILE_ERROR: A general file error.
193 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
194 	\todo Implemented using SetTo(entry_ref*, uint32). Check, if necessary
195 		  to reimplement!
196 */
197 status_t
198 BFile::SetTo(const BEntry *entry, uint32 openMode)
199 {
200 	Unset();
201 
202 	if (!entry)
203 		return (fCStatus = B_BAD_VALUE);
204 	if (entry->InitCheck() != B_OK)
205 		return (fCStatus = entry->InitCheck());
206 
207 	openMode |= O_CLOEXEC;
208 
209 	int fd = _kern_open(entry->fDirFd, entry->fName, openMode | O_CLOEXEC,
210 		DEFFILEMODE & ~__gUmask);
211 	if (fd >= 0) {
212 		set_fd(fd);
213 		fMode = openMode;
214 		fCStatus = B_OK;
215 	} else
216 		fCStatus = fd;
217 
218 	return fCStatus;
219 }
220 
221 // SetTo
222 /*! \brief Re-initializes the BFile to the file referred to by the
223 		   supplied path name and according to the specified open mode.
224 	\param path the file's path name
225 	\param openMode the mode in which the file should be opened
226 	\return
227 	- \c B_OK: Everything went fine.
228 	- \c B_BAD_VALUE: \c NULL \a path or bad \a openMode.
229 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
230 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
231 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
232 	- \c B_NO_MEMORY: Insufficient memory for operation.
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 */
238 status_t
239 BFile::SetTo(const char *path, uint32 openMode)
240 {
241 	Unset();
242 
243 	if (!path)
244 		return (fCStatus = B_BAD_VALUE);
245 
246 	openMode |= O_CLOEXEC;
247 
248 	int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask);
249 	if (fd >= 0) {
250 		set_fd(fd);
251 		fMode = openMode;
252 		fCStatus = B_OK;
253 	} else
254 		fCStatus = fd;
255 
256 	return fCStatus;
257 }
258 
259 // SetTo
260 /*! \brief Re-initializes the BFile to the file referred to by the
261 		   supplied path name relative to the specified BDirectory and
262 		   according to the specified open mode.
263 	\param dir the BDirectory, relative to which the file's path name is
264 		   given
265 	\param path the file's path name relative to \a dir
266 	\param openMode the mode in which the file should be opened
267 	- \c B_OK: Everything went fine.
268 	- \c B_BAD_VALUE: \c NULL \a dir or \a path or bad \a openMode.
269 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
270 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
271 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
272 	- \c B_NO_MEMORY: Insufficient memory for operation.
273 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
274 	- \c B_BUSY: A node was busy.
275 	- \c B_FILE_ERROR: A general file error.
276 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
277 	\todo Implemented using SetTo(BEntry*, uint32). Check, if necessary
278 		  to reimplement!
279 */
280 status_t
281 BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode)
282 {
283 	Unset();
284 
285 	if (!dir)
286 		return (fCStatus = B_BAD_VALUE);
287 
288 	openMode |= O_CLOEXEC;
289 
290 	int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask);
291 	if (fd >= 0) {
292 		set_fd(fd);
293 		fMode = openMode;
294 		fCStatus = B_OK;
295 	} else
296 		fCStatus = fd;
297 
298 	return fCStatus;
299 }
300 
301 // IsReadable
302 //! Returns whether the file is readable.
303 /*!	\return
304 	- \c true, if the BFile has been initialized properly and the file has
305 	  been been opened for reading,
306 	- \c false, otherwise.
307 */
308 bool
309 BFile::IsReadable() const
310 {
311 	return (InitCheck() == B_OK
312 			&& ((fMode & O_RWMASK) == O_RDONLY
313 				|| (fMode & O_RWMASK) == O_RDWR));
314 }
315 
316 // IsWritable
317 //!	Returns whether the file is writable.
318 /*!	\return
319 	- \c true, if the BFile has been initialized properly and the file has
320 	  been opened for writing,
321 	- \c false, otherwise.
322 */
323 bool
324 BFile::IsWritable() const
325 {
326 	return (InitCheck() == B_OK
327 			&& ((fMode & O_RWMASK) == O_WRONLY
328 				|| (fMode & O_RWMASK) == O_RDWR));
329 }
330 
331 // Read
332 //!	Reads a number of bytes from the file into a buffer.
333 /*!	\param buffer the buffer the data from the file shall be written to
334 	\param size the number of bytes that shall be read
335 	\return the number of bytes actually read or an error code
336 */
337 ssize_t
338 BFile::Read(void *buffer, size_t size)
339 {
340 	if (InitCheck() != B_OK)
341 		return InitCheck();
342 	return _kern_read(get_fd(), -1, buffer, size);
343 }
344 
345 // ReadAt
346 /*!	\brief Reads a number of bytes from a certain position within the file
347 		   into a buffer.
348 	\param location the position (in bytes) within the file from which the
349 		   data shall be read
350 	\param buffer the buffer the data from the file shall be written to
351 	\param size the number of bytes that shall be read
352 	\return the number of bytes actually read or an error code
353 */
354 ssize_t
355 BFile::ReadAt(off_t location, void *buffer, size_t size)
356 {
357 	if (InitCheck() != B_OK)
358 		return InitCheck();
359 	if (location < 0)
360 		return B_BAD_VALUE;
361 	return _kern_read(get_fd(), location, buffer, size);
362 }
363 
364 // Write
365 //!	Writes a number of bytes from a buffer into the file.
366 /*!	\param buffer the buffer containing the data to be written to the file
367 	\param size the number of bytes that shall be written
368 	\return the number of bytes actually written or an error code
369 */
370 ssize_t
371 BFile::Write(const void *buffer, size_t size)
372 {
373 	if (InitCheck() != B_OK)
374 		return InitCheck();
375 	return _kern_write(get_fd(), -1, buffer, size);
376 }
377 
378 // WriteAt
379 /*!	\brief Writes a number of bytes from a buffer at a certain position
380 		   into the file.
381 	\param location the position (in bytes) within the file at which the data
382 		   shall be written
383 	\param buffer the buffer containing the data to be written to the file
384 	\param size the number of bytes that shall be written
385 	\return the number of bytes actually written or an error code
386 */
387 ssize_t
388 BFile::WriteAt(off_t location, const void *buffer, size_t size)
389 {
390 	if (InitCheck() != B_OK)
391 		return InitCheck();
392 	if (location < 0)
393 		return B_BAD_VALUE;
394 	return _kern_write(get_fd(), location, buffer, size);
395 }
396 
397 // Seek
398 //!	Seeks to another read/write position within the file.
399 /*!	It is allowed to seek past the end of the file. A subsequent call to
400 	Write() will pad the file with undefined data. Seeking before the
401 	beginning of the file will fail and the behavior of subsequent Read()
402 	or Write() invocations will be undefined.
403 	\param offset new read/write position, depending on \a seekMode relative
404 		   to the beginning or the end of the file or the current position
405 	\param seekMode:
406 		- \c SEEK_SET: move relative to the beginning of the file
407 		- \c SEEK_CUR: move relative to the current position
408 		- \c SEEK_END: move relative to the end of the file
409 	\return
410 	- the new read/write position relative to the beginning of the file
411 	- \c B_ERROR when trying to seek before the beginning of the file
412 	- \c B_FILE_ERROR, if the file is not properly initialized
413 */
414 off_t
415 BFile::Seek(off_t offset, uint32 seekMode)
416 {
417 	if (InitCheck() != B_OK)
418 		return B_FILE_ERROR;
419 	return _kern_seek(get_fd(), offset, seekMode);
420 }
421 
422 // Position
423 //!	Returns the current read/write position within the file.
424 /*!	\return
425 	- the current read/write position relative to the beginning of the file
426 	- \c B_ERROR, after a Seek() before the beginning of the file
427 	- \c B_FILE_ERROR, if the file has not been initialized
428 */
429 off_t
430 BFile::Position() const
431 {
432 	if (InitCheck() != B_OK)
433 		return B_FILE_ERROR;
434 	return _kern_seek(get_fd(), 0, SEEK_CUR);
435 }
436 
437 // SetSize
438 //!	Sets the size of the file.
439 /*!	If the file is shorter than \a size bytes it will be padded with
440 	unspecified data to the requested size. If it is larger, it will be
441 	truncated.
442 	Note: There's no problem with setting the size of a BFile opened in
443 	\c B_READ_ONLY mode, unless the file resides on a read only volume.
444 	\param size the new file size
445 	\return
446 	- \c B_OK, if everything went fine
447 	- \c B_NOT_ALLOWED, if trying to set the size of a file on a read only
448 	  volume
449 	- \c B_DEVICE_FULL, if there's not enough space left on the volume
450 */
451 status_t
452 BFile::SetSize(off_t size)
453 {
454 	if (InitCheck() != B_OK)
455 		return InitCheck();
456 	if (size < 0)
457 		return B_BAD_VALUE;
458 	struct stat statData;
459 	statData.st_size = size;
460 	return set_stat(statData, B_STAT_SIZE);
461 }
462 
463 // =
464 //!	Assigns another BFile to this BFile.
465 /*!	If the other BFile is uninitialized, this one will be too. Otherwise it
466 	will refer to the same file using the same mode, unless an error occurs.
467 	\param file the original BFile
468 	\return a reference to this BFile
469 */
470 BFile &
471 BFile::operator=(const BFile &file)
472 {
473 	if (&file != this) {	// no need to assign us to ourselves
474 		Unset();
475 		if (file.InitCheck() == B_OK) {
476 			// duplicate the file descriptor
477 			int fd = _kern_dup(file.get_fd());
478 			// set it
479 			if (fd >= 0) {
480 				fFd = fd;
481 				fMode = file.fMode;
482 				fCStatus = B_OK;
483 			} else
484 				fCStatus = fd;
485 		}
486 	}
487 	return *this;
488 }
489 
490 
491 // FBC
492 void BFile::_PhiloFile1() {}
493 void BFile::_PhiloFile2() {}
494 void BFile::_PhiloFile3() {}
495 void BFile::_PhiloFile4() {}
496 void BFile::_PhiloFile5() {}
497 void BFile::_PhiloFile6() {}
498 
499 
500 // get_fd
501 /*!	Returns the file descriptor.
502 	To be used instead of accessing the BNode's private \c fFd member directly.
503 	\return the file descriptor, or -1, if not properly initialized.
504 */
505 int
506 BFile::get_fd() const
507 {
508 	return fFd;
509 }
510 
511 // close_fd
512 /*!	Overrides BNode::close_fd() solely for R5 binary compatibility.
513 */
514 void
515 BFile::close_fd()
516 {
517 	BNode::close_fd();
518 }
519 
520 
521 #ifdef USE_OPENBEOS_NAMESPACE
522 };		// namespace OpenBeOS
523 #endif
524 
525