ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sys_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/sys_unix.cpp (file contents):
Revision 1.3 by cebix, 1999-10-14T11:37:47Z vs.
Revision 1.33 by asvitkine, 2010-10-19T03:21:52Z

# Line 1 | Line 1
1   /*
2   *  sys_unix.cpp - System dependent routines, Unix implementation
3   *
4 < *  Basilisk II (C) 1997-1999 Christian Bauer
4 > *  Basilisk II (C) Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 24 | Line 24
24   #include <sys/stat.h>
25   #include <errno.h>
26  
27 + #ifdef HAVE_AVAILABILITYMACROS_H
28 + #include <AvailabilityMacros.h>
29 + #endif
30 +
31   #ifdef __linux__
32 + #include <sys/mount.h>
33   #include <linux/cdrom.h>
34   #include <linux/fd.h>
35   #include <linux/major.h>
36   #include <linux/kdev_t.h>
37 < #include <linux/unistd.h>
38 <
34 < #ifdef __NR__llseek
35 < _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);
36 < #else
37 < static int _llseek(uint fd, ulong hi, ulong lo, loff_t *res, uint wh)
38 < {
39 <        if (hi)
40 <                return -1;
41 <        *res = lseek(fd, lo, wh);
42 <        if (*res == -1)
43 <                return -1;
44 <        return 0;
45 < }
46 < #endif
37 > #include <dirent.h>
38 > #include <limits.h>
39   #endif
40  
41   #if defined(__FreeBSD__) || defined(__NetBSD__)
42   #include <sys/cdio.h>
43   #endif
44  
45 + #if defined __APPLE__ && defined __MACH__
46 + #include <sys/disk.h>
47 + #if (defined AQUA || defined HAVE_FRAMEWORK_COREFOUNDATION)
48 + #ifndef __MACOSX__
49 + #define __MACOSX__ MAC_OS_X_VERSION_MIN_REQUIRED
50 + #endif
51 + #endif
52 + #endif
53 +
54   #include "main.h"
55   #include "macos_util.h"
56   #include "prefs.h"
57   #include "user_strings.h"
58   #include "sys.h"
59  
60 + #if defined(BINCUE)
61 + #include "bincue_unix.h"
62 + #endif
63 +
64 + #if defined(HAVE_LIBVHD)
65 + #include "vhd_unix.h"
66 + #endif
67 +
68 +
69   #define DEBUG 0
70   #include "debug.h"
71  
62
72   // File handles are pointers to these structures
73   struct file_handle {
74 <        char *name;             // Copy of device/file name
74 >        char *name;             // Copy of device/file name
75          int fd;
76 +
77          bool is_file;           // Flag: plain file or /dev/something?
78          bool is_floppy;         // Flag: floppy device
79          bool is_cdrom;          // Flag: CD-ROM device
80          bool read_only;         // Copy of Sys_open() flag
81 +
82          loff_t start_byte;      // Size of file header (if any)
83          loff_t file_size;       // Size of file data (only valid if is_file is true)
84  
85 +        bool is_media_present;          // Flag: media is inserted and available
86 +
87   #if defined(__linux__)
88          int cdrom_cap;          // CD-ROM capability flags (only valid if is_cdrom is true)
89   #elif defined(__FreeBSD__)
90          struct ioc_capability cdrom_cap;
91 + #elif defined(__APPLE__) && defined(__MACH__)
92 +        char *ioctl_name;       // For CDs on OS X - a device for special ioctls
93 +        int ioctl_fd;
94 + #endif
95 +
96 + #if defined(BINCUE)
97 +        bool is_bincue;         // Flag: BIN CUE file
98 +        void *bincue_fd;
99   #endif
100 +
101 + #if defined(HAVE_LIBVHD)
102 +        bool is_vhd;            // Flag: VHD file
103 +        void *vhd_fd;
104 + #endif
105 + };
106 +
107 + // Open file handles
108 + struct open_file_handle {
109 +        file_handle *fh;
110 +        open_file_handle *next;
111   };
112 + static open_file_handle *open_file_handles = NULL;
113  
114   // File handle of first floppy drive (for SysMountFirstFloppy())
115   static file_handle *first_floppy = NULL;
116  
117 + // Prototypes
118 + static void cdrom_close(file_handle *fh);
119 + static bool cdrom_open(file_handle *fh, const char *path = NULL);
120 +
121  
122   /*
123   *  Initialization
# Line 88 | Line 125 | static file_handle *first_floppy = NULL;
125  
126   void SysInit(void)
127   {
128 + #if defined __MACOSX__
129 +        extern void DarwinSysInit(void);
130 +        DarwinSysInit();
131 + #endif
132   }
133  
134  
# Line 97 | Line 138 | void SysInit(void)
138  
139   void SysExit(void)
140   {
141 + #if defined __MACOSX__
142 +        extern void DarwinSysExit(void);
143 +        DarwinSysExit();
144 + #endif
145 + }
146 +
147 +
148 + /*
149 + *  Manage open file handles
150 + */
151 +
152 + static void sys_add_file_handle(file_handle *fh)
153 + {
154 +        open_file_handle *p = new open_file_handle;
155 +        p->fh = fh;
156 +        p->next = open_file_handles;
157 +        open_file_handles = p;
158 + }
159 +
160 + static void sys_remove_file_handle(file_handle *fh)
161 + {
162 +        open_file_handle *p = open_file_handles;
163 +        open_file_handle *q = NULL;
164 +
165 +        while (p) {
166 +                if (p->fh == fh) {
167 +                        if (q)
168 +                                q->next = p->next;
169 +                        else
170 +                                open_file_handles = p->next;
171 +                        delete p;
172 +                        break;
173 +                }
174 +                q = p;
175 +                p = p->next;
176 +        }
177 + }
178 +
179 +
180 + /*
181 + *  Account for media that has just arrived
182 + */
183 +
184 + void SysMediaArrived(const char *path, int type)
185 + {
186 +        // Replace the "cdrom" entry (we are polling, it's unique)
187 +        if (type == MEDIA_CD && !PrefsFindBool("nocdrom"))
188 +                PrefsReplaceString("cdrom", path);
189 +
190 +        // Wait for media to be available for reading
191 +        if (open_file_handles) {
192 +                const int MAX_WAIT = 5;
193 +                for (int i = 0; i < MAX_WAIT; i++) {
194 +                        if (access(path, R_OK) == 0)
195 +                                break;
196 +                        switch (errno) {
197 +                        case ENOENT: // Unlikely
198 +                        case EACCES: // MacOS X is mounting the media
199 +                                sleep(1);
200 +                                continue;
201 +                        }
202 +                        printf("WARNING: Cannot access %s (%s)\n", path, strerror(errno));
203 +                        return;
204 +                }
205 +        }
206 +
207 +        for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
208 +                file_handle * const fh = p->fh;
209 +
210 +                // Re-open CD-ROM device
211 +                if (fh->is_cdrom && type == MEDIA_CD) {
212 +                        cdrom_close(fh);
213 +                        if (cdrom_open(fh, path)) {
214 +                                fh->is_media_present = true;
215 +                                MountVolume(fh);
216 +                        }
217 +                }
218 +        }
219 + }
220 +
221 +
222 + /*
223 + *  Account for media that has just been removed
224 + */
225 +
226 + void SysMediaRemoved(const char *path, int type)
227 + {
228 +        if ((type & MEDIA_REMOVABLE) != MEDIA_CD)
229 +                return;
230 +
231 +        for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
232 +                file_handle * const fh = p->fh;
233 +
234 +                // Mark media as not available
235 +                if (!fh->is_cdrom || !fh->is_media_present)
236 +                        continue;
237 +                if (fh->name && strcmp(fh->name, path) == 0) {
238 +                        fh->is_media_present = false;
239 +                        break;
240 +                }
241 + #if defined __MACOSX__
242 +                if (fh->ioctl_name && strcmp(fh->ioctl_name, path) == 0) {
243 +                        fh->is_media_present = false;
244 +                        break;
245 +                }
246 + #endif
247 +        }
248   }
249  
250  
# Line 119 | Line 267 | void SysMountFirstFloppy(void)
267   void SysAddFloppyPrefs(void)
268   {
269   #if defined(__linux__)
270 <        PrefsAddString("floppy", "/dev/fd0H1440");
271 <        PrefsAddString("floppy", "/dev/fd1H1440");
270 >        DIR *fd_dir = opendir("/dev/floppy");
271 >        if (fd_dir) {
272 >                struct dirent *floppy_dev;
273 >                while ((floppy_dev = readdir(fd_dir)) != NULL) {
274 >                        if (strstr(floppy_dev->d_name, "u1440") != NULL) {
275 >                                char fd_dev[20];
276 >                                sprintf(fd_dev, "/dev/floppy/%s", floppy_dev->d_name);
277 >                                PrefsAddString("floppy", fd_dev);
278 >                        }
279 >                }
280 >                closedir(fd_dir);
281 >        } else {
282 >                PrefsAddString("floppy", "/dev/fd0");
283 >                PrefsAddString("floppy", "/dev/fd1");
284 >        }
285   #elif defined(__NetBSD__)
286          PrefsAddString("floppy", "/dev/fd0a");
287          PrefsAddString("floppy", "/dev/fd1a");
288 + #elif defined(__APPLE__) && defined(__MACH__)
289 +  #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
290 +        extern  void DarwinAddFloppyPrefs(void);
291 +
292 +        DarwinAddFloppyPrefs();
293 +  #else
294 +        // Until I can convince the other guys that my Darwin code is useful,
295 +        // we just add something safe (a non-existant device):
296 +        PrefsAddString("floppy", "/dev/null");
297 +  #endif
298   #else
299          PrefsAddString("floppy", "/dev/fd0");
300          PrefsAddString("floppy", "/dev/fd1");
# Line 134 | Line 305 | void SysAddFloppyPrefs(void)
305   /*
306   *  This gets called when no "disk" prefs items are found
307   *  It scans for available HFS volumes and adds appropriate prefs items
308 + *      On OS X, we could do the same, but on an OS X machine I think it is
309 + *      very unlikely that any mounted volumes would contain a system which
310 + *      is old enough to boot a 68k Mac, so we just do nothing here for now.
311   */
312  
313   void SysAddDiskPrefs(void)
# Line 145 | Line 319 | void SysAddDiskPrefs(void)
319                  while(fgets(line, 255, f)) {
320                          // Read line
321                          int len = strlen(line);
322 <                        if (len == 0)
322 >                        if (len == 0 || line[0] == '#')
323                                  continue;
324                          line[len-1] = 0;
325  
# Line 175 | Line 349 | void SysAddCDROMPrefs(void)
349                  return;
350  
351   #if defined(__linux__)
352 <        PrefsAddString("cdrom", "/dev/cdrom");
353 < #elif defined(__FreeBSD__)
352 >        if (access("/dev/.devfsd", F_OK) < 0)
353 >                PrefsAddString("cdrom", "/dev/cdrom");
354 >        else {
355 >                DIR *cd_dir = opendir("/dev/cdroms");
356 >                if (cd_dir) {
357 >                        struct dirent *cdrom_dev;
358 >                        while ((cdrom_dev = readdir(cd_dir)) != NULL) {
359 >                                if (strcmp(cdrom_dev->d_name, ".") != 0 && strcmp(cdrom_dev->d_name, "..") != 0) {
360 >                                        char cd_dev[20];
361 >                                        sprintf(cd_dev, "/dev/cdroms/%s", cdrom_dev->d_name);
362 >                                        PrefsAddString("cdrom", cd_dev);
363 >                                }
364 >                        }
365 >                        closedir(cd_dir);
366 >                }
367 >        }
368 > #elif defined __MACOSX__
369 >        // There is no predefined path for CD-ROMs on MacOS X. Rather, we
370 >        // define a single fake CD-ROM entry for the emulated MacOS.
371 >        // XXX this means we handle only CD-ROM drive at a time, wherever
372 >        // the disk is, the latest one is used.
373 >        PrefsAddString("cdrom", "/dev/poll/cdrom");
374 > #elif defined(__FreeBSD__) || defined(__NetBSD__)
375          PrefsAddString("cdrom", "/dev/cd0c");
181 #elif defined(__NetBSD__)
182        PrefsAddString("cdrom", "/dev/cd0d");
376   #endif
377   }
378  
# Line 191 | Line 384 | void SysAddCDROMPrefs(void)
384   void SysAddSerialPrefs(void)
385   {
386   #if defined(__linux__)
387 <        PrefsAddString("seriala", "/dev/ttyS0");
388 <        PrefsAddString("serialb", "/dev/ttyS1");
387 >        if (access("/dev/.devfsd", F_OK) < 0) {
388 >                PrefsAddString("seriala", "/dev/ttyS0");
389 >                PrefsAddString("serialb", "/dev/ttyS1");
390 >        } else {
391 >                PrefsAddString("seriala", "/dev/tts/0");
392 >                PrefsAddString("serialb", "/dev/tts/1");
393 >        }
394   #elif defined(__FreeBSD__)
395          PrefsAddString("seriala", "/dev/cuaa0");
396          PrefsAddString("serialb", "/dev/cuaa1");
397   #elif defined(__NetBSD__)
398          PrefsAddString("seriala", "/dev/tty00");
399          PrefsAddString("serialb", "/dev/tty01");
400 + #elif defined(__APPLE__) && defined(__MACH__)
401 +  #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
402 +        extern  void DarwinAddSerialPrefs(void);
403 +
404 +        DarwinAddSerialPrefs();
405 +  #else
406 +        // Until I can convince the other guys that my Darwin code is useful,
407 +        // we just add something safe (non-existant devices):
408 +        PrefsAddString("seriala", "/dev/null");
409 +        PrefsAddString("serialb", "/dev/null");
410 +  #endif
411 + #endif
412 + }
413 +
414 +
415 + /*
416 + *  Open CD-ROM device and initialize internal data
417 + */
418 +
419 + static bool cdrom_open_1(file_handle *fh)
420 + {
421 + #if defined __MACOSX__
422 +        // In OS X, the device name is OK for sending ioctls to,
423 +        // but not for reading raw CDROM data from.
424 +        // (it seems to have extra data padded in)
425 +        //
426 +        // So, we keep the already opened file handle,
427 +        // and open a slightly different file for CDROM data
428 +        //
429 +        fh->ioctl_fd = fh->fd;
430 +        fh->ioctl_name = fh->name;
431 +        fh->fd = -1;
432 +        fh->name = (char *)malloc(strlen(fh->ioctl_name) + 3);
433 +        if (fh->name) {
434 +                strcpy(fh->name, fh->ioctl_name);
435 +                strcat(fh->name, "s1");
436 +                fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
437 +        }
438 +        if (fh->ioctl_fd < 0)
439 +                return false;
440 + #endif
441 +        return true;
442 + }
443 +
444 + bool cdrom_open(file_handle *fh, const char *path)
445 + {
446 +        if (path)
447 +                fh->name = strdup(path);
448 +        fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
449 +        fh->start_byte = 0;
450 +        if (!cdrom_open_1(fh))
451 +                return false;
452 +        return fh->fd >= 0;
453 + }
454 +
455 +
456 + /*
457 + *  Close a CD-ROM device
458 + */
459 +
460 + void cdrom_close(file_handle *fh)
461 + {
462 +
463 +        if (fh->fd >= 0) {
464 +                close(fh->fd);
465 +                fh->fd = -1;
466 +        }
467 +        if (fh->name) {
468 +                free(fh->name);
469 +                fh->name = NULL;
470 +        }
471 + #if defined __MACOSX__
472 +        if (fh->ioctl_fd >= 0) {
473 +                close(fh->ioctl_fd);
474 +                fh->ioctl_fd = -1;
475 +        }
476 +        if (fh->ioctl_name) {
477 +                free(fh->ioctl_name);
478 +                fh->ioctl_name = NULL;
479 +        }
480   #endif
481   }
482  
# Line 240 | Line 518 | static bool is_drive_mounted(const char
518   /*
519   *  Open file/device, create new file handle (returns NULL on error)
520   */
521 +
522 + static file_handle *open_filehandle(const char *name)
523 + {
524 +                file_handle *fh = new file_handle;
525 +                memset(fh, 0, sizeof(file_handle));
526 +                fh->name = strdup(name);
527 +                fh->fd = -1;
528 + #if defined __MACOSX__
529 +                fh->ioctl_fd = -1;
530 +                fh->ioctl_name = NULL;
531 + #endif
532 +                return fh;
533 + }
534  
535   void *Sys_open(const char *name, bool read_only)
536   {
# Line 250 | Line 541 | void *Sys_open(const char *name, bool re
541   #else
542          bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0;
543   #endif
544 +        bool is_floppy = strncmp(name, "/dev/fd", 7) == 0;
545 +
546 +        bool is_polled_media = strncmp(name, "/dev/poll/", 10) == 0;
547 +        if (is_floppy) // Floppy open fails if there's no disk inserted
548 +                is_polled_media = true;
549 +
550 + #if defined __MACOSX__
551 +        // There is no set filename in /dev which is the cdrom,
552 +        // so we have to see if it is any of the devices that we found earlier
553 +        {
554 +                int index = 0;
555 +                const char *str;
556 +                while ((str = PrefsFindString("cdrom", index++)) != NULL) {
557 +                        if (is_polled_media || strcmp(str, name) == 0) {
558 +                                is_cdrom = true;
559 +                                read_only = true;
560 +                                break;
561 +                        }
562 +                }
563 +        }
564 + #endif
565  
566          D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
567  
# Line 272 | Line 584 | void *Sys_open(const char *name, bool re
584          }
585  
586          // Open file/device
587 < #if defined(__linux__)
587 >
588 > #if defined(BINCUE)
589 >        void *binfd = open_bincue(name);
590 >        if (binfd) {
591 >                file_handle *fh = open_filehandle(name);
592 >                D(bug("opening %s as bincue\n", name));
593 >                fh->bincue_fd = binfd;
594 >                fh->is_bincue = true;
595 >                fh->read_only = true;
596 >                fh->is_media_present = true;
597 >                sys_add_file_handle(fh);
598 >                return fh;
599 >        }
600 > #endif
601 >
602 >
603 > #if defined(HAVE_LIBVHD)
604 >        int vhdsize;
605 >        void *vhdfd = vhd_unix_open(name, &vhdsize, read_only);
606 >        if (vhdfd) {
607 >                file_handle *fh = open_filehandle(name);
608 >                D(bug("opening %s as vnd\n", name));
609 >                fh->is_vhd = true;
610 >                fh->vhd_fd = vhdfd;
611 >                fh->read_only = read_only;
612 >                fh->file_size = vhdsize;
613 >                fh->is_media_present = true;
614 >                sys_add_file_handle(fh);
615 >                return fh;
616 >        }
617 > #endif
618 >
619 > #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__)
620          int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0));
621   #else
622          int fd = open(name, read_only ? O_RDONLY : O_RDWR);
# Line 282 | Line 626 | void *Sys_open(const char *name, bool re
626                  read_only = true;
627                  fd = open(name, O_RDONLY);
628          }
629 <        if (fd >= 0) {
630 <                file_handle *fh = new file_handle;
287 <                fh->name = strdup(name);
629 >        if (fd >= 0 || is_polled_media) {
630 >                file_handle *fh = open_filehandle(name);
631                  fh->fd = fd;
632                  fh->is_file = is_file;
633                  fh->read_only = read_only;
634 <                fh->start_byte = 0;
635 <                fh->is_floppy = false;
293 <                fh->is_cdrom = false;
634 >                fh->is_floppy = is_floppy;
635 >                fh->is_cdrom = is_cdrom;
636                  if (fh->is_file) {
637 +                        fh->is_media_present = true;
638                          // Detect disk image file layout
639                          loff_t size = 0;
297 #if defined(__linux__)
298                        _llseek(fh->fd, 0, 0, &size, SEEK_END);
299 #else
640                          size = lseek(fd, 0, SEEK_END);
301 #endif
641                          uint8 data[256];
642                          lseek(fd, 0, SEEK_SET);
643                          read(fd, data, 256);
# Line 306 | Line 645 | void *Sys_open(const char *name, bool re
645                  } else {
646                          struct stat st;
647                          if (fstat(fd, &st) == 0) {
648 +                                fh->is_media_present = true;
649                                  if (S_ISBLK(st.st_mode)) {
650                                          fh->is_cdrom = is_cdrom;
651   #if defined(__linux__)
# Line 316 | Line 656 | void *Sys_open(const char *name, bool re
656                                                  if (fh->cdrom_cap < 0)
657                                                          fh->cdrom_cap = 0;
658                                          }
319 #else
320                                        fh->cdrom_cap = 0;
659   #endif
660 < #elif defined(__FreeBSD__) || defined(__NetBSD__)
660 > #elif defined(__FreeBSD__)
661                                          fh->is_floppy = ((st.st_rdev >> 16) == 2);
662   #ifdef CDIOCCAPABILITY
663                                          if (is_cdrom) {
664                                                  if (ioctl(fh->fd, CDIOCCAPABILITY, &fh->cdrom_cap) < 0)
665                                                          memset(&fh->cdrom_cap, 0, sizeof(fh->cdrom_cap));
666                                          }
329 #else
330                                        fh->cdrom_cap = 0;
667   #endif
668 + #elif defined(__NetBSD__)
669 +                                        fh->is_floppy = ((st.st_rdev >> 16) == 2);
670   #endif
671                                  }
672 + #if defined __MACOSX__
673 +                                if (is_cdrom) {
674 +                                        fh->is_cdrom = true;
675 +                                        fh->is_floppy = false;
676 +                                        if (cdrom_open_1(fh))
677 +                                                fh->is_media_present = true;
678 +                                }
679 + #endif
680                          }
681                  }
682                  if (fh->is_floppy && first_floppy == NULL)
683                          first_floppy = fh;
684 +                sys_add_file_handle(fh);
685                  return fh;
686          } else {
687                  printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno));
# Line 353 | Line 700 | void Sys_close(void *arg)
700          if (!fh)
701                  return;
702  
703 <        close(fh->fd);
703 >        sys_remove_file_handle(fh);
704 >
705 > #if defined(HAVE_LIBVHD)
706 >        if (fh->is_vhd)
707 >                vhd_unix_close(fh->vhd_fd);
708 > #endif
709 >
710 > #if defined(BINCUE)
711 >        if (fh->is_bincue)
712 >                close_bincue(fh->bincue_fd);
713 > #endif
714 >
715 >        if (fh->is_cdrom)
716 >                cdrom_close(fh);
717 >        if (fh->fd >= 0)
718 >                close(fh->fd);
719          if (fh->name)
720                  free(fh->name);
721          delete fh;
# Line 371 | Line 733 | size_t Sys_read(void *arg, void *buffer,
733          if (!fh)
734                  return 0;
735  
736 + #if defined(BINCUE)
737 +        if (fh->is_bincue)
738 +                return read_bincue(fh->bincue_fd, buffer, offset, length);
739 + #endif
740 +
741 + #if defined(HAVE_LIBVHD)
742 +        if (fh->is_vhd)
743 +                return vhd_unix_read(fh->vhd_fd, buffer, offset, length);
744 + #endif
745 +
746          // Seek to position
375 #if defined(__linux__)
376        loff_t pos = offset + fh->start_byte, res;
377        if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
378                return 0;
379 #else
747          if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
748                  return 0;
382 #endif
749  
750          // Read data
751          return read(fh->fd, buffer, length);
# Line 397 | Line 763 | size_t Sys_write(void *arg, void *buffer
763          if (!fh)
764                  return 0;
765  
766 + #if defined(HAVE_LIBVHD)
767 +        if (fh->is_vhd)
768 +                return vhd_unix_write(fh->vhd_fd, buffer, offset, length);
769 + #endif
770 +
771          // Seek to position
401 #if defined(__linux__)
402        loff_t pos = offset + fh->start_byte, res;
403        if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
404                return 0;
405 #else
772          if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
773                  return 0;
408 #endif
774  
775          // Write data
776          return write(fh->fd, buffer, length);
# Line 422 | Line 787 | loff_t SysGetFileSize(void *arg)
787          if (!fh)
788                  return true;
789  
790 + #if defined(BINCUE)
791 +        if (fh->is_bincue)
792 +                return size_bincue(fh->bincue_fd);
793 + #endif
794 +
795 + #if defined(HAVE_LIBVHD)
796 +        if (fh->is_vhd)
797 +                return fh->file_size;
798 + #endif
799 +
800          if (fh->is_file)
801                  return fh->file_size;
802          else {
803 +                long blocks;
804   #if defined(__linux__)
805 <                loff_t pos = 0;
806 <                _llseek(fh->fd, 0, 0, &pos, SEEK_END);
807 <                return pos - fh->start_byte;
805 >                if (ioctl(fh->fd, BLKGETSIZE, &blocks) < 0)
806 >                        return 0;
807 >                D(bug(" BLKGETSIZE returns %d blocks\n", blocks));
808 >                return (loff_t)blocks * 512;
809 > #elif defined __MACOSX__
810 >                uint32 block_size;
811 >                if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKSIZE, &block_size) < 0)
812 >                        return 0;
813 >                D(bug(" DKIOCGETBLOCKSIZE returns %lu bytes\n", (unsigned long)block_size));
814 >                uint64 block_count;
815 >                if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKCOUNT, &block_count) < 0)
816 >                        return 0;
817 >                D(bug(" DKIOCGETBLOCKCOUNT returns %llu blocks\n", (unsigned long long)block_count));
818 >                return block_count * block_size;
819   #else
820                  return lseek(fh->fd, 0, SEEK_END) - fh->start_byte;
821   #endif
# Line 448 | Line 835 | void SysEject(void *arg)
835  
836   #if defined(__linux__)
837          if (fh->is_floppy) {
838 <                fsync(fh->fd);
839 <                ioctl(fh->fd, FDFLUSH);
840 <                ioctl(fh->fd, FDEJECT);
838 >                if (fh->fd >= 0) {
839 >                        fsync(fh->fd);
840 >                        ioctl(fh->fd, FDFLUSH);
841 >                        ioctl(fh->fd, FDEJECT);
842 >                        close(fh->fd);  // Close and reopen so the driver will see the media change
843 >                }
844 >                fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR);
845          } else if (fh->is_cdrom) {
846                  ioctl(fh->fd, CDROMEJECT);
847                  close(fh->fd);  // Close and reopen so the driver will see the media change
# Line 459 | Line 850 | void SysEject(void *arg)
850   #elif defined(__FreeBSD__) || defined(__NetBSD__)
851          if (fh->is_floppy) {
852                  fsync(fh->fd);
462                //ioctl(fh->fd, FDFLUSH);
463                //ioctl(fh->fd, FDEJECT);
853          } else if (fh->is_cdrom) {
854                  ioctl(fh->fd, CDIOCEJECT);
855                  close(fh->fd);  // Close and reopen so the driver will see the media change
856                  fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
857          }
858 + #elif defined(__APPLE__) && defined(__MACH__)
859 +        if (fh->is_cdrom && fh->is_media_present) {
860 +                close(fh->fd);
861 +                fh->fd = -1;
862 +                if (ioctl(fh->ioctl_fd, DKIOCEJECT) < 0) {
863 +                        D(bug(" DKIOCEJECT failed on file %s: %s\n",
864 +                                   fh->ioctl_name, strerror(errno)));
865 +
866 +                        // If we are running MacOS X, the device may be in busy
867 +                        // state because the Finder has mounted the disk
868 +                        close(fh->ioctl_fd);
869 +                        fh->ioctl_fd = -1;
870 +
871 +                        // Try to use "diskutil eject" but it can take up to 5
872 +                        // seconds to complete
873 +                        static const char eject_cmd[] = "/usr/sbin/diskutil eject %s 2>&1 >/dev/null";
874 +                        char *cmd = (char *)alloca(strlen(eject_cmd) + strlen(fh->ioctl_name) + 1);
875 +                        sprintf(cmd, eject_cmd, fh->ioctl_name);
876 +                        system(cmd);
877 +                }
878 +                fh->is_media_present = false;
879 +        }
880   #endif
881   }
882  
# Line 497 | Line 908 | bool SysIsReadOnly(void *arg)
908  
909   #if defined(__linux__)
910          if (fh->is_floppy) {
911 <                struct floppy_drive_struct stat;
912 <                ioctl(fh->fd, FDGETDRVSTAT, &stat);
913 <                return !(stat.flags & FD_DISK_WRITABLE);
911 >                if (fh->fd >= 0) {
912 >                        struct floppy_drive_struct stat;
913 >                        ioctl(fh->fd, FDGETDRVSTAT, &stat);
914 >                        return !(stat.flags & FD_DISK_WRITABLE);
915 >                } else
916 >                        return true;
917          } else
918   #endif
919                  return fh->read_only;
# Line 516 | Line 930 | bool SysIsFixedDisk(void *arg)
930          if (!fh)
931                  return true;
932  
933 + #if defined(HAVE_LIBVHD)
934 +        if (fh->is_vhd)
935 +                return true;
936 + #endif
937 +
938          if (fh->is_file)
939                  return true;
940          else if (fh->is_floppy || fh->is_cdrom)
# Line 535 | Line 954 | bool SysIsDiskInserted(void *arg)
954          if (!fh)
955                  return false;
956  
957 + #if defined(HAVE_LIBVHD)
958 +        if (fh->is_vhd)
959 +                return true;
960 + #endif
961 +
962          if (fh->is_file) {
963                  return true;
964  
# Line 542 | Line 966 | bool SysIsDiskInserted(void *arg)
966          } else if (fh->is_floppy) {
967                  char block[512];
968                  lseek(fh->fd, 0, SEEK_SET);
969 <                return read(fh->fd, block, 512) == 512;
969 >                ssize_t actual = read(fh->fd, block, 512);
970 >                if (actual < 0) {
971 >                        close(fh->fd);  // Close and reopen so the driver will see the media change
972 >                        fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR);
973 >                        actual = read(fh->fd, block, 512);
974 >                }
975 >                return actual == 512;
976          } else if (fh->is_cdrom) {
977 + #ifdef CDROM_MEDIA_CHANGED
978 +                if (fh->cdrom_cap & CDC_MEDIA_CHANGED) {
979 +                        // If we don't do this, all attempts to read from a disc fail
980 +                        // once the tray has been opened (altough the TOC reads fine).
981 +                        // Can somebody explain this to me?
982 +                        if (ioctl(fh->fd, CDROM_MEDIA_CHANGED) == 1) {
983 +                                close(fh->fd);
984 +                                fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
985 +                        }
986 +                }
987 + #endif
988   #ifdef CDROM_DRIVE_STATUS
989                  if (fh->cdrom_cap & CDC_DRIVE_STATUS) {
990                          return ioctl(fh->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
# Line 557 | Line 998 | bool SysIsDiskInserted(void *arg)
998          } else if (fh->is_cdrom) {
999                  struct ioc_toc_header header;
1000                  return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0;
1001 + #elif defined __MACOSX__
1002 +        } else if (fh->is_cdrom || fh->is_floppy) {
1003 +                return fh->is_media_present;
1004   #endif
1005  
1006          } else
# Line 608 | Line 1052 | bool SysCDReadTOC(void *arg, uint8 *toc)
1052          if (!fh)
1053                  return false;
1054  
1055 + #if defined(BINCUE)
1056 +        if (fh->is_bincue)
1057 +                return readtoc_bincue(fh->bincue_fd, toc);
1058 + #endif
1059 +
1060          if (fh->is_cdrom) {
1061 +
1062   #if defined(__linux__)
1063                  uint8 *p = toc + 2;
1064  
# Line 655 | Line 1105 | bool SysCDReadTOC(void *arg, uint8 *toc)
1105                  *toc++ = toc_size >> 8;
1106                  *toc++ = toc_size & 0xff;
1107                  return true;
1108 < #elif defined(__FreeBSD__) || defined(__NetBSD__)
1108 > #elif defined __MACOSX__ && defined MAC_OS_X_VERSION_10_2
1109 >                if (fh->is_media_present) {
1110 >                        extern bool DarwinCDReadTOC(char *name, uint8 *toc);
1111 >                        return DarwinCDReadTOC(fh->name, toc);
1112 >                }
1113 >                return false;
1114 > #elif defined(__FreeBSD__)
1115                  uint8 *p = toc + 2;
1116  
1117                  // Header
# Line 701 | Line 1157 | bool SysCDReadTOC(void *arg, uint8 *toc)
1157                  *toc++ = toc_size >> 8;
1158                  *toc++ = toc_size & 0xff;
1159                  return true;
1160 + #elif defined(__NetBSD__)
1161 +                uint8 *p = toc + 2;
1162 +
1163 +                // Header
1164 +                struct ioc_toc_header header;
1165 +                if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0)
1166 +                        return false;
1167 +                *p++ = header.starting_track;
1168 +                *p++ = header.ending_track;
1169 +
1170 +                // Tracks (this is nice... :-)
1171 +                struct ioc_read_toc_entry entries;
1172 +                entries.address_format = CD_MSF_FORMAT;
1173 +                entries.starting_track = 1;
1174 +                entries.data_len = 800;
1175 +                entries.data = (cd_toc_entry *)p;
1176 +                if (ioctl(fh->fd, CDIOREADTOCENTRIES, &entries) < 0)
1177 +                        return false;
1178 +
1179 +                // TOC size
1180 +                int toc_size = p - toc;
1181 +                *toc++ = toc_size >> 8;
1182 +                *toc++ = toc_size & 0xff;
1183 +                return true;
1184 + #else
1185 +                return false;
1186   #endif
1187          } else
1188                  return false;
# Line 717 | Line 1199 | bool SysCDGetPosition(void *arg, uint8 *
1199          if (!fh)
1200                  return false;
1201  
1202 + #if defined(BINCUE)
1203 +        if (fh->is_bincue)
1204 +                return GetPosition_bincue(fh->bincue_fd, pos);
1205 + #endif
1206 +
1207          if (fh->is_cdrom) {
1208   #if defined(__linux__)
1209                  cdrom_subchnl chan;
# Line 764 | Line 1251 | bool SysCDGetPosition(void *arg, uint8 *
1251                  *pos++ = chan.data->what.position.reladdr.msf.second;
1252                  *pos++ = chan.data->what.position.reladdr.msf.frame;
1253                  return true;
1254 + #else
1255 +                return false;
1256   #endif
1257          } else
1258                  return false;
# Line 780 | Line 1269 | bool SysCDPlay(void *arg, uint8 start_m,
1269          if (!fh)
1270                  return false;
1271  
1272 + #if defined(BINCUE)
1273 +        if (fh->is_bincue)
1274 +                return CDPlay_bincue(fh->bincue_fd, start_m, start_s, start_f, end_m, end_s, end_f);
1275 + #endif
1276 +
1277          if (fh->is_cdrom) {
1278   #if defined(__linux__)
1279                  cdrom_msf play;
# Line 799 | Line 1293 | bool SysCDPlay(void *arg, uint8 start_m,
1293                  play.end_s = end_s;
1294                  play.end_f = end_f;
1295                  return ioctl(fh->fd, CDIOCPLAYMSF, &play) == 0;
1296 + #else
1297 +                return false;
1298   #endif
1299          } else
1300                  return false;
# Line 815 | Line 1311 | bool SysCDPause(void *arg)
1311          if (!fh)
1312                  return false;
1313  
1314 + #if defined(BINCUE)
1315 +        if (fh->is_bincue)
1316 +                return CDPause_bincue(fh->bincue_fd);
1317 + #endif
1318 +
1319          if (fh->is_cdrom) {
1320   #if defined(__linux__)
1321                  return ioctl(fh->fd, CDROMPAUSE) == 0;
1322   #elif defined(__FreeBSD__) || defined(__NetBSD__)
1323                  return ioctl(fh->fd, CDIOCPAUSE) == 0;
1324 + #else
1325 +                return false;
1326   #endif
1327          } else
1328                  return false;
# Line 836 | Line 1339 | bool SysCDResume(void *arg)
1339          if (!fh)
1340                  return false;
1341  
1342 + #if defined(BINCUE)
1343 +        if (fh->is_bincue)
1344 +                return CDResume_bincue(fh->bincue_fd);
1345 + #endif
1346 +
1347 +
1348          if (fh->is_cdrom) {
1349   #if defined(__linux__)
1350                  return ioctl(fh->fd, CDROMRESUME) == 0;
1351   #elif defined(__FreeBSD__) || defined(__NetBSD__)
1352                  return ioctl(fh->fd, CDIOCRESUME) == 0;
1353 + #else
1354 +                return false;
1355   #endif
1356          } else
1357                  return false;
# Line 857 | Line 1368 | bool SysCDStop(void *arg, uint8 lead_out
1368          if (!fh)
1369                  return false;
1370  
1371 + #if defined(BINCUE)
1372 +        if (fh->is_bincue)
1373 +                return CDStop_bincue(fh->bincue_fd);
1374 + #endif
1375 +
1376 +
1377          if (fh->is_cdrom) {
1378   #if defined(__linux__)
1379                  return ioctl(fh->fd, CDROMSTOP) == 0;
1380   #elif defined(__FreeBSD__) || defined(__NetBSD__)
1381                  return ioctl(fh->fd, CDIOCSTOP) == 0;
1382 + #else
1383 +                return false;
1384   #endif
1385          } else
1386                  return false;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines