|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
25: *
26: * IOLogicalDisk.m
27: *
28: * HISTORY
29: * 05-Mar-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import <driverkit/return.h>
34: #import <driverkit/IODisk.h>
35: #ifdef KERNEL
36: #import <kernserv/prototypes.h>
37: #import <mach/mach_interface.h>
38: #import <driverkit/kernelDiskMethods.h>
39: #else KERNEL
40: #import <mach/mach.h>
41: #import <bsd/libc.h>
42: #endif KERNEL
43: #import <driverkit/IOLogicalDisk.h>
44: #import <driverkit/Device_ddm.h>
45: #import <driverkit/generalFuncs.h>
46: #import <driverkit/SCSIDisk.h>
47:
48: @interface IOLogicalDisk(private)
49: - (IOReturn)_diskParamCommon :(u_int)logicalOffset
50: length : (u_int)bytesReq
51: deviceOffset : (unsigned *)deviceOffset
52: bytesToMove : (u_int *)bytesToMove;
53:
54: - (IOReturn)computePartition :(u_int)logicalOffset
55: length : (u_int)bytesReq
56: byteOffset : (unsigned long long *)byteOffset
57: bytesToMove : (u_int *)bytesToMove;
58:
59: /* This must be a class method since it's called by
60: * a class method in DiskPartition.
61: */
62:
63: + (IOReturn) reblock : (id)physicalDisk
64: : (BOOL)read
65: : (unsigned long long)offset /* bytes */
66: : (unsigned)length /* bytes */
67: : (unsigned char *)buffer
68: : (vm_task_t)client
69: : (void *)pending
70: : (unsigned)physsize; /* phys blocksize */
71: @end
72:
73: @implementation IOLogicalDisk
74:
75: /*
76: * Standard IODiskDeviceReadingAndWriting methods. We translate into raw device
77: * parameters and pass along to _physicalDisk.
78: */
79: #ifdef KERNEL
80:
81: - (IOReturn) readAt : (unsigned)offset
82: length : (unsigned)length
83: buffer : (unsigned char *)buffer
84: actualLength : (unsigned *)actualLength
85: client : (vm_task_t)client
86: {
87: IOReturn rtn;
88: unsigned bytesToMove;
89: unsigned long long byteposition;
90:
91: rtn = [self computePartition:offset
92: length : length
93: byteOffset : &byteposition
94: bytesToMove:&bytesToMove];
95:
96: if (rtn) {
97: return(rtn);
98: }
99:
100: /* If the request is aligned with the physical block size, we
101: * send it directly to the driver. If not, we have to use the
102: * (synchronous) reblocking IO function to handle size and/or
103: * alignment mismatches.
104: */
105:
106: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) {
107:
108: return([[self class] commonReadWrite
109: : _physicalDisk
110: : YES /* it's a read */
111: : byteposition /* byte offset */
112: : (unsigned)bytesToMove /* bytes */
113: : (unsigned char *)buffer
114: : (vm_task_t)client
115: : (void *)NULL
116: : (u_int *)actualLength]);
117:
118: } else { /* neatly aligned */
119:
120: return([_physicalDisk readAt:(byteposition / _physicalBlockSize)
121: length:bytesToMove
122: buffer:buffer
123: actualLength:actualLength
124: client:client]);
125: }
126: }
127:
128: - (IOReturn) readAsyncAt : (unsigned)offset
129: length : (unsigned)length
130: buffer : (unsigned char *)buffer
131: pending : (void *)pending
132: client : (vm_task_t)client
133: {
134: IOReturn rtn;
135: unsigned bytesToMove;
136: unsigned long long byteposition;
137:
138: rtn = [self computePartition:offset
139: length : length
140: byteOffset : &byteposition
141: bytesToMove:&bytesToMove];
142:
143: if (rtn) {
144: return(rtn);
145: }
146:
147: /* If the request is aligned with the physical block size, we
148: * send it directly to the driver. If not, we have to use the
149: * (synchronous) reblocking IO function to handle size and/or
150: * alignment mismatches.
151: */
152:
153: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) {
154:
155: return([[self class] commonReadWrite
156: : _physicalDisk
157: : YES
158: : byteposition /* byte offset */
159: : (unsigned)bytesToMove /* bytes */
160: : (unsigned char *)buffer
161: : (vm_task_t)client
162: : (void *)pending
163: : (u_int *)NULL]);
164:
165: } else { /* neatly aligned */
166: return([_physicalDisk readAsyncAt:(byteposition / _physicalBlockSize)
167: length:bytesToMove
168: buffer:buffer
169: pending:pending
170: client:client]);
171: }
172: }
173:
174: - (IOReturn) writeAt : (unsigned)offset
175: length : (unsigned)length
176: buffer : (unsigned char *)buffer
177: actualLength : (unsigned *)actualLength
178: client : (vm_task_t)client
179: {
180: unsigned deviceBlock;
181: IOReturn rtn;
182: unsigned bytesToMove;
183: unsigned long long byteposition;
184:
185: if ([self isWriteProtected]) {
186: return IO_R_NOT_WRITABLE;
187: }
188:
189: rtn = [self computePartition:offset
190: length : length
191: byteOffset : &byteposition
192: bytesToMove:&bytesToMove];
193:
194: if (rtn) {
195: return(rtn);
196: }
197:
198: /* If the request is aligned with the physical block size, we
199: * send it directly to the driver. If not, we have to use the
200: * (synchronous) reblocking IO function to handle size and/or
201: * alignment mismatches.
202: */
203:
204: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) {
205:
206: return([[self class] commonReadWrite
207: : _physicalDisk
208: : NO /* it's a write */
209: : byteposition /* byte offset */
210: : (unsigned)bytesToMove /* bytes */
211: : (unsigned char *)buffer
212: : (vm_task_t)client
213: : (void *)NULL
214: : (u_int *)actualLength]);
215:
216: } else { /* neatly aligned */
217:
218: return([_physicalDisk writeAt:(byteposition / _physicalBlockSize)
219: length:bytesToMove
220: buffer:buffer
221: actualLength:actualLength
222: client:client]);
223: }
224: }
225:
226: - (IOReturn) writeAsyncAt : (unsigned)offset
227: length : (unsigned)length
228: buffer : (unsigned char *)buffer
229: pending : (void *)pending
230: client : (vm_task_t)client
231: {
232: unsigned deviceBlock;
233: IOReturn rtn;
234: unsigned bytesToMove;
235: unsigned long long byteposition;
236:
237: if ([self isWriteProtected]) {
238: return IO_R_NOT_WRITABLE;
239: }
240:
241: rtn = [self computePartition:offset
242: length : length
243: byteOffset : &byteposition
244: bytesToMove:&bytesToMove];
245:
246: if (rtn) {
247: return(rtn);
248: }
249:
250: /* If the request is aligned with the physical block size, we
251: * send it directly to the driver. If not, we have to use the
252: * (synchronous) reblocking IO function to handle size and/or
253: * alignment mismatches.
254: */
255:
256: if (byteposition % _physicalBlockSize || length % _physicalBlockSize) {
257:
258: return([[self class] commonReadWrite
259: : _physicalDisk
260: : NO
261: : byteposition /* byte offset */
262: : (unsigned)bytesToMove /* bytes */
263: : (unsigned char *)buffer
264: : (vm_task_t)client
265: : (void *)pending
266: : (u_int *)NULL]);
267:
268: } else { /* neatly aligned */
269:
270: return([_physicalDisk writeAsyncAt:(byteposition / _physicalBlockSize)
271: length:bytesToMove
272: buffer:buffer
273: pending:pending
274: client:client]);
275: }
276: }
277:
278: #else KERNEL
279:
280: //xxxxx These copies of the routines have not been updated for reblocking.
281: // They aren't used.
282:
283: - (IOReturn) readAt : (unsigned)offset
284: length : (unsigned)length
285: buffer : (unsigned char *)buffer
286: actualLength : (unsigned *)actualLength
287: {
288: unsigned deviceBlock;
289: IOReturn rtn;
290: unsigned bytesToMove;
291:
292: if(rtn = [self _diskParamCommon:offset
293: length : length
294: deviceOffset : &deviceBlock
295: bytesToMove:&bytesToMove])
296: return(rtn);
297: return([_physicalDisk readAt:deviceBlock
298: length:bytesToMove
299: buffer:buffer
300: actualLength:actualLength]);
301: }
302:
303: - (IOReturn) readAsyncAt : (unsigned)offset
304: length : (unsigned)length
305: buffer : (unsigned char *)buffer
306: pending : (void *)pending
307: {
308: unsigned deviceBlock;
309: IOReturn rtn;
310: unsigned bytesToMove;
311:
312: if(rtn = [self _diskParamCommon:offset
313: length : length
314: deviceOffset : &deviceBlock
315: bytesToMove:&bytesToMove])
316: return(rtn);
317: return([_physicalDisk readAsyncAt:deviceBlock
318: length:bytesToMove
319: buffer:buffer
320: pending:pending]);
321: }
322:
323: - (IOReturn) writeAt : (unsigned)offset
324: length : (unsigned)length
325: buffer : (unsigned char *)buffer
326: actualLength : (unsigned *)actualLength
327: {
328: unsigned deviceBlock;
329: IOReturn rtn;
330: unsigned bytesToMove;
331:
332: if ([self isWriteProtected])
333: return IO_R_NOT_WRITABLE;
334: if(rtn = [self _diskParamCommon:offset
335: length : length
336: deviceOffset : &deviceBlock
337: bytesToMove:&bytesToMove])
338: return(rtn);
339: return([_physicalDisk writeAt:deviceBlock
340: length:bytesToMove
341: buffer:buffer
342: actualLength:actualLength]);
343: }
344:
345: - (IOReturn) writeAsyncAt : (unsigned)offset
346: length : (unsigned)length
347: buffer : (unsigned char *)buffer
348: pending : (void *)pending
349: {
350: unsigned deviceBlock;
351: IOReturn rtn;
352: unsigned bytesToMove;
353:
354: if ([self isWriteProtected])
355: return IO_R_NOT_WRITABLE;
356: if(rtn = [self _diskParamCommon:offset
357: length : length
358: deviceOffset : &deviceBlock
359: bytesToMove:&bytesToMove])
360: return(rtn);
361: return([_physicalDisk writeAsyncAt:deviceBlock
362: length:bytesToMove
363: buffer:buffer
364: pending:pending]);
365: }
366:
367: #endif KERNEL
368:
369: - (IODiskReadyState)updateReadyState
370: {
371: return [_physicalDisk updateReadyState];
372: }
373:
374: /*
375: * Open a connection to physDevice. FIXME: when do we close??
376: */
377: - (IOReturn)connectToPhysicalDisk : physicalDisk
378: {
379: IOReturn rtn = IO_R_SUCCESS;
380:
381: xpr_disk("connectToPhysicalDiskice\n", 1,2,3,4,5);
382: _physicalDisk = physicalDisk;
383: [self setIsPhysical:0];
384:
385: /*
386: * Get some instance variables which must be the same as the
387: * physDevice's.
388: */
389: _physicalBlockSize = [physicalDisk blockSize];
390: [self setRemovable:[physicalDisk isRemovable]];
391: [self setFormattedInternal:[physicalDisk isFormatted]];
392: [self setWriteProtected:[physicalDisk isWriteProtected]];
393: [self setLogicalDisk:nil];
394: #ifdef KERNEL
395: [self setDevAndIdInfo:[physicalDisk devAndIdInfo]];
396: #endif KERNEL
397: return(rtn);
398: }
399:
400: - (void)setPartitionBase : (unsigned)partBase
401: {
402: _partitionBase = partBase;
403: }
404:
405:
406: /*
407: * Determine if this LogicalDisk (or any other LogicalDisks in the
408: * logicalDisk list) are currently open. Returns NO if none open, else
409: * YES.
410: */
411: - (BOOL)isOpen
412: {
413: if([self isInstanceOpen])
414: return(YES);
415: else if([self nextLogicalDisk])
416: return([[self nextLogicalDisk] isOpen]);
417: else
418: return(NO);
419: }
420:
421: /*
422: * Free self and any objects in logicalDisk chain.
423: */
424: - free
425: {
426: id nextLd;
427:
428: nextLd = [self nextLogicalDisk];
429: if(nextLd) {
430: [nextLd free];
431: }
432: return([super free]);
433: }
434:
435: - physicalDisk
436: {
437: return(_physicalDisk);
438: }
439:
440: - (unsigned)physicalBlockSize
441: {
442: return(_physicalBlockSize);
443: }
444:
445: - (void)setPhysicalBlockSize : (unsigned)size
446: {
447: _physicalBlockSize = size;
448: }
449:
450: /*
451: * Pass this on to _physicalDisk.
452: */
453: - (IOReturn)isDiskReady : (BOOL)prompt
454: {
455: return [_physicalDisk isDiskReady:prompt];
456: }
457:
458: /*
459: * Determine if any logical disks in the _logicalDisk chain except
460: * for self are open.
461: */
462: - (BOOL)isAnyOtherOpen
463: {
464: id logDisk = [_physicalDisk nextLogicalDisk];
465: while(logDisk) {
466: if((logDisk != self) && [logDisk isInstanceOpen]) {
467: return YES;
468: }
469: logDisk = [logDisk nextLogicalDisk];
470: }
471: return NO;
472: }
473:
474: - (BOOL)isInstanceOpen
475: {
476: return _instanceOpen;
477: }
478:
479: - (void)setInstanceOpen : (BOOL)isOpen
480: {
481: _instanceOpen = (isOpen ? YES : NO);
482: }
483:
484: /*-----------------------------------------*/
485:
486: /* Common read/write function; handles reblocking of misaligned requests. */
487:
488: + (IOReturn) commonReadWrite : (id)physicalDisk
489: : (BOOL)read
490: : (unsigned long long)byteposition
491: : (unsigned)length /* bytes */
492: : (unsigned char *)buffer
493: : (vm_task_t)client
494: : (void *)pending
495: : (u_int *)actualLength
496: {
497: IOReturn rtn = IO_R_SUCCESS;
498: unsigned long aligncount; /* bytes */
499: unsigned long integralblocks;
500: unsigned long integralbytes;
501: unsigned long transfer;
502: unsigned long originallength;
503: unsigned long physsize; /* physical blocksize */
504: // unsigned char *origbuf;
505: u_int tempactual;
506:
507: //origbuf = buffer;
508: originallength = length;
509: tempactual = 0;
510: physsize = [physicalDisk blockSize];
511:
512: /* If the beginning of the request is not properly aligned
513: * with the device block size, or it's less than a block,
514: * we have to reblock it here to get ourselves aligned.
515: */
516:
517: if ((byteposition % physsize) || (length < physsize)) {
518:
519: /* Compute the number of bytes needed
520: * to bring us into sync with the real size.
521: */
522: aligncount = physsize - (byteposition % physsize);
523: if (aligncount > length) { /* a short read of less than a real block */
524: aligncount = length;
525: }
526:
527: rtn = [[IOLogicalDisk class] reblock
528: : physicalDisk
529: : read /* read or write */
530: : byteposition /* start byte position */
531: : aligncount /* byte count */
532: : buffer
533: : client
534: : pending
535: : physsize];
536: length -= aligncount; /* update length (bytes) */
537: byteposition += aligncount; /* update start byte position */
538: buffer += aligncount; /* update buffer */
539: }
540:
541: /* Now we're aligned. Transfer any integral-block "middle" part
542: * of the request. The integer divide below excludes any "odd" bytes
543: * at the end of the request which aren't part of an integral number
544: * of device blocks.
545: */
546:
547: if (length > 0 && (rtn == IO_R_SUCCESS)) { /* there's more left to do */
548:
549: integralblocks = length / physsize; /* zero if no full blocks */
550:
551: if (integralblocks) { /* transfer this many aligned blocks */
552: integralbytes = integralblocks * physsize;
553:
554: if (read) {
555: rtn = [physicalDisk readAt:(byteposition / physsize)
556: length:integralbytes
557: buffer:buffer
558: actualLength:&tempactual
559: client:client];
560: } else {
561: rtn = [physicalDisk writeAt:(byteposition / physsize)
562: length:integralbytes
563: buffer:buffer
564: actualLength:&tempactual
565: client:client];
566: }
567:
568: length -= integralbytes; /* update length (bytes) */
569: byteposition += integralbytes; /* update start block */
570: buffer += integralbytes; /* update buffer */
571: }
572: }
573:
574: /* If there are any "odd" bytes at the end of the request,
575: * transfer these now via reblocking.
576: */
577:
578: if (length > 0 && (rtn == IO_R_SUCCESS)) { /* there's more to do */
579:
580: rtn = [[IOLogicalDisk class] reblock
581: : physicalDisk
582: : read
583: : byteposition
584: : length
585: : buffer
586: : client
587: : pending
588: : physsize];
589: }
590:
591: /* We only remember the actual length if the transfer succeeds. */
592:
593: if (rtn == IO_R_SUCCESS) {
594: tempactual = originallength;
595: }
596:
597: /* Since we've been doing sync IOs here, we have to force a
598: * completion if the caller's request was async. Done here,
599: * this is ugly, but we have little choice with the current design.
600: */
601:
602: if (pending) { /* async: force an I/O completion (ugly) */
603: [physicalDisk completeTransfer
604: : pending
605: withStatus : rtn
606: actualLength : tempactual];
607: } else { /* sync */
608: *actualLength = tempactual;
609: }
610:
611: return(rtn);
612: }
613: @end
614:
615: /*
616: * Generate device-specific parameters from logical parameters.
617: */
618: @implementation IOLogicalDisk(private)
619:
620: - (IOReturn)_diskParamCommon :(unsigned)logicalOffset
621: length : (unsigned)length
622: deviceOffset : (unsigned*)deviceOffset
623: bytesToMove : (unsigned *)bytesToMove
624: {
625: unsigned ratio = 0; // bogus compiler warning
626: int deviceBlocks;
627: int logicalBlocks;
628: unsigned block_size;
629: unsigned dev_size;
630: IOReturn rtn;
631: const char *name = [self name];
632:
633: /*
634: * Note we have to 'fault in' a possible non-present physical disk in
635: * order to get its physical parameters...
636: */
637: rtn = [_physicalDisk isDiskReady:YES];
638: switch(rtn) {
639: case IO_R_SUCCESS:
640: break;
641: case IO_R_NO_DISK:
642: xpr_err("%s diskParamCommon: disk not present\n",
643: name, 2,3,4,5);
644: return(rtn);
645: default:
646: IOLog("%s deviceRwCommon: bogus return from isDiskReady "
647: "(%s)\n",
648: name, [self stringFromReturn:rtn]);
649: return(rtn);
650: }
651:
652: block_size = [self blockSize];
653: dev_size = [self diskSize];
654:
655: if(length % block_size) {
656: IOLog("%s: Bytes requested not multiple of block size\n",
657: name);
658: return(IO_R_INVALID_ARG);
659: }
660: logicalBlocks = length / block_size;
661: if((logicalOffset + logicalBlocks) > dev_size) {
662: if(logicalOffset >= dev_size)
663: return(IO_R_INVALID_ARG);
664:
665: /*
666: * Truncate.
667: */
668: logicalBlocks = dev_size - logicalOffset;
669: }
670: ratio = block_size / _physicalBlockSize;
671: deviceBlocks = logicalBlocks * ratio;
672: *deviceOffset = (logicalOffset * ratio) + _partitionBase;
673: *bytesToMove = deviceBlocks * _physicalBlockSize;
674: return(IO_R_SUCCESS);
675: }
676:
677: - (IOReturn)computePartition :(unsigned)logicalOffset
678: length : (unsigned)length
679: byteOffset : (unsigned long long *)byteOffset
680: bytesToMove : (unsigned *)bytesToMove
681: {
682: unsigned physicalBlocksize;
683: unsigned logicalBlocksize;
684: IOReturn rtn;
685: const char *name = [self name];
686:
687: unsigned long long partbase;
688: unsigned long long partsize;
689: unsigned long long partend;
690: unsigned long long reqbase;
691:
692: /*
693: * Note we have to 'fault in' a possible non-present physical disk in
694: * order to get its physical parameters...
695: */
696: rtn = [_physicalDisk isDiskReady:YES];
697: switch(rtn) {
698: case IO_R_SUCCESS:
699: break;
700: case IO_R_NO_DISK:
701: xpr_err("%s diskParamCommon: disk not present\n",
702: name, 2,3,4,5);
703: return(rtn);
704: default:
705: IOLog("%s deviceRwCommon: bogus return from isDiskReady "
706: "(%s)\n",
707: name, [self stringFromReturn:rtn]);
708: return(rtn);
709: }
710:
711: /* We compute partition information here based on the notion of
712: * block size, but for better results these boundaries should
713: * have been set up in bytes from the start.
714: */
715: physicalBlocksize = [_physicalDisk blockSize];
716: logicalBlocksize = [self blockSize];
717:
718: /* If we don't (yet) know our logical block size, we have to
719: * default to the physical block size.
720: */
721: if (logicalBlocksize == 0) { /* we don't know (yet)*/
722: logicalBlocksize = physicalBlocksize;
723: }
724:
725: /* The partition base is usually in physical blocks, except when
726: * we are reblocking HFS on CD-ROM. In that case, all computations
727: * are done in 512-byte logical blocks.
728: *
729: * Is there a better way to detect that we're an HFS partition?
730: */
731: if (logicalBlocksize != physicalBlocksize &&
732: logicalBlocksize == 512) { /* must be HFS */
733: partbase = (unsigned long long)_partitionBase *
734: (unsigned long long)logicalBlocksize;
735: } else {
736: partbase = (unsigned long long)_partitionBase *
737: (unsigned long long)physicalBlocksize;
738: }
739: partsize = (unsigned long long)[self diskSize] *
740: (unsigned long long)logicalBlocksize;
741: partend = partbase + partsize;
742:
743: /* The caller's block offset is in units expressed by the
744: * partitioning scheme. NeXT labeled disks are usually 1024 bytes,
745: * HFS is always 512.)
746: */
747: reqbase = ((unsigned long long)logicalOffset *
748: (unsigned long long)logicalBlocksize) + partbase;
749:
750: if (reqbase < partbase || reqbase > partend) {
751: return(IO_R_INVALID_ARG);
752: }
753:
754: if ((reqbase + length) > partend) {
755: length = partend - reqbase; /* truncate the request */
756: }
757:
758: *byteOffset = reqbase;
759: *bytesToMove = length;
760: return(IO_R_SUCCESS);
761: }
762:
763: /* Copy data to (write) or from (read) a misaligned part of a physical block: */
764:
765: #define MAX_REBLOCK_SIZE 2048
766:
767: + (IOReturn) reblock : (id)physicalDisk
768: : (BOOL)read
769: : (unsigned long long)offset /* bytes */
770: : (unsigned)length /* bytes */
771: : (unsigned char *)buffer
772: : (vm_task_t)client
773: : (void *)pending
774: : (unsigned)physsize /* phys blocksize */
775: {
776: IOReturn rtn;
777: unsigned long physblock;
778: int bufoffset;
779: u_int tempactual;
780: id controller;
781: char *reblockbuf;
782: void *freePtr;
783: unsigned freeCnt;
784:
785: /* Allocate a buffer to hold the (larger) device block. This isn't
786: * efficient since we allocate and free the buffer each time through,
787: * but we're just trying to make the thing work for now.
788: */
789:
790: controller = [physicalDisk controller];
791: reblockbuf = (char *)[controller allocateBufferOfLength:MAX_REBLOCK_SIZE
792: actualStart:&freePtr
793: actualLength:&freeCnt];
794:
795: bzero(reblockbuf,MAX_REBLOCK_SIZE);
796:
797: /* Figure out which physical block we need, and load it: */
798:
799: physblock = offset / physsize;
800:
801: rtn = [physicalDisk readAt
802: :physblock
803: length:physsize
804: buffer:reblockbuf
805: actualLength:&tempactual
806: client:client];
807:
808: if (rtn != IO_R_SUCCESS) {
809: return(rtn);
810: }
811:
812: /* Now copy what the client wants, in the direction specified: */
813:
814: bufoffset = offset % physsize;
815:
816: if (read) {
817: bcopy(&reblockbuf[bufoffset],buffer,length); /* read : buf to client */
818: } else {
819: bcopy(buffer,&reblockbuf[bufoffset],length); /* write: client to buf */
820:
821: /* If writing, flush the buffer to the device: */
822: rtn = [physicalDisk writeAt:physblock
823: length:physsize
824: buffer:reblockbuf
825: actualLength:&tempactual
826: client:client];
827: }
828:
829: IOFree(freePtr,freeCnt);
830: return(IO_R_SUCCESS);
831: }
832:
833: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.