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.
26BFile::BFile()
27	:
28	fMode(0)
29{
30}
31
32
33// Creates a copy of the supplied BFile.
34BFile::BFile(const BFile& file)
35	:
36	fMode(0)
37{
38	*this = file;
39}
40
41
42// Creates a BFile and initializes it to the file referred to by
43// the supplied entry_ref and according to the specified open mode.
44BFile::BFile(const entry_ref* ref, uint32 openMode)
45	:
46	fMode(0)
47{
48	SetTo(ref, openMode);
49}
50
51
52// Creates a BFile and initializes it to the file referred to by
53// the supplied BEntry and according to the specified open mode.
54BFile::BFile(const BEntry* entry, uint32 openMode)
55	:
56	fMode(0)
57{
58	SetTo(entry, openMode);
59}
60
61
62// Creates a BFile and initializes it to the file referred to by
63// the supplied path name and according to the specified open mode.
64BFile::BFile(const char* path, uint32 openMode)
65	:
66	fMode(0)
67{
68	SetTo(path, openMode);
69}
70
71
72// Creates a BFile and initializes it to the file referred to by
73// the supplied path name relative to the specified BDirectory and
74// according to the specified open mode.
75BFile::BFile(const BDirectory *dir, const char* path, uint32 openMode)
76	:
77	fMode(0)
78{
79	SetTo(dir, path, openMode);
80}
81
82
83// Frees all allocated resources.
84BFile::~BFile()
85{
86	// Also called by the BNode destructor, but we rather try to avoid
87	// problems with calling virtual functions in the base class destructor.
88	// Depending on the compiler implementation an object may be degraded to
89	// an object of the base class after the destructor of the derived class
90	// has been executed.
91	close_fd();
92}
93
94
95// Re-initializes the BFile to the file referred to by the
96// supplied entry_ref and according to the specified open mode.
97status_t
98BFile::SetTo(const entry_ref* ref, uint32 openMode)
99{
100	Unset();
101
102	if (!ref)
103		return (fCStatus = B_BAD_VALUE);
104
105	// if ref->name is absolute, let the path-only SetTo() do the job
106	if (BPrivate::Storage::is_absolute_path(ref->name))
107		return SetTo(ref->name, openMode);
108
109	openMode |= O_CLOEXEC;
110
111	int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
112		openMode, DEFFILEMODE & ~__gUmask);
113	if (fd >= 0) {
114		set_fd(fd);
115		fMode = openMode;
116		fCStatus = B_OK;
117	} else
118		fCStatus = fd;
119
120	return fCStatus;
121}
122
123
124// Re-initializes the BFile to the file referred to by the
125// supplied BEntry and according to the specified open mode.
126status_t
127BFile::SetTo(const BEntry* entry, uint32 openMode)
128{
129	Unset();
130
131	if (!entry)
132		return (fCStatus = B_BAD_VALUE);
133	if (entry->InitCheck() != B_OK)
134		return (fCStatus = entry->InitCheck());
135
136	openMode |= O_CLOEXEC;
137
138	int fd = _kern_open(entry->fDirFd, entry->fName, openMode | O_CLOEXEC,
139		DEFFILEMODE & ~__gUmask);
140	if (fd >= 0) {
141		set_fd(fd);
142		fMode = openMode;
143		fCStatus = B_OK;
144	} else
145		fCStatus = fd;
146
147	return fCStatus;
148}
149
150
151// Re-initializes the BFile to the file referred to by the
152// supplied path name and according to the specified open mode.
153status_t
154BFile::SetTo(const char* path, uint32 openMode)
155{
156	Unset();
157
158	if (!path)
159		return (fCStatus = B_BAD_VALUE);
160
161	openMode |= O_CLOEXEC;
162
163	int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask);
164	if (fd >= 0) {
165		set_fd(fd);
166		fMode = openMode;
167		fCStatus = B_OK;
168	} else
169		fCStatus = fd;
170
171	return fCStatus;
172}
173
174
175// Re-initializes the BFile to the file referred to by the
176// supplied path name relative to the specified BDirectory and
177// according to the specified open mode.
178status_t
179BFile::SetTo(const BDirectory* dir, const char* path, uint32 openMode)
180{
181	Unset();
182
183	if (!dir)
184		return (fCStatus = B_BAD_VALUE);
185
186	openMode |= O_CLOEXEC;
187
188	int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask);
189	if (fd >= 0) {
190		set_fd(fd);
191		fMode = openMode;
192		fCStatus = B_OK;
193	} else
194		fCStatus = fd;
195
196	return fCStatus;
197}
198
199
200// Reports whether or not the file is readable.
201bool
202BFile::IsReadable() const
203{
204	return InitCheck() == B_OK
205		&& ((fMode & O_RWMASK) == O_RDONLY || (fMode & O_RWMASK) == O_RDWR);
206}
207
208
209// Reports whether or not the file is writable.
210bool
211BFile::IsWritable() const
212{
213	return InitCheck() == B_OK
214		&& ((fMode & O_RWMASK) == O_WRONLY || (fMode & O_RWMASK) == O_RDWR);
215}
216
217
218// Reads a number of bytes from the file into a buffer.
219ssize_t
220BFile::Read(void* buffer, size_t size)
221{
222	if (InitCheck() != B_OK)
223		return InitCheck();
224	return _kern_read(get_fd(), -1, buffer, size);
225}
226
227
228// Reads a number of bytes from a certain position within the file
229// into a buffer.
230ssize_t
231BFile::ReadAt(off_t location, void* buffer, size_t size)
232{
233	if (InitCheck() != B_OK)
234		return InitCheck();
235	if (location < 0)
236		return B_BAD_VALUE;
237
238	return _kern_read(get_fd(), location, buffer, size);
239}
240
241
242// Writes a number of bytes from a buffer into the file.
243ssize_t
244BFile::Write(const void* buffer, size_t size)
245{
246	if (InitCheck() != B_OK)
247		return InitCheck();
248	return _kern_write(get_fd(), -1, buffer, size);
249}
250
251
252// Writes a number of bytes from a buffer at a certain position
253// into the file.
254ssize_t
255BFile::WriteAt(off_t location, const void* buffer, size_t size)
256{
257	if (InitCheck() != B_OK)
258		return InitCheck();
259	if (location < 0)
260		return B_BAD_VALUE;
261
262	return _kern_write(get_fd(), location, buffer, size);
263}
264
265
266// Seeks to another read/write position within the file.
267off_t
268BFile::Seek(off_t offset, uint32 seekMode)
269{
270	if (InitCheck() != B_OK)
271		return B_FILE_ERROR;
272	return _kern_seek(get_fd(), offset, seekMode);
273}
274
275
276// Gets the current read/write position within the file.
277off_t
278BFile::Position() const
279{
280	if (InitCheck() != B_OK)
281		return B_FILE_ERROR;
282	return _kern_seek(get_fd(), 0, SEEK_CUR);
283}
284
285
286// Sets the size of the file.
287status_t
288BFile::SetSize(off_t size)
289{
290	if (InitCheck() != B_OK)
291		return InitCheck();
292	if (size < 0)
293		return B_BAD_VALUE;
294	struct stat statData;
295	statData.st_size = size;
296	return set_stat(statData, B_STAT_SIZE | B_STAT_SIZE_INSECURE);
297}
298
299
300// Gets the size of the file.
301status_t
302BFile::GetSize(off_t* size) const
303{
304	return BStatable::GetSize(size);
305}
306
307
308// Assigns another BFile to this BFile.
309BFile&
310BFile::operator=(const BFile &file)
311{
312	if (&file != this) {
313		// no need to assign us to ourselves
314		Unset();
315		if (file.InitCheck() == B_OK) {
316			// duplicate the file descriptor
317			int fd = _kern_dup(file.get_fd());
318			// set it
319			if (fd >= 0) {
320				fFd = fd;
321				fMode = file.fMode;
322				fCStatus = B_OK;
323			} else
324				fCStatus = fd;
325		}
326	}
327	return *this;
328}
329
330
331// FBC
332void BFile::_PhiloFile1() {}
333void BFile::_PhiloFile2() {}
334void BFile::_PhiloFile3() {}
335void BFile::_PhiloFile4() {}
336void BFile::_PhiloFile5() {}
337void BFile::_PhiloFile6() {}
338
339
340/*!	Gets the file descriptor of the BFile.
341
342	To be used instead of accessing the BNode's private \c fFd member directly.
343
344	\returns The file descriptor, or -1 if not properly initialized.
345*/
346int
347BFile::get_fd() const
348{
349	return fFd;
350}
351
352
353//! Overrides BNode::close_fd() for binary compatibility with BeOS R5.
354void
355BFile::close_fd()
356{
357	BNode::close_fd();
358}
359