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.20 by gbeauche, 2003-10-12T21:55:44Z vs.
Revision 1.30 by gbeauche, 2008-01-01T09:40:33Z

# Line 1 | Line 1
1   /*
2   *  sys_unix.cpp - System dependent routines, Unix implementation
3   *
4 < *  Basilisk II (C) 1997-2003 Christian Bauer
4 > *  Basilisk II (C) 1997-2008 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>
33 #include <linux/unistd.h>
37   #include <dirent.h>
35
36 #ifdef __NR__llseek
37 _syscall5(int, _llseek, unsigned int, fd, unsigned long, hi, unsigned long, lo, loff_t *, res, unsigned int, wh);
38 #else
39 static int _llseek(unsigned int fd, unsigned long hi, unsigned long lo, loff_t *res, unsigned int wh)
40 {
41        if (hi)
42                return -1;
43        *res = lseek(fd, lo, wh);
44        if (*res == -1)
45                return -1;
46        return 0;
47 }
48 #endif
38   #endif
39  
40   #if defined(__FreeBSD__) || defined(__NetBSD__)
41   #include <sys/cdio.h>
42   #endif
43  
44 + #if defined __APPLE__ && defined __MACH__
45 + #include <sys/disk.h>
46 + #if (defined AQUA || defined HAVE_FRAMEWORK_COREFOUNDATION)
47 + #ifndef __MACOSX__
48 + #define __MACOSX__ MAC_OS_X_VERSION_MIN_REQUIRED
49 + #endif
50 + #endif
51 + #endif
52 +
53   #include "main.h"
54   #include "macos_util.h"
55   #include "prefs.h"
# Line 64 | Line 62 | static int _llseek(unsigned int fd, unsi
62  
63   // File handles are pointers to these structures
64   struct file_handle {
65 <        char *name;             // Copy of device/file name
65 >        char *name;                     // Copy of device/file name
66          int fd;
67          bool is_file;           // Flag: plain file or /dev/something?
68          bool is_floppy;         // Flag: floppy device
# Line 72 | Line 70 | struct file_handle {
70          bool read_only;         // Copy of Sys_open() flag
71          loff_t start_byte;      // Size of file header (if any)
72          loff_t file_size;       // Size of file data (only valid if is_file is true)
73 +        bool is_media_present;          // Flag: media is inserted and available
74  
75   #if defined(__linux__)
76          int cdrom_cap;          // CD-ROM capability flags (only valid if is_cdrom is true)
# Line 83 | Line 82 | struct file_handle {
82   #endif
83   };
84  
85 + // Open file handles
86 + struct open_file_handle {
87 +        file_handle *fh;
88 +        open_file_handle *next;
89 + };
90 + static open_file_handle *open_file_handles = NULL;
91 +
92   // File handle of first floppy drive (for SysMountFirstFloppy())
93   static file_handle *first_floppy = NULL;
94  
95 + // Prototypes
96 + static void cdrom_close(file_handle *fh);
97 + static bool cdrom_open(file_handle *fh, const char *path = NULL);
98 +
99  
100   /*
101   *  Initialization
# Line 93 | Line 103 | static file_handle *first_floppy = NULL;
103  
104   void SysInit(void)
105   {
106 + #if defined __MACOSX__
107 +        extern void DarwinSysInit(void);
108 +        DarwinSysInit();
109 + #endif
110   }
111  
112  
# Line 102 | Line 116 | void SysInit(void)
116  
117   void SysExit(void)
118   {
119 + #if defined __MACOSX__
120 +        extern void DarwinSysExit(void);
121 +        DarwinSysExit();
122 + #endif
123 + }
124 +
125 +
126 + /*
127 + *  Manage open file handles
128 + */
129 +
130 + static void sys_add_file_handle(file_handle *fh)
131 + {
132 +        open_file_handle *p = new open_file_handle;
133 +        p->fh = fh;
134 +        p->next = open_file_handles;
135 +        open_file_handles = p;
136 + }
137 +
138 + static void sys_remove_file_handle(file_handle *fh)
139 + {
140 +        open_file_handle *p = open_file_handles;
141 +        open_file_handle *q = NULL;
142 +
143 +        while (p) {
144 +                if (p->fh == fh) {
145 +                        if (q)
146 +                                q->next = p->next;
147 +                        else
148 +                                open_file_handles = p->next;
149 +                        delete p;
150 +                        break;
151 +                }
152 +                q = p;
153 +                p = p->next;
154 +        }
155 + }
156 +
157 +
158 + /*
159 + *  Account for media that has just arrived
160 + */
161 +
162 + void SysMediaArrived(const char *path, int type)
163 + {
164 +        // Replace the "cdrom" entry (we are polling, it's unique)
165 +        if (type == MEDIA_CD && !PrefsFindBool("nocdrom"))
166 +                PrefsReplaceString("cdrom", path);
167 +
168 +        // Wait for media to be available for reading
169 +        if (open_file_handles) {
170 +                const int MAX_WAIT = 5;
171 +                for (int i = 0; i < MAX_WAIT; i++) {
172 +                        if (access(path, R_OK) == 0)
173 +                                break;
174 +                        switch (errno) {
175 +                        case ENOENT: // Unlikely
176 +                        case EACCES: // MacOS X is mounting the media
177 +                                sleep(1);
178 +                                continue;
179 +                        }
180 +                        printf("WARNING: Cannot access %s (%s)\n", path, strerror(errno));
181 +                        return;
182 +                }
183 +        }
184 +
185 +        for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
186 +                file_handle * const fh = p->fh;
187 +
188 +                // Re-open CD-ROM device
189 +                if (fh->is_cdrom && type == MEDIA_CD) {
190 +                        cdrom_close(fh);
191 +                        if (cdrom_open(fh, path)) {
192 +                                fh->is_media_present = true;
193 +                                MountVolume(fh);
194 +                        }
195 +                }
196 +        }
197 + }
198 +
199 +
200 + /*
201 + *  Account for media that has just been removed
202 + */
203 +
204 + void SysMediaRemoved(const char *path, int type)
205 + {
206 +        if ((type & MEDIA_REMOVABLE) != MEDIA_CD)
207 +                return;
208 +
209 +        for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
210 +                file_handle * const fh = p->fh;
211 +
212 +                // Mark media as not available
213 +                if (!fh->is_cdrom || !fh->is_media_present)
214 +                        continue;
215 +                if (fh->name && strcmp(fh->name, path) == 0) {
216 +                        fh->is_media_present = false;
217 +                        break;
218 +                }
219 + #if defined __MACOSX__
220 +                if (fh->ioctl_name && strcmp(fh->ioctl_name, path) == 0) {
221 +                        fh->is_media_present = false;
222 +                        break;
223 +                }
224 + #endif
225 +        }
226   }
227  
228  
# Line 124 | Line 245 | void SysMountFirstFloppy(void)
245   void SysAddFloppyPrefs(void)
246   {
247   #if defined(__linux__)
248 <        if (access("/dev/.devfsd", F_OK) < 0) {
249 <                PrefsAddString("floppy", "/dev/fd0u1440");
250 <                PrefsAddString("floppy", "/dev/fd1u1440");
251 <        } else {
252 <                DIR *fd_dir = opendir("/dev/floppy");
253 <                if (fd_dir) {
254 <                        struct dirent *floppy_dev;
255 <                        while ((floppy_dev = readdir(fd_dir)) != NULL) {
135 <                                if (strstr(floppy_dev->d_name, "u1440") != NULL) {
136 <                                        char fd_dev[20];
137 <                                        sprintf(fd_dev, "/dev/floppy/%s", floppy_dev->d_name);
138 <                                        PrefsAddString("floppy", fd_dev);
139 <                                }
248 >        DIR *fd_dir = opendir("/dev/floppy");
249 >        if (fd_dir) {
250 >                struct dirent *floppy_dev;
251 >                while ((floppy_dev = readdir(fd_dir)) != NULL) {
252 >                        if (strstr(floppy_dev->d_name, "u1440") != NULL) {
253 >                                char fd_dev[20];
254 >                                sprintf(fd_dev, "/dev/floppy/%s", floppy_dev->d_name);
255 >                                PrefsAddString("floppy", fd_dev);
256                          }
141                        closedir(fd_dir);
257                  }
258 +                closedir(fd_dir);
259 +        } else {
260 +                PrefsAddString("floppy", "/dev/fd0");
261 +                PrefsAddString("floppy", "/dev/fd1");
262          }
263   #elif defined(__NetBSD__)
264          PrefsAddString("floppy", "/dev/fd0a");
265          PrefsAddString("floppy", "/dev/fd1a");
266   #elif defined(__APPLE__) && defined(__MACH__)
267 <        // FIXME: We assume an Aqua build causes <AvailabilityMacros.h> to
268 <        // be included, thusly enabling this part of code that would cause
269 <        // Basilisk II to hang otherwise.
270 < #ifdef MAC_OS_X_VERSION_10_0
271 <        PrefsAddString("floppy", "/dev/fd/0");
272 <        PrefsAddString("floppy", "/dev/fd/1");
273 < #endif
267 >  #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
268 >        extern  void DarwinAddFloppyPrefs(void);
269 >
270 >        DarwinAddFloppyPrefs();
271 >  #else
272 >        // Until I can convince the other guys that my Darwin code is useful,
273 >        // we just add something safe (a non-existant device):
274 >        PrefsAddString("floppy", "/dev/null");
275 >  #endif
276   #else
277          PrefsAddString("floppy", "/dev/fd0");
278          PrefsAddString("floppy", "/dev/fd1");
# Line 222 | Line 343 | void SysAddCDROMPrefs(void)
343                          closedir(cd_dir);
344                  }
345          }
346 < #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_0)
347 <        extern  void DarwinAddCDROMPrefs(void);
348 <
349 <        DarwinAddCDROMPrefs();
346 > #elif defined __MACOSX__
347 >        // There is no predefined path for CD-ROMs on MacOS X. Rather, we
348 >        // define a single fake CD-ROM entry for the emulated MacOS.
349 >        // XXX this means we handle only CD-ROM drive at a time, wherever
350 >        // the disk is, the latest one is used.
351 >        PrefsAddString("cdrom", "/dev/poll/cdrom");
352   #elif defined(__FreeBSD__) || defined(__NetBSD__)
353          PrefsAddString("cdrom", "/dev/cd0c");
354   #endif
# Line 253 | Line 376 | void SysAddSerialPrefs(void)
376          PrefsAddString("seriala", "/dev/tty00");
377          PrefsAddString("serialb", "/dev/tty01");
378   #elif defined(__APPLE__) && defined(__MACH__)
379 <        // FIXME: We assume an Aqua build causes <AvailabilityMacros.h> to
380 <        // be included, thusly enabling this part of code that would cause
381 <        // Basilisk II to hang otherwise.
382 < #ifdef MAC_OS_X_VERSION_10_0
383 <        PrefsAddString("seriala", "/dev/ttys0");
384 <        PrefsAddString("serialb", "/dev/ttys1");
379 >  #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
380 >        extern  void DarwinAddSerialPrefs(void);
381 >
382 >        DarwinAddSerialPrefs();
383 >  #else
384 >        // Until I can convince the other guys that my Darwin code is useful,
385 >        // we just add something safe (non-existant devices):
386 >        PrefsAddString("seriala", "/dev/null");
387 >        PrefsAddString("serialb", "/dev/null");
388 >  #endif
389   #endif
390 < //      PrefsAddString("seriala", "/dev/cu.modem");
391 < //      PrefsAddString("serialb", "/dev/cu.IrDA-IrCOMMch-b");
390 > }
391 >
392 >
393 > /*
394 > *  Open CD-ROM device and initialize internal data
395 > */
396 >
397 > static bool cdrom_open_1(file_handle *fh)
398 > {
399 > #if defined __MACOSX__
400 >        // In OS X, the device name is OK for sending ioctls to,
401 >        // but not for reading raw CDROM data from.
402 >        // (it seems to have extra data padded in)
403 >        //
404 >        // So, we keep the already opened file handle,
405 >        // and open a slightly different file for CDROM data
406 >        //
407 >        fh->ioctl_fd = fh->fd;
408 >        fh->ioctl_name = fh->name;
409 >        fh->fd = -1;
410 >        fh->name = (char *)malloc(strlen(fh->ioctl_name) + 3);
411 >        if (fh->name) {
412 >                strcpy(fh->name, fh->ioctl_name);
413 >                strcat(fh->name, "s1");
414 >                fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
415 >        }
416 >        if (fh->ioctl_fd < 0)
417 >                return false;
418 > #endif
419 >        return true;
420 > }
421 >
422 > bool cdrom_open(file_handle *fh, const char *path)
423 > {
424 >        if (path)
425 >                fh->name = strdup(path);
426 >        fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
427 >        fh->start_byte = 0;
428 >        if (!cdrom_open_1(fh))
429 >                return false;
430 >        return fh->fd >= 0;
431 > }
432 >
433 >
434 > /*
435 > *  Close a CD-ROM device
436 > */
437 >
438 > void cdrom_close(file_handle *fh)
439 > {
440 >        if (fh->fd >= 0) {
441 >                close(fh->fd);
442 >                fh->fd = -1;
443 >        }
444 >        if (fh->name) {
445 >                free(fh->name);
446 >                fh->name = NULL;
447 >        }
448 > #if defined __MACOSX__
449 >        if (fh->ioctl_fd >= 0) {
450 >                close(fh->ioctl_fd);
451 >                fh->ioctl_fd = -1;
452 >        }
453 >        if (fh->ioctl_name) {
454 >                free(fh->ioctl_name);
455 >                fh->ioctl_name = NULL;
456 >        }
457   #endif
458   }
459  
# Line 313 | Line 505 | void *Sys_open(const char *name, bool re
505   #else
506          bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0;
507   #endif
508 +        bool is_floppy = strncmp(name, "/dev/fd", 7) == 0;
509  
510 < #if defined(__APPLE__) && defined(__MACH__)
511 <        //
510 >        bool is_polled_media = strncmp(name, "/dev/poll/", 10) == 0;
511 >        if (is_floppy) // Floppy open fails if there's no disk inserted
512 >                is_polled_media = true;
513 >
514 > #if defined __MACOSX__
515          // There is no set filename in /dev which is the cdrom,
516          // so we have to see if it is any of the devices that we found earlier
321        //
322        const char      *cdrom;
323        int                     tmp = 0;
324
325        while ( (cdrom = PrefsFindString("cdrom", tmp) ) != NULL )
517          {
518 <                if ( strcmp(name, cdrom) == 0 )
519 <                {
520 <                        is_cdrom = 1;
521 <                        read_only = 1;
522 <                        break;
518 >                int index = 0;
519 >                const char *str;
520 >                while ((str = PrefsFindString("cdrom", index++)) != NULL) {
521 >                        if (is_polled_media || strcmp(str, name) == 0) {
522 >                                is_cdrom = true;
523 >                                read_only = true;
524 >                                break;
525 >                        }
526                  }
333                ++tmp;
527          }
528   #endif
529  
# Line 355 | Line 548 | void *Sys_open(const char *name, bool re
548          }
549  
550          // Open file/device
551 < #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
551 > #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__)
552          int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0));
553   #else
554          int fd = open(name, read_only ? O_RDONLY : O_RDWR);
# Line 365 | Line 558 | void *Sys_open(const char *name, bool re
558                  read_only = true;
559                  fd = open(name, O_RDONLY);
560          }
561 <        if (fd >= 0) {
561 >        if (fd >= 0 || is_polled_media) {
562                  file_handle *fh = new file_handle;
563                  fh->name = strdup(name);
564                  fh->fd = fd;
565                  fh->is_file = is_file;
566                  fh->read_only = read_only;
567                  fh->start_byte = 0;
568 <                fh->is_floppy = false;
569 <                fh->is_cdrom = false;
568 >                fh->is_floppy = is_floppy;
569 >                fh->is_cdrom = is_cdrom;
570 >                fh->is_media_present = false;
571 > #if defined __MACOSX__
572 >                fh->ioctl_fd = -1;
573 >                fh->ioctl_name = NULL;
574 > #endif
575                  if (fh->is_file) {
576 +                        fh->is_media_present = true;
577                          // Detect disk image file layout
578                          loff_t size = 0;
380 #if defined(__linux__)
381                        _llseek(fh->fd, 0, 0, &size, SEEK_END);
382 #else
579                          size = lseek(fd, 0, SEEK_END);
384 #endif
580                          uint8 data[256];
581                          lseek(fd, 0, SEEK_SET);
582                          read(fd, data, 256);
# Line 389 | Line 584 | void *Sys_open(const char *name, bool re
584                  } else {
585                          struct stat st;
586                          if (fstat(fd, &st) == 0) {
587 +                                fh->is_media_present = true;
588                                  if (S_ISBLK(st.st_mode)) {
589                                          fh->is_cdrom = is_cdrom;
590   #if defined(__linux__)
# Line 416 | Line 612 | void *Sys_open(const char *name, bool re
612                                          fh->is_floppy = ((st.st_rdev >> 16) == 2);
613   #endif
614                                  }
615 < #if defined(__APPLE__) && defined(__MACH__)
616 <
617 <                                // In OS X, the device name is OK for sending ioctls to,
618 <                                // but not for reading raw CDROM data from.
619 <                                // (it seems to have extra data padded in)
620 <                                //
425 <                                // So, we keep the already opened fiole handle,
426 <                                // and open a slightly different file for CDROM data
427 <                                //
428 <                                if ( is_cdrom )
429 <                                {
430 <                                        fh->ioctl_name  = fh->name;
431 <                                        fh->ioctl_fd    = fh->fd;
432 <
433 <                                        fh->name = (char *) malloc(strlen(name) + 2);
434 <                                        if ( fh->name )
435 <                                        {
436 <                                                *fh->name = '\0';
437 <                                                strcat(fh->name, name);
438 <                                                strcat(fh->name, "s1");
439 <                                                fh->fd = open(fh->name, (read_only ? O_RDONLY : O_RDWR));
440 <                                                if ( fh->fd < 0 ) {
441 <                                                        printf("WARNING: Cannot open %s (%s)\n",
442 <                                                                                        fh->name, strerror(errno));
443 <                                                        return NULL;
444 <                                                }
445 <                                        }
615 > #if defined __MACOSX__
616 >                                if (is_cdrom) {
617 >                                        fh->is_cdrom = true;
618 >                                        fh->is_floppy = false;
619 >                                        if (cdrom_open_1(fh))
620 >                                                fh->is_media_present = true;
621                                  }
622   #endif
623                          }
624                  }
625                  if (fh->is_floppy && first_floppy == NULL)
626                          first_floppy = fh;
627 +                sys_add_file_handle(fh);
628                  return fh;
629          } else {
630                  printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno));
# Line 467 | Line 643 | void Sys_close(void *arg)
643          if (!fh)
644                  return;
645  
646 <        close(fh->fd);
646 >        sys_remove_file_handle(fh);
647 >
648 >        if (fh->is_cdrom)
649 >                cdrom_close(fh);
650 >        if (fh->fd >= 0)
651 >                close(fh->fd);
652          if (fh->name)
653                  free(fh->name);
654          delete fh;
# Line 486 | Line 667 | size_t Sys_read(void *arg, void *buffer,
667                  return 0;
668  
669          // Seek to position
489 #if defined(__linux__)
490        loff_t pos = offset + fh->start_byte, res;
491        if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
492                return 0;
493 #else
670          if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
671                  return 0;
496 #endif
672  
673          // Read data
674          return read(fh->fd, buffer, length);
# Line 512 | Line 687 | size_t Sys_write(void *arg, void *buffer
687                  return 0;
688  
689          // Seek to position
515 #if defined(__linux__)
516        loff_t pos = offset + fh->start_byte, res;
517        if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
518                return 0;
519 #else
690          if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
691                  return 0;
522 #endif
692  
693          // Write data
694          return write(fh->fd, buffer, length);
# Line 545 | Line 714 | loff_t SysGetFileSize(void *arg)
714                          return 0;
715                  D(bug(" BLKGETSIZE returns %d blocks\n", blocks));
716                  return (loff_t)blocks * 512;
717 + #elif defined __MACOSX__
718 +                uint32 block_size;
719 +                if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKSIZE, &block_size) < 0)
720 +                        return 0;
721 +                D(bug(" DKIOCGETBLOCKSIZE returns %lu bytes\n", (unsigned long)block_size));
722 +                uint64 block_count;
723 +                if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKCOUNT, &block_count) < 0)
724 +                        return 0;
725 +                D(bug(" DKIOCGETBLOCKCOUNT returns %llu blocks\n", (unsigned long long)block_count));
726 +                return block_count * block_size;
727   #else
728                  return lseek(fh->fd, 0, SEEK_END) - fh->start_byte;
729   #endif
# Line 564 | Line 743 | void SysEject(void *arg)
743  
744   #if defined(__linux__)
745          if (fh->is_floppy) {
746 <                fsync(fh->fd);
747 <                ioctl(fh->fd, FDFLUSH);
748 <                ioctl(fh->fd, FDEJECT);
749 <                close(fh->fd);  // Close and reopen so the driver will see the media change
746 >                if (fh->fd >= 0) {
747 >                        fsync(fh->fd);
748 >                        ioctl(fh->fd, FDFLUSH);
749 >                        ioctl(fh->fd, FDEJECT);
750 >                        close(fh->fd);  // Close and reopen so the driver will see the media change
751 >                }
752                  fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR);
753          } else if (fh->is_cdrom) {
754                  ioctl(fh->fd, CDROMEJECT);
# Line 583 | Line 764 | void SysEject(void *arg)
764                  fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
765          }
766   #elif defined(__APPLE__) && defined(__MACH__)
767 <        if ( fh->is_cdrom ) {
587 <
588 <                // Stolen from IOKit/storage/IOMediaBSDClient.h
589 <                #define DKIOCEJECT _IO('d', 21)
590 <
767 >        if (fh->is_cdrom && fh->is_media_present) {
768                  close(fh->fd);
769 <                if ( ioctl(fh->ioctl_fd, DKIOCEJECT) < 0 )
770 <                {
771 <                        printf("ioctl(DKIOCEJECT) failed on file %s: %s\n",
772 <                                                                fh->ioctl_name, strerror(errno));
596 <
597 <                        // If we are running OSX, the device may be is busy
598 <                        // due to the Finder having the disk mounted and open,
599 <                        // so we have to use another method.
600 <
601 <                        // The only problem is that this takes about 5 seconds:
602 <
603 <                        char    *cmd = (char *) malloc(30+sizeof(fh->name));
769 >                fh->fd = -1;
770 >                if (ioctl(fh->ioctl_fd, DKIOCEJECT) < 0) {
771 >                        D(bug(" DKIOCEJECT failed on file %s: %s\n",
772 >                                   fh->ioctl_name, strerror(errno)));
773  
774 <                        if ( ! cmd )
775 <                                return;
774 >                        // If we are running MacOS X, the device may be in busy
775 >                        // state because the Finder has mounted the disk
776                          close(fh->ioctl_fd);
777 <                        sprintf(cmd, "diskutil eject %s 2>&1 >/dev/null", fh->name);
777 >                        fh->ioctl_fd = -1;
778 >
779 >                        // Try to use "diskutil eject" but it can take up to 5
780 >                        // seconds to complete
781 >                        static const char eject_cmd[] = "/usr/sbin/diskutil eject %s 2>&1 >/dev/null";
782 >                        char *cmd = (char *)alloca(strlen(eject_cmd) + strlen(fh->ioctl_name) + 1);
783 >                        sprintf(cmd, eject_cmd, fh->ioctl_name);
784                          system(cmd);
785                  }
786 +                fh->is_media_present = false;
787          }
788   #endif
789   }
# Line 640 | Line 816 | bool SysIsReadOnly(void *arg)
816  
817   #if defined(__linux__)
818          if (fh->is_floppy) {
819 <                struct floppy_drive_struct stat;
820 <                ioctl(fh->fd, FDGETDRVSTAT, &stat);
821 <                return !(stat.flags & FD_DISK_WRITABLE);
819 >                if (fh->fd >= 0) {
820 >                        struct floppy_drive_struct stat;
821 >                        ioctl(fh->fd, FDGETDRVSTAT, &stat);
822 >                        return !(stat.flags & FD_DISK_WRITABLE);
823 >                } else
824 >                        return true;
825          } else
826   #endif
827                  return fh->read_only;
# Line 717 | Line 896 | bool SysIsDiskInserted(void *arg)
896          } else if (fh->is_cdrom) {
897                  struct ioc_toc_header header;
898                  return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0;
899 + #elif defined __MACOSX__
900 +        } else if (fh->is_cdrom || fh->is_floppy) {
901 +                return fh->is_media_present;
902   #endif
903  
904          } else
# Line 815 | Line 997 | bool SysCDReadTOC(void *arg, uint8 *toc)
997                  *toc++ = toc_size >> 8;
998                  *toc++ = toc_size & 0xff;
999                  return true;
1000 < #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_2)
1001 <                extern  bool    DarwinCDReadTOC(char *name, uint8 *toc);
1002 <
1003 <                return  DarwinCDReadTOC(fh->name, toc);
1000 > #elif defined __MACOSX__ && defined MAC_OS_X_VERSION_10_2
1001 >                if (fh->is_media_present) {
1002 >                        extern bool DarwinCDReadTOC(char *name, uint8 *toc);
1003 >                        return DarwinCDReadTOC(fh->name, toc);
1004 >                }
1005 >                return false;
1006   #elif defined(__FreeBSD__)
1007                  uint8 *p = toc + 2;
1008  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines