xref: /haiku/src/system/boot/loader/file_systems/amiga_ffs/File.cpp (revision 97901ec593ec4dd50ac115c1c35a6d72f6e489a5)
1 /*
2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 ** Distributed under the terms of the OpenBeOS License.
4 */
5 
6 
7 #include "File.h"
8 
9 #include <errno.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 
13 #include <util/kernel_cpp.h>
14 
15 
16 namespace FFS {
17 
18 class Stream {
19 	public:
20 		Stream(int device, FileBlock &node);
21 		~Stream();
22 
23 		status_t InitCheck();
24 		ssize_t ReadAt(off_t offset, uint8 *buffer, size_t size);
25 
26 	private:
27 		int32 BlockOffset(off_t offset) const;
28 		int32 BlockIndex(off_t offset) const;
29 		int32 ExtensionBlockOffset(off_t offset) const;
30 		status_t ReadNextExtension();
31 
32 		int			fDevice;
33 		FileBlock	&fNode;
34 		FileBlock	fBlock;
35 		int32		fExtensionBlockOffset;
36 };
37 
38 
39 Stream::Stream(int device, FileBlock &node)
40 	:
41 	fDevice(device),
42 	fNode(node)
43 {
44 	void *buffer = malloc(fNode.BlockSize());
45 	if (buffer == NULL)
46 		return;
47 
48 	fExtensionBlockOffset = 0;
49 	fBlock.SetTo(buffer, fNode.BlockSize());
50 }
51 
52 
53 Stream::~Stream()
54 {
55 	free(fBlock.BlockData());
56 }
57 
58 
59 status_t
60 Stream::InitCheck()
61 {
62 	return fBlock.BlockData() != NULL ? B_OK : B_NO_MEMORY;
63 }
64 
65 
66 int32
67 Stream::BlockOffset(off_t offset) const
68 {
69 	return offset % fNode.BlockSize();
70 }
71 
72 
73 int32
74 Stream::BlockIndex(off_t offset) const
75 {
76 	return (offset % (fNode.BlockSize() * fNode.NumDataBlocks())) / fNode.BlockSize();
77 }
78 
79 
80 int32
81 Stream::ExtensionBlockOffset(off_t offset) const
82 {
83 	return offset / (fNode.BlockSize() * fNode.NumDataBlocks());
84 }
85 
86 
87 status_t
88 Stream::ReadNextExtension()
89 {
90 	int32 next;
91 	if (fExtensionBlockOffset == 0)
92 		next = fNode.NextExtension();
93 	else
94 		next = fBlock.NextExtension();
95 
96 	if (read_pos(fDevice, next * fNode.BlockSize(), fBlock.BlockData(), fNode.BlockSize()) < B_OK)
97 		return B_ERROR;
98 
99 	return fBlock.ValidateCheckSum();
100 }
101 
102 
103 ssize_t
104 Stream::ReadAt(off_t offset, uint8 *buffer, size_t size)
105 {
106 	if (offset < 0)
107 		return B_BAD_VALUE;
108 	if (offset + size > fNode.Size())
109 		size = fNode.Size() - offset;
110 
111 	ssize_t bytesLeft = (ssize_t)size;
112 
113 	while (bytesLeft != 0) {
114 		int32 extensionBlock = ExtensionBlockOffset(offset);
115 
116 		// get the right extension block
117 
118 		if (extensionBlock < fExtensionBlockOffset)
119 			fExtensionBlockOffset = 1;
120 
121 		while (fExtensionBlockOffset < extensionBlock) {
122 			if (ReadNextExtension() != B_OK)
123 				return B_ERROR;
124 
125 			fExtensionBlockOffset++;
126 		}
127 
128 		// read the data block into memory
129 
130 		int32 block;
131 		if (extensionBlock == 0)
132 			block = fNode.DataBlock(BlockIndex(offset));
133 		else
134 			block = fBlock.DataBlock(BlockIndex(offset));
135 
136 		int32 blockOffset = BlockOffset(offset);
137 		int32 toRead = fNode.BlockSize() - blockOffset;
138 		if (toRead > bytesLeft)
139 			toRead = bytesLeft;
140 
141 		ssize_t bytesRead = read_pos(fDevice, block * fNode.BlockSize() + blockOffset,
142 			buffer, toRead);
143 		if (bytesRead < 0)
144 			return errno;
145 
146 		bytesLeft -= bytesRead;
147 		buffer += bytesRead;
148 		offset += fNode.BlockSize() - blockOffset;
149 	}
150 
151 	return size;
152 }
153 
154 
155 //	#pragma mark -
156 
157 
158 File::File(Volume &volume, int32 block)
159 	:
160 	fVolume(volume)
161 {
162 	void *data = malloc(volume.BlockSize());
163 	if (data == NULL)
164 		return;
165 
166 	if (read_pos(volume.Device(), block * volume.BlockSize(), data, volume.BlockSize()) == volume.BlockSize())
167 		fNode.SetTo(data, volume.BlockSize());
168 }
169 
170 
171 File::~File()
172 {
173 }
174 
175 
176 status_t
177 File::InitCheck()
178 {
179 	if (!fNode.IsFile())
180 		return B_BAD_TYPE;
181 
182 	return fNode.ValidateCheckSum();
183 }
184 
185 
186 status_t
187 File::Open(void **_cookie, int mode)
188 {
189 	Stream *stream = new(nothrow) Stream(fVolume.Device(), fNode);
190 	if (stream == NULL)
191 		return B_NO_MEMORY;
192 
193 	if (stream->InitCheck() != B_OK) {
194 		delete stream;
195 		return B_NO_MEMORY;
196 	}
197 
198 	*_cookie = (void *)stream;
199 	return B_OK;
200 }
201 
202 
203 status_t
204 File::Close(void *cookie)
205 {
206 	Stream *stream = (Stream *)cookie;
207 
208 	delete stream;
209 	return B_OK;
210 }
211 
212 
213 ssize_t
214 File::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
215 {
216 	Stream *stream = (Stream *)cookie;
217 	if (stream == NULL)
218 		return B_BAD_VALUE;
219 
220 	return stream->ReadAt(pos, (uint8 *)buffer, bufferSize);
221 }
222 
223 
224 ssize_t
225 File::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
226 {
227 	return EROFS;
228 }
229 
230 
231 status_t
232 File::GetName(char *nameBuffer, size_t bufferSize) const
233 {
234 	return fNode.GetName(nameBuffer, bufferSize);
235 }
236 
237 
238 int32
239 File::Type() const
240 {
241 	return S_IFREG;
242 }
243 
244 
245 off_t
246 File::Size() const
247 {
248 	return fNode.Size();
249 }
250 
251 
252 ino_t
253 File::Inode() const
254 {
255 	return fNode.HeaderKey();
256 }
257 
258 }	// namespace FFS
259