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