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
21extern mode_t __gUmask;
22	// declared in sys/umask.c
23
24
25#ifdef USE_OPENBEOS_NAMESPACE
26namespace OpenBeOS {
27#endif
28
29// constructor
30//! Creates an uninitialized BFile.
31BFile::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*/
43BFile::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*/
58BFile::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*/
73BFile::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*/
88BFile::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*/
106BFile::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*/
118BFile::~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*/
156status_t
157BFile::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*/
198status_t
199BFile::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*/
239status_t
240BFile::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*/
281status_t
282BFile::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*/
309bool
310BFile::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*/
324bool
325BFile::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*/
338ssize_t
339BFile::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*/
355ssize_t
356BFile::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*/
371ssize_t
372BFile::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*/
388ssize_t
389BFile::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*/
415off_t
416BFile::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*/
430off_t
431BFile::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*/
452status_t
453BFile::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
465status_t
466BFile::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*/
479BFile &
480BFile::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
501void BFile::_PhiloFile1() {}
502void BFile::_PhiloFile2() {}
503void BFile::_PhiloFile3() {}
504void BFile::_PhiloFile4() {}
505void BFile::_PhiloFile5() {}
506void 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*/
514int
515BFile::get_fd() const
516{
517	return fFd;
518}
519
520// close_fd
521/*!	Overrides BNode::close_fd() solely for R5 binary compatibility.
522*/
523void
524BFile::close_fd()
525{
526	BNode::close_fd();
527}
528
529
530#ifdef USE_OPENBEOS_NAMESPACE
531};		// namespace OpenBeOS
532#endif
533
534