1 // ----------------------------------------------------------------------
2 // This software is part of the Haiku distribution and is covered
3 // by the MIT License.
4 //
5 // File Name: virtualdrive.c
6 //
7 // Description: Driver that emulates virtual drives.
8 //
9 // Author: Marcus Overhagen <Marcus@Overhagen.de>
10 // Ingo Weinhold <bonefish@users.sf.net>
11 // Axel Doerfler <axeld@pinc-software.de>
12 // ----------------------------------------------------------------------
13
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <malloc.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <KernelExport.h>
22 #include <Drivers.h>
23 #include <Errors.h>
24
25 #include "lock.h"
26 #include "virtualdrive.h"
27 #include "virtualdrive_icon.h"
28
29 /*
30 [2:07] <geist> when you open the file in the driver, use stat() to see if it's a file. if it is, call ioctl 10000 on the underlying file
31 [2:07] <geist> that's the disable-cache ioctl
32 [2:08] <geist> bfs is probably doing the same algorithm, and seeing that you are a device and not a file, and so it doesn't call 10000 on you
33 [2:08] <marcus_o> thanks, I will try calling it
34 [2:08] <geist> and dont bother using dosfs as a host fs, it wont work
35 [2:09] <geist> bfs is the only fs that's reasonably safe being reentered like that, but only if the underlying one is opened with the cache disabled on that file
36 [2:09] <geist> that ioctl is used on the swap file as well
37 [2:10] <marcus_o> I'm currently allocating memory in the driver's write() function hook
38 [2:10] <geist> cant do that
39 */
40
41 //#define TRACE(x) dprintf x
42 #define TRACE(x) ;
43 #define MB (1024LL * 1024LL)
44
45 static int dev_index_for_path(const char *path);
46
47 /* -----
48 null-terminated array of device names supported by this driver
49 ----- */
50
51 static const char *sVirtualDriveName[] = {
52 VIRTUAL_DRIVE_DIRECTORY_REL "/0",
53 VIRTUAL_DRIVE_DIRECTORY_REL "/1",
54 VIRTUAL_DRIVE_DIRECTORY_REL "/2",
55 VIRTUAL_DRIVE_DIRECTORY_REL "/3",
56 VIRTUAL_DRIVE_DIRECTORY_REL "/4",
57 VIRTUAL_DRIVE_DIRECTORY_REL "/5",
58 VIRTUAL_DRIVE_DIRECTORY_REL "/6",
59 VIRTUAL_DRIVE_DIRECTORY_REL "/7",
60 VIRTUAL_DRIVE_DIRECTORY_REL "/8",
61 VIRTUAL_DRIVE_DIRECTORY_REL "/9",
62 VIRTUAL_DRIVE_CONTROL_DEVICE_REL,
63 NULL
64 };
65
66 int32 api_version = B_CUR_DRIVER_API_VERSION;
67 extern device_hooks sVirtualDriveHooks;
68
69 lock driverlock;
70
71 typedef struct device_info {
72 int32 open_count;
73 int fd;
74 off_t size;
75 bool unused;
76 bool registered;
77 char file[B_PATH_NAME_LENGTH];
78 const char *device_path;
79 device_geometry geometry;
80 } device_info;
81
82 #define kDeviceCount 11
83 #define kDataDeviceCount (kDeviceCount - 1)
84 #define kControlDevice (kDeviceCount - 1)
85 struct device_info gDeviceInfos[kDeviceCount];
86
87 static int32 gRegistrationCount = 0;
88 static int gControlDeviceFD = -1;
89
90 static thread_id gLockOwner = -1;
91 static int32 gLockOwnerNesting = 0;
92
93
94 // lock_driver
95 void
lock_driver()96 lock_driver()
97 {
98 thread_id thread = find_thread(NULL);
99 if (gLockOwner != thread) {
100 LOCK(driverlock);
101 gLockOwner = thread;
102 }
103 gLockOwnerNesting++;
104 }
105
106
107 // unlock_driver
108 void
unlock_driver()109 unlock_driver()
110 {
111 thread_id thread = find_thread(NULL);
112 if (gLockOwner == thread && --gLockOwnerNesting == 0) {
113 gLockOwner = -1;
114 UNLOCK(driverlock);
115 }
116 }
117
118
119 // is_valid_device_index
120 static inline
121 bool
is_valid_device_index(int32 index)122 is_valid_device_index(int32 index)
123 {
124 return (index >= 0 && index < kDeviceCount);
125 }
126
127
128 // is_valid_data_device_index
129 static inline
130 bool
is_valid_data_device_index(int32 index)131 is_valid_data_device_index(int32 index)
132 {
133 return (is_valid_device_index(index) && index != kControlDevice);
134 }
135
136
137 // dev_index_for_path
138 static
139 int
dev_index_for_path(const char * path)140 dev_index_for_path(const char *path)
141 {
142 int i;
143 for (i = 0; i < kDeviceCount; i++) {
144 if (!strcmp(path, gDeviceInfos[i].device_path))
145 return i;
146 }
147 return -1;
148 }
149
150
151 // clear_device_info
152 static
153 void
clear_device_info(int32 index)154 clear_device_info(int32 index)
155 {
156 TRACE(("virtualdrive: clear_device_info(%ld)\n", index));
157
158 device_info &info = gDeviceInfos[index];
159 info.open_count = 0;
160 info.fd = -1;
161 info.size = 0;
162 info.unused = (index != kDeviceCount - 1);
163 info.registered = !info.unused;
164 info.file[0] = '\0';
165 info.device_path = sVirtualDriveName[index];
166 info.geometry.read_only = true;
167 }
168
169
170 // init_device_info
171 static
172 status_t
init_device_info(int32 index,virtual_drive_info * initInfo)173 init_device_info(int32 index, virtual_drive_info *initInfo)
174 {
175 if (!is_valid_data_device_index(index) || !initInfo)
176 return B_BAD_VALUE;
177
178 device_info &info = gDeviceInfos[index];
179 if (!info.unused)
180 return B_BAD_VALUE;
181
182 bool readOnly = (initInfo->use_geometry && initInfo->geometry.read_only);
183
184 // open the file
185 int fd = open(initInfo->file_name, (readOnly ? O_RDONLY : O_RDWR));
186 if (fd < 0)
187 return errno;
188
189 status_t error = B_OK;
190
191 // get the file size
192 off_t fileSize = 0;
193 struct stat st;
194 if (fstat(fd, &st) == 0)
195 fileSize = st.st_size;
196 else
197 error = errno;
198
199 // If we shall use the supplied geometry, we enlarge the file, if
200 // necessary. Otherwise we fill in the geometry according to the size of the file.
201 off_t size = 0;
202 if (error == B_OK) {
203 if (initInfo->use_geometry) {
204 // use the supplied geometry
205 info.geometry = initInfo->geometry;
206 size = (off_t)info.geometry.bytes_per_sector
207 * info.geometry.sectors_per_track
208 * info.geometry.cylinder_count
209 * info.geometry.head_count;
210 if (size > fileSize) {
211 if (!readOnly) {
212 if (ftruncate(fd, size) != 0)
213 error = errno;
214 } else
215 error = B_NOT_ALLOWED;
216 }
217 } else {
218 // fill in the geometry
219 // default to 512 bytes block size
220 uint32 blockSize = 512;
221 // Optimally we have only 1 block per sector and only one head.
222 // Since we have only a uint32 for the cylinder count, this won't work
223 // for files > 2TB. So, we set the head count to the minimally possible
224 // value.
225 off_t blocks = fileSize / blockSize;
226 uint32 heads = (blocks + ULONG_MAX - 1) / ULONG_MAX;
227 if (heads == 0)
228 heads = 1;
229 info.geometry.bytes_per_sector = blockSize;
230 info.geometry.sectors_per_track = 1;
231 info.geometry.cylinder_count = blocks / heads;
232 info.geometry.head_count = heads;
233 info.geometry.device_type = B_DISK; // TODO: Add a new constant.
234 info.geometry.removable = false;
235 info.geometry.read_only = false;
236 info.geometry.write_once = false;
237 size = (off_t)info.geometry.bytes_per_sector
238 * info.geometry.sectors_per_track
239 * info.geometry.cylinder_count
240 * info.geometry.head_count;
241 }
242 }
243
244 if (error == B_OK) {
245 // Disable caching for underlying file! (else this driver will deadlock)
246 // We probably cannot resize the file once the cache has been disabled!
247
248 // This applies to BeOS only:
249 // Work around a bug in BFS: the file is not synced before the cache is
250 // turned off, and thus causing possible inconsistencies.
251 // Unfortunately, this only solves one half of the issue; there is
252 // no way to remove the blocks in the cache, so changes made to the
253 // image have the chance to get lost.
254 fsync(fd);
255
256 // This is a special reserved ioctl() opcode not defined anywhere in
257 // the Be headers.
258 if (ioctl(fd, 10000) != 0) {
259 dprintf("virtualdrive: disable caching ioctl failed\n");
260 return errno;
261 }
262 }
263
264 // fill in the rest of the device_info structure
265 if (error == B_OK) {
266 // open_count doesn't have to be changed here (virtualdrive_open() will do that for us)
267 info.fd = fd;
268 info.size = size;
269 info.unused = false;
270 info.registered = true;
271 strcpy(info.file, initInfo->file_name);
272 info.device_path = sVirtualDriveName[index];
273 } else {
274 // cleanup on error
275 close(fd);
276 if (info.open_count == 0)
277 clear_device_info(index);
278 }
279 return error;
280 }
281
282
283 // uninit_device_info
284 static
285 status_t
uninit_device_info(int32 index)286 uninit_device_info(int32 index)
287 {
288 if (!is_valid_data_device_index(index))
289 return B_BAD_VALUE;
290
291 device_info &info = gDeviceInfos[index];
292 if (info.unused)
293 return B_BAD_VALUE;
294
295 close(info.fd);
296 clear_device_info(index);
297 return B_OK;
298 }
299
300
301 // #pragma mark -
302 // public driver API
303
304
305 status_t
init_hardware(void)306 init_hardware(void)
307 {
308 TRACE(("virtualdrive: init_hardware\n"));
309 return B_OK;
310 }
311
312
313 status_t
init_driver(void)314 init_driver(void)
315 {
316 TRACE(("virtualdrive: init\n"));
317
318 new_lock(&driverlock, "virtualdrive lock");
319
320 // init the device infos
321 for (int32 i = 0; i < kDeviceCount; i++)
322 clear_device_info(i);
323
324 return B_OK;
325 }
326
327
328 void
uninit_driver(void)329 uninit_driver(void)
330 {
331 TRACE(("virtualdrive: uninit\n"));
332 free_lock(&driverlock);
333 }
334
335
336 const char **
publish_devices(void)337 publish_devices(void)
338 {
339 TRACE(("virtualdrive: publish_devices\n"));
340 return sVirtualDriveName;
341 }
342
343
344 device_hooks *
find_device(const char * name)345 find_device(const char* name)
346 {
347 TRACE(("virtualdrive: find_device(%s)\n", name));
348 return &sVirtualDriveHooks;
349 }
350
351
352 // #pragma mark -
353 // the device hooks
354
355
356 static status_t
virtualdrive_open(const char * name,uint32 flags,void ** cookie)357 virtualdrive_open(const char *name, uint32 flags, void **cookie)
358 {
359 TRACE(("virtualdrive: open %s\n",name));
360
361 *cookie = (void *)-1;
362
363 lock_driver();
364
365 int32 devIndex = dev_index_for_path(name);
366
367 TRACE(("virtualdrive: devIndex %ld!\n", devIndex));
368
369 if (!is_valid_device_index(devIndex)) {
370 TRACE(("virtualdrive: wrong index!\n"));
371 unlock_driver();
372 return B_ERROR;
373 }
374
375 if (gDeviceInfos[devIndex].unused) {
376 TRACE(("virtualdrive: device is unused!\n"));
377 unlock_driver();
378 return B_ERROR;
379 }
380
381 if (!gDeviceInfos[devIndex].registered) {
382 TRACE(("virtualdrive: device has been unregistered!\n"));
383 unlock_driver();
384 return B_ERROR;
385 }
386
387 // store index in cookie
388 *cookie = (void *)devIndex;
389
390 gDeviceInfos[devIndex].open_count++;
391
392 unlock_driver();
393 return B_OK;
394 }
395
396
397 static status_t
virtualdrive_close(void * cookie)398 virtualdrive_close(void *cookie)
399 {
400 int32 devIndex = (int)cookie;
401
402 TRACE(("virtualdrive: close() devIndex = %ld\n", devIndex));
403 if (!is_valid_data_device_index(devIndex))
404 return B_OK;
405
406 lock_driver();
407
408 gDeviceInfos[devIndex].open_count--;
409 if (gDeviceInfos[devIndex].open_count == 0 && !gDeviceInfos[devIndex].registered) {
410 // The last FD is closed and the device has been unregistered. Free its info.
411 uninit_device_info(devIndex);
412 }
413
414 unlock_driver();
415
416 return B_OK;
417 }
418
419
420 static status_t
virtualdrive_read(void * cookie,off_t position,void * buffer,size_t * numBytes)421 virtualdrive_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
422 {
423 TRACE(("virtualdrive: read pos = 0x%08Lx, bytes = 0x%08lx\n", position, *numBytes));
424
425 // check parameters
426 int devIndex = (int)cookie;
427 if (devIndex == kControlDevice) {
428 TRACE(("virtualdrive: reading from control device not allowed\n"));
429 return B_NOT_ALLOWED;
430 }
431 if (position < 0)
432 return B_BAD_VALUE;
433
434 lock_driver();
435 device_info &info = gDeviceInfos[devIndex];
436 // adjust position and numBytes according to the file size
437 if (position > info.size)
438 position = info.size;
439 if (position + *numBytes > info.size)
440 *numBytes = info.size - position;
441 // read
442 status_t error = B_OK;
443 ssize_t bytesRead = read_pos(info.fd, position, buffer, *numBytes);
444 if (bytesRead < 0)
445 error = errno;
446 else
447 *numBytes = bytesRead;
448 unlock_driver();
449 return error;
450 }
451
452
453 static status_t
virtualdrive_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)454 virtualdrive_write(void *cookie, off_t position, const void *buffer, size_t *numBytes)
455 {
456 TRACE(("virtualdrive: write pos = 0x%08Lx, bytes = 0x%08lx\n", position, *numBytes));
457
458 // check parameters
459 int devIndex = (int)cookie;
460 if (devIndex == kControlDevice) {
461 TRACE(("virtualdrive: writing to control device not allowed\n"));
462 return B_NOT_ALLOWED;
463 }
464 if (position < 0)
465 return B_BAD_VALUE;
466
467 lock_driver();
468 device_info &info = gDeviceInfos[devIndex];
469 // adjust position and numBytes according to the file size
470 if (position > info.size)
471 position = info.size;
472 if (position + *numBytes > info.size)
473 *numBytes = info.size - position;
474 // read
475 status_t error = B_OK;
476 ssize_t bytesRead = write_pos(info.fd, position, buffer, *numBytes);
477 if (bytesRead < 0)
478 error = errno;
479 else
480 *numBytes = bytesRead;
481 unlock_driver();
482 return error;
483 }
484
485
486 static status_t
virtualdrive_control(void * cookie,uint32 op,void * arg,size_t len)487 virtualdrive_control(void *cookie, uint32 op, void *arg, size_t len)
488 {
489 TRACE(("virtualdrive: ioctl\n"));
490
491 int devIndex = (int)cookie;
492 device_info &info = gDeviceInfos[devIndex];
493
494 if (devIndex == kControlDevice || info.unused) {
495 // control device or unused data device
496 switch (op) {
497 case B_GET_DEVICE_SIZE:
498 case B_SET_NONBLOCKING_IO:
499 case B_SET_BLOCKING_IO:
500 case B_GET_READ_STATUS:
501 case B_GET_WRITE_STATUS:
502 case B_GET_ICON:
503 case B_GET_GEOMETRY:
504 case B_GET_BIOS_GEOMETRY:
505 case B_GET_MEDIA_STATUS:
506 case B_SET_UNINTERRUPTABLE_IO:
507 case B_SET_INTERRUPTABLE_IO:
508 case B_FLUSH_DRIVE_CACHE:
509 case B_GET_BIOS_DRIVE_ID:
510 case B_GET_DRIVER_FOR_DEVICE:
511 case B_SET_DEVICE_SIZE:
512 case B_SET_PARTITION:
513 case B_FORMAT_DEVICE:
514 case B_EJECT_DEVICE:
515 case B_LOAD_MEDIA:
516 case B_GET_NEXT_OPEN_DEVICE:
517 TRACE(("virtualdrive: another ioctl: %lx (%lu)\n", op, op));
518 return B_BAD_VALUE;
519
520 case VIRTUAL_DRIVE_REGISTER_FILE:
521 {
522 TRACE(("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE\n"));
523
524 virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
525 if (devIndex != kControlDevice || driveInfo == NULL
526 || driveInfo->magic != VIRTUAL_DRIVE_MAGIC
527 || driveInfo->drive_info_size != sizeof(virtual_drive_info))
528 return B_BAD_VALUE;
529
530 status_t error = B_ERROR;
531 int32 i;
532
533 lock_driver();
534
535 // first, look if we already have opened that file and see
536 // if it's available to us which happens when it has been
537 // halted but is still in use by other components
538 for (i = 0; i < kDataDeviceCount; i++) {
539 if (!gDeviceInfos[i].unused
540 && gDeviceInfos[i].fd == -1
541 && !gDeviceInfos[i].registered
542 && !strcmp(gDeviceInfos[i].file, driveInfo->file_name)) {
543 // mark device as unused, so that init_device_info() will succeed
544 gDeviceInfos[i].unused = true;
545 error = B_OK;
546 break;
547 }
548 }
549
550 if (error != B_OK) {
551 // find an unused data device
552 for (i = 0; i < kDataDeviceCount; i++) {
553 if (gDeviceInfos[i].unused) {
554 error = B_OK;
555 break;
556 }
557 }
558 }
559
560 if (error == B_OK) {
561 // we found a device slot, let's initialize it
562 error = init_device_info(i, driveInfo);
563 if (error == B_OK) {
564 // return the device path
565 strcpy(driveInfo->device_name, "/dev/");
566 strcat(driveInfo->device_name, gDeviceInfos[i].device_path);
567
568 // on the first registration we need to open the
569 // control device to stay loaded
570 if (gRegistrationCount++ == 0) {
571 char path[B_PATH_NAME_LENGTH];
572 strcpy(path, "/dev/");
573 strcat(path, info.device_path);
574 gControlDeviceFD = open(path, O_RDONLY);
575 }
576 }
577 }
578
579 unlock_driver();
580 return error;
581 }
582 case VIRTUAL_DRIVE_UNREGISTER_FILE:
583 case VIRTUAL_DRIVE_GET_INFO:
584 TRACE(("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE/"
585 "VIRTUAL_DRIVE_GET_INFO on control device\n"));
586 // these are called on used data files only!
587 return B_BAD_VALUE;
588
589 default:
590 TRACE(("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op));
591 return B_BAD_VALUE;
592 }
593 } else {
594 // used data device
595 switch (op) {
596 case B_GET_DEVICE_SIZE:
597 TRACE(("virtualdrive: B_GET_DEVICE_SIZE\n"));
598 *(size_t*)arg = info.size;
599 return B_OK;
600
601 case B_SET_NONBLOCKING_IO:
602 TRACE(("virtualdrive: B_SET_NONBLOCKING_IO\n"));
603 return B_OK;
604
605 case B_SET_BLOCKING_IO:
606 TRACE(("virtualdrive: B_SET_BLOCKING_IO\n"));
607 return B_OK;
608
609 case B_GET_READ_STATUS:
610 TRACE(("virtualdrive: B_GET_READ_STATUS\n"));
611 *(bool*)arg = true;
612 return B_OK;
613
614 case B_GET_WRITE_STATUS:
615 TRACE(("virtualdrive: B_GET_WRITE_STATUS\n"));
616 *(bool*)arg = true;
617 return B_OK;
618
619 case B_GET_ICON:
620 {
621 TRACE(("virtualdrive: B_GET_ICON\n"));
622 device_icon *icon = (device_icon *)arg;
623
624 if (icon->icon_size == kPrimaryImageWidth) {
625 memcpy(icon->icon_data, kPrimaryImageBits, kPrimaryImageWidth * kPrimaryImageHeight);
626 } else if (icon->icon_size == kSecondaryImageWidth) {
627 memcpy(icon->icon_data, kSecondaryImageBits, kSecondaryImageWidth * kSecondaryImageHeight);
628 } else
629 return B_ERROR;
630
631 return B_OK;
632 }
633
634 case B_GET_GEOMETRY:
635 TRACE(("virtualdrive: B_GET_GEOMETRY\n"));
636 *(device_geometry *)arg = info.geometry;
637 return B_OK;
638
639 case B_GET_BIOS_GEOMETRY:
640 {
641 TRACE(("virtualdrive: B_GET_BIOS_GEOMETRY\n"));
642 device_geometry *dg = (device_geometry *)arg;
643 dg->bytes_per_sector = 512;
644 dg->sectors_per_track = info.size / (512 * 1024);
645 dg->cylinder_count = 1024;
646 dg->head_count = 1;
647 dg->device_type = info.geometry.device_type;
648 dg->removable = info.geometry.removable;
649 dg->read_only = info.geometry.read_only;
650 dg->write_once = info.geometry.write_once;
651 return B_OK;
652 }
653
654 case B_GET_MEDIA_STATUS:
655 TRACE(("virtualdrive: B_GET_MEDIA_STATUS\n"));
656 *(status_t*)arg = B_NO_ERROR;
657 return B_OK;
658
659 case B_SET_UNINTERRUPTABLE_IO:
660 TRACE(("virtualdrive: B_SET_UNINTERRUPTABLE_IO\n"));
661 return B_OK;
662
663 case B_SET_INTERRUPTABLE_IO:
664 TRACE(("virtualdrive: B_SET_INTERRUPTABLE_IO\n"));
665 return B_OK;
666
667 case B_FLUSH_DRIVE_CACHE:
668 TRACE(("virtualdrive: B_FLUSH_DRIVE_CACHE\n"));
669 return B_OK;
670
671 case B_GET_BIOS_DRIVE_ID:
672 TRACE(("virtualdrive: B_GET_BIOS_DRIVE_ID\n"));
673 *(uint8*)arg = 0xF8;
674 return B_OK;
675
676 case B_GET_DRIVER_FOR_DEVICE:
677 case B_SET_DEVICE_SIZE:
678 case B_SET_PARTITION:
679 case B_FORMAT_DEVICE:
680 case B_EJECT_DEVICE:
681 case B_LOAD_MEDIA:
682 case B_GET_NEXT_OPEN_DEVICE:
683 TRACE(("virtualdrive: another ioctl: %lx (%lu)\n", op, op));
684 return B_BAD_VALUE;
685
686 case VIRTUAL_DRIVE_REGISTER_FILE:
687 TRACE(("virtualdrive: VIRTUAL_DRIVE_REGISTER_FILE (data)\n"));
688 return B_BAD_VALUE;
689 case VIRTUAL_DRIVE_UNREGISTER_FILE:
690 {
691 TRACE(("virtualdrive: VIRTUAL_DRIVE_UNREGISTER_FILE\n"));
692 lock_driver();
693
694 bool immediately = (bool)arg;
695 bool wasRegistered = info.registered;
696
697 info.registered = false;
698
699 // on the last unregistration we need to close the
700 // control device
701 if (wasRegistered && --gRegistrationCount == 0) {
702 close(gControlDeviceFD);
703 gControlDeviceFD = -1;
704 }
705
706 // if we "immediately" is true, we will stop our service immediately
707 // and close the underlying file, open it for other uses
708 if (immediately) {
709 TRACE(("virtualdrive: close file descriptor\n"));
710 // we cannot use uninit_device_info() here, since that does
711 // a little too much and would open the device for other
712 // uses.
713 close(info.fd);
714 info.fd = -1;
715 }
716
717 unlock_driver();
718 return B_OK;
719 }
720 case VIRTUAL_DRIVE_GET_INFO:
721 {
722 TRACE(("virtualdrive: VIRTUAL_DRIVE_GET_INFO\n"));
723
724 virtual_drive_info *driveInfo = (virtual_drive_info *)arg;
725 if (driveInfo == NULL
726 || driveInfo->magic != VIRTUAL_DRIVE_MAGIC
727 || driveInfo->drive_info_size != sizeof(virtual_drive_info))
728 return B_BAD_VALUE;
729
730 strcpy(driveInfo->file_name, info.file);
731 strcpy(driveInfo->device_name, "/dev/");
732 strcat(driveInfo->device_name, info.device_path);
733 driveInfo->geometry = info.geometry;
734 driveInfo->use_geometry = true;
735 driveInfo->halted = info.fd == -1;
736 return B_OK;
737 }
738
739 default:
740 TRACE(("virtualdrive: unknown ioctl: %lx (%lu)\n", op, op));
741 return B_BAD_VALUE;
742 }
743 }
744
745 }
746
747
748 static status_t
virtualdrive_free(void * cookie)749 virtualdrive_free(void *cookie)
750 {
751 TRACE(("virtualdrive: free cookie()\n"));
752 return B_OK;
753 }
754
755
756 /* -----
757 function pointers for the device hooks entry points
758 ----- */
759
760 device_hooks sVirtualDriveHooks = {
761 virtualdrive_open, /* -> open entry point */
762 virtualdrive_close, /* -> close entry point */
763 virtualdrive_free, /* -> free cookie */
764 virtualdrive_control, /* -> control entry point */
765 virtualdrive_read, /* -> read entry point */
766 virtualdrive_write /* -> write entry point */
767 };
768
769