1/*
2 * Copyright (c) 2007 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "optical.h"
25
26#include <paths.h>
27#include <string.h>
28#include <CoreFoundation/CoreFoundation.h>
29#include <IOKit/IOKitLib.h>
30#include <IOKit/storage/IOMedia.h>
31#include <IOKit/storage/IOBDMedia.h>
32#include <IOKit/storage/IOCDMedia.h>
33#include <IOKit/storage/IODVDMedia.h>
34
35static io_service_t
36__io_media_copy_whole_media(io_service_t media)
37{
38    io_service_t parent;
39    CFTypeRef property;
40
41    IOObjectRetain(media);
42
43    while (media) {
44        if (IOObjectConformsTo(media, kIOMediaClass)) {
45            property = IORegistryEntryCreateCFProperty(media, CFSTR(kIOMediaWholeKey), kCFAllocatorDefault, 0);
46            if (property) {
47                CFRelease(property);
48                if (property == kCFBooleanTrue)
49                    break;
50            }
51        }
52        parent = IO_OBJECT_NULL;
53        IORegistryEntryGetParentEntry(media, kIOServicePlane, &parent);
54        IOObjectRelease(media);
55        media = parent;
56    }
57
58    return media;
59}
60
61static io_service_t
62__io_media_create_from_bsd_name(const char *name)
63{
64    if (!strncmp(_PATH_DEV, name, strlen(_PATH_DEV)))
65        name += strlen(_PATH_DEV);
66
67    return IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, name));
68}
69
70static int
71__io_media_is_writable(io_service_t media)
72{
73    int writable = 0;
74    CFTypeRef property;
75
76    property = IORegistryEntryCreateCFProperty(media, CFSTR(kIOMediaWritableKey), kCFAllocatorDefault, 0);
77    if (property) {
78        CFRelease(property);
79        if (property == kCFBooleanTrue) {
80            writable = _OPTICAL_WRITABLE_SECTOR;
81
82            if (IOObjectConformsTo(media, kIOBDMediaClass)) {
83                property = IORegistryEntryCreateCFProperty(media, CFSTR(kIOBDMediaTypeKey), kCFAllocatorDefault, 0);
84                if (property) {
85                    if (CFEqual(property, CFSTR(kIOBDMediaTypeR)))
86                        writable = _OPTICAL_WRITABLE_PACKET | _OPTICAL_WRITABLE_ONCE;   /* BD-R */
87                    else if (CFEqual(property, CFSTR(kIOBDMediaTypeRE)))
88                        writable = _OPTICAL_WRITABLE_PACKET;                           /* BD-RE */
89                    CFRelease(property);
90                }
91            } else if (IOObjectConformsTo(media, kIOCDMediaClass)) {
92                property = IORegistryEntryCreateCFProperty(media, CFSTR(kIOCDMediaTypeKey), kCFAllocatorDefault, 0);
93                if (property) {
94                    if (CFEqual(property, CFSTR(kIOCDMediaTypeR)))
95                        writable = _OPTICAL_WRITABLE_PACKET | _OPTICAL_WRITABLE_ONCE;   /* CD-R */
96                    else if (CFEqual(property, CFSTR(kIOCDMediaTypeRW)))
97                        writable = _OPTICAL_WRITABLE_PACKET;                            /* CD-RW */
98
99                    CFRelease(property);
100                }
101            } else if (IOObjectConformsTo(media, kIODVDMediaClass)) {
102                property = IORegistryEntryCreateCFProperty(media, CFSTR(kIODVDMediaTypeKey), kCFAllocatorDefault, 0);
103                if (property) {
104                    if (CFEqual(property, CFSTR(kIODVDMediaTypeR)))
105                        writable = _OPTICAL_WRITABLE_PACKET | _OPTICAL_WRITABLE_ONCE;   /* DVD-R */
106                    else if (CFEqual(property, CFSTR(kIODVDMediaTypeRW)))
107                        writable = _OPTICAL_WRITABLE_PACKET;                            /* DVD-RW */
108                    else if (CFEqual(property, CFSTR(kIODVDMediaTypePlusR)))
109                        writable = _OPTICAL_WRITABLE_PACKET | _OPTICAL_WRITABLE_ONCE;   /* DVD+R */
110                    else if (CFEqual(property, CFSTR(kIODVDMediaTypePlusRW)))
111                        writable = _OPTICAL_WRITABLE_PACKET;                            /* DVD+RW */
112                    else if (CFEqual(property, CFSTR(kIODVDMediaTypeHDR)))
113                        writable = _OPTICAL_WRITABLE_PACKET | _OPTICAL_WRITABLE_ONCE;   /* HD DVD-R */
114
115                    CFRelease(property);
116                }
117            }
118        }
119    }
120
121    return writable;
122}
123
124int
125_optical_is_writable(const char *dev)
126{
127    int writable = 0;
128    io_service_t media;
129    io_service_t whole;
130
131    media = __io_media_create_from_bsd_name(dev);
132    if (media) {
133        writable = __io_media_is_writable(media);
134        if (writable) {
135            whole = __io_media_copy_whole_media(media);
136            if (whole) {
137                writable = __io_media_is_writable(whole);
138
139                IOObjectRelease(whole);
140            }
141        }
142        IOObjectRelease(media);
143    }
144
145    return writable;
146}
147