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