1 /* $Id: disk.c 15.12 1999/03/25 22:05:00 Michiel Exp Michiel $ */
3 * Revision 15.12 1999/03/25 22:05:00 Michiel
4 * fixed deldir related (beta) bug
6 * Revision 15.11 1999/02/22 16:25:30 Michiel
7 * Changes for increasing deldir capacity
9 * Revision 15.10 1998/09/27 11:26:37 Michiel
12 * Revision 15.9 1998/09/03 07:12:14 Michiel
14 * bugfixes 118, 121, 123 and superindexblocks and td64 support
16 * Revision 15.8 1998/04/23 22:27:07 Michiel
17 * FakeCachedRead toegevoegd om munglist check hits te voorkomen
18 * Bug in WriteToFile opgelost: toevoeging CorrectAnodeAc
20 * Revision 15.7 1997/03/03 22:04:04 Michiel
23 * Revision 15.6 1996/03/14 19:32:56 Michiel
24 * Fixed ChangeFileSize bug: had no effect when # blocks remained constant
26 * Revision 15.5 1996/01/03 09:58:36 Michiel
27 * replaced CopyMem() by memcpy()
29 * Revision 15.4 1995/12/21 11:59:31 Michiel
30 * bugfixes: ValidateCache() block flushing and
31 * WriteToFile expensive last block
33 * Revision 15.3 1995/12/21 11:32:44 Michiel
36 * Revision 15.2 1995/12/14 13:24:08 Michiel
39 * Revision 15.1 1995/12/05 15:47:27 Michiel
40 * Rollover files implemented
41 * Restructured: ReadFromObject, WriteToObject etc
44 * Revision 14.4 1995/11/15 15:44:40 Michiel
45 * WriteToFile, ChangeFileSize adapted to postponed op.
47 * Revision 14.3 1995/11/07 14:57:31 Michiel
48 * support for online directory update in WriteToFile and ChangeFileSize
49 * ReservedAreaLock check
51 * Revision 14.2 1995/10/11 23:25:24 Michiel
52 * UpdateSlot added: improved sequential write
54 * Revision 14.1 1995/10/11 22:18:30 Michiel
55 * new data-caching algorithm
57 * Revision 13.2 1995/10/05 11:01:32 Michiel
60 * Revision 13.1 1995/10/03 11:08:55 Michiel
61 * merged with developtree: anodecache
63 * Revision 12.15 1995/09/04 09:57:10 Michiel
64 * mask check now starts at first whole block and includes last block
66 * Revision 12.14 1995/09/01 11:20:15 Michiel
67 * RawRead and RawWrite error handling changed:
68 * on error a retry|cancel requester appears. Retry and
69 * same volumecheck changed. Numsofterrors update added.
71 * Revision 12.13 1995/08/24 13:48:26 Michiel
72 * TD_DiskChange checking enabled
74 * Revision 12.12 1995/08/21 04:25:48 Michiel
75 * better checks for out of memory
77 * Revision 12.11 1995/08/04 04:13:15 Michiel
78 * extra CUTDOWN protection
80 * Revision 12.10 1995/07/21 06:48:51 Michiel
82 * bugfix: MaxTransfer now doesn't have to be multiple of blocksize
84 * Revision 12.9 1995/07/11 17:29:31 Michiel
85 * ErrorMsg () calls use messages.c variables now.
87 * Revision 12.8 1995/07/07 14:39:17 Michiel
90 * Revision 12.7 1995/06/19 09:42:45 Michiel
91 * Rawwrite returns error if softprotect is on
93 * Revision 12.6 1995/06/16 10:00:15 Michiel
94 * using Allec & FreeBufMem
96 * Revision 12.5 1995/06/16 04:06:29 Michiel
97 * No Touch () in write, just MakeBlockDirty
99 * Revision 12.4 1995/05/20 12:12:12 Michiel
100 * Updated messages to reflect Ami-FileLock
104 * Revision 12.3 1995/03/30 11:54:29 Michiel
105 * Write & Setfilesize now set the checknotify flag
107 * Revision 12.2 1995/02/15 16:43:39 Michiel
109 * Using new headers (struct.h & blocks.h)
111 * Revision 12.1 1995/02/02 11:26:11 Michiel
112 * Version number fix. No changes.
114 * Revision 11.8 1995/01/29 07:34:57 Michiel
116 * ReadFromFile, WriteToFile completely rewritten
118 * DataCaching updated
120 * Revision 11.7 1995/01/26 12:20:42 Michiel
123 * Revision 11.6 1995/01/24 17:44:34 Michiel
126 * Revision 11.5 1995/01/24 15:54:20 Michiel
127 * DirectRead, CachedRead etc
129 * Revision 11.4 1995/01/23 16:43:35 Michiel
130 * Directwrite in WriteToFile added
132 * Revision 11.3 1995/01/18 04:29:34 Michiel
133 * Bugfixes. Now ready for beta release.
135 * Revision 11.2 1995/01/15 05:24:44 Michiel
136 * trackdisk specific parts inhibited
138 * Revision 11.1 1995/01/08 16:17:32 Michiel
139 * Compiled (new MODE_BIG version)
141 * Revision 10.4 1994/11/15 18:06:58 Michiel
142 * __USE_SYSBASE moved..
144 * Revision 10.3 1994/10/28 06:06:40 Michiel
145 * uses new listentry field anodenr
147 * Revision 10.2 1994/10/27 11:30:12 Michiel
148 * *** empty log message ***
150 * Revision 10.1 1994/10/24 11:16:28 Michiel
157 #define __USE_SYSBASE
159 #include <exec/types.h>
160 #include <exec/memory.h>
161 #include <exec/devices.h>
163 #include <dos/filehandler.h>
173 #include "disk_protos.h"
174 #include "allocation_protos.h"
175 #include "volume_protos.h"
176 #include "directory_protos.h"
177 #include "anodes_protos.h"
178 #include "update_protos.h"
179 #include "checkaccess_protos.h"
181 #define PROFILE_OFF()
184 /**********************************************************************/
186 /**********************************************************************/
189 static UBYTE debugbuf
[120];
191 #define DebugOn debug++
192 #define DebugOff debug=0
193 #define DebugMsg(msg) if(debug) {NormalErrorMsg(msg, NULL);debug=0;}
194 #define DebugMsgNum(msg, num) sprintf(debugbuf, "%s 0x%08lx.", msg, num); \
195 if(debug) {NormalErrorMsg(debugbuf, NULL);debug=0;}
196 #define DebugMsgName(msg, name) sprintf(debugbuf, "%s >%s<.", msg, name); \
197 if(debug) {NormalErrorMsg(debugbuf, NULL);debug=0;}
202 #define DebugMsgNum(msg,num)
203 #define DebugMsgName(msg, name)
206 enum vctype
{read
, write
};
207 static int CheckDataCache(ULONG blocknr
, globaldata
*g
);
208 static int CachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
);
209 static int FakeCachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
);
210 static UBYTE
*CachedReadD(ULONG blknr
, SIPTR
*err
, globaldata
*g
);
211 static int CachedWrite(UBYTE
*data
, ULONG blocknr
, globaldata
*g
);
212 static void ValidateCache(ULONG blocknr
, ULONG numblocks
, enum vctype
, globaldata
*g
);
213 static void UpdateSlot(int slotnr
, globaldata
*g
);
214 static ULONG
ReadFromRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
215 static ULONG
WriteToRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
216 static LONG
SeekInRollover(fileentry_t
*file
, LONG offset
, LONG mode
, SIPTR
*error
, globaldata
*g
);
217 static LONG
ChangeRolloverSize(fileentry_t
*file
, LONG releof
, LONG mode
, SIPTR
*error
, globaldata
*g
);
218 static ULONG
ReadFromFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
219 static ULONG
WriteToFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
, SIPTR
*error
, globaldata
*g
);
221 /**********************************************************************/
225 /**********************************************************************/
227 ULONG
ReadFromObject(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
228 SIPTR
*error
, globaldata
*g
)
230 if (!CheckReadAccess(file
,error
,g
))
233 /* check anodechain, make if not there */
234 if (!file
->anodechain
)
236 DB(Trace(2,"ReadFromObject","getting anodechain"));
237 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
239 *error
= ERROR_NO_FREE_STORE
;
245 if (IsRollover(file
->le
.info
))
246 return ReadFromRollover(file
,buffer
,size
,error
,g
);
249 return ReadFromFile(file
,buffer
,size
,error
,g
);
252 ULONG
WriteToObject(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
253 SIPTR
*error
, globaldata
*g
)
255 /* check write access */
256 if (!CheckWriteAccess(file
, error
, g
))
259 /* check anodechain, make if not there */
260 if (!file
->anodechain
)
262 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
264 *error
= ERROR_NO_FREE_STORE
;
269 /* changing file -> set notify flag */
270 file
->checknotify
= 1;
274 if (IsRollover(file
->le
.info
))
275 return WriteToRollover(file
,buffer
,size
,error
,g
);
278 return WriteToFile(file
,buffer
,size
,error
,g
);
281 LONG
SeekInObject(fileentry_t
*file
, LONG offset
, LONG mode
, SIPTR
*error
,
285 if (!CheckOperateFile(file
,error
,g
))
288 /* check anodechain, make if not there */
289 if (!file
->anodechain
)
291 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
293 *error
= ERROR_NO_FREE_STORE
;
299 if (IsRollover(file
->le
.info
))
300 return SeekInRollover(file
,offset
,mode
,error
,g
);
303 return SeekInFile(file
,offset
,mode
,error
,g
);
306 LONG
ChangeObjectSize(fileentry_t
*file
, LONG releof
, LONG mode
,
307 SIPTR
*error
, globaldata
*g
)
310 if (!CheckChangeAccess(file
, error
, g
))
313 /* Changing file -> set notify flag */
314 file
->checknotify
= 1;
317 /* check anodechain, make if not there */
318 if (!file
->anodechain
)
320 if (!(file
->anodechain
= GetAnodeChain(file
->le
.anodenr
, g
)))
322 *error
= ERROR_NO_FREE_STORE
;
328 if (IsRollover(file
->le
.info
))
329 return ChangeRolloverSize(file
,releof
,mode
,error
,g
);
332 return ChangeFileSize(file
,releof
,mode
,error
,g
);
337 /**********************************************************************
339 **********************************************************************/
343 /* Read from rollover: at end of file,
346 static ULONG
ReadFromRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
347 SIPTR
*error
, globaldata
*g
)
349 #define direntry_m file->le.info.file.direntry
350 #define filesize_m file->le.info.file.direntry->size
352 struct extrafields extrafields
;
355 LONG end
, virtualoffset
, virtualend
, t
;
357 DB(Trace(1,"ReadFromRollover","size = %lx offset = %lx\n",size
,file
->offset
));
359 GetExtraFields(direntry_m
,&extrafields
);
361 /* limit access to end of file */
362 virtualoffset
= file
->offset
- extrafields
.rollpointer
;
363 if (virtualoffset
< 0) virtualoffset
+= filesize_m
;
364 virtualend
= virtualoffset
+ size
;
365 virtualend
= min(virtualend
, extrafields
.virtualsize
);
366 end
= virtualend
- virtualoffset
+ file
->offset
;
368 if (end
> filesize_m
)
370 q
= filesize_m
- file
->offset
;
371 if ((read
= ReadFromFile(file
, buffer
, q
, error
, g
)) != q
)
376 SeekInFile(file
, 0, OFFSET_BEGINNING
, error
, g
);
379 q
= end
- file
->offset
;
380 t
= ReadFromFile(file
, buffer
, q
, error
, g
);
392 /* Write to rollover file. First write upto end of rollover. Then
394 * Max virtualsize = filesize-1
396 static ULONG
WriteToRollover(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
397 SIPTR
*error
, globaldata
*g
)
399 #define direntry_m file->le.info.file.direntry
400 #define filesize_m file->le.info.file.direntry->size
402 struct extrafields extrafields
;
403 struct direntry
*destentry
;
404 union objectinfo directory
;
406 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
409 LONG end
, virtualend
, virtualoffset
, t
;
412 DB(Trace(1,"WriteToRollover","size = %lx offset=%lx, file=%lx\n",size
,file
->offset
,file
));
413 GetExtraFields(direntry_m
,&extrafields
);
414 end
= file
->offset
+ size
;
416 /* new virtual size */
417 virtualoffset
= file
->offset
- extrafields
.rollpointer
;
418 if (virtualoffset
< 0) virtualoffset
+= filesize_m
;
419 virtualend
= virtualoffset
+ size
;
420 if (virtualend
>= extrafields
.virtualsize
)
422 extrafields
.virtualsize
= min(filesize_m
-1, virtualend
);
426 while (end
> filesize_m
)
428 q
= filesize_m
- file
->offset
;
429 t
= WriteToFile(file
, buffer
, q
, error
, g
);
430 if (t
== -1) return (ULONG
)t
;
432 if (t
!= q
) return (ULONG
)written
;
435 SeekInFile(file
, 0, OFFSET_BEGINNING
, error
, g
);
438 q
= end
- file
->offset
;
439 t
= WriteToFile(file
, buffer
, q
, error
, g
);
445 /* change rollpointer etc */
446 if (extend
&& extrafields
.virtualsize
== filesize_m
- 1)
447 extrafields
.rollpointer
= end
+ 1; /* byte PAST eof is offset 0 */
448 destentry
= (struct direntry
*)entrybuffer
;
449 memcpy(destentry
, direntry_m
, direntry_m
->next
);
450 AddExtraFields(destentry
, &extrafields
);
453 if (!GetParent(&file
->le
.info
, &directory
, error
, g
))
456 ChangeDirEntry(file
->le
.info
.file
, destentry
, &directory
, &fi
, g
);
458 return (ULONG
)written
;
464 static LONG
SeekInRollover(fileentry_t
*file
, LONG offset
, LONG mode
, SIPTR
*error
, globaldata
*g
)
466 #define filesize_m file->le.info.file.direntry->size
467 #define direntry_m file->le.info.file.direntry
469 struct extrafields extrafields
;
470 LONG oldvirtualoffset
, virtualoffset
;
471 ULONG anodeoffset
, blockoffset
;
473 DB(Trace(1,"SeekInRollover","offset = %ld mode=%ld\n",offset
,mode
));
474 GetExtraFields(direntry_m
,&extrafields
);
477 oldvirtualoffset
= file
->offset
- extrafields
.rollpointer
;
478 if (oldvirtualoffset
< 0) oldvirtualoffset
+= filesize_m
;
482 case OFFSET_BEGINNING
:
483 virtualoffset
= offset
;
487 virtualoffset
= extrafields
.virtualsize
+ offset
;
491 virtualoffset
= oldvirtualoffset
+ offset
;
495 *error
= ERROR_SEEK_ERROR
;
499 if ((virtualoffset
> extrafields
.virtualsize
) || virtualoffset
< 0)
501 *error
= ERROR_SEEK_ERROR
;
505 /* calculate real offset */
506 file
->offset
= virtualoffset
+ extrafields
.rollpointer
;
507 if (file
->offset
> filesize_m
)
508 file
->offset
-= filesize_m
;
510 /* calculate new values */
511 anodeoffset
= file
->offset
>> BLOCKSHIFT
;
512 blockoffset
= file
->offset
& (BLOCKSIZE
-1);
513 file
->currnode
= &file
->anodechain
->head
;
514 CorrectAnodeAC(&file
->currnode
, &anodeoffset
, g
);
516 file
->anodeoffset
= anodeoffset
;
517 file
->blockoffset
= blockoffset
;
519 return oldvirtualoffset
;
526 static LONG
ChangeRolloverSize(fileentry_t
*file
, LONG releof
, LONG mode
,
527 SIPTR
*error
, globaldata
*g
)
529 #define filesize_m file->le.info.file.direntry->size
530 #define direntry_m file->le.info.file.direntry
532 struct extrafields extrafields
;
533 LONG virtualeof
, virtualoffset
;
534 union objectinfo directory
;
536 struct direntry
*destentry
;
537 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
539 DB(Trace(1,"ChangeRolloverSize","offset = %ld mode=%ld\n",releof
,mode
));
540 GetExtraFields(direntry_m
,&extrafields
);
544 case OFFSET_BEGINNING
:
549 virtualeof
= extrafields
.virtualsize
+ releof
;
553 virtualoffset
= file
->offset
- extrafields
.rollpointer
;
554 if (virtualoffset
< 0) virtualoffset
+= filesize_m
;
555 virtualeof
= virtualoffset
+ releof
;
557 default: /* bogus parameter -> ERROR_SEEK_ERROR */
564 *error
= ERROR_SEEK_ERROR
;
568 /* change virtual size */
569 if (virtualeof
>= filesize_m
)
570 extrafields
.virtualsize
= filesize_m
- 1;
572 extrafields
.virtualsize
= virtualeof
;
574 /* we don't update other filehandles or current offset here */
576 /* commit directoryentry changes */
577 destentry
= (struct direntry
*)entrybuffer
;
578 memcpy(destentry
, direntry_m
, direntry_m
->next
);
579 AddExtraFields(destentry
, &extrafields
);
582 if (!GetParent(&file
->le
.info
, &directory
, error
, g
))
585 ChangeDirEntry(file
->le
.info
.file
, destentry
, &directory
, &fi
, g
);
593 #endif /* ROLLOVER */
599 ** Reads 'size' bytes from file to buffer (if not readprotected)
600 ** result: #butes read; -1 = error; 0 = eof
602 static ULONG
ReadFromFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
603 SIPTR
*error
, globaldata
*g
)
605 ULONG anodeoffset
, blockoffset
, blockstoread
;
606 ULONG fullblks
, bytesleft
;
608 UBYTE
*data
= NULL
, *dataptr
;
609 BOOL directread
= FALSE
;
610 struct anodechainnode
*chnode
;
612 struct deldirentry
*dde
;
615 DB(Trace(1,"ReadFromFile","size = %lx offset = %lx\n",size
,file
->offset
));
616 if (!CheckReadAccess(file
, error
, g
))
619 /* correct size and check if zero */
621 if (IsDelFile(file
->le
.info
)) {
622 if (!(dde
= GetDeldirEntryQuick(file
->le
.info
.delfile
.slotnr
, g
)))
624 t
= dde
->size
- file
->offset
;
628 t
= file
->le
.info
.file
.direntry
->size
- file
->offset
;
630 if (!(size
= min(t
, size
)))
634 anodeoffset
= file
->anodeoffset
;
635 blockoffset
= file
->blockoffset
;
636 chnode
= file
->currnode
;
637 t
= blockoffset
+ size
;
638 fullblks
= t
>>BLOCKSHIFT
; /* # full blocks */
639 bytesleft
= t
&(BLOCKSIZE
-1); /* # bytes in last incomplete block */
641 /* check mask, both at start and end */
642 t
= (((IPTR
)(buffer
-blockoffset
+BLOCKSIZE
))&~g
->dosenvec
->de_Mask
) ||
643 (((IPTR
)(buffer
+size
-bytesleft
))&~g
->dosenvec
->de_Mask
);
649 * - larger than one block (use 'direct' cached read for just one)
651 if (!t
|| (fullblks
<2*DIRECTSIZE
&& (blockoffset
+size
>BLOCKSIZE
) &&
652 (blockoffset
|| (bytesleft
&&fullblks
<DIRECTSIZE
))))
654 /* full indirect read */
655 blockstoread
= fullblks
+ (bytesleft
>0);
656 if (!(data
= AllocBufmem (blockstoread
<<BLOCKSHIFT
, g
)))
658 *error
= ERROR_NO_FREE_STORE
;
667 blockstoread
= fullblks
;
670 /* read first blockpart */
673 data
= CachedReadD(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
676 NextBlockAC(&chnode
, &anodeoffset
, g
);
679 t
= BLOCKSIZE
-blockoffset
;
681 memcpy(dataptr
, data
+blockoffset
, t
);
686 bytesleft
= 0; /* single block access */
691 /* read middle part */
692 while (blockstoread
&& !*error
)
694 if ((blockstoread
+ anodeoffset
) >= chnode
->an
.clustersize
)
695 t
= chnode
->an
.clustersize
- anodeoffset
; /* read length */
699 *error
= DiskRead(dataptr
, t
, chnode
->an
.blocknr
+ anodeoffset
, g
);
703 dataptr
+= t
<<BLOCKSHIFT
;
705 CorrectAnodeAC(&chnode
, &anodeoffset
, g
);
709 /* read last block part/ copy read data to buffer */
713 memcpy(buffer
, data
+blockoffset
, size
);
716 data
= CachedReadD(chnode
->an
.blocknr
+anodeoffset
, error
, g
);
718 memcpy(dataptr
, data
, bytesleft
);
726 file
->anodeoffset
+= fullblks
;
727 file
->blockoffset
= (file
->blockoffset
+ size
)&(BLOCKSIZE
-1); // not bytesleft!!
728 CorrectAnodeAC(&file
->currnode
, &file
->anodeoffset
, g
);
729 file
->offset
+= size
;
734 DB(Trace(1,"Read","failed\n"));
745 ** - Copy data in file at current position;
746 ** - Automatic fileextension;
747 ** - Error = bytecount <> opdracht
748 ** - On error no position update
750 ** - Clear Archivebit -> done by Touch()
751 **V- directory protection (amigados does not do this)
753 ** result: num bytes written; DOPUS wants -1 = error;
755 ** Implementation parts
757 ** - Test on writeprotection; yes -> error;
760 ** - Write firstblockpart
761 ** - Write all whole blocks
762 ** - Write last block
763 ** - | Update directory (if no errors)
764 ** | Deextent filesize (if error)
766 static ULONG
WriteToFile(fileentry_t
*file
, UBYTE
*buffer
, ULONG size
,
767 SIPTR
*error
, globaldata
*g
)
770 ULONG totalblocks
, oldblocksinfile
, oldfilesize
, newfileoffset
;
771 ULONG newblocksinfile
, bytestowrite
, blockstofill
;
772 ULONG anodeoffset
, blockoffset
;
773 UBYTE
*data
= NULL
, *dataptr
;
774 BOOL directwrite
= FALSE
;
775 struct anodechainnode
*chnode
;
778 DB(Trace(1,"WriteToFile","size = %lx offset=%lx, file=%lx\n",size
,file
->offset
,file
));
779 /* initialization values */
780 chnode
= file
->currnode
;
781 anodeoffset
= file
->anodeoffset
;
782 blockoffset
= file
->blockoffset
;
783 totalblocks
= (blockoffset
+ size
+ BLOCKSIZE
-1)>>BLOCKSHIFT
; /* total # changed blocks */
784 if (!(bytestowrite
= size
)) /* # bytes to be done */
787 /* filesize extend */
788 oldfilesize
= file
->le
.info
.file
.direntry
->size
;
789 newfileoffset
= file
->offset
+ size
;
790 oldblocksinfile
= (oldfilesize
+ BLOCKSIZE
-1)>>BLOCKSHIFT
;
791 newblocksinfile
= (newfileoffset
+ BLOCKSIZE
-1)>>BLOCKSHIFT
;
792 if (newblocksinfile
> oldblocksinfile
)
794 t
= newblocksinfile
- oldblocksinfile
;
795 if (!AllocateBlocksAC(file
->anodechain
, t
, &file
->le
.info
.file
, g
))
797 file
->le
.info
.file
.direntry
->size
= oldfilesize
;
798 *error
= ERROR_DISK_FULL
;
802 /* BUG 980422: this CorrectAnodeAC mode because of AllocateBlockAC!! AND
803 * because anodeoffset can be outside last block! (filepointer is
806 CorrectAnodeAC(&chnode
,&anodeoffset
,g
);
809 maskok
= (((IPTR
)(buffer
-blockoffset
+BLOCKSIZE
))&~g
->dosenvec
->de_Mask
) ||
810 (((IPTR
)(buffer
-blockoffset
+(totalblocks
<<BLOCKSHIFT
)))&~g
->dosenvec
->de_Mask
);
817 if (!maskok
|| (totalblocks
<2*DIRECTSIZE
&& (blockoffset
+size
>BLOCKSIZE
*2) &&
818 (blockoffset
|| totalblocks
<DIRECTSIZE
)))
821 /* allocate temporary data buffer */
822 if (!(dataptr
= data
= AllocBufmem(totalblocks
<<BLOCKSHIFT
, g
)))
824 *error
= ERROR_NO_FREE_STORE
;
828 /* first blockpart */
831 *error
= DiskRead(dataptr
, 1, chnode
->an
.blocknr
+ anodeoffset
, g
);
832 bytestowrite
+= blockoffset
;
833 if (bytestowrite
<BLOCKSIZE
)
834 bytestowrite
= BLOCKSIZE
; /* the first could also be the last block */
837 /* copy all 'to be written' to databuffer */
838 memcpy(dataptr
+blockoffset
, buffer
, size
);
846 /* first blockpart */
847 if (blockoffset
|| (totalblocks
==1 && newfileoffset
> oldfilesize
))
849 ULONG fbp
; /* first block part */
854 slotnr
= CachedRead(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
860 /* for one block no offset growing file */
861 slotnr
= FakeCachedRead(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
864 /* copy data to cache and mark block as dirty */
865 firstblock
= &g
->dc
.data
[slotnr
<<BLOCKSHIFT
];
866 fbp
= BLOCKSIZE
-blockoffset
;
867 fbp
= min(bytestowrite
, fbp
); /* the first could also be the last block */
868 memcpy(firstblock
+blockoffset
, buffer
, fbp
);
869 MarkDataDirty(slotnr
);
871 NextBlockAC(&chnode
, &anodeoffset
, g
);
878 /* write following blocks. If done, then blockoffset always 0 */
879 if (newfileoffset
> oldfilesize
)
881 blockstofill
= totalblocks
;
882 bytestowrite
= totalblocks
<<BLOCKSHIFT
;
885 blockstofill
= bytestowrite
>>BLOCKSHIFT
;
887 while (blockstofill
&& !*error
)
889 if (blockstofill
+ anodeoffset
>= chnode
->an
.clustersize
)
890 t
= chnode
->an
.clustersize
- anodeoffset
; /* t is # blocks to write now */
894 *error
= DiskWrite(dataptr
, t
, chnode
->an
.blocknr
+ anodeoffset
, g
);
898 dataptr
+= t
<<BLOCKSHIFT
;
899 bytestowrite
-= t
<<BLOCKSHIFT
;
901 CorrectAnodeAC(&chnode
, &anodeoffset
, g
);
905 /* write last block (RAW because cache direct) */
906 if (bytestowrite
&& !*error
)
910 slotnr
= CachedRead(chnode
->an
.blocknr
+ anodeoffset
, error
, g
);
913 lastblock
= &g
->dc
.data
[slotnr
<<BLOCKSHIFT
];
914 memcpy(lastblock
, dataptr
, bytestowrite
);
915 MarkDataDirty(slotnr
);
919 /* free mem for indirect write */
924 file
->anodeoffset
+= (blockoffset
+ size
)>>BLOCKSHIFT
;
925 file
->blockoffset
= (blockoffset
+ size
)&(BLOCKSIZE
-1);
926 CorrectAnodeAC(&file
->currnode
, &file
->anodeoffset
, g
);
927 file
->offset
+= size
;
928 file
->le
.info
.file
.direntry
->size
= max(oldfilesize
, file
->offset
);
929 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
934 if (newblocksinfile
>oldblocksinfile
)
936 /* restore old state of file */
938 file
->le
.info
.file
.direntry
->size
= oldfilesize
;
939 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
940 FreeBlocksAC(file
->anodechain
, newblocksinfile
-oldblocksinfile
, freeanodes
, g
);
942 FreeBlocksAC(file
->anodechain
, newblocksinfile
-oldblocksinfile
, freeanodes
, g
);
943 file
->le
.info
.file
.direntry
->size
= oldfilesize
;
944 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
948 DB(Trace(1,"WriteToFile","failed\n"));
957 ** - set fileposition
958 ** - if wrong position, resultposition unknown and error
959 ** - result = old position to start of file, -1 = error
961 ** - the end of the file is 0 from end
963 LONG
SeekInFile(fileentry_t
*file
, LONG offset
, LONG mode
, SIPTR
*error
, globaldata
*g
)
965 LONG oldoffset
, newoffset
;
966 ULONG anodeoffset
, blockoffset
;
968 struct deldirentry
*delfile
= NULL
;
970 DB(Trace(1,"SeekInFile","offset = %ld mode=%ld\n",offset
,mode
));
971 if (IsDelFile(file
->le
.info
))
972 if (!(delfile
= GetDeldirEntryQuick(file
->le
.info
.delfile
.slotnr
, g
)))
977 oldoffset
= file
->offset
;
980 case OFFSET_BEGINNING
:
987 newoffset
= delfile
->size
+ offset
;
990 newoffset
= file
->le
.info
.file
.direntry
->size
+ offset
;
994 newoffset
= oldoffset
+ offset
;
998 *error
= ERROR_SEEK_ERROR
;
1003 if ((newoffset
> (delfile
? delfile
->size
:
1004 file
->le
.info
.file
.direntry
->size
)) || (newoffset
< 0))
1006 if ((newoffset
> file
->le
.info
.file
.direntry
->size
) || (newoffset
< 0))
1009 *error
= ERROR_SEEK_ERROR
;
1013 /* calculate new values */
1014 anodeoffset
= newoffset
>> BLOCKSHIFT
;
1015 blockoffset
= newoffset
& (BLOCKSIZE
-1);
1016 file
->currnode
= &file
->anodechain
->head
;
1017 CorrectAnodeAC(&file
->currnode
, &anodeoffset
, g
);
1018 /* DiskSeek(anode.blocknr + anodeoffset, g); */
1020 file
->anodeoffset
= anodeoffset
;
1021 file
->blockoffset
= blockoffset
;
1022 file
->offset
= newoffset
;
1027 /* Changes the length of a file
1028 ** Returns new length; -1 if failure
1031 ** 'Seek with extend'
1032 ** change other locks
1035 LONG
ChangeFileSize(fileentry_t
*file
, LONG releof
, LONG mode
, SIPTR
*error
,
1040 ULONG myanode
, oldblocksinfile
, newblocksinfile
, oldfilesize
;
1043 DB(Trace(1,"ChangeFileSize","offset = %ld mode=%ld\n",releof
,mode
));
1044 if (!CheckChangeAccess(file
, error
, g
))
1047 /* Changing file -> set notify flag */
1048 file
->checknotify
= 1;
1051 /* calculate new eof (ala 'Seek') */
1054 case OFFSET_BEGINNING
:
1059 abseof
= file
->le
.info
.file
.direntry
->size
+ releof
;
1062 case OFFSET_CURRENT
:
1063 abseof
= file
->offset
+ releof
;
1067 *error
= ERROR_SEEK_ERROR
;
1073 *error
= ERROR_SEEK_ERROR
;
1077 /* change allocation (ala WriteToFile) */
1078 oldfilesize
= file
->le
.info
.file
.direntry
->size
;
1079 oldblocksinfile
= (file
->le
.info
.file
.direntry
->size
+ BLOCKSIZE
-1)>>BLOCKSHIFT
;
1080 newblocksinfile
= (abseof
+BLOCKSIZE
-1)>>BLOCKSHIFT
;
1082 if (newblocksinfile
> oldblocksinfile
)
1084 /* new blocks, 4*allocated anode, dirblock */
1085 t
= newblocksinfile
- oldblocksinfile
;
1086 if (!AllocateBlocksAC(file
->anodechain
, t
, &file
->le
.info
.file
, g
))
1088 file
->le
.info
.file
.direntry
->size
= oldfilesize
;
1089 *error
= ERROR_DISK_FULL
;
1093 /* change directory: in case of allocate this has to be done
1096 file
->le
.info
.file
.direntry
->size
= abseof
;
1097 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
1099 else if (oldblocksinfile
> newblocksinfile
)
1101 /* change directoryentry beforehand (needed for postponed delete but not
1102 * allowed for online updating allocate).
1104 file
->le
.info
.file
.direntry
->size
= abseof
;
1105 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
1107 t
= oldblocksinfile
- newblocksinfile
;
1108 FreeBlocksAC(file
->anodechain
, t
, freeanodes
, g
);
1110 /* PS: there will always be an anode left, since FreeBlocksAC
1111 * doesn't delete the last anode
1116 /* no change in number of blocks, just change directory entry */
1117 file
->le
.info
.file
.direntry
->size
= abseof
;
1118 MakeBlockDirty((struct cachedblock
*)file
->le
.info
.file
.dirblock
, g
);
1121 /* change filehandles (including own) */
1122 myanode
= file
->le
.anodenr
;
1123 for (fe
= HeadOf(&g
->currentvolume
->fileentries
); fe
->next
; fe
=fe
->next
)
1125 if (fe
->anodenr
== myanode
)
1127 if (IsFileEntry(fe
) && ((fileentry_t
*)fe
)->offset
>= abseof
)
1128 SeekInFile((fileentry_t
*)fe
, abseof
, OFFSET_BEGINNING
, error
, g
);
1136 /**********************************************************************/
1138 /**********************************************************************/
1140 /* check datacache. return cache slotnr or -1
1143 static int CheckDataCache(ULONG blocknr
, globaldata
*g
)
1147 for (i
= 0; i
< g
->dc
.size
; i
++)
1149 if (g
->dc
.ref
[i
].blocknr
== blocknr
)
1156 /* get block from cache or put it in cache if it wasn't
1157 * there already. return cache slotnr. errors are indicated by 'error'
1160 static int CachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
)
1165 i
= CheckDataCache(blocknr
, g
);
1166 if (i
!= -1) return i
;
1168 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1171 *error
= RawRead(&g
->dc
.data
[i
<<BLOCKSHIFT
], 1, blocknr
, g
);
1172 g
->dc
.roving
= (g
->dc
.roving
+1)&g
->dc
.mask
;
1173 g
->dc
.ref
[i
].dirty
= 0;
1174 g
->dc
.ref
[i
].blocknr
= blocknr
;
1178 static int FakeCachedRead(ULONG blocknr
, SIPTR
*error
, globaldata
*g
)
1183 i
= CheckDataCache(blocknr
, g
);
1184 if (i
!= -1) return i
;
1186 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1189 memset(&g
->dc
.data
[i
<<BLOCKSHIFT
], 0xAA, BLOCKSIZE
);
1190 g
->dc
.roving
= (g
->dc
.roving
+1)&g
->dc
.mask
;
1191 g
->dc
.ref
[i
].dirty
= 0;
1192 g
->dc
.ref
[i
].blocknr
= blocknr
;
1196 static UBYTE
*CachedReadD(ULONG blknr
, SIPTR
*err
, globaldata
*g
)
1200 i
= CachedRead(blknr
,err
,g
);
1204 return &g
->dc
.data
[i
<<BLOCKSHIFT
];
1207 /* write block in cache. if block was already cached,
1208 * overwrite it. return slotnr (never fails).
1210 static int CachedWrite(UBYTE
*data
, ULONG blocknr
, globaldata
*g
)
1214 i
= CheckDataCache(blocknr
, g
);
1218 g
->dc
.roving
= (g
->dc
.roving
+1)&g
->dc
.mask
;
1219 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1222 memcpy(&g
->dc
.data
[i
<<BLOCKSHIFT
], data
, BLOCKSIZE
);
1223 g
->dc
.ref
[i
].dirty
= 1;
1224 g
->dc
.ref
[i
].blocknr
= blocknr
;
1229 /* flush all blocks in datacache (without updating them first).
1231 void FlushDataCache(globaldata
*g
)
1235 for (i
=0; i
<g
->dc
.size
; i
++)
1236 g
->dc
.ref
[i
].blocknr
= 0;
1239 /* write all dirty blocks to disk
1241 void UpdateDataCache(globaldata
*g
)
1245 for (i
=0; i
<g
->dc
.size
; i
++)
1246 if (g
->dc
.ref
[i
].dirty
&& g
->dc
.ref
[i
].blocknr
)
1251 /* update a data cache slot, and any adjacent blocks
1253 static void UpdateSlot(int slotnr
, globaldata
*g
)
1258 blocknr
= g
->dc
.ref
[slotnr
].blocknr
;
1260 /* find out how many adjacent blocks can be written */
1261 for (i
=slotnr
; i
<g
->dc
.size
; i
++)
1263 if (g
->dc
.ref
[i
].blocknr
!= blocknr
++)
1265 g
->dc
.ref
[i
].dirty
= 0;
1269 RawWrite(&g
->dc
.data
[slotnr
<<BLOCKSHIFT
], i
-slotnr
, g
->dc
.ref
[slotnr
].blocknr
, g
);
1272 /* update cache to reflect blocks read to or written
1273 * from disk. to be called before disk is accessed.
1275 static void ValidateCache(ULONG blocknr
, ULONG numblocks
, enum vctype vctype
, globaldata
*g
)
1279 ENTER("ValidateCache");
1280 for (i
=0; i
<g
->dc
.size
; i
++)
1282 if (g
->dc
.ref
[i
].blocknr
>= blocknr
&&
1283 g
->dc
.ref
[i
].blocknr
< blocknr
+ numblocks
)
1287 if (g
->dc
.ref
[i
].dirty
)
1291 g
->dc
.ref
[i
].blocknr
= 0;
1297 /**********************************************************************/
1298 /* DEVICECOMMANDS */
1299 /* DEVICECOMMANDS */
1300 /* DEVICECOMMANDS */
1301 /**********************************************************************/
1306 ** Reads 'blocks' complete blocks in a caller supplied buffer.
1308 ** input : - buffer: buffer for data
1309 ** - blockstoread: number of blocks to read
1310 ** - blocknr: starting block
1312 ** global: - disk is used to get request struct
1314 ** result: errornr, 0=ok
1316 ULONG
DiskRead(UBYTE
*buffer
, ULONG blockstoread
, ULONG blocknr
, globaldata
*g
)
1321 DB(Trace(1, "DiskRead", "%ld blocks from %ld firstblock %ld\n",
1322 (ULONG
)blockstoread
, (ULONG
)blocknr
, g
->firstblock
));
1324 if (blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1329 if (blockstoread
== 1)
1331 slotnr
= CachedRead(blocknr
, &error
, g
);
1332 memcpy(buffer
, &g
->dc
.data
[slotnr
<<BLOCKSHIFT
], BLOCKSIZE
);
1335 ValidateCache(blocknr
, blockstoread
, read
, g
);
1336 return RawRead(buffer
, blockstoread
, blocknr
, g
);
1342 ** Writes 'blocks' complete blocks from a buffer.
1344 ** input : - buffer: the data
1345 ** - blockstowrite: number of blocks to write
1346 ** - blocknr: starting block
1348 ** global: - disk is used to get request struct
1350 ** result: errornr, 0=ok
1352 ULONG
DiskWrite(UBYTE
*buffer
, ULONG blockstowrite
, ULONG blocknr
, globaldata
*g
)
1357 DB(Trace(1, "DiskWrite", "%ld blocks from %ld + %ld\n", blockstowrite
, blocknr
,
1360 if (blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1365 if (blockstowrite
== 1)
1367 CachedWrite(buffer
, blocknr
, g
);
1370 ValidateCache(blocknr
, blockstowrite
, write
, g
);
1371 error
= RawWrite(buffer
, blockstowrite
, blocknr
, g
);
1373 /* cache last block written */
1376 buffer
+= ((blockstowrite
-1)<<BLOCKSHIFT
);
1377 slotnr
= CachedWrite(buffer
, blocknr
+blockstowrite
-1, g
);
1378 g
->dc
.ref
[slotnr
].dirty
= 0; // we just wrote it
1384 * SCSI direct functions
1389 int DoSCSICommand(UBYTE
*data
, ULONG datalen
, UBYTE
*command
,
1390 UWORD commandlen
, UBYTE direction
, globaldata
*g
)
1392 g
->scsicmd
.scsi_Data
= (UWORD
*)data
;
1393 g
->scsicmd
.scsi_Length
= datalen
;
1394 g
->scsicmd
.scsi_Command
= command
;
1395 g
->scsicmd
.scsi_CmdLength
= commandlen
;
1396 g
->scsicmd
.scsi_Flags
= SCSIF_AUTOSENSE
| direction
; /* SCSIF_READ or SCSIF_WRITE */
1397 g
->scsicmd
.scsi_SenseData
= g
->sense
;
1398 g
->scsicmd
.scsi_SenseLength
= 18;
1399 g
->scsicmd
.scsi_SenseActual
= 0;
1401 g
->request
->iotd_Req
.io_Length
= sizeof(struct SCSICmd
);
1402 g
->request
->iotd_Req
.io_Data
= (APTR
)&g
->scsicmd
;
1403 g
->request
->iotd_Req
.io_Command
= HD_SCSICMD
;
1404 DoIO((struct IORequest
*)g
->request
);
1405 if (g
->scsicmd
.scsi_Status
)
1412 ULONG
RawRead(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1415 ULONG transfer
, maxtransfer
;
1418 if(blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1421 blocknr
+= g
->firstblock
;
1422 if(!(InPartition(blocknr
) && InPartition(blocknr
+blocks
-1)))
1424 ErrorMsg(AFS_ERROR_READ_OUTSIDE
, NULL
, g
);
1425 return ERROR_SEEK_ERROR
;
1428 /* chop in maxtransfer chunks */
1429 maxtransfer
= g
->dosenvec
->de_MaxTransfer
>> BLOCKSHIFT
;
1432 transfer
= min(blocks
,maxtransfer
);
1433 *((UWORD
*)&cmdbuf
[0]) = 0x2800;
1434 *((ULONG
*)&cmdbuf
[2]) = blocknr
;
1435 *((ULONG
*)&cmdbuf
[6]) = transfer
<<8;
1437 if (!DoSCSICommand(buffer
,transfer
<<BLOCKSHIFT
,cmdbuf
,10,SCSIF_READ
,g
))
1441 args
[0] = g
->sense
[2];
1442 args
[1] = blocknr
- g
->firstblock
;
1443 while ((g
->ErrorMsg
)(AFS_ERROR_READ_ERROR
, args
, 2, g
))
1445 if (CheckCurrentVolumeBack(g
))
1448 if (!g
->softprotect
)
1453 if (g
->currentvolume
)
1454 g
->currentvolume
->numsofterrors
++;
1457 buffer
+= transfer
<<BLOCKSHIFT
;
1459 blocknr
+= transfer
;
1466 * VVV Todo: SCSI ErrorNumber in requester
1469 ULONG
RawWrite(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1472 ULONG transfer
, maxtransfer
;
1475 if(blocknr
== (ULONG
)-1)
1478 return ERROR_DISK_WRITE_PROTECTED
;
1480 blocknr
+= g
->firstblock
;
1481 if (!(InPartition(blocknr
) && InPartition(blocknr
+blocks
-1)))
1483 ErrorMsg (AFS_ERROR_WRITE_OUTSIDE
, NULL
, g
);
1484 return ERROR_SEEK_ERROR
;
1487 /* chop in maxtransfer chunks */
1488 maxtransfer
= g
->dosenvec
->de_MaxTransfer
>> BLOCKSHIFT
;
1491 transfer
= min(blocks
,maxtransfer
);
1492 *((UWORD
*)&cmdbuf
[0]) = 0x2a00;
1493 *((ULONG
*)&cmdbuf
[2]) = blocknr
;
1494 *((ULONG
*)&cmdbuf
[6]) = transfer
<<8;
1496 if (!DoSCSICommand(buffer
,blocks
<<BLOCKSHIFT
,cmdbuf
,10,SCSIF_WRITE
,g
))
1500 args
[0] = g
->sense
[2];
1501 args
[1] = blocknr
- g
->firstblock
;
1502 while ((g
->ErrorMsg
)(AFS_ERROR_WRITE_ERROR
, args
, 2, g
))
1504 if (CheckCurrentVolumeBack(g
))
1507 if (!g
->softprotect
)
1512 if (g
->currentvolume
)
1513 g
->currentvolume
->numsofterrors
++;
1516 buffer
+= transfer
<<BLOCKSHIFT
;
1518 blocknr
+= transfer
;
1524 #else /* SCSI Direct */
1530 /* Geometry MUST be loaded!!
1532 ULONG
RawRead(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1534 struct IOExtTD
*request
;
1536 ULONG io_length
, io_transfer
, io_offset
, io_actual
= 0, io_startblock
= 0;
1539 DB(Trace(1, "RawRead", "%ld blocks from %ld firstblock %ld\n",
1540 (ULONG
)blocks
, (ULONG
)blocknr
, g
->firstblock
));
1543 if(blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1546 realblocknr
= blocknr
+ g
->firstblock
;
1547 if(!(InPartition(realblocknr
) && InPartition(realblocknr
+blocks
-1)))
1549 ErrorMsg (AFS_ERROR_READ_OUTSIDE
, NULL
, g
);
1550 return ERROR_SEEK_ERROR
;
1553 io_length
= blocks
<< BLOCKSHIFT
;
1554 io_offset
= realblocknr
<< BLOCKSHIFT
;
1557 // upper 32 bit of offset
1558 io_actual
= realblocknr
>> (32-BLOCKSHIFT
);
1559 io_startblock
= realblocknr
;
1562 while (io_length
> 0)
1564 io_transfer
= min(io_length
, g
->dosenvec
->de_MaxTransfer
);
1565 io_transfer
&= ~(BLOCKSIZE
-1);
1566 request
= g
->request
;
1567 request
->iotd_Req
.io_Command
= CMD_READ
;
1568 request
->iotd_Req
.io_Length
= io_transfer
;
1569 request
->iotd_Req
.io_Data
= io_buffer
; // bufmemtype ??
1570 request
->iotd_Req
.io_Offset
= io_offset
;
1572 request
->iotd_Req
.io_Actual
= io_actual
;
1573 request
->iotd_Req
.io_Command
= TD_READ64
;
1577 if (DoIO((struct IORequest
*)request
) != 0)
1581 args
[0] = request
->iotd_Req
.io_Error
;
1582 args
[1] = blocknr
; /* should be realblocknr ?? */
1583 while ((g
->ErrorMsg
)(AFS_ERROR_READ_ERROR
, args
, 2, g
))
1585 if (CheckCurrentVolumeBack(g
))
1588 if (!g
->softprotect
)
1593 if (g
->currentvolume
)
1594 g
->currentvolume
->numsofterrors
++;
1595 DB(Trace(1,"RawRead","readerror nr %ld\n", args
[0], args
[1]));
1596 return ERROR_NOT_A_DOS_DISK
;
1599 io_buffer
+= io_transfer
;
1600 io_length
-= io_transfer
;
1602 io_startblock
+= (io_transfer
>> BLOCKSHIFT
);
1603 io_offset
= io_startblock
<< BLOCKSHIFT
;
1604 io_actual
= io_startblock
>> (32-BLOCKSHIFT
);
1606 io_offset
+= io_transfer
;
1615 static ULONG
TD_Format(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1617 struct IOExtTD
*request
;
1620 DB(Trace(1, "TD_Format", "%ld blocks from %ld + %ld\n", blocks
, blocknr
,
1624 if (blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1627 realblocknr
= blocknr
+ g
->firstblock
;
1628 if(!InPartition(realblocknr
))
1630 ErrorMsg (AFS_ERROR_WRITE_OUTSIDE
, NULL
, g
);
1631 return ERROR_SEEK_ERROR
;
1634 request
= g
->request
;
1635 request
->iotd_Req
.io_Command
= TD_FORMAT
;
1636 request
->iotd_Req
.io_Length
= blocks
*BLOCKSIZE
;
1637 request
->iotd_Req
.io_Data
= buffer
; // bufmemtype ??
1638 request
->iotd_Req
.io_Offset
= realblocknr
*BLOCKSIZE
;
1640 if(DoIO((struct IORequest
*)request
) != NULL
)
1644 args
[0] = request
->iotd_Req
.io_Error
;
1645 args
[1] = blocknr
; /* should be realblocknr?? */
1646 while ((g
->ErrorMsg
)(AFS_ERROR_WRITE_ERROR
, args
, 2, g
))
1648 if (CheckCurrentVolumeBack(g
))
1651 if (!g
->softprotect
)
1656 if (g
->currentvolume
)
1657 g
->currentvolume
->numsofterrors
++;
1658 DB(Trace(1,"TD_Format","writeerror nr %d\n", args
[0], args
[1]));
1659 return ERROR_NOT_A_DOS_DISK
;
1664 #endif /* TRACKDISK */
1667 ULONG
RawWrite(UBYTE
*buffer
, ULONG blocks
, ULONG blocknr
, globaldata
*g
)
1669 struct IOExtTD
*request
;
1671 ULONG io_length
, io_transfer
, io_offset
, io_actual
= 0, io_startblock
= 0;
1674 DB(Trace(1, "RawWrite", "%ld blocks from %ld + %ld\n", blocks
, blocknr
,
1678 if(blocknr
== (ULONG
)-1) // blocknr of uninitialised anode
1682 return ERROR_DISK_WRITE_PROTECTED
;
1684 realblocknr
= blocknr
+ g
->firstblock
;
1685 if (!(InPartition(realblocknr
) && InPartition(realblocknr
+blocks
-1)))
1687 ErrorMsg (AFS_ERROR_WRITE_OUTSIDE
, NULL
, g
);
1688 return ERROR_SEEK_ERROR
;
1691 io_length
= blocks
<< BLOCKSHIFT
;
1692 io_offset
= realblocknr
<< BLOCKSHIFT
;
1695 // upper 32 bit of offset
1696 io_actual
= realblocknr
>> (32 - BLOCKSHIFT
);
1697 io_startblock
= realblocknr
;
1700 while(io_length
> 0)
1702 io_transfer
= min(io_length
, g
->dosenvec
->de_MaxTransfer
);
1703 io_transfer
&= ~(BLOCKSIZE
-1);
1704 request
= g
->request
;
1705 request
->iotd_Req
.io_Command
= CMD_WRITE
;
1706 request
->iotd_Req
.io_Length
= io_transfer
;
1707 request
->iotd_Req
.io_Data
= io_buffer
; // bufmemtype ??
1708 request
->iotd_Req
.io_Offset
= io_offset
;
1710 request
->iotd_Req
.io_Actual
= io_actual
;
1711 request
->iotd_Req
.io_Command
= TD_WRITE64
;
1715 if (DoIO((struct IORequest
*)request
) != 0)
1719 args
[0] = request
->iotd_Req
.io_Error
;
1720 args
[1] = blocknr
; /* should be realblocknr?? */
1721 while ((g
->ErrorMsg
)(AFS_ERROR_WRITE_ERROR
, args
, 2, g
))
1723 if (CheckCurrentVolumeBack(g
))
1726 if (!g
->softprotect
)
1731 if (g
->currentvolume
)
1732 g
->currentvolume
->numsofterrors
++;
1733 DB(Trace(1,"RawWrite","writeerror nr %d\n", args
[0], args
[1]));
1734 return ERROR_NOT_A_DOS_DISK
;
1737 io_buffer
+= io_transfer
;
1738 io_length
-= io_transfer
;
1740 io_startblock
+= (io_transfer
>> BLOCKSHIFT
);
1741 io_offset
= io_startblock
<< BLOCKSHIFT
;
1742 io_actual
= io_startblock
>> (32-BLOCKSHIFT
);
1744 io_offset
+= io_transfer
;
1751 #endif /* SCSIDIRECT */
1753 /*************************************************************************/
1755 /* turn drivemotor off */
1756 void MotorOff(globaldata
*g
)
1758 struct IOExtTD
*request
= g
->request
;
1762 request
->iotd_Req
.io_Command
= TD_MOTOR
;
1763 request
->iotd_Req
.io_Length
= 0;
1764 request
->iotd_Count
= g
->changecount
;
1766 DoIO((struct IORequest
*)request
);