xref: /haiku/src/kits/storage/File.cpp (revision e9191cc2d1222d633e806bea3ee9c6fc806844a2)
15905a0aeSAxel Dörfler /*
2160f2d10SAxel Dörfler  * Copyright 2002-2009, Haiku Inc.
35905a0aeSAxel Dörfler  * Distributed under the terms of the MIT License.
45905a0aeSAxel Dörfler  *
55905a0aeSAxel Dörfler  * Authors:
65905a0aeSAxel Dörfler  *		Tyler Dauwalder
75905a0aeSAxel Dörfler  *		Ingo Weinhold, bonefish@users.sf.net
852a38012Sejakowatz  */
952a38012Sejakowatz 
105905a0aeSAxel Dörfler 
11b06942c6SIngo Weinhold #include <fcntl.h>
12ca9e5772SIngo Weinhold #include <unistd.h>
1352a38012Sejakowatz 
14db10640dSIngo Weinhold #include <Directory.h>
1552a38012Sejakowatz #include <Entry.h>
1652a38012Sejakowatz #include <File.h>
17a121b8c8SAxel Dörfler #include <fs_interface.h>
18b38c9e18SAxel Dörfler #include <NodeMonitor.h>
190af6bcebSOliver Tappe #include "storage_support.h"
20db10640dSIngo Weinhold 
21db10640dSIngo Weinhold #include <syscalls.h>
22160f2d10SAxel Dörfler #include <umask.h>
233af4214aSAxel Dörfler 
243af4214aSAxel Dörfler 
25*e9191cc2SJohn Scipione // Creates an uninitialized BFile.
2652a38012Sejakowatz BFile::BFile()
27160f2d10SAxel Dörfler 	:
2852a38012Sejakowatz 	fMode(0)
2952a38012Sejakowatz {
3052a38012Sejakowatz }
3152a38012Sejakowatz 
325905a0aeSAxel Dörfler 
33*e9191cc2SJohn Scipione // Creates a copy of the supplied BFile.
3452a38012Sejakowatz BFile::BFile(const BFile& file)
35160f2d10SAxel Dörfler 	:
3652a38012Sejakowatz 	fMode(0)
3752a38012Sejakowatz {
3852a38012Sejakowatz 	*this = file;
3952a38012Sejakowatz }
4052a38012Sejakowatz 
415905a0aeSAxel Dörfler 
42*e9191cc2SJohn Scipione // Creates a BFile and initializes it to the file referred to by
43*e9191cc2SJohn Scipione // the supplied entry_ref and according to the specified open mode.
4452a38012Sejakowatz BFile::BFile(const entry_ref* ref, uint32 openMode)
45160f2d10SAxel Dörfler 	:
4652a38012Sejakowatz 	fMode(0)
4752a38012Sejakowatz {
4852a38012Sejakowatz 	SetTo(ref, openMode);
4952a38012Sejakowatz }
5052a38012Sejakowatz 
515905a0aeSAxel Dörfler 
52*e9191cc2SJohn Scipione // Creates a BFile and initializes it to the file referred to by
53*e9191cc2SJohn Scipione // the supplied BEntry and according to the specified open mode.
5452a38012Sejakowatz BFile::BFile(const BEntry* entry, uint32 openMode)
55160f2d10SAxel Dörfler 	:
5652a38012Sejakowatz 	fMode(0)
5752a38012Sejakowatz {
5852a38012Sejakowatz 	SetTo(entry, openMode);
5952a38012Sejakowatz }
6052a38012Sejakowatz 
615905a0aeSAxel Dörfler 
62*e9191cc2SJohn Scipione // Creates a BFile and initializes it to the file referred to by
63*e9191cc2SJohn Scipione // the supplied path name and according to the specified open mode.
6452a38012Sejakowatz BFile::BFile(const char* path, uint32 openMode)
65160f2d10SAxel Dörfler 	:
6652a38012Sejakowatz 	fMode(0)
6752a38012Sejakowatz {
6852a38012Sejakowatz 	SetTo(path, openMode);
6952a38012Sejakowatz }
7052a38012Sejakowatz 
715905a0aeSAxel Dörfler 
72*e9191cc2SJohn Scipione // Creates a BFile and initializes it to the file referred to by
73*e9191cc2SJohn Scipione // the supplied path name relative to the specified BDirectory and
74*e9191cc2SJohn Scipione // according to the specified open mode.
7523d36867Sbeveloper BFile::BFile(const BDirectory *dir, const char* path, uint32 openMode)
76160f2d10SAxel Dörfler 	:
7752a38012Sejakowatz 	fMode(0)
7852a38012Sejakowatz {
7952a38012Sejakowatz 	SetTo(dir, path, openMode);
8052a38012Sejakowatz }
8152a38012Sejakowatz 
825905a0aeSAxel Dörfler 
83*e9191cc2SJohn Scipione // Frees all allocated resources.
8452a38012Sejakowatz BFile::~BFile()
8552a38012Sejakowatz {
8652a38012Sejakowatz 	// Also called by the BNode destructor, but we rather try to avoid
8752a38012Sejakowatz 	// problems with calling virtual functions in the base class destructor.
8852a38012Sejakowatz 	// Depending on the compiler implementation an object may be degraded to
8952a38012Sejakowatz 	// an object of the base class after the destructor of the derived class
9052a38012Sejakowatz 	// has been executed.
9152a38012Sejakowatz 	close_fd();
9252a38012Sejakowatz }
9352a38012Sejakowatz 
945905a0aeSAxel Dörfler 
95*e9191cc2SJohn Scipione // Re-initializes the BFile to the file referred to by the
96*e9191cc2SJohn Scipione // supplied entry_ref and according to the specified open mode.
9752a38012Sejakowatz status_t
9852a38012Sejakowatz BFile::SetTo(const entry_ref* ref, uint32 openMode)
9952a38012Sejakowatz {
10052a38012Sejakowatz 	Unset();
101b06942c6SIngo Weinhold 
102db10640dSIngo Weinhold 	if (!ref)
103db10640dSIngo Weinhold 		return (fCStatus = B_BAD_VALUE);
104b06942c6SIngo Weinhold 
1050af6bcebSOliver Tappe 	// if ref->name is absolute, let the path-only SetTo() do the job
1060af6bcebSOliver Tappe 	if (BPrivate::Storage::is_absolute_path(ref->name))
1070af6bcebSOliver Tappe 		return SetTo(ref->name, openMode);
1080af6bcebSOliver Tappe 
109b06942c6SIngo Weinhold 	openMode |= O_CLOEXEC;
110b06942c6SIngo Weinhold 
111db10640dSIngo Weinhold 	int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
1123af4214aSAxel Dörfler 		openMode, DEFFILEMODE & ~__gUmask);
113db10640dSIngo Weinhold 	if (fd >= 0) {
114db10640dSIngo Weinhold 		set_fd(fd);
115db10640dSIngo Weinhold 		fMode = openMode;
116db10640dSIngo Weinhold 		fCStatus = B_OK;
117db10640dSIngo Weinhold 	} else
118db10640dSIngo Weinhold 		fCStatus = fd;
119b06942c6SIngo Weinhold 
120db10640dSIngo Weinhold 	return fCStatus;
12152a38012Sejakowatz }
12252a38012Sejakowatz 
1235905a0aeSAxel Dörfler 
124*e9191cc2SJohn Scipione // Re-initializes the BFile to the file referred to by the
125*e9191cc2SJohn Scipione // supplied BEntry and according to the specified open mode.
12652a38012Sejakowatz status_t
12752a38012Sejakowatz BFile::SetTo(const BEntry* entry, uint32 openMode)
12852a38012Sejakowatz {
12952a38012Sejakowatz 	Unset();
130b06942c6SIngo Weinhold 
131db10640dSIngo Weinhold 	if (!entry)
132db10640dSIngo Weinhold 		return (fCStatus = B_BAD_VALUE);
133db10640dSIngo Weinhold 	if (entry->InitCheck() != B_OK)
134db10640dSIngo Weinhold 		return (fCStatus = entry->InitCheck());
135b06942c6SIngo Weinhold 
136b06942c6SIngo Weinhold 	openMode |= O_CLOEXEC;
137b06942c6SIngo Weinhold 
1383af4214aSAxel Dörfler 	int fd = _kern_open(entry->fDirFd, entry->fName, openMode | O_CLOEXEC,
1393af4214aSAxel Dörfler 		DEFFILEMODE & ~__gUmask);
140db10640dSIngo Weinhold 	if (fd >= 0) {
141db10640dSIngo Weinhold 		set_fd(fd);
142db10640dSIngo Weinhold 		fMode = openMode;
143db10640dSIngo Weinhold 		fCStatus = B_OK;
144db10640dSIngo Weinhold 	} else
145db10640dSIngo Weinhold 		fCStatus = fd;
146b06942c6SIngo Weinhold 
147db10640dSIngo Weinhold 	return fCStatus;
14852a38012Sejakowatz }
14952a38012Sejakowatz 
1505905a0aeSAxel Dörfler 
151*e9191cc2SJohn Scipione // Re-initializes the BFile to the file referred to by the
152*e9191cc2SJohn Scipione // supplied path name and according to the specified open mode.
15352a38012Sejakowatz status_t
15452a38012Sejakowatz BFile::SetTo(const char* path, uint32 openMode)
15552a38012Sejakowatz {
15652a38012Sejakowatz 	Unset();
157b06942c6SIngo Weinhold 
158db10640dSIngo Weinhold 	if (!path)
159db10640dSIngo Weinhold 		return (fCStatus = B_BAD_VALUE);
160b06942c6SIngo Weinhold 
161b06942c6SIngo Weinhold 	openMode |= O_CLOEXEC;
162b06942c6SIngo Weinhold 
1633af4214aSAxel Dörfler 	int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask);
164db10640dSIngo Weinhold 	if (fd >= 0) {
165db10640dSIngo Weinhold 		set_fd(fd);
166db10640dSIngo Weinhold 		fMode = openMode;
167db10640dSIngo Weinhold 		fCStatus = B_OK;
16852a38012Sejakowatz 	} else
169db10640dSIngo Weinhold 		fCStatus = fd;
170b06942c6SIngo Weinhold 
171db10640dSIngo Weinhold 	return fCStatus;
17252a38012Sejakowatz }
17352a38012Sejakowatz 
1745905a0aeSAxel Dörfler 
175*e9191cc2SJohn Scipione // Re-initializes the BFile to the file referred to by the
176*e9191cc2SJohn Scipione // supplied path name relative to the specified BDirectory and
177*e9191cc2SJohn Scipione // according to the specified open mode.
17852a38012Sejakowatz status_t
17952a38012Sejakowatz BFile::SetTo(const BDirectory* dir, const char* path, uint32 openMode)
18052a38012Sejakowatz {
18152a38012Sejakowatz 	Unset();
182b06942c6SIngo Weinhold 
183db10640dSIngo Weinhold 	if (!dir)
184db10640dSIngo Weinhold 		return (fCStatus = B_BAD_VALUE);
185b06942c6SIngo Weinhold 
186b06942c6SIngo Weinhold 	openMode |= O_CLOEXEC;
187b06942c6SIngo Weinhold 
1883af4214aSAxel Dörfler 	int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask);
189db10640dSIngo Weinhold 	if (fd >= 0) {
190db10640dSIngo Weinhold 		set_fd(fd);
191db10640dSIngo Weinhold 		fMode = openMode;
192db10640dSIngo Weinhold 		fCStatus = B_OK;
193db10640dSIngo Weinhold 	} else
194db10640dSIngo Weinhold 		fCStatus = fd;
195b06942c6SIngo Weinhold 
196db10640dSIngo Weinhold 	return fCStatus;
19752a38012Sejakowatz }
19852a38012Sejakowatz 
1995905a0aeSAxel Dörfler 
200*e9191cc2SJohn Scipione // Reports whether or not the file is readable.
20152a38012Sejakowatz bool
20252a38012Sejakowatz BFile::IsReadable() const
20352a38012Sejakowatz {
2045905a0aeSAxel Dörfler 	return InitCheck() == B_OK
2055905a0aeSAxel Dörfler 		&& ((fMode & O_RWMASK) == O_RDONLY || (fMode & O_RWMASK) == O_RDWR);
20652a38012Sejakowatz }
20752a38012Sejakowatz 
2085905a0aeSAxel Dörfler 
209*e9191cc2SJohn Scipione // Reports whether or not the file is writable.
21052a38012Sejakowatz bool
21152a38012Sejakowatz BFile::IsWritable() const
21252a38012Sejakowatz {
2135905a0aeSAxel Dörfler 	return InitCheck() == B_OK
2145905a0aeSAxel Dörfler 		&& ((fMode & O_RWMASK) == O_WRONLY || (fMode & O_RWMASK) == O_RDWR);
21552a38012Sejakowatz }
21652a38012Sejakowatz 
2175905a0aeSAxel Dörfler 
218*e9191cc2SJohn Scipione // Reads a number of bytes from the file into a buffer.
21952a38012Sejakowatz ssize_t
22052a38012Sejakowatz BFile::Read(void* buffer, size_t size)
22152a38012Sejakowatz {
222db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
223db10640dSIngo Weinhold 		return InitCheck();
224db10640dSIngo Weinhold 	return _kern_read(get_fd(), -1, buffer, size);
22552a38012Sejakowatz }
22652a38012Sejakowatz 
2275905a0aeSAxel Dörfler 
228*e9191cc2SJohn Scipione // Reads a number of bytes from a certain position within the file
229*e9191cc2SJohn Scipione // into a buffer.
23052a38012Sejakowatz ssize_t
23152a38012Sejakowatz BFile::ReadAt(off_t location, void* buffer, size_t size)
23252a38012Sejakowatz {
233db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
234db10640dSIngo Weinhold 		return InitCheck();
235db10640dSIngo Weinhold 	if (location < 0)
236db10640dSIngo Weinhold 		return B_BAD_VALUE;
2373debfe51SBruno G. Albuquerque 
2385905a0aeSAxel Dörfler 	return _kern_read(get_fd(), location, buffer, size);
23952a38012Sejakowatz }
24052a38012Sejakowatz 
2415905a0aeSAxel Dörfler 
242*e9191cc2SJohn Scipione // Writes a number of bytes from a buffer into the file.
24352a38012Sejakowatz ssize_t
24452a38012Sejakowatz BFile::Write(const void* buffer, size_t size)
24552a38012Sejakowatz {
246db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
247db10640dSIngo Weinhold 		return InitCheck();
248db10640dSIngo Weinhold 	return _kern_write(get_fd(), -1, buffer, size);
24952a38012Sejakowatz }
25052a38012Sejakowatz 
2515905a0aeSAxel Dörfler 
252*e9191cc2SJohn Scipione // Writes a number of bytes from a buffer at a certain position
253*e9191cc2SJohn Scipione // into the file.
25452a38012Sejakowatz ssize_t
25552a38012Sejakowatz BFile::WriteAt(off_t location, const void* buffer, size_t size)
25652a38012Sejakowatz {
257db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
258db10640dSIngo Weinhold 		return InitCheck();
259db10640dSIngo Weinhold 	if (location < 0)
260db10640dSIngo Weinhold 		return B_BAD_VALUE;
26140da55c3SStephan Aßmus 
2625905a0aeSAxel Dörfler 	return _kern_write(get_fd(), location, buffer, size);
26352a38012Sejakowatz }
26452a38012Sejakowatz 
2655905a0aeSAxel Dörfler 
266*e9191cc2SJohn Scipione // Seeks to another read/write position within the file.
26752a38012Sejakowatz off_t
26852a38012Sejakowatz BFile::Seek(off_t offset, uint32 seekMode)
26952a38012Sejakowatz {
270db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
271db10640dSIngo Weinhold 		return B_FILE_ERROR;
272db10640dSIngo Weinhold 	return _kern_seek(get_fd(), offset, seekMode);
27352a38012Sejakowatz }
27452a38012Sejakowatz 
2755905a0aeSAxel Dörfler 
276*e9191cc2SJohn Scipione // Gets the current read/write position within the file.
27752a38012Sejakowatz off_t
27852a38012Sejakowatz BFile::Position() const
27952a38012Sejakowatz {
280db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
281db10640dSIngo Weinhold 		return B_FILE_ERROR;
282db10640dSIngo Weinhold 	return _kern_seek(get_fd(), 0, SEEK_CUR);
28352a38012Sejakowatz }
28452a38012Sejakowatz 
2855905a0aeSAxel Dörfler 
286*e9191cc2SJohn Scipione // Sets the size of the file.
28752a38012Sejakowatz status_t
28852a38012Sejakowatz BFile::SetSize(off_t size)
28952a38012Sejakowatz {
290db10640dSIngo Weinhold 	if (InitCheck() != B_OK)
291db10640dSIngo Weinhold 		return InitCheck();
292db10640dSIngo Weinhold 	if (size < 0)
293db10640dSIngo Weinhold 		return B_BAD_VALUE;
29452a38012Sejakowatz 	struct stat statData;
29552a38012Sejakowatz 	statData.st_size = size;
296a121b8c8SAxel Dörfler 	return set_stat(statData, B_STAT_SIZE | B_STAT_SIZE_INSECURE);
29752a38012Sejakowatz }
29852a38012Sejakowatz 
2995905a0aeSAxel Dörfler 
300*e9191cc2SJohn Scipione // Gets the size of the file.
30139c991c0SStephan Aßmus status_t
30239c991c0SStephan Aßmus BFile::GetSize(off_t* size) const
30339c991c0SStephan Aßmus {
30439c991c0SStephan Aßmus 	return BStatable::GetSize(size);
30539c991c0SStephan Aßmus }
30639c991c0SStephan Aßmus 
3075905a0aeSAxel Dörfler 
308*e9191cc2SJohn Scipione // Assigns another BFile to this BFile.
30952a38012Sejakowatz BFile&
31052a38012Sejakowatz BFile::operator=(const BFile &file)
31152a38012Sejakowatz {
312*e9191cc2SJohn Scipione 	if (&file != this) {
313*e9191cc2SJohn Scipione 		// no need to assign us to ourselves
31452a38012Sejakowatz 		Unset();
31552a38012Sejakowatz 		if (file.InitCheck() == B_OK) {
31652a38012Sejakowatz 			// duplicate the file descriptor
317db10640dSIngo Weinhold 			int fd = _kern_dup(file.get_fd());
31852a38012Sejakowatz 			// set it
319db10640dSIngo Weinhold 			if (fd >= 0) {
320db10640dSIngo Weinhold 				fFd = fd;
32152a38012Sejakowatz 				fMode = file.fMode;
322db10640dSIngo Weinhold 				fCStatus = B_OK;
323db10640dSIngo Weinhold 			} else
324db10640dSIngo Weinhold 				fCStatus = fd;
32552a38012Sejakowatz 		}
32652a38012Sejakowatz 	}
32752a38012Sejakowatz 	return *this;
32852a38012Sejakowatz }
32952a38012Sejakowatz 
33052a38012Sejakowatz 
33152a38012Sejakowatz // FBC
3327c44680aSIngo Weinhold void BFile::_PhiloFile1() {}
3337c44680aSIngo Weinhold void BFile::_PhiloFile2() {}
3347c44680aSIngo Weinhold void BFile::_PhiloFile3() {}
3357c44680aSIngo Weinhold void BFile::_PhiloFile4() {}
3367c44680aSIngo Weinhold void BFile::_PhiloFile5() {}
3377c44680aSIngo Weinhold void BFile::_PhiloFile6() {}
33852a38012Sejakowatz 
33952a38012Sejakowatz 
340*e9191cc2SJohn Scipione // Gets the file descriptor of the BFile.
341db10640dSIngo Weinhold int
34252a38012Sejakowatz BFile::get_fd() const
34352a38012Sejakowatz {
34452a38012Sejakowatz 	return fFd;
34552a38012Sejakowatz }
34652a38012Sejakowatz 
3475905a0aeSAxel Dörfler 
348*e9191cc2SJohn Scipione // Overrides BNode::close_fd() for binary compatibility with BeOS R5.
3494b9ec73eSIngo Weinhold void
3504b9ec73eSIngo Weinhold BFile::close_fd()
3514b9ec73eSIngo Weinhold {
3524b9ec73eSIngo Weinhold 	BNode::close_fd();
3534b9ec73eSIngo Weinhold }
354