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