27 |
#include <unistd.h> |
#include <unistd.h> |
28 |
#include <fcntl.h> |
#include <fcntl.h> |
29 |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
30 |
|
#if defined (__GNUC__) && (__GNUC__ >= 4) |
31 |
|
#include <sys/disk.h> |
32 |
|
#else |
33 |
|
#include <dev/disk.h> |
34 |
|
#endif |
35 |
#include <sys/types.h> |
#include <sys/types.h> |
36 |
#include <sys/stat.h> |
#include <sys/stat.h> |
37 |
#include <errno.h> |
#include <errno.h> |
38 |
#include <paths.h> |
#include <paths.h> |
39 |
#ifdef _CARBON_ |
#if defined(_CARBON_) || defined(__APPLE__) |
40 |
#include <sys/param.h> |
#include <sys/param.h> |
41 |
#include <IOKit/IOKitLib.h> |
#include <IOKit/IOKitLib.h> |
42 |
#include <IOKit/IOBSD.h> |
#include <IOKit/IOBSD.h> |
47 |
#include <CoreFoundation/CoreFoundation.h> |
#include <CoreFoundation/CoreFoundation.h> |
48 |
#endif |
#endif |
49 |
|
|
50 |
|
#if defined(_CARBON_) || defined(__APPLE__) |
51 |
|
|
52 |
|
// These definitions were taken from mount_cd9660.c |
53 |
|
// There are some similar definitions in IOCDTypes.h |
54 |
|
// however there seems to be some dissagreement in |
55 |
|
// the definition of CDTOC.length |
56 |
|
struct _CDMSF { |
57 |
|
u_char minute; |
58 |
|
u_char second; |
59 |
|
u_char frame; |
60 |
|
}; |
61 |
|
|
62 |
|
#define MSF_TO_LBA(msf) \ |
63 |
|
(((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150) |
64 |
|
|
65 |
|
struct _CDTOC_Desc { |
66 |
|
u_char session; |
67 |
|
u_char ctrl_adr; /* typed to be machine and compiler independent */ |
68 |
|
u_char tno; |
69 |
|
u_char point; |
70 |
|
struct _CDMSF address; |
71 |
|
u_char zero; |
72 |
|
struct _CDMSF p; |
73 |
|
}; |
74 |
|
|
75 |
|
struct _CDTOC { |
76 |
|
u_short length; /* in native cpu endian */ |
77 |
|
u_char first_session; |
78 |
|
u_char last_session; |
79 |
|
struct _CDTOC_Desc trackdesc[1]; |
80 |
|
}; |
81 |
|
|
82 |
|
// Most of the following Mac CDROM IO functions were taken from Apple's IOKit |
83 |
|
// examples (BSD style license). ReadTOC() function was taken from the Bochs x86 |
84 |
|
// Emulator (LGPL). Most probably they have taken it however also from some |
85 |
|
// other BSD style licensed example code as well ... |
86 |
|
|
87 |
|
// Returns an iterator across all CD media (class IOCDMedia). Caller is responsible for releasing |
88 |
|
// the iterator when iteration is complete. |
89 |
|
static kern_return_t FindEjectableCDMedia(io_iterator_t *mediaIterator) { |
90 |
|
kern_return_t kernResult; |
91 |
|
CFMutableDictionaryRef classesToMatch; |
92 |
|
|
93 |
|
// CD media are instances of class kIOCDMediaClass |
94 |
|
classesToMatch = IOServiceMatching(kIOCDMediaClass); |
95 |
|
if (classesToMatch == NULL) { |
96 |
|
printf("IOServiceMatching returned a NULL dictionary.\n"); |
97 |
|
} else { |
98 |
|
CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue); |
99 |
|
// Each IOMedia object has a property with key kIOMediaEjectableKey which is true if the |
100 |
|
// media is indeed ejectable. So add this property to the CFDictionary we're matching on. |
101 |
|
} |
102 |
|
|
103 |
|
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, mediaIterator); |
104 |
|
|
105 |
|
return kernResult; |
106 |
|
} |
107 |
|
|
108 |
|
// Given an iterator across a set of CD media, return the BSD path to the |
109 |
|
// next one. If no CD media was found the path name is set to an empty string. |
110 |
|
static kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize) { |
111 |
|
io_object_t nextMedia; |
112 |
|
kern_return_t kernResult = KERN_FAILURE; |
113 |
|
|
114 |
|
*bsdPath = '\0'; |
115 |
|
|
116 |
|
nextMedia = IOIteratorNext(mediaIterator); |
117 |
|
if (nextMedia) { |
118 |
|
CFTypeRef bsdPathAsCFString; |
119 |
|
|
120 |
|
bsdPathAsCFString = IORegistryEntryCreateCFProperty(nextMedia, |
121 |
|
CFSTR(kIOBSDNameKey), |
122 |
|
kCFAllocatorDefault, |
123 |
|
0); |
124 |
|
if (bsdPathAsCFString) { |
125 |
|
strlcpy(bsdPath, _PATH_DEV, maxPathSize); |
126 |
|
|
127 |
|
// Add "r" before the BSD node name from the I/O Registry to specify the raw disk |
128 |
|
// node. The raw disk nodes receive I/O requests directly and do not go through |
129 |
|
// the buffer cache. |
130 |
|
|
131 |
|
strlcat(bsdPath, "r", maxPathSize); |
132 |
|
|
133 |
|
size_t devPathLength = strlen(bsdPath); |
134 |
|
|
135 |
|
if (CFStringGetCString((CFStringRef)bsdPathAsCFString, |
136 |
|
bsdPath + devPathLength, |
137 |
|
maxPathSize - devPathLength, |
138 |
|
kCFStringEncodingUTF8)) { |
139 |
|
printf("BSD path: %s\n", bsdPath); |
140 |
|
kernResult = KERN_SUCCESS; |
141 |
|
} |
142 |
|
|
143 |
|
CFRelease(bsdPathAsCFString); |
144 |
|
} |
145 |
|
|
146 |
|
IOObjectRelease(nextMedia); |
147 |
|
} |
148 |
|
|
149 |
|
return kernResult; |
150 |
|
} |
151 |
|
|
152 |
|
// Given the path to a CD drive, open the drive. |
153 |
|
// Return the file descriptor associated with the device. |
154 |
|
static int OpenDrive(const char *bsdPath) { |
155 |
|
int fileDescriptor; |
156 |
|
|
157 |
|
// This open() call will fail with a permissions error if the sample has been changed to |
158 |
|
// look for non-removable media. This is because device nodes for fixed-media devices are |
159 |
|
// owned by root instead of the current console user. |
160 |
|
|
161 |
|
fileDescriptor = open(bsdPath, O_RDONLY); |
162 |
|
|
163 |
|
if (fileDescriptor == -1) { |
164 |
|
printf("Error opening device %s: ", bsdPath); |
165 |
|
perror(NULL); |
166 |
|
} |
167 |
|
|
168 |
|
return fileDescriptor; |
169 |
|
} |
170 |
|
|
171 |
|
// Given the file descriptor for a whole-media CD device, read a sector from the drive. |
172 |
|
// Return true if successful, otherwise false. |
173 |
|
static Boolean ReadSector(int fileDescriptor) { |
174 |
|
char *buffer; |
175 |
|
ssize_t numBytes; |
176 |
|
u_int32_t blockSize; |
177 |
|
|
178 |
|
// This ioctl call retrieves the preferred block size for the media. It is functionally |
179 |
|
// equivalent to getting the value of the whole media object's "Preferred Block Size" |
180 |
|
// property from the IORegistry. |
181 |
|
if (ioctl(fileDescriptor, DKIOCGETBLOCKSIZE, &blockSize)) { |
182 |
|
perror("Error getting preferred block size"); |
183 |
|
|
184 |
|
// Set a reasonable default if we can't get the actual preferred block size. A real |
185 |
|
// app would probably want to bail at this point. |
186 |
|
blockSize = kCDSectorSizeCDDA; |
187 |
|
} |
188 |
|
|
189 |
|
printf("Media has block size of %d bytes.\n", blockSize); |
190 |
|
|
191 |
|
// Allocate a buffer of the preferred block size. In a real application, performance |
192 |
|
// can be improved by reading as many blocks at once as you can. |
193 |
|
buffer = (char*) malloc(blockSize); |
194 |
|
|
195 |
|
// Do the read. Note that we use read() here, not fread(), since this is a raw device |
196 |
|
// node. |
197 |
|
numBytes = read(fileDescriptor, buffer, blockSize); |
198 |
|
|
199 |
|
// Free our buffer. Of course, a real app would do something useful with the data first. |
200 |
|
free(buffer); |
201 |
|
|
202 |
|
return numBytes == blockSize ? true : false; |
203 |
|
} |
204 |
|
|
205 |
|
// Given the file descriptor for a device, close that device. |
206 |
|
static void CloseDrive(int fileDescriptor) { |
207 |
|
close(fileDescriptor); |
208 |
|
} |
209 |
|
|
210 |
|
// path is the BSD path to a raw device such as /dev/rdisk1 |
211 |
|
static struct _CDTOC * ReadTOC(const char *devpath) { |
212 |
|
struct _CDTOC * toc_p = NULL; |
213 |
|
io_iterator_t iterator = 0; |
214 |
|
io_registry_entry_t service = 0; |
215 |
|
CFDictionaryRef properties = 0; |
216 |
|
CFDataRef data = 0; |
217 |
|
mach_port_t port = 0; |
218 |
|
char *devname; |
219 |
|
|
220 |
|
if ((devname = strrchr(devpath, '/')) != NULL) { |
221 |
|
++devname; |
222 |
|
} else { |
223 |
|
devname = (char *) devpath; |
224 |
|
} |
225 |
|
|
226 |
|
if (IOMasterPort(bootstrap_port, &port) != KERN_SUCCESS) { |
227 |
|
fprintf(stderr, "IOMasterPort failed\n"); |
228 |
|
goto Exit; |
229 |
|
} |
230 |
|
|
231 |
|
if (IOServiceGetMatchingServices(port, IOBSDNameMatching(port, 0, devname), |
232 |
|
&iterator) != KERN_SUCCESS) { |
233 |
|
fprintf(stderr, "IOServiceGetMatchingServices failed\n"); |
234 |
|
goto Exit; |
235 |
|
} |
236 |
|
|
237 |
|
service = IOIteratorNext(iterator); |
238 |
|
|
239 |
|
IOObjectRelease(iterator); |
240 |
|
|
241 |
|
iterator = 0; |
242 |
|
|
243 |
|
while (service && !IOObjectConformsTo(service, "IOCDMedia")) { |
244 |
|
if (IORegistryEntryGetParentIterator(service, kIOServicePlane, |
245 |
|
&iterator) != KERN_SUCCESS) |
246 |
|
{ |
247 |
|
fprintf(stderr, "IORegistryEntryGetParentIterator failed\n"); |
248 |
|
goto Exit; |
249 |
|
} |
250 |
|
|
251 |
|
IOObjectRelease(service); |
252 |
|
service = IOIteratorNext(iterator); |
253 |
|
IOObjectRelease(iterator); |
254 |
|
} |
255 |
|
|
256 |
|
if (!service) { |
257 |
|
fprintf(stderr, "CD media not found\n"); |
258 |
|
goto Exit; |
259 |
|
} |
260 |
|
|
261 |
|
if (IORegistryEntryCreateCFProperties(service, (__CFDictionary **) &properties, |
262 |
|
kCFAllocatorDefault, |
263 |
|
kNilOptions) != KERN_SUCCESS) |
264 |
|
{ |
265 |
|
fprintf(stderr, "IORegistryEntryGetParentIterator failed\n"); |
266 |
|
goto Exit; |
267 |
|
} |
268 |
|
|
269 |
|
data = (CFDataRef) CFDictionaryGetValue(properties, CFSTR(kIOCDMediaTOCKey)); |
270 |
|
if (data == NULL) { |
271 |
|
fprintf(stderr, "CFDictionaryGetValue failed\n"); |
272 |
|
goto Exit; |
273 |
|
} else { |
274 |
|
CFRange range; |
275 |
|
CFIndex buflen; |
276 |
|
|
277 |
|
buflen = CFDataGetLength(data) + 1; |
278 |
|
range = CFRangeMake(0, buflen); |
279 |
|
toc_p = (struct _CDTOC *) malloc(buflen); |
280 |
|
if (toc_p == NULL) { |
281 |
|
fprintf(stderr, "Out of memory\n"); |
282 |
|
goto Exit; |
283 |
|
} else { |
284 |
|
CFDataGetBytes(data, range, (unsigned char *) toc_p); |
285 |
|
} |
286 |
|
|
287 |
|
/* |
288 |
|
fprintf(stderr, "Table of contents\n length %d first %d last %d\n", |
289 |
|
toc_p->length, toc_p->first_session, toc_p->last_session); |
290 |
|
*/ |
291 |
|
|
292 |
|
CFRelease(properties); |
293 |
|
} |
294 |
|
|
295 |
|
Exit: |
296 |
|
|
297 |
|
if (service) { |
298 |
|
IOObjectRelease(service); |
299 |
|
} |
300 |
|
|
301 |
|
return toc_p; |
302 |
|
} |
303 |
|
|
304 |
|
#endif // defined(_CARBON_) || defined(__APPLE__) |
305 |
|
|
306 |
////////////////////////////////// |
////////////////////////////////// |
307 |
// AkaiSample: |
// AkaiSample: |
308 |
AkaiSample::AkaiSample(DiskImage* pDisk, AkaiVolume* pParent, const AkaiDirEntry& DirEntry) |
AkaiSample::AkaiSample(DiskImage* pDisk, AkaiVolume* pParent, const AkaiDirEntry& DirEntry) |
826 |
if (mDirEntry.mType != AKAI_TYPE_DIR_S1000 && mDirEntry.mType != AKAI_TYPE_DIR_S3000) |
if (mDirEntry.mType != AKAI_TYPE_DIR_S1000 && mDirEntry.mType != AKAI_TYPE_DIR_S3000) |
827 |
{ |
{ |
828 |
printf("Creating Unknown Volume type! %d\n",mDirEntry.mType); |
printf("Creating Unknown Volume type! %d\n",mDirEntry.mType); |
829 |
#ifdef _WIN32_ |
#ifdef WIN32 |
830 |
OutputDebugString("Creating Unknown Volume type!\n"); |
OutputDebugString("Creating Unknown Volume type!\n"); |
831 |
#endif |
#endif |
832 |
} |
} |
1502 |
mSize = dg.BytesPerSector * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.Cylinders.LowPart; |
mSize = dg.BytesPerSector * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.Cylinders.LowPart; |
1503 |
mClusterSize = dg.BytesPerSector; |
mClusterSize = dg.BytesPerSector; |
1504 |
} |
} |
1505 |
#elif defined _CARBON_ |
#elif defined(_CARBON_) || defined(__APPLE__) |
1506 |
kern_return_t kernResult; |
kern_return_t kernResult; |
1507 |
io_iterator_t mediaIterator; |
io_iterator_t mediaIterator; |
1508 |
char bsdPath[ MAXPATHLEN ]; |
char bsdPath[ MAXPATHLEN ]; |
1581 |
mCluster = (uint)-1; |
mCluster = (uint)-1; |
1582 |
mStartFrame = -1; |
mStartFrame = -1; |
1583 |
mEndFrame = -1; |
mEndFrame = -1; |
1584 |
#ifdef _WIN32_ |
#ifdef WIN32 |
1585 |
mpCache = (char*) VirtualAlloc(NULL,mClusterSize,MEM_COMMIT,PAGE_READWRITE); |
mpCache = (char*) VirtualAlloc(NULL,mClusterSize,MEM_COMMIT,PAGE_READWRITE); |
1586 |
#else |
#else |
1587 |
mpCache = NULL; // we allocate the cache later when we know what type of media we access |
mpCache = NULL; // we allocate the cache later when we know what type of media we access |
1590 |
|
|
1591 |
DiskImage::~DiskImage() |
DiskImage::~DiskImage() |
1592 |
{ |
{ |
1593 |
#ifdef _WIN32_ |
#ifdef WIN32 |
1594 |
if (mFile != INVALID_HANDLE_VALUE) |
if (mFile != INVALID_HANDLE_VALUE) |
1595 |
{ |
{ |
1596 |
CloseHandle(mFile); |
CloseHandle(mFile); |
1597 |
} |
} |
1598 |
#elif defined _CARBON_ || LINUX |
#elif defined _CARBON_ || defined(__APPLE__) || LINUX |
1599 |
if (mFile) |
if (mFile) |
1600 |
{ |
{ |
1601 |
close(mFile); |
close(mFile); |
1603 |
#endif |
#endif |
1604 |
if (mpCache) |
if (mpCache) |
1605 |
{ |
{ |
1606 |
#ifdef _WIN32_ |
#ifdef WIN32 |
1607 |
VirtualFree(mpCache, 0, MEM_RELEASE); |
VirtualFree(mpCache, 0, MEM_RELEASE); |
1608 |
#elif defined _CARBON_ || LINUX |
#elif defined(_CARBON_) || defined(__APPLE__) || LINUX |
1609 |
free(mpCache); |
free(mpCache); |
1610 |
#endif |
#endif |
1611 |
} |
} |
1664 |
: mPos / mClusterSize + mStartFrame; |
: mPos / mClusterSize + mStartFrame; |
1665 |
if (mCluster != requestedCluster) { // read the requested cluster into cache |
if (mCluster != requestedCluster) { // read the requested cluster into cache |
1666 |
mCluster = requestedCluster; |
mCluster = requestedCluster; |
1667 |
#ifdef _WIN32_ |
#ifdef WIN32 |
1668 |
if (mCluster * mClusterSize != SetFilePointer(mFile, mCluster * mClusterSize, NULL, FILE_BEGIN)) { |
if (mCluster * mClusterSize != SetFilePointer(mFile, mCluster * mClusterSize, NULL, FILE_BEGIN)) { |
1669 |
printf("ERROR: couldn't seek device!\n"); |
printf("ERROR: couldn't seek device!\n"); |
1670 |
if ((readbytes > 0) && (mEndian != eEndianNative)) { |
if ((readbytes > 0) && (mEndian != eEndianNative)) { |
1678 |
} |
} |
1679 |
DWORD size; |
DWORD size; |
1680 |
ReadFile(mFile, mpCache, mClusterSize, &size, NULL); |
ReadFile(mFile, mpCache, mClusterSize, &size, NULL); |
1681 |
#elif defined _CARBON_ || LINUX |
#elif defined(_CARBON_) || defined(__APPLE__) || LINUX |
1682 |
if (mCluster * mClusterSize != lseek(mFile, mCluster * mClusterSize, SEEK_SET)) |
if (mCluster * mClusterSize != lseek(mFile, mCluster * mClusterSize, SEEK_SET)) |
1683 |
return readbytes / WordSize; |
return readbytes / WordSize; |
1684 |
// printf("trying to read %d bytes from device!\n",mClusterSize); |
// printf("trying to read %d bytes from device!\n",mClusterSize); |
1780 |
} |
} |
1781 |
|
|
1782 |
void DiskImage::OpenStream(const char* path) { |
void DiskImage::OpenStream(const char* path) { |
1783 |
#ifdef _WIN32_ |
#ifdef WIN32 |
1784 |
mFile = CreateFile(path, GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,NULL); |
mFile = CreateFile(path, GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,NULL); |
1785 |
BY_HANDLE_FILE_INFORMATION FileInfo; |
BY_HANDLE_FILE_INFORMATION FileInfo; |
1786 |
GetFileInformationByHandle(mFile,&FileInfo); |
GetFileInformationByHandle(mFile,&FileInfo); |
1787 |
mSize = FileInfo.nFileSizeLow; |
mSize = FileInfo.nFileSizeLow; |
1788 |
#elif _CARBON_ || LINUX |
#elif defined(_CARBON_) || defined(__APPLE__) || LINUX |
1789 |
struct stat filestat; |
struct stat filestat; |
1790 |
stat(path,&filestat); |
stat(path,&filestat); |
1791 |
mFile = open(path, O_RDONLY | O_NONBLOCK); |
mFile = open(path, O_RDONLY | O_NONBLOCK); |
1801 |
mSize = filestat.st_size; |
mSize = filestat.st_size; |
1802 |
mClusterSize = DISK_CLUSTER_SIZE; |
mClusterSize = DISK_CLUSTER_SIZE; |
1803 |
mpCache = (char*) malloc(mClusterSize); |
mpCache = (char*) malloc(mClusterSize); |
1804 |
} |
} else { // CDROM |
1805 |
else { // CDROM |
#if defined(_CARBON_) || defined(__APPLE__) |
1806 |
|
printf("Can't open %s: not a regular file\n", path); |
1807 |
|
#else // Linux ... |
1808 |
mRegularFile = false; |
mRegularFile = false; |
1809 |
mClusterSize = CD_FRAMESIZE; |
mClusterSize = CD_FRAMESIZE; |
1810 |
mpCache = (char*) malloc(mClusterSize); |
mpCache = (char*) malloc(mClusterSize); |
1864 |
mStartFrame = start; |
mStartFrame = start; |
1865 |
mEndFrame = end; |
mEndFrame = end; |
1866 |
mSize = length * CD_FRAMESIZE; |
mSize = length * CD_FRAMESIZE; |
1867 |
|
#endif |
1868 |
} // CDROM |
} // CDROM |
1869 |
#endif |
#endif |
1870 |
} |
} |
1871 |
|
|
1872 |
bool DiskImage::WriteImage(const char* path) |
bool DiskImage::WriteImage(const char* path) |
1873 |
{ |
{ |
1874 |
#if _CARBON_ || LINUX |
#if defined(_CARBON_) || defined(__APPLE__) || LINUX |
1875 |
const uint bufferSize = 524288; // 512 kB |
const uint bufferSize = 524288; // 512 kB |
1876 |
int fOut = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_TRUNC); |
int fOut = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_TRUNC); |
1877 |
if (mFile <= 0) { |
if (mFile <= 0) { |