2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include "FileDevice.h"
15 #include <fs_interface.h>
20 static const uint32 kBlockSize
= 512;
22 static const uint8 kDeviceIcon
[] = {
23 0x6e, 0x63, 0x69, 0x66, 0x08, 0x05, 0x00, 0x04, 0x00, 0x54, 0x02, 0x00,
24 0x06, 0x02, 0x3b, 0x01, 0x9b, 0x3a, 0xa2, 0x35, 0xbc, 0x24, 0x3e, 0x3c,
25 0x71, 0xd2, 0x48, 0xd1, 0x7c, 0x49, 0x84, 0x91, 0x00, 0xe7, 0xbb, 0x8f,
26 0xff, 0xc9, 0x98, 0x67, 0x02, 0x00, 0x06, 0x02, 0x3b, 0xa7, 0x11, 0x38,
27 0xd0, 0xc8, 0xbb, 0xf4, 0xb8, 0x3e, 0x90, 0xe6, 0x4a, 0xed, 0x7c, 0x48,
28 0x5b, 0xd7, 0x00, 0x8a, 0x56, 0x1d, 0xff, 0xb5, 0x7a, 0x3a, 0x02, 0x00,
29 0x06, 0x02, 0xbb, 0x6f, 0xcb, 0xb8, 0xd4, 0xc8, 0x39, 0xaa, 0x71, 0xbc,
30 0x39, 0x92, 0x49, 0x2f, 0xf1, 0x48, 0xd9, 0x6a, 0x00, 0xff, 0xc7, 0x90,
31 0xff, 0xff, 0xf4, 0xea, 0x03, 0x66, 0x33, 0x00, 0x03, 0xff, 0xdf, 0xc0,
32 0x03, 0xad, 0x72, 0x38, 0x11, 0x0a, 0x06, 0x26, 0x54, 0x3a, 0x46, 0x4c,
33 0x45, 0x5c, 0x4b, 0x4c, 0x60, 0x3e, 0x60, 0x0a, 0x06, 0x38, 0x22, 0x26,
34 0x2e, 0x26, 0x4f, 0x3c, 0x5a, 0x4e, 0x48, 0x4e, 0x2a, 0x0a, 0x04, 0x26,
35 0x2e, 0x26, 0x4f, 0x3c, 0x5a, 0x3c, 0x37, 0x0a, 0x04, 0x3c, 0x37, 0x3c,
36 0x5a, 0x4e, 0x48, 0x4e, 0x2a, 0x0a, 0x04, 0x38, 0x22, 0x26, 0x2e, 0x3c,
37 0x37, 0x4e, 0x2a, 0x0a, 0x04, 0x28, 0x32, 0x28, 0x4e, 0x3a, 0x57, 0x3a,
38 0x39, 0x0a, 0x04, 0x2a, 0x4d, 0x2b, 0x46, 0x38, 0x49, 0x2a, 0x43, 0x0a,
39 0x04, 0x2a, 0x4d, 0x36, 0x52, 0x38, 0x49, 0x2b, 0x46, 0x0a, 0x04, 0x2a,
40 0x4d, 0x38, 0x54, 0x38, 0x49, 0x36, 0x52, 0x0a, 0x04, 0x2e, 0x4c, 0xbb,
41 0x2b, 0xc5, 0xd3, 0xbb, 0x2b, 0xc5, 0x07, 0x2e, 0x4a, 0x0a, 0x04, 0x2c,
42 0x49, 0x34, 0x4d, 0x34, 0x4b, 0x2c, 0x47, 0x0a, 0x04, 0x2a, 0x35, 0x2a,
43 0x40, 0x2b, 0x38, 0x38, 0x3b, 0x0a, 0x04, 0x36, 0x44, 0x2a, 0x40, 0x38,
44 0x46, 0x38, 0x3b, 0x0a, 0x04, 0x2b, 0x38, 0x2a, 0x40, 0x36, 0x44, 0x38,
45 0x3b, 0x0a, 0x04, 0x2e, 0xbe, 0x67, 0x2e, 0xbf, 0x33, 0xbb, 0x2d, 0xc0,
46 0x3f, 0xbb, 0x2d, 0xbf, 0x73, 0x0a, 0x04, 0x2c, 0xbd, 0x29, 0x2c, 0xbd,
47 0xf5, 0x34, 0x3f, 0x34, 0x3d, 0x08, 0x02, 0x2a, 0x4e, 0x2a, 0x54, 0x0e,
48 0x0a, 0x01, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x10, 0x10, 0x01, 0x17,
49 0x84, 0x20, 0x04, 0x0a, 0x00, 0x01, 0x10, 0x30, 0x30, 0x29, 0x01, 0x17,
50 0x84, 0x20, 0x04, 0x0a, 0x00, 0x01, 0x10, 0x30, 0x40, 0x1b, 0x01, 0x17,
51 0x84, 0x20, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x10, 0x01, 0x17, 0x84, 0x00,
52 0x04, 0x0a, 0x02, 0x01, 0x02, 0x00, 0x0a, 0x03, 0x01, 0x03, 0x00, 0x0a,
53 0x04, 0x01, 0x04, 0x00, 0x0a, 0x05, 0x01, 0x05, 0x00, 0x0a, 0x06, 0x02,
54 0x0b, 0x06, 0x00, 0x0a, 0x02, 0x02, 0x07, 0x0d, 0x00, 0x0a, 0x07, 0x02,
55 0x0c, 0x08, 0x00, 0x0a, 0x03, 0x02, 0x09, 0x0e, 0x08, 0x15, 0xff, 0x0a,
56 0x00, 0x02, 0x0a, 0x0f, 0x08, 0x15, 0xff
60 struct FileDevice::Cookie
{
77 FileDevice::FileDevice()
85 FileDevice::~FileDevice()
93 FileDevice::Init(const char* path
)
95 fFD
= open(path
, O_RDONLY
| O_NOTRAVERSE
);
100 if (fstat(fFD
, &st
) != 0)
103 if (!S_ISREG(st
.st_mode
))
106 fFileSize
= st
.st_size
/ kBlockSize
* kBlockSize
;
113 FileDevice::InitDevice()
120 FileDevice::UninitDevice()
126 FileDevice::Removed()
133 FileDevice::HasSelect() const
140 FileDevice::HasDeselect() const
147 FileDevice::HasRead() const
154 FileDevice::HasWrite() const
161 FileDevice::HasIO() const
169 FileDevice::Open(const char* path
, int openMode
, void** _cookie
)
173 status_t error
= vfs_get_vnode_from_fd(fFD
, true, &vnode
);
178 int fd
= vfs_open_vnode(vnode
, openMode
, true);
180 vfs_put_vnode(vnode
);
183 // our vnode reference does now belong to the FD
185 Cookie
* cookie
= new(std::nothrow
) Cookie(fd
);
186 if (cookie
== NULL
) {
197 FileDevice::Read(void* _cookie
, off_t pos
, void* buffer
, size_t* _length
)
199 Cookie
* cookie
= (Cookie
*)_cookie
;
201 ssize_t bytesRead
= pread(cookie
->fd
, buffer
, *_length
, pos
);
207 *_length
= bytesRead
;
213 FileDevice::Write(void* _cookie
, off_t pos
, const void* buffer
, size_t* _length
)
215 Cookie
* cookie
= (Cookie
*)_cookie
;
217 ssize_t bytesWritten
= pwrite(cookie
->fd
, buffer
, *_length
, pos
);
218 if (bytesWritten
< 0) {
223 *_length
= bytesWritten
;
229 FileDevice::IO(void* _cookie
, io_request
* request
)
231 // Cookie* cookie = (Cookie*)_cookie;
232 // return do_fd_io(cookie->fd, request);
233 // TODO: The implementation is fine in principle, but do_fd_io() requires either
234 // the io() hook or the {read,write}_pages() hooks of the underlying FS to be
235 // implemented, which we can't guarantee. do_fd_io() should work around by using
236 // read() and write(), but it's all quite of a mess, since we mix up the io()
237 // hook -- which ATM has the semantics of uncached_io() hook (i.e. ignoring the
238 // file cache) -- with the actual io() hook semantics (i.e. using the file
240 return B_UNSUPPORTED
;
244 template<typename ResultType
>
246 set_ioctl_result(const ResultType
& result
, void* buffer
, size_t length
)
248 // NOTE: We omit the buffer size check for sake of callers (e.g. BFS) not
249 // specifying a length argument.
250 // if (sizeof(ResultType) < length)
251 // return B_BAD_VALUE;
254 return B_BAD_ADDRESS
;
256 if (!IS_USER_ADDRESS(buffer
))
257 return user_memcpy(buffer
, &result
, sizeof(ResultType
));
259 memcpy(buffer
, &result
, sizeof(ResultType
));
265 FileDevice::Control(void* _cookie
, int32 op
, void* buffer
, size_t length
)
267 Cookie
* cookie
= (Cookie
*)_cookie
;
270 case B_GET_DEVICE_SIZE
:
271 return set_ioctl_result(
272 (uint64
)fFileSize
> (uint64
)(~(size_t)0) ? ~(size_t)0 : (size_t)fFileSize
,
275 case B_SET_BLOCKING_IO
:
276 case B_SET_NONBLOCKING_IO
:
277 // TODO: Translate to O_NONBLOCK and pass on!
280 case B_GET_READ_STATUS
:
281 case B_GET_WRITE_STATUS
:
282 // TODO: poll() the FD!
283 return set_ioctl_result(true, buffer
, length
);
286 return B_UNSUPPORTED
;
288 case B_GET_ICON_NAME
:
289 return user_strlcpy((char *)buffer
, "devices/device-volume",
293 case B_GET_VECTOR_ICON
:
295 if (length
!= sizeof(device_icon
)) {
299 device_icon iconData
;
300 if (user_memcpy(&iconData
, buffer
, sizeof(device_icon
)) != B_OK
) {
301 return B_BAD_ADDRESS
;
304 if (iconData
.icon_size
>= (int32
)sizeof(kDeviceIcon
)) {
305 if (user_memcpy(iconData
.icon_data
, kDeviceIcon
,
306 sizeof(kDeviceIcon
)) != B_OK
) {
307 return B_BAD_ADDRESS
;
311 iconData
.icon_size
= sizeof(kDeviceIcon
);
312 return user_memcpy(buffer
, &iconData
, sizeof(device_icon
));
316 case B_GET_BIOS_GEOMETRY
:
318 // fill in the geometry
319 // Optimally we have only 1 block per sector and only one head.
320 // Since we have only a uint32 for the cylinder count, this won't
321 // work for files > 2TB. So, we set the head count to the minimally
323 off_t blocks
= fFileSize
/ kBlockSize
;
324 uint32 heads
= (blocks
+ 0xfffffffe) / 0xffffffff;
328 device_geometry geometry
;
329 geometry
.bytes_per_sector
= kBlockSize
;
330 geometry
.sectors_per_track
= 1;
331 geometry
.cylinder_count
= blocks
/ heads
;
332 geometry
.head_count
= heads
;
333 geometry
.device_type
= B_DISK
;
334 geometry
.removable
= false;
335 geometry
.read_only
= false;
336 geometry
.write_once
= false;
338 return set_ioctl_result(geometry
, buffer
, length
);
341 case B_GET_MEDIA_STATUS
:
342 return set_ioctl_result((status_t
)B_OK
, buffer
, length
);
344 case B_SET_INTERRUPTABLE_IO
:
345 case B_SET_UNINTERRUPTABLE_IO
:
348 case B_FLUSH_DRIVE_CACHE
:
349 return fsync(cookie
->fd
) == 0 ? B_OK
: errno
;
351 case B_GET_BIOS_DRIVE_ID
:
352 return set_ioctl_result((uint8
)0xf8, buffer
, length
);
354 case B_GET_DRIVER_FOR_DEVICE
:
355 case B_SET_DEVICE_SIZE
:
356 case B_SET_PARTITION
:
357 case B_FORMAT_DEVICE
:
360 case B_GET_NEXT_OPEN_DEVICE
:
370 FileDevice::Select(void* _cookie
, uint8 event
, selectsync
* sync
)
372 // TODO: Support (select_fd())!
373 return B_UNSUPPORTED
;
378 FileDevice::Deselect(void* cookie
, uint8 event
, selectsync
* sync
)
380 // TODO: Support (deselect_fd())!
381 return B_UNSUPPORTED
;
386 FileDevice::Close(void* cookie
)
388 // TODO: This should probably really close the FD. Depending on the
389 // underlying FS operations could block and close() would be needed to
396 FileDevice::Free(void* _cookie
)
398 delete (Cookie
*)_cookie
;