1/* 2 * Copyright (c) 1999-2000, 2002, 2005, 2007-2008 Apple 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#include "SRuntime.h" 24#include "../fsck_hfs.h" 25 26#if BSD 27 28#include <unistd.h> 29#include <errno.h> 30#include <sys/ioctl.h> 31 32#include <IOKit/storage/IOMediaBSDClient.h> 33 34#else 35 36#include <Files.h> 37#include <Device.h> 38#include <Disks.h> 39 40#endif 41 42 43OSErr GetDeviceSize(int driveRefNum, UInt64 *numBlocks, UInt32 *blockSize) 44{ 45#if BSD 46 UInt64 devBlockCount = 0; 47 int devBlockSize = 0; 48 49 if (ioctl(driveRefNum, DKIOCGETBLOCKCOUNT, &devBlockCount) < 0) { 50 plog("ioctl(DKIOCGETBLOCKCOUNT) for fd %d: %s\n", driveRefNum, strerror(errno)); 51 return (-1); 52 } 53 54 if (ioctl(driveRefNum, DKIOCGETBLOCKSIZE, &devBlockSize) < 0) { 55 plog("ioctl(DKIOCGETBLOCKSIZE) for fd %d: %s\n", driveRefNum, strerror(errno)); 56 return (-1); 57 } 58 59 if (devBlockSize != 512) { 60 *numBlocks = (devBlockCount * (UInt64)devBlockSize) / 512; 61 *blockSize = 512; 62 } else { 63 *numBlocks = devBlockCount; 64 *blockSize = devBlockSize; 65 } 66 return (0); 67#else 68 /* Various Mac OS device constants */ 69 enum 70 { 71 /* return format list status code */ 72 kFmtLstCode = 6, 73 74 /* reference number of .SONY driver */ 75 kSonyRefNum = 0xfffb, 76 77 /* values returned by DriveStatus in DrvSts.twoSideFmt */ 78 kSingleSided = 0, 79 kDoubleSided = -1, 80 kSingleSidedSize = 800, /* 400K */ 81 kDoubleSidedSize = 1600, /* 800K */ 82 83 /* values in DrvQEl.qType */ 84 kWordDrvSiz = 0, 85 kLongDrvSiz = 1, 86 87 /* more than enough formatListRecords */ 88 kMaxFormatListRecs = 16 89 }; 90 91 ParamBlockRec pb; 92 FormatListRec formatListRecords[kMaxFormatListRecs]; 93 DrvSts status; 94 short formatListRecIndex; 95 OSErr result; 96 unsigned long blocks = 0; 97 98 99 /* Attempt to get the drive's format list. */ 100 /* (see the Technical Note "What Your Sony Drives For You") */ 101 102 pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive; 103 pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum; 104 pb.cntrlParam.csCode = kFmtLstCode; 105 pb.cntrlParam.csParam[0] = kMaxFormatListRecs; 106 *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0]; 107 108 result = PBStatusSync(&pb); 109 110 if ( result == noErr ) 111 { 112 /* The drive supports ReturnFormatList status call. */ 113 114 /* Get the current disk's size. */ 115 for( formatListRecIndex = 0; 116 formatListRecIndex < pb.cntrlParam.csParam[0]; 117 ++formatListRecIndex ) 118 { 119 if ( (formatListRecords[formatListRecIndex].formatFlags & 120 diCIFmtFlagsCurrentMask) != 0 ) 121 { 122 blocks = formatListRecords[formatListRecIndex].volSize; 123 } 124 } 125 if ( blocks == 0 ) 126 { 127 /* This should never happen */ 128 result = paramErr; 129 } 130 } 131 else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum ) 132 { 133 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */ 134 135 result = DriveStatus(driveQElementPtr->dQDrive, &status); 136 if ( result == noErr ) 137 { 138 switch ( status.twoSideFmt ) 139 { 140 case kSingleSided: 141 blocks = kSingleSidedSize; 142 break; 143 144 case kDoubleSided: 145 blocks = kDoubleSidedSize; 146 break; 147 148 default: // This should never happen 149 result = paramErr; 150 break; 151 } 152 } 153 } 154 else 155 { 156 /* The drive is not a floppy and it doesn't support ReturnFormatList */ 157 /* so use the dQDrvSz field(s) */ 158 159 result = noErr; /* reset result */ 160 161 switch ( driveQElementPtr->qType ) 162 { 163 case kWordDrvSiz: 164 blocks = driveQElementPtr->dQDrvSz; 165 break; 166 167 case kLongDrvSiz: 168 blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) + 169 driveQElementPtr->dQDrvSz; 170 break; 171 172 default: // This should never happen 173 result = paramErr; 174 break; 175 } 176 } 177 178 *numBlocks = blocks; 179 *blockSize = 512; 180 181 return( result ); 182#endif 183} 184 185 186OSErr DeviceRead(int device, int drive, void* buffer, SInt64 offset, UInt32 reqBytes, UInt32 *actBytes) 187{ 188#if BSD 189 off_t seek_off; 190 ssize_t nbytes; 191 192 *actBytes = 0; 193 194 seek_off = lseek(device, offset, SEEK_SET); 195 if (seek_off == -1) { 196 plog("# DeviceRead: lseek(%qd) failed with %d\n", offset, errno); 197 return (errno); 198 } 199 200 nbytes = read(device, buffer, reqBytes); 201 if (nbytes == -1) 202 return (errno); 203 if (nbytes == 0) { 204 plog("CANNOT READ: BLK %ld\n", (long)offset/512); 205 return (5); 206 } 207 208 *actBytes = nbytes; 209 return (0); 210 211#else 212 OSErr err; 213 XIOParam pb; 214 215 pb.ioVRefNum = drive; 216 pb.ioRefNum = device; 217 pb.ioPosMode = fsFromStart; 218 pb.ioReqCount = reqBytes; 219 pb.ioBuffer = buffer; 220 221 if ( (offset & 0xFFFFFFFF00000000) != 0 ) 222 { 223 *(SInt64*)&pb.ioWPosOffset = offset; 224 pb.ioPosMode |= (1 << kWidePosOffsetBit); 225 } 226 else 227 { 228 ((IOParam*)&pb)->ioPosOffset = offset; 229 } 230 231 err = PBReadSync( (ParamBlockRec *)&pb ); 232 233 return (err); 234#endif 235} 236 237 238OSErr DeviceWrite(int device, int drive, void* buffer, SInt64 offset, UInt32 reqBytes, UInt32 *actBytes) 239{ 240#if BSD 241 off_t seek_off; 242 ssize_t nbytes; 243 244 *actBytes = 0; 245 246 seek_off = lseek(device, offset, SEEK_SET); 247 if (seek_off == -1) { 248 plog("# DeviceRead: lseek(%qd) failed with %d\n", offset, errno); 249 return (errno); 250 } 251 252 nbytes = write(device, buffer, reqBytes); 253 if (nbytes == -1) { 254 return (errno); 255 } 256 if (nbytes == 0) { 257 plog("CANNOT WRITE: BLK %ld\n", (long)offset/512); 258 return (5); 259 } 260 261 *actBytes = nbytes; 262 return (0); 263#else 264 OSErr err; 265 XIOParam pb; 266 267 pb.ioVRefNum = drive; 268 pb.ioRefNum = device; 269 pb.ioPosMode = fsFromStart; 270 pb.ioReqCount = reqBytes; 271 pb.ioBuffer = buffer; 272 273 if ( (offset & 0xFFFFFFFF00000000) != 0 ) 274 { 275 *(SInt64*)&pb.ioWPosOffset = offset; 276 pb.ioPosMode |= (1 << kWidePosOffsetBit); 277 } 278 else 279 { 280 ((IOParam*)&pb)->ioPosOffset = offset; 281 } 282 283 err = PBWriteSync( (ParamBlockRec *)&pb ); 284 285 return (err); 286#endif 287} 288