xref: /haiku/src/kits/storage/File.cpp (revision 91054f1d38dd7827c0f0ba9490c213775ec7b471)
1 /*
2  * Copyright 2002-2008, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Tyler Dauwalder
7  *		Ingo Weinhold, bonefish@users.sf.net
8  */
9 
10 
11 #include <fcntl.h>
12 #include <unistd.h>
13 
14 #include <Directory.h>
15 #include <Entry.h>
16 #include <File.h>
17 #include <fs_interface.h>
18 #include <NodeMonitor.h>
19 #include "storage_support.h"
20 
21 #include <syscalls.h>
22 
23 
24 extern mode_t __gUmask;
25 	// declared in sys/umask.c
26 
27 
28 //! Creates an uninitialized BFile.
29 BFile::BFile()
30 	 : BNode(),
31 	   BPositionIO(),
32 	   fMode(0)
33 {
34 }
35 
36 
37 //! Creates a copy of the supplied BFile.
38 /*! If \a file is uninitialized, the newly constructed BFile will be, too.
39 	\param file the BFile object to be copied
40 */
41 BFile::BFile(const BFile &file)
42 	 : BNode(),
43 	   BPositionIO(),
44 	   fMode(0)
45 {
46 	*this = file;
47 }
48 
49 
50 /*! \brief Creates a BFile and initializes it to the file referred to by
51 		   the supplied entry_ref and according to the specified open mode.
52 	\param ref the entry_ref referring to the file
53 	\param openMode the mode in which the file should be opened
54 	\see SetTo() for values for \a openMode
55 */
56 BFile::BFile(const entry_ref *ref, uint32 openMode)
57 	 : BNode(),
58 	   BPositionIO(),
59 	   fMode(0)
60 {
61 	SetTo(ref, openMode);
62 }
63 
64 
65 /*! \brief Creates a BFile and initializes it to the file referred to by
66 		   the supplied BEntry and according to the specified open mode.
67 	\param entry the BEntry referring to the file
68 	\param openMode the mode in which the file should be opened
69 	\see SetTo() for values for \a openMode
70 */
71 BFile::BFile(const BEntry *entry, uint32 openMode)
72 	 : BNode(),
73 	   BPositionIO(),
74 	   fMode(0)
75 {
76 	SetTo(entry, openMode);
77 }
78 
79 
80 /*! \brief Creates a BFile and initializes it to the file referred to by
81 		   the supplied path name and according to the specified open mode.
82 	\param path the file's path name
83 	\param openMode the mode in which the file should be opened
84 	\see SetTo() for values for \a openMode
85 */
86 BFile::BFile(const char *path, uint32 openMode)
87 	 : BNode(),
88 	   BPositionIO(),
89 	   fMode(0)
90 {
91 	SetTo(path, openMode);
92 }
93 
94 
95 /*! \brief Creates a BFile and initializes it to the file referred to by
96 		   the supplied path name relative to the specified BDirectory and
97 		   according to the specified open mode.
98 	\param dir the BDirectory, relative to which the file's path name is
99 		   given
100 	\param path the file's path name relative to \a dir
101 	\param openMode the mode in which the file should be opened
102 	\see SetTo() for values for \a openMode
103 */
104 BFile::BFile(const BDirectory *dir, const char *path, uint32 openMode)
105 	 : BNode(),
106 	   BPositionIO(),
107 	   fMode(0)
108 {
109 	SetTo(dir, path, openMode);
110 }
111 
112 
113 /*! \brief Frees all allocated resources.
114 	If the file is properly initialized, the file's file descriptor is closed.
115 */
116 BFile::~BFile()
117 {
118 	// Also called by the BNode destructor, but we rather try to avoid
119 	// problems with calling virtual functions in the base class destructor.
120 	// Depending on the compiler implementation an object may be degraded to
121 	// an object of the base class after the destructor of the derived class
122 	// has been executed.
123 	close_fd();
124 }
125 
126 
127 /*! \brief Re-initializes the BFile to the file referred to by the
128 		   supplied entry_ref and according to the specified open mode.
129 	\param ref the entry_ref referring to the file
130 	\param openMode the mode in which the file should be opened
131 	\a openMode must be a bitwise or of exactly one of the flags
132 	- \c B_READ_ONLY: The file is opened read only.
133 	- \c B_WRITE_ONLY: The file is opened write only.
134 	- \c B_READ_WRITE: The file is opened for random read/write access.
135 	and any number of the flags
136 	- \c B_CREATE_FILE: A new file will be created, if it does not already
137 	  exist.
138 	- \c B_FAIL_IF_EXISTS: If the file does already exist and B_CREATE_FILE is
139 	  set, SetTo() fails.
140 	- \c B_ERASE_FILE: An already existing file is truncated to zero size.
141 	- \c B_OPEN_AT_END: Seek() to the end of the file after opening.
142 	\return
143 	- \c B_OK: Everything went fine.
144 	- \c B_BAD_VALUE: \c NULL \a ref or bad \a openMode.
145 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
146 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
147 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
148 	- \c B_NO_MEMORY: Insufficient memory for operation.
149 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
150 	- \c B_BUSY: A node was busy.
151 	- \c B_FILE_ERROR: A general file error.
152 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
153 */
154 status_t
155 BFile::SetTo(const entry_ref *ref, uint32 openMode)
156 {
157 	Unset();
158 
159 	if (!ref)
160 		return (fCStatus = B_BAD_VALUE);
161 
162 	// if ref->name is absolute, let the path-only SetTo() do the job
163 	if (BPrivate::Storage::is_absolute_path(ref->name))
164 		return SetTo(ref->name, openMode);
165 
166 	openMode |= O_CLOEXEC;
167 
168 	int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
169 		openMode, DEFFILEMODE & ~__gUmask);
170 	if (fd >= 0) {
171 		set_fd(fd);
172 		fMode = openMode;
173 		fCStatus = B_OK;
174 	} else
175 		fCStatus = fd;
176 
177 	return fCStatus;
178 }
179 
180 
181 /*! \brief Re-initializes the BFile to the file referred to by the
182 		   supplied BEntry and according to the specified open mode.
183 	\param entry the BEntry referring to the file
184 	\param openMode the mode in which the file should be opened
185 	\return
186 	- \c B_OK: Everything went fine.
187 	- \c B_BAD_VALUE: \c NULL \a entry or bad \a openMode.
188 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
189 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
190 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
191 	- \c B_NO_MEMORY: Insufficient memory for operation.
192 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
193 	- \c B_BUSY: A node was busy.
194 	- \c B_FILE_ERROR: A general file error.
195 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
196 	\todo Implemented using SetTo(entry_ref*, uint32). Check, if necessary
197 		  to reimplement!
198 */
199 status_t
200 BFile::SetTo(const BEntry *entry, uint32 openMode)
201 {
202 	Unset();
203 
204 	if (!entry)
205 		return (fCStatus = B_BAD_VALUE);
206 	if (entry->InitCheck() != B_OK)
207 		return (fCStatus = entry->InitCheck());
208 
209 	openMode |= O_CLOEXEC;
210 
211 	int fd = _kern_open(entry->fDirFd, entry->fName, openMode | O_CLOEXEC,
212 		DEFFILEMODE & ~__gUmask);
213 	if (fd >= 0) {
214 		set_fd(fd);
215 		fMode = openMode;
216 		fCStatus = B_OK;
217 	} else
218 		fCStatus = fd;
219 
220 	return fCStatus;
221 }
222 
223 
224 /*! \brief Re-initializes the BFile to the file referred to by the
225 		   supplied path name and according to the specified open mode.
226 	\param path the file's path name
227 	\param openMode the mode in which the file should be opened
228 	\return
229 	- \c B_OK: Everything went fine.
230 	- \c B_BAD_VALUE: \c NULL \a path or bad \a openMode.
231 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
232 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
233 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
234 	- \c B_NO_MEMORY: Insufficient memory for operation.
235 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
236 	- \c B_BUSY: A node was busy.
237 	- \c B_FILE_ERROR: A general file error.
238 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
239 */
240 status_t
241 BFile::SetTo(const char *path, uint32 openMode)
242 {
243 	Unset();
244 
245 	if (!path)
246 		return (fCStatus = B_BAD_VALUE);
247 
248 	openMode |= O_CLOEXEC;
249 
250 	int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask);
251 	if (fd >= 0) {
252 		set_fd(fd);
253 		fMode = openMode;
254 		fCStatus = B_OK;
255 	} else
256 		fCStatus = fd;
257 
258 	return fCStatus;
259 }
260 
261 
262 /*! \brief Re-initializes the BFile to the file referred to by the
263 		   supplied path name relative to the specified BDirectory and
264 		   according to the specified open mode.
265 	\param dir the BDirectory, relative to which the file's path name is
266 		   given
267 	\param path the file's path name relative to \a dir
268 	\param openMode the mode in which the file should be opened
269 	- \c B_OK: Everything went fine.
270 	- \c B_BAD_VALUE: \c NULL \a dir or \a path or bad \a openMode.
271 	- \c B_ENTRY_NOT_FOUND: File not found or failed to create file.
272 	- \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed.
273 	- \c B_PERMISSION_DENIED: File permissions didn't allow operation.
274 	- \c B_NO_MEMORY: Insufficient memory for operation.
275 	- \c B_LINK_LIMIT: Indicates a cyclic loop within the file system.
276 	- \c B_BUSY: A node was busy.
277 	- \c B_FILE_ERROR: A general file error.
278 	- \c B_NO_MORE_FDS: The application has run out of file descriptors.
279 	\todo Implemented using SetTo(BEntry*, uint32). Check, if necessary
280 		  to reimplement!
281 */
282 status_t
283 BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode)
284 {
285 	Unset();
286 
287 	if (!dir)
288 		return (fCStatus = B_BAD_VALUE);
289 
290 	openMode |= O_CLOEXEC;
291 
292 	int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask);
293 	if (fd >= 0) {
294 		set_fd(fd);
295 		fMode = openMode;
296 		fCStatus = B_OK;
297 	} else
298 		fCStatus = fd;
299 
300 	return fCStatus;
301 }
302 
303 
304 /*! \brief Returns whether the file is readable.
305 	\return
306 	- \c true, if the BFile has been initialized properly and the file has
307 	  been been opened for reading,
308 	- \c false, otherwise.
309 */
310 bool
311 BFile::IsReadable() const
312 {
313 	return InitCheck() == B_OK
314 		&& ((fMode & O_RWMASK) == O_RDONLY || (fMode & O_RWMASK) == O_RDWR);
315 }
316 
317 
318 /*!	\brief 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_RWMASK) == O_WRONLY || (fMode & O_RWMASK) == O_RDWR);
329 }
330 
331 
332 /*!	\brief 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 
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 
362 	return _kern_read(get_fd(), location, buffer, size);
363 }
364 
365 
366 /*!	\brief 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 
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 
396 	return _kern_write(get_fd(), location, buffer, size);
397 }
398 
399 
400 /*!	\brief Seeks to another read/write position within the file.
401 	It is allowed to seek past the end of the file. A subsequent call to
402 	Write() will pad the file with undefined data. Seeking before the
403 	beginning of the file will fail and the behavior of subsequent Read()
404 	or Write() invocations will be undefined.
405 	\param offset new read/write position, depending on \a seekMode relative
406 		   to the beginning or the end of the file or the current position
407 	\param seekMode:
408 		- \c SEEK_SET: move relative to the beginning of the file
409 		- \c SEEK_CUR: move relative to the current position
410 		- \c SEEK_END: move relative to the end of the file
411 	\return
412 	- the new read/write position relative to the beginning of the file
413 	- \c B_ERROR when trying to seek before the beginning of the file
414 	- \c B_FILE_ERROR, if the file is not properly initialized
415 */
416 off_t
417 BFile::Seek(off_t offset, uint32 seekMode)
418 {
419 	if (InitCheck() != B_OK)
420 		return B_FILE_ERROR;
421 	return _kern_seek(get_fd(), offset, seekMode);
422 }
423 
424 
425 /*!	\brief Returns the current read/write position within the file.
426 	\return
427 	- the current read/write position relative to the beginning of the file
428 	- \c B_ERROR, after a Seek() before the beginning of the file
429 	- \c B_FILE_ERROR, if the file has not been initialized
430 */
431 off_t
432 BFile::Position() const
433 {
434 	if (InitCheck() != B_OK)
435 		return B_FILE_ERROR;
436 	return _kern_seek(get_fd(), 0, SEEK_CUR);
437 }
438 
439 
440 /*!	\brief Sets the size of the file.
441 	If the file is shorter than \a size bytes it will be padded with
442 	unspecified data to the requested size. If it is larger, it will be
443 	truncated.
444 	Note: There's no problem with setting the size of a BFile opened in
445 	\c B_READ_ONLY mode, unless the file resides on a read only volume.
446 	\param size the new file size
447 	\return
448 	- \c B_OK, if everything went fine
449 	- \c B_NOT_ALLOWED, if trying to set the size of a file on a read only
450 	  volume
451 	- \c B_DEVICE_FULL, if there's not enough space left on the volume
452 */
453 status_t
454 BFile::SetSize(off_t size)
455 {
456 	if (InitCheck() != B_OK)
457 		return InitCheck();
458 	if (size < 0)
459 		return B_BAD_VALUE;
460 	struct stat statData;
461 	statData.st_size = size;
462 	return set_stat(statData, B_STAT_SIZE | B_STAT_SIZE_INSECURE);
463 }
464 
465 
466 status_t
467 BFile::GetSize(off_t* size) const
468 {
469 	return BStatable::GetSize(size);
470 }
471 
472 
473 /*!	\brief 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 /*!	Returns the file descriptor.
510 	To be used instead of accessing the BNode's private \c fFd member directly.
511 	\return the file descriptor, or -1, if not properly initialized.
512 */
513 int
514 BFile::get_fd() const
515 {
516 	return fFd;
517 }
518 
519 
520 /*!	Overrides BNode::close_fd() solely for R5 binary compatibility.
521 */
522 void
523 BFile::close_fd()
524 {
525 	BNode::close_fd();
526 }
527 
528