vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / disk / virtual / remote_disk / remote_disk.cpp
blob193811c081859bc97708faaba9f966ecdface563
1 /*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include <string.h>
8 #include <KernelExport.h>
9 #include <Drivers.h>
11 #include <lock.h>
12 #include <util/AutoLock.h>
13 #include <util/kernel_cpp.h>
15 #include "RemoteDisk.h"
18 //#define TRACE_REMOTE_DISK
19 #ifdef TRACE_REMOTE_DISK
20 # define TRACE(x) dprintf x
21 #else
22 # define TRACE(x) do {} while (false)
23 #endif
26 const bigtime_t kInitRetryDelay = 10 * 1000000LL; // 10 s
28 enum {
29 MAX_REMOTE_DISKS = 1
33 struct RemoteDiskDevice : recursive_lock {
34 RemoteDisk* remoteDisk;
35 bigtime_t lastInitRetryTime;
37 RemoteDiskDevice()
39 remoteDisk(NULL),
40 lastInitRetryTime(-1)
44 ~RemoteDiskDevice()
46 delete remoteDisk;
47 Uninit();
50 status_t Init()
52 recursive_lock_init(this, "remote disk device");
53 return B_OK;
56 void Uninit()
58 recursive_lock_destroy(this);
61 status_t LazyInitDisk()
63 if (remoteDisk)
64 return B_OK;
66 // don't try to init, if the last attempt wasn't long enough ago
67 if (lastInitRetryTime >= 0
68 && system_time() < lastInitRetryTime + kInitRetryDelay) {
69 return B_ERROR;
72 // create the object
73 remoteDisk = new(nothrow) RemoteDisk;
74 if (!remoteDisk) {
75 lastInitRetryTime = system_time();
76 return B_NO_MEMORY;
79 // find a server
80 TRACE(("remote_disk: FindAnyRemoteDisk()\n"));
81 status_t error = remoteDisk->FindAnyRemoteDisk();
82 if (error != B_OK) {
83 delete remoteDisk;
84 remoteDisk = NULL;
85 lastInitRetryTime = system_time();
86 return B_NO_MEMORY;
89 return B_OK;
92 void GetGeometry(device_geometry* geometry, bool bios)
94 // TODO: Respect "bios" argument!
95 geometry->bytes_per_sector = REMOTE_DISK_BLOCK_SIZE;
96 geometry->sectors_per_track = 1;
97 geometry->cylinder_count = remoteDisk->Size() / REMOTE_DISK_BLOCK_SIZE;
98 geometry->head_count = 1;
99 geometry->device_type = B_DISK;
100 geometry->removable = true;
101 geometry->read_only = remoteDisk->IsReadOnly();
102 geometry->write_once = false;
106 typedef RecursiveLocker DeviceLocker;
109 static const char* kPublishedNames[] = {
110 "disk/virtual/remote_disk/0/raw",
111 // "misc/remote_disk_control",
112 NULL
115 static RemoteDiskDevice* sDevices;
118 // #pragma mark - internal functions
121 // device_for_name
122 static RemoteDiskDevice*
123 device_for_name(const char* name)
125 for (int i = 0; i < MAX_REMOTE_DISKS; i++) {
126 if (strcmp(name, kPublishedNames[i]) == 0)
127 return sDevices + i;
129 return NULL;
133 // #pragma mark - data device hooks
136 static status_t
137 remote_disk_open(const char* name, uint32 flags, void** cookie)
139 RemoteDiskDevice* device = device_for_name(name);
140 TRACE(("remote_disk_open(\"%s\") -> %p\n", name, device));
141 if (!device)
142 return B_BAD_VALUE;
144 DeviceLocker locker(device);
145 status_t error = device->LazyInitDisk();
146 if (error != B_OK)
147 return error;
149 *cookie = device;
151 return B_OK;
155 static status_t
156 remote_disk_close(void* cookie)
158 TRACE(("remote_disk_close(%p)\n", cookie));
160 // nothing to do
161 return B_OK;
165 static status_t
166 remote_disk_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
168 TRACE(("remote_disk_read(%p, %lld, %p, %lu)\n", cookie, position, buffer,
169 *numBytes));
171 RemoteDiskDevice* device = (RemoteDiskDevice*)cookie;
172 DeviceLocker locker(device);
174 ssize_t bytesRead = device->remoteDisk->ReadAt(position, buffer, *numBytes);
175 if (bytesRead < 0) {
176 *numBytes = 0;
177 TRACE(("remote_disk_read() failed: %s\n", strerror(bytesRead)));
178 return bytesRead;
181 *numBytes = bytesRead;
182 TRACE(("remote_disk_read() done: %ld\n", bytesRead));
183 return B_OK;
187 static status_t
188 remote_disk_write(void* cookie, off_t position, const void* buffer,
189 size_t* numBytes)
191 TRACE(("remote_disk_write(%p, %lld, %p, %lu)\n", cookie, position, buffer,
192 *numBytes));
194 RemoteDiskDevice* device = (RemoteDiskDevice*)cookie;
195 DeviceLocker locker(device);
197 ssize_t bytesWritten = device->remoteDisk->WriteAt(position, buffer,
198 *numBytes);
199 if (bytesWritten < 0) {
200 *numBytes = 0;
201 TRACE(("remote_disk_write() failed: %s\n", strerror(bytesRead)));
202 return bytesWritten;
205 *numBytes = bytesWritten;
206 TRACE(("remote_disk_written() done: %ld\n", bytesWritten));
207 return B_OK;
211 static status_t
212 remote_disk_control(void* cookie, uint32 op, void* arg, size_t len)
214 TRACE(("remote_disk_control(%p, %lu, %p, %lu)\n", cookie, op, arg, len));
216 RemoteDiskDevice* device = (RemoteDiskDevice*)cookie;
217 DeviceLocker locker(device);
219 // used data device
220 switch (op) {
221 case B_GET_DEVICE_SIZE:
222 TRACE(("remote_disk: B_GET_DEVICE_SIZE\n"));
223 *(size_t*)arg = device->remoteDisk->Size();
224 return B_OK;
226 case B_SET_NONBLOCKING_IO:
227 TRACE(("remote_disk: B_SET_NONBLOCKING_IO\n"));
228 return B_OK;
230 case B_SET_BLOCKING_IO:
231 TRACE(("remote_disk: B_SET_BLOCKING_IO\n"));
232 return B_OK;
234 case B_GET_READ_STATUS:
235 TRACE(("remote_disk: B_GET_READ_STATUS\n"));
236 *(bool*)arg = true;
237 return B_OK;
239 case B_GET_WRITE_STATUS:
240 TRACE(("remote_disk: B_GET_WRITE_STATUS\n"));
241 *(bool*)arg = true;
242 return B_OK;
244 case B_GET_ICON:
246 TRACE(("remote_disk: B_GET_ICON\n"));
247 return B_BAD_VALUE;
250 case B_GET_GEOMETRY:
251 TRACE(("remote_disk: B_GET_GEOMETRY\n"));
252 device->GetGeometry((device_geometry*)arg, false);
253 return B_OK;
255 case B_GET_BIOS_GEOMETRY:
257 TRACE(("remote_disk: B_GET_BIOS_GEOMETRY\n"));
258 device->GetGeometry((device_geometry*)arg, true);
259 return B_OK;
262 case B_GET_MEDIA_STATUS:
263 TRACE(("remote_disk: B_GET_MEDIA_STATUS\n"));
264 *(status_t*)arg = B_NO_ERROR;
265 return B_OK;
267 case B_SET_UNINTERRUPTABLE_IO:
268 TRACE(("remote_disk: B_SET_UNINTERRUPTABLE_IO\n"));
269 return B_OK;
271 case B_SET_INTERRUPTABLE_IO:
272 TRACE(("remote_disk: B_SET_INTERRUPTABLE_IO\n"));
273 return B_OK;
275 case B_FLUSH_DRIVE_CACHE:
276 TRACE(("remote_disk: B_FLUSH_DRIVE_CACHE\n"));
277 return B_OK;
279 case B_GET_BIOS_DRIVE_ID:
280 TRACE(("remote_disk: B_GET_BIOS_DRIVE_ID\n"));
281 *(uint8*)arg = 0xF8;
282 return B_OK;
284 case B_GET_DRIVER_FOR_DEVICE:
285 case B_SET_DEVICE_SIZE:
286 case B_SET_PARTITION:
287 case B_FORMAT_DEVICE:
288 case B_EJECT_DEVICE:
289 case B_LOAD_MEDIA:
290 case B_GET_NEXT_OPEN_DEVICE:
291 TRACE(("remote_disk: another ioctl: %lx (%lu)\n", op, op));
292 return B_BAD_VALUE;
294 default:
295 TRACE(("remote_disk: unknown ioctl: %lx (%lu)\n", op, op));
296 return B_BAD_VALUE;
301 static status_t
302 remote_disk_free(void* cookie)
304 TRACE(("remote_disk_free(%p)\n", cookie));
306 // nothing to do
307 return B_OK;
311 static device_hooks sDataDeviceHooks = {
312 remote_disk_open,
313 remote_disk_close,
314 remote_disk_free,
315 remote_disk_control,
316 remote_disk_read,
317 remote_disk_write
321 // #pragma mark - public API
324 int32 api_version = B_CUR_DRIVER_API_VERSION;
327 status_t
328 init_hardware(void)
330 TRACE(("remote_disk: init_hardware()\n"));
332 return B_OK;
336 status_t
337 init_driver(void)
339 TRACE(("remote_disk: init_driver()\n"));
341 sDevices = new(nothrow) RemoteDiskDevice[MAX_REMOTE_DISKS];
342 if (!sDevices)
343 return B_NO_MEMORY;
345 status_t error = B_OK;
346 for (int i = 0; error == B_OK && i < MAX_REMOTE_DISKS; i++)
347 error = sDevices[i].Init();
349 if (error != B_OK) {
350 delete[] sDevices;
351 sDevices = NULL;
352 return error;
355 return B_OK;
359 void
360 uninit_driver(void)
362 TRACE(("remote_disk: uninit_driver()\n"));
364 delete[] sDevices;
368 const char**
369 publish_devices(void)
371 TRACE(("remote_disk: publish_devices()\n"));
372 return kPublishedNames;
376 device_hooks*
377 find_device(const char* name)
379 TRACE(("remote_disk: find_device(%s)\n", name));
380 return &sDataDeviceHooks;