genmodule: Fix handler modules types' initialization
[AROS.git] / rom / filesys / pfs3 / fs / disk.c
blobd9285196826ab1b5896c94554c5c4c8a27779be9
1 /* $Id: disk.c 15.12 1999/03/25 22:05:00 Michiel Exp Michiel $ */
2 /* $Log: disk.c $
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
10 * ErrorMsg param
12 * Revision 15.9 1998/09/03 07:12:14 Michiel
13 * versie 17.4
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
21 * Release 16.21
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
34 * code cleanup
36 * Revision 15.2 1995/12/14 13:24:08 Michiel
37 * Direct SCSI support
39 * Revision 15.1 1995/12/05 15:47:27 Michiel
40 * Rollover files implemented
41 * Restructured: ReadFromObject, WriteToObject etc
42 * bugfixes
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
58 * minor changes
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
81 * DELDIR adaptions
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
88 * AFSLITE stuff
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
101 * CUTDOWN version
102 * protection update
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
108 * Release version
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
115 * Major update
116 * ReadFromFile, WriteToFile completely rewritten
117 * CachedRead added
118 * DataCaching updated
120 * Revision 11.7 1995/01/26 12:20:42 Michiel
121 * a minor change
123 * Revision 11.6 1995/01/24 17:44:34 Michiel
124 * bug fixes
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
151 * first RCS revision
152 * */
154 #define TESTING 1
156 //#define DEBUG 1
157 #define __USE_SYSBASE
159 #include <exec/types.h>
160 #include <exec/memory.h>
161 #include <exec/devices.h>
162 #include <exec/io.h>
163 #include <dos/filehandler.h>
164 //#include <sprof.h>
165 #include <string.h>
166 #include <stdio.h>
167 #include <math.h>
168 #include "debug.h"
170 // own includes
171 #include "blocks.h"
172 #include "struct.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()
182 #define PROFILE_ON()
184 /**********************************************************************/
185 /* DEBUG */
186 /**********************************************************************/
188 #ifdef DEBUG
189 static UBYTE debugbuf[120];
190 extern BOOL debug;
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;}
198 #else
199 #define DebugOn
200 #define DebugOff
201 #define DebugMsg(m)
202 #define DebugMsgNum(msg,num)
203 #define DebugMsgName(msg, name)
204 #endif
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 /**********************************************************************/
222 /* READ & WRITE */
223 /* READ & WRITE */
224 /* READ & WRITE */
225 /**********************************************************************/
227 ULONG ReadFromObject(fileentry_t *file, UBYTE *buffer, ULONG size,
228 SIPTR *error, globaldata *g)
230 if (!CheckReadAccess(file,error,g))
231 return -1;
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;
240 return -1;
244 #if ROLLOVER
245 if (IsRollover(file->le.info))
246 return ReadFromRollover(file,buffer,size,error,g);
247 else
248 #endif
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))
257 return -1;
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;
265 return -1;
269 /* changing file -> set notify flag */
270 file->checknotify = 1;
271 g->dirty = 1;
273 #if ROLLOVER
274 if (IsRollover(file->le.info))
275 return WriteToRollover(file,buffer,size,error,g);
276 else
277 #endif
278 return WriteToFile(file,buffer,size,error,g);
281 LONG SeekInObject(fileentry_t *file, LONG offset, LONG mode, SIPTR *error,
282 globaldata *g)
284 /* check access */
285 if (!CheckOperateFile(file,error,g))
286 return -1;
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;
294 return -1;
298 #if ROLLOVER
299 if (IsRollover(file->le.info))
300 return SeekInRollover(file,offset,mode,error,g);
301 else
302 #endif
303 return SeekInFile(file,offset,mode,error,g);
306 LONG ChangeObjectSize(fileentry_t *file, LONG releof, LONG mode,
307 SIPTR *error, globaldata *g)
309 /* check access */
310 if (!CheckChangeAccess(file, error, g))
311 return -1;
313 /* Changing file -> set notify flag */
314 file->checknotify = 1;
315 *error = 0;
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;
323 return -1;
327 #if ROLLOVER
328 if (IsRollover(file->le.info))
329 return ChangeRolloverSize(file,releof,mode,error,g);
330 else
331 #endif
332 return ChangeFileSize(file,releof,mode,error,g);
337 /**********************************************************************
339 **********************************************************************/
341 #if ROLLOVER
343 /* Read from rollover: at end of file,
344 * goto start
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;
353 ULONG read = 0;
354 LONG q; // quantity
355 LONG end, virtualoffset, virtualend, t;
357 DB(Trace(1,"ReadFromRollover","size = %lx offset = %lx\n",size,file->offset));
358 if (!size) return 0;
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)
372 return read;
374 end -= filesize_m;
375 buffer += q;
376 SeekInFile(file, 0, OFFSET_BEGINNING, error, g);
379 q = end - file->offset;
380 t = ReadFromFile(file, buffer, q, error, g);
381 if (t == -1)
382 return (ULONG)t;
383 else
384 read += t;
386 return read;
388 #undef filesize_m
389 #undef direntry_m
392 /* Write to rollover file. First write upto end of rollover. Then
393 * flip to start.
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;
405 struct fileinfo fi;
406 UBYTE entrybuffer[MAX_ENTRYSIZE];
407 LONG written = 0;
408 LONG q; // quantity
409 LONG end, virtualend, virtualoffset, t;
410 BOOL extend = FALSE;
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);
423 extend = TRUE;
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;
431 written += t;
432 if (t != q) return (ULONG)written;
433 end -= filesize_m;
434 buffer += q;
435 SeekInFile(file, 0, OFFSET_BEGINNING, error, g);
438 q = end - file->offset;
439 t = WriteToFile(file, buffer, q, error, g);
440 if (t == -1)
441 return (ULONG)t;
442 else
443 written += t;
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);
452 /* commit changes */
453 if (!GetParent(&file->le.info, &directory, error, g))
454 return DOSFALSE;
455 else
456 ChangeDirEntry(file->le.info.file, destentry, &directory, &fi, g);
458 return (ULONG)written;
460 #undef direntry_m
461 #undef filesize_m
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);
476 /* do the seeking */
477 oldvirtualoffset = file->offset - extrafields.rollpointer;
478 if (oldvirtualoffset < 0) oldvirtualoffset += filesize_m;
480 switch (mode)
482 case OFFSET_BEGINNING:
483 virtualoffset = offset;
484 break;
486 case OFFSET_END:
487 virtualoffset = extrafields.virtualsize + offset;
488 break;
490 case OFFSET_CURRENT:
491 virtualoffset = oldvirtualoffset + offset;
492 break;
494 default:
495 *error = ERROR_SEEK_ERROR;
496 return -1;
499 if ((virtualoffset > extrafields.virtualsize) || virtualoffset < 0)
501 *error = ERROR_SEEK_ERROR;
502 return -1;
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;
521 #undef filesize_m
522 #undef direntry_m
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;
535 struct fileinfo fi;
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);
542 switch (mode)
544 case OFFSET_BEGINNING:
545 virtualeof = releof;
546 break;
548 case OFFSET_END:
549 virtualeof = extrafields.virtualsize + releof;
550 break;
552 case OFFSET_CURRENT:
553 virtualoffset = file->offset - extrafields.rollpointer;
554 if (virtualoffset < 0) virtualoffset += filesize_m;
555 virtualeof = virtualoffset + releof;
556 break;
557 default: /* bogus parameter -> ERROR_SEEK_ERROR */
558 virtualeof = -1;
559 break;
562 if (virtualeof < 0)
564 *error = ERROR_SEEK_ERROR;
565 return -1;
568 /* change virtual size */
569 if (virtualeof >= filesize_m)
570 extrafields.virtualsize = filesize_m - 1;
571 else
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);
581 /* commit changes */
582 if (!GetParent(&file->le.info, &directory, error, g))
583 return DOSFALSE;
584 else
585 ChangeDirEntry(file->le.info.file, destentry, &directory, &fi, g);
587 return virtualeof;
589 #undef filesize_m
590 #undef direntry_m
593 #endif /* ROLLOVER */
595 /* <ReadFromFile>
597 ** Specification:
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;
607 ULONG register t;
608 UBYTE *data = NULL, *dataptr;
609 BOOL directread = FALSE;
610 struct anodechainnode *chnode;
611 #if DELDIR
612 struct deldirentry *dde;
613 #endif
615 DB(Trace(1,"ReadFromFile","size = %lx offset = %lx\n",size,file->offset));
616 if (!CheckReadAccess(file, error, g))
617 return -1;
619 /* correct size and check if zero */
620 #if DELDIR
621 if (IsDelFile(file->le.info)) {
622 if (!(dde = GetDeldirEntryQuick(file->le.info.delfile.slotnr, g)))
623 return -1;
624 t = dde->size - file->offset;
626 else
627 #endif
628 t = file->le.info.file.direntry->size - file->offset;
630 if (!(size = min(t, size)))
631 return 0;
633 /* initialize */
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);
644 t = !t;
646 /* read indirect if
647 * - mask failure
648 * - too small
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;
659 return -1;
661 dataptr = data;
663 else
665 /* direct read */
666 directread = TRUE;
667 blockstoread = fullblks;
668 dataptr = buffer;
670 /* read first blockpart */
671 if (blockoffset)
673 data = CachedReadD(chnode->an.blocknr + anodeoffset, error, g);
674 if (data)
676 NextBlockAC(&chnode, &anodeoffset, g);
678 /* calc numbytes */
679 t = BLOCKSIZE-blockoffset;
680 t = min(t, size);
681 memcpy(dataptr, data+blockoffset, t);
682 dataptr+=t;
683 if (blockstoread)
684 blockstoread--;
685 else
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 */
696 else
697 t = blockstoread;
699 *error = DiskRead(dataptr, t, chnode->an.blocknr + anodeoffset, g);
700 if (!*error)
702 blockstoread -= t;
703 dataptr += t<<BLOCKSHIFT;
704 anodeoffset += t;
705 CorrectAnodeAC(&chnode, &anodeoffset, g);
709 /* read last block part/ copy read data to buffer */
710 if (!*error)
712 if (!directread)
713 memcpy(buffer, data+blockoffset, size);
714 else if (bytesleft)
716 data = CachedReadD(chnode->an.blocknr+anodeoffset, error, g);
717 if (data)
718 memcpy(dataptr, data, bytesleft);
722 if (!directread)
723 FreeBufmem(data, g);
724 if (!*error)
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;
730 return size;
732 else
734 DB(Trace(1,"Read","failed\n"));
735 return -1;
741 /* <WriteToFile>
743 ** Specification:
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;
758 ** - Initialisation
759 ** - Extend filesize
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)
769 ULONG maskok, t;
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;
776 int slotnr;
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 */
785 return 0;
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;
799 return -1;
802 /* BUG 980422: this CorrectAnodeAC mode because of AllocateBlockAC!! AND
803 * because anodeoffset can be outside last block! (filepointer is
804 * byte 0 new block
806 CorrectAnodeAC(&chnode,&anodeoffset,g);
808 /* check mask */
809 maskok = (((IPTR)(buffer-blockoffset+BLOCKSIZE))&~g->dosenvec->de_Mask) ||
810 (((IPTR)(buffer-blockoffset+(totalblocks<<BLOCKSHIFT)))&~g->dosenvec->de_Mask);
811 maskok = !maskok;
813 /* write indirect if
814 * - mask failure
815 * - too small
817 if (!maskok || (totalblocks<2*DIRECTSIZE && (blockoffset+size>BLOCKSIZE*2) &&
818 (blockoffset || totalblocks<DIRECTSIZE)))
820 /* indirect */
821 /* allocate temporary data buffer */
822 if (!(dataptr = data = AllocBufmem(totalblocks<<BLOCKSHIFT, g)))
824 *error = ERROR_NO_FREE_STORE;
825 goto wtf_error;
828 /* first blockpart */
829 if (blockoffset)
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);
840 else
842 /* direct */
843 dataptr = buffer;
844 directwrite = TRUE;
846 /* first blockpart */
847 if (blockoffset || (totalblocks==1 && newfileoffset > oldfilesize))
849 ULONG fbp; /* first block part */
850 UBYTE *firstblock;
852 if (blockoffset)
854 slotnr = CachedRead(chnode->an.blocknr + anodeoffset, error, g);
855 if (*error)
856 goto wtf_error;
858 else
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);
872 bytestowrite -= fbp;
873 dataptr += fbp;
874 totalblocks--;
878 /* write following blocks. If done, then blockoffset always 0 */
879 if (newfileoffset > oldfilesize)
881 blockstofill = totalblocks;
882 bytestowrite = totalblocks<<BLOCKSHIFT;
884 else
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 */
891 else
892 t = blockstofill;
894 *error = DiskWrite(dataptr, t, chnode->an.blocknr + anodeoffset, g);
895 if (!*error)
897 blockstofill -= t;
898 dataptr += t<<BLOCKSHIFT;
899 bytestowrite -= t<<BLOCKSHIFT;
900 anodeoffset += t;
901 CorrectAnodeAC(&chnode, &anodeoffset, g);
905 /* write last block (RAW because cache direct) */
906 if (bytestowrite && !*error)
908 UBYTE *lastblock;
910 slotnr = CachedRead(chnode->an.blocknr + anodeoffset, error, g);
911 if (!*error)
913 lastblock = &g->dc.data[slotnr<<BLOCKSHIFT];
914 memcpy(lastblock, dataptr, bytestowrite);
915 MarkDataDirty(slotnr);
919 /* free mem for indirect write */
920 if (!directwrite)
921 FreeBufmem(data, g);
922 if (!*error)
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);
930 return size;
933 wtf_error:
934 if (newblocksinfile>oldblocksinfile)
936 /* restore old state of file */
937 #if VERSION23
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);
941 #else
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);
945 #endif
948 DB(Trace(1,"WriteToFile","failed\n"));
949 return -1;
953 /* SeekInFile
955 ** Specification:
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;
967 #if DELDIR
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)))
973 return -1;
974 #endif
976 /* do the seeking */
977 oldoffset = file->offset;
978 switch (mode)
980 case OFFSET_BEGINNING:
981 newoffset = offset;
982 break;
984 case OFFSET_END:
985 #if DELDIR
986 if (delfile)
987 newoffset = delfile->size + offset;
988 else
989 #endif
990 newoffset = file->le.info.file.direntry->size + offset;
991 break;
993 case OFFSET_CURRENT:
994 newoffset = oldoffset + offset;
995 break;
997 default:
998 *error = ERROR_SEEK_ERROR;
999 return -1;
1002 #if DELDIR
1003 if ((newoffset > (delfile ? delfile->size :
1004 file->le.info.file.direntry->size)) || (newoffset < 0))
1005 #else
1006 if ((newoffset > file->le.info.file.direntry->size) || (newoffset < 0))
1007 #endif
1009 *error = ERROR_SEEK_ERROR;
1010 return -1;
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;
1023 return oldoffset;
1027 /* Changes the length of a file
1028 ** Returns new length; -1 if failure
1030 ** Check if allowed
1031 ** 'Seek with extend'
1032 ** change other locks
1033 ** change direntry
1035 LONG ChangeFileSize(fileentry_t *file, LONG releof, LONG mode, SIPTR *error,
1036 globaldata *g)
1038 listentry_t *fe;
1039 LONG abseof, t;
1040 ULONG myanode, oldblocksinfile, newblocksinfile, oldfilesize;
1042 /* check access */
1043 DB(Trace(1,"ChangeFileSize","offset = %ld mode=%ld\n",releof,mode));
1044 if (!CheckChangeAccess(file, error, g))
1045 return -1;
1047 /* Changing file -> set notify flag */
1048 file->checknotify = 1;
1049 *error = 0;
1051 /* calculate new eof (ala 'Seek') */
1052 switch (mode)
1054 case OFFSET_BEGINNING:
1055 abseof = releof;
1056 break;
1058 case OFFSET_END:
1059 abseof = file->le.info.file.direntry->size + releof;
1060 break;
1062 case OFFSET_CURRENT:
1063 abseof = file->offset + releof;
1064 break;
1066 default:
1067 *error = ERROR_SEEK_ERROR;
1068 return DOSFALSE;
1071 if (abseof < 0)
1073 *error = ERROR_SEEK_ERROR;
1074 return -1;
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;
1090 return -1;
1093 /* change directory: in case of allocate this has to be done
1094 * afterwards
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
1114 else
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);
1132 return abseof;
1136 /**********************************************************************/
1137 /* CACHE STUFF */
1138 /**********************************************************************/
1140 /* check datacache. return cache slotnr or -1
1141 * if not found
1143 static int CheckDataCache(ULONG blocknr, globaldata *g)
1145 int i;
1147 for (i = 0; i < g->dc.size; i++)
1149 if (g->dc.ref[i].blocknr == blocknr)
1150 return i;
1153 return -1;
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'
1158 * (null = ok)
1160 static int CachedRead(ULONG blocknr, SIPTR *error, globaldata *g)
1162 int i;
1164 *error = 0;
1165 i = CheckDataCache(blocknr, g);
1166 if (i != -1) return i;
1167 i = g->dc.roving;
1168 if (g->dc.ref[i].dirty && g->dc.ref[i].blocknr)
1169 UpdateSlot(i, g);
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;
1175 return i;
1178 static int FakeCachedRead(ULONG blocknr, SIPTR *error, globaldata *g)
1180 int i;
1182 *error = 0;
1183 i = CheckDataCache(blocknr, g);
1184 if (i != -1) return i;
1185 i = g->dc.roving;
1186 if (g->dc.ref[i].dirty && g->dc.ref[i].blocknr)
1187 UpdateSlot(i, g);
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;
1193 return i;
1196 static UBYTE *CachedReadD(ULONG blknr, SIPTR *err, globaldata *g)
1198 int i;
1200 i = CachedRead(blknr,err,g);
1201 if (*err)
1202 return NULL;
1203 else
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)
1212 int i;
1214 i = CheckDataCache(blocknr, g);
1215 if (i == -1)
1217 i = g->dc.roving;
1218 g->dc.roving = (g->dc.roving+1)&g->dc.mask;
1219 if (g->dc.ref[i].dirty && g->dc.ref[i].blocknr)
1220 UpdateSlot(i, g);
1222 memcpy(&g->dc.data[i<<BLOCKSHIFT], data, BLOCKSIZE);
1223 g->dc.ref[i].dirty = 1;
1224 g->dc.ref[i].blocknr = blocknr;
1225 return i;
1229 /* flush all blocks in datacache (without updating them first).
1231 void FlushDataCache(globaldata *g)
1233 int i;
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)
1243 int i;
1245 for (i=0; i<g->dc.size; i++)
1246 if (g->dc.ref[i].dirty && g->dc.ref[i].blocknr)
1247 UpdateSlot (i, g);
1251 /* update a data cache slot, and any adjacent blocks
1253 static void UpdateSlot(int slotnr, globaldata *g)
1255 ULONG blocknr;
1256 int i;
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++)
1264 break;
1265 g->dc.ref[i].dirty = 0;
1268 /* write them */
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)
1277 int i;
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)
1285 if (vctype == read)
1287 if (g->dc.ref[i].dirty)
1288 UpdateSlot(i, g);
1290 else // flush
1291 g->dc.ref[i].blocknr = 0;
1297 /**********************************************************************/
1298 /* DEVICECOMMANDS */
1299 /* DEVICECOMMANDS */
1300 /* DEVICECOMMANDS */
1301 /**********************************************************************/
1304 /* DiskRead
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)
1318 SIPTR error;
1319 int slotnr;
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
1325 return 1;
1326 if (!blockstoread)
1327 return 0;
1329 if (blockstoread == 1)
1331 slotnr = CachedRead(blocknr, &error, g);
1332 memcpy(buffer, &g->dc.data[slotnr<<BLOCKSHIFT], BLOCKSIZE);
1333 return error;
1335 ValidateCache(blocknr, blockstoread, read, g);
1336 return RawRead(buffer, blockstoread, blocknr, g);
1340 /* DiskWrite
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)
1354 ULONG slotnr;
1355 ULONG error = 0;
1357 DB(Trace(1, "DiskWrite", "%ld blocks from %ld + %ld\n", blockstowrite, blocknr,
1358 g->firstblock));
1360 if (blocknr == (ULONG)-1) // blocknr of uninitialised anode
1361 return 1;
1362 if (!blockstowrite)
1363 return 0;
1365 if (blockstowrite == 1)
1367 CachedWrite(buffer, blocknr, g);
1368 return 0;
1370 ValidateCache(blocknr, blockstowrite, write, g);
1371 error = RawWrite(buffer, blockstowrite, blocknr, g);
1373 /* cache last block written */
1374 if (!error)
1376 buffer += ((blockstowrite-1)<<BLOCKSHIFT);
1377 slotnr = CachedWrite(buffer, blocknr+blockstowrite-1, g);
1378 g->dc.ref[slotnr].dirty = 0; // we just wrote it
1380 return error;
1384 * SCSI direct functions
1387 #if SCSIDIRECT
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)
1406 return 0;
1407 else
1408 return 1;
1412 ULONG RawRead(UBYTE *buffer, ULONG blocks, ULONG blocknr, globaldata *g)
1414 UBYTE cmdbuf[10];
1415 ULONG transfer, maxtransfer;
1417 retry_read:
1418 if(blocknr == (ULONG)-1) // blocknr of uninitialised anode
1419 return 1;
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;
1430 while (blocks > 0)
1432 transfer = min(blocks,maxtransfer);
1433 *((UWORD *)&cmdbuf[0]) = 0x2800;
1434 *((ULONG *)&cmdbuf[2]) = blocknr;
1435 *((ULONG *)&cmdbuf[6]) = transfer<<8;
1436 PROFILE_OFF();
1437 if (!DoSCSICommand(buffer,transfer<<BLOCKSHIFT,cmdbuf,10,SCSIF_READ,g))
1439 ULONG args[2];
1440 PROFILE_ON();
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))
1446 goto retry_read;
1448 if (!g->softprotect)
1450 g->softprotect = 1;
1451 g->protectkey = ~0;
1453 if (g->currentvolume)
1454 g->currentvolume->numsofterrors++;
1456 PROFILE_ON();
1457 buffer += transfer<<BLOCKSHIFT;
1458 blocks -= transfer;
1459 blocknr += transfer;
1462 return 0;
1466 * VVV Todo: SCSI ErrorNumber in requester
1469 ULONG RawWrite(UBYTE *buffer, ULONG blocks, ULONG blocknr, globaldata *g)
1471 UBYTE cmdbuf[10];
1472 ULONG transfer, maxtransfer;
1474 retry_write:
1475 if(blocknr == (ULONG)-1)
1476 return 1;
1477 if(g->softprotect)
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;
1489 while (blocks > 0)
1491 transfer = min(blocks,maxtransfer);
1492 *((UWORD *)&cmdbuf[0]) = 0x2a00;
1493 *((ULONG *)&cmdbuf[2]) = blocknr;
1494 *((ULONG *)&cmdbuf[6]) = transfer<<8;
1495 PROFILE_OFF();
1496 if (!DoSCSICommand(buffer,blocks<<BLOCKSHIFT,cmdbuf,10,SCSIF_WRITE,g))
1498 ULONG args[2];
1499 PROFILE_ON();
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))
1505 goto retry_write;
1507 if (!g->softprotect)
1509 g->softprotect = 1;
1510 g->protectkey = ~0;
1512 if (g->currentvolume)
1513 g->currentvolume->numsofterrors++;
1515 PROFILE_ON();
1516 buffer += transfer<<BLOCKSHIFT;
1517 blocks -= transfer;
1518 blocknr += transfer;
1521 return 0;
1524 #else /* SCSI Direct */
1527 * Normal commands
1530 /* Geometry MUST be loaded!!
1532 ULONG RawRead(UBYTE *buffer, ULONG blocks, ULONG blocknr, globaldata *g)
1534 struct IOExtTD *request;
1535 ULONG realblocknr;
1536 ULONG io_length, io_transfer, io_offset, io_actual = 0, io_startblock = 0;
1537 UBYTE *io_buffer;
1539 DB(Trace(1, "RawRead", "%ld blocks from %ld firstblock %ld\n",
1540 (ULONG)blocks, (ULONG)blocknr, g->firstblock));
1542 retry_read:
1543 if(blocknr == (ULONG)-1) // blocknr of uninitialised anode
1544 return 1;
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;
1555 io_buffer = buffer;
1556 if (g->td64mode) {
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;
1571 if (g->td64mode) {
1572 request->iotd_Req.io_Actual = io_actual;
1573 request->iotd_Req.io_Command = TD_READ64;
1576 PROFILE_OFF();
1577 if (DoIO((struct IORequest*)request) != 0)
1579 ULONG args[2];
1580 PROFILE_ON();
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))
1586 goto retry_read;
1588 if (!g->softprotect)
1590 g->softprotect = 1;
1591 g->protectkey = ~0;
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;
1598 PROFILE_ON();
1599 io_buffer += io_transfer;
1600 io_length -= io_transfer;
1601 if (g->td64mode) {
1602 io_startblock += (io_transfer >> BLOCKSHIFT);
1603 io_offset = io_startblock << BLOCKSHIFT;
1604 io_actual = io_startblock >> (32-BLOCKSHIFT);
1605 } else {
1606 io_offset += io_transfer;
1610 return 0;
1614 #if TRACKDISK
1615 static ULONG TD_Format(UBYTE *buffer, ULONG blocks, ULONG blocknr, globaldata *g)
1617 struct IOExtTD *request;
1618 ULONG realblocknr;
1620 DB(Trace(1, "TD_Format", "%ld blocks from %ld + %ld\n", blocks, blocknr,
1621 g->firstblock));
1623 retry_format:
1624 if (blocknr == (ULONG)-1) // blocknr of uninitialised anode
1625 return(1);
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;
1639 PROFILE_OFF();
1640 if(DoIO((struct IORequest*)request) != NULL)
1642 ULONG args[2];
1643 PROFILE_ON();
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))
1649 goto retry_format;
1651 if (!g->softprotect)
1653 g->softprotect = 1;
1654 g->protectkey = ~0;
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;
1661 PROFILE_ON();
1662 return NULL;
1664 #endif /* TRACKDISK */
1667 ULONG RawWrite(UBYTE *buffer, ULONG blocks, ULONG blocknr, globaldata *g)
1669 struct IOExtTD *request;
1670 ULONG realblocknr;
1671 ULONG io_length, io_transfer, io_offset, io_actual = 0, io_startblock = 0;
1672 UBYTE *io_buffer;
1674 DB(Trace(1, "RawWrite", "%ld blocks from %ld + %ld\n", blocks, blocknr,
1675 g->firstblock));
1677 retry_write:
1678 if(blocknr == (ULONG)-1) // blocknr of uninitialised anode
1679 return 1;
1681 if (g->softprotect)
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;
1693 io_buffer = buffer;
1694 if (g->td64mode) {
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;
1709 if (g->td64mode) {
1710 request->iotd_Req.io_Actual = io_actual;
1711 request->iotd_Req.io_Command = TD_WRITE64;
1714 PROFILE_OFF();
1715 if (DoIO((struct IORequest*)request) != 0)
1717 ULONG args[2];
1718 PROFILE_ON();
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))
1724 goto retry_write;
1726 if (!g->softprotect)
1728 g->softprotect = 1;
1729 g->protectkey = ~0;
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;
1736 PROFILE_ON();
1737 io_buffer += io_transfer;
1738 io_length -= io_transfer;
1739 if (g->td64mode) {
1740 io_startblock += (io_transfer >> BLOCKSHIFT);
1741 io_offset = io_startblock << BLOCKSHIFT;
1742 io_actual = io_startblock >> (32-BLOCKSHIFT);
1743 } else {
1744 io_offset += io_transfer;
1748 return 0;
1751 #endif /* SCSIDIRECT */
1753 /*************************************************************************/
1755 /* turn drivemotor off */
1756 void MotorOff(globaldata *g)
1758 struct IOExtTD *request = g->request;
1760 if(g->removable)
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);