vfs: check userland buffers before reading them.
[haiku.git] / src / system / boot / loader / file_systems / amiga_ffs / File.cpp
blobcb9da33ef38c59ff402c2f1b9c3655433208589b
1 /*
2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "File.h"
9 #include <errno.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
14 using std::nothrow;
17 namespace FFS {
20 class Stream {
21 public:
22 Stream(int device, FileBlock &node);
23 ~Stream();
25 status_t InitCheck();
26 ssize_t ReadAt(off_t offset, uint8 *buffer, size_t size);
28 private:
29 int32 BlockOffset(off_t offset) const;
30 int32 BlockIndex(off_t offset) const;
31 int32 ExtensionBlockOffset(off_t offset) const;
32 status_t ReadNextExtension();
34 int fDevice;
35 FileBlock &fNode;
36 FileBlock fBlock;
37 int32 fExtensionBlockOffset;
41 Stream::Stream(int device, FileBlock &node)
43 fDevice(device),
44 fNode(node)
46 void *buffer = malloc(fNode.BlockSize());
47 if (buffer == NULL)
48 return;
50 fExtensionBlockOffset = 0;
51 fBlock.SetTo(buffer, fNode.BlockSize());
55 Stream::~Stream()
57 free(fBlock.BlockData());
61 status_t
62 Stream::InitCheck()
64 return fBlock.BlockData() != NULL ? B_OK : B_NO_MEMORY;
68 int32
69 Stream::BlockOffset(off_t offset) const
71 return offset % fNode.BlockSize();
75 int32
76 Stream::BlockIndex(off_t offset) const
78 return (offset % (fNode.BlockSize() * fNode.NumDataBlocks())) / fNode.BlockSize();
82 int32
83 Stream::ExtensionBlockOffset(off_t offset) const
85 return offset / (fNode.BlockSize() * fNode.NumDataBlocks());
89 status_t
90 Stream::ReadNextExtension()
92 int32 next;
93 if (fExtensionBlockOffset == 0)
94 next = fNode.NextExtension();
95 else
96 next = fBlock.NextExtension();
98 if (read_pos(fDevice, next * fNode.BlockSize(), fBlock.BlockData(), fNode.BlockSize()) < B_OK)
99 return B_ERROR;
101 return fBlock.ValidateCheckSum();
105 ssize_t
106 Stream::ReadAt(off_t offset, uint8 *buffer, size_t size)
108 if (offset < 0)
109 return B_BAD_VALUE;
110 if (offset + (off_t)size > fNode.Size())
111 size = fNode.Size() - offset;
113 ssize_t bytesLeft = (ssize_t)size;
115 while (bytesLeft != 0) {
116 int32 extensionBlock = ExtensionBlockOffset(offset);
118 // get the right extension block
120 if (extensionBlock < fExtensionBlockOffset)
121 fExtensionBlockOffset = 1;
123 while (fExtensionBlockOffset < extensionBlock) {
124 if (ReadNextExtension() != B_OK)
125 return B_ERROR;
127 fExtensionBlockOffset++;
130 // read the data block into memory
132 int32 block;
133 if (extensionBlock == 0)
134 block = fNode.DataBlock(BlockIndex(offset));
135 else
136 block = fBlock.DataBlock(BlockIndex(offset));
138 int32 blockOffset = BlockOffset(offset);
139 int32 toRead = fNode.BlockSize() - blockOffset;
140 if (toRead > bytesLeft)
141 toRead = bytesLeft;
143 ssize_t bytesRead = read_pos(fDevice, block * fNode.BlockSize() + blockOffset,
144 buffer, toRead);
145 if (bytesRead < 0)
146 return errno;
148 bytesLeft -= bytesRead;
149 buffer += bytesRead;
150 offset += fNode.BlockSize() - blockOffset;
153 return size;
157 // #pragma mark -
160 File::File(Volume &volume, int32 block)
162 fVolume(volume)
164 void *data = malloc(volume.BlockSize());
165 if (data == NULL)
166 return;
168 if (read_pos(volume.Device(), block * volume.BlockSize(), data, volume.BlockSize()) == volume.BlockSize())
169 fNode.SetTo(data, volume.BlockSize());
173 File::~File()
178 status_t
179 File::InitCheck()
181 if (!fNode.IsFile())
182 return B_BAD_TYPE;
184 return fNode.ValidateCheckSum();
188 status_t
189 File::Open(void **_cookie, int mode)
191 Stream *stream = new(nothrow) Stream(fVolume.Device(), fNode);
192 if (stream == NULL)
193 return B_NO_MEMORY;
195 if (stream->InitCheck() != B_OK) {
196 delete stream;
197 return B_NO_MEMORY;
200 *_cookie = (void *)stream;
201 return B_OK;
205 status_t
206 File::Close(void *cookie)
208 Stream *stream = (Stream *)cookie;
210 delete stream;
211 return B_OK;
215 ssize_t
216 File::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
218 Stream *stream = (Stream *)cookie;
219 if (stream == NULL)
220 return B_BAD_VALUE;
222 return stream->ReadAt(pos, (uint8 *)buffer, bufferSize);
226 ssize_t
227 File::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
229 return EROFS;
233 status_t
234 File::GetName(char *nameBuffer, size_t bufferSize) const
236 return fNode.GetName(nameBuffer, bufferSize);
240 int32
241 File::Type() const
243 return S_IFREG;
247 off_t
248 File::Size() const
250 return fNode.Size();
254 ino_t
255 File::Inode() const
257 return fNode.HeaderKey();
261 } // namespace FFS