home *** CD-ROM | disk | FTP | other *** search
- // Schreiben.c
- // 06 Dec 1996 11:24:07
-
- #ifndef BACKUP_INCLUDE
- #include "IncludeAll.c"
- #endif
- #include "Backup.h"
- #include "FileSelect.h"
- #include "Backup_proto.h"
- #include "BackupStrings.h"
- #include "Writer.h"
-
- #define d(x) ;
-
- #define WRITEPROC_STACK 8192l // Stack für Writer-Prozeß
-
- #define MAXBUFFUSE 3 // maximale Anzahl gleichzeitige Requests an Device
-
-
- #define TXPORTSIG(Sig) ((Sig) & WriterTxPortMask)
-
-
- static int WriterRxPortHandler(void);
- static void SendWriter(unsigned short Class);
- static BOOL WriterInit(void);
- static BOOL WriterInitDisks(void);
- static short WriterShutdown(void);
- static void TapeFull(struct TapeIO *TapeReq);
- static short ErrorCheck(struct IOExtTD *req, struct IOExtTD *verreq, BOOL bufwrite);
- static short TapeErrorCheck(struct TapeIO *TapeReq, BOOL bufwrite);
- static short DiskError(struct IOExtTD *req, const char *text, short errno, BOOL bufwrite);
- static void RetryRequests(void);
- static short WriteLabel(unsigned long diranf, unsigned long LogicalDirAnf, unsigned long dirlen,
- unsigned long diranz, long lastoffset, unsigned long DirCks,
- short DiskNr, BOOL QFA);
- static BOOL Schreiben(void);
- static short SchreibStatus(void);
- static short NamenSchreiben(BOOL WriteOutDir);
- static short WriteDir(struct Disk *Dsk, struct IOExtTD *WrtIO,
- struct TapeIO *WrtTIO, BOOL toTape, unsigned long DirSektor);
- static void FixupDir(short NewDiskNr, unsigned long LastByte);
- static short WriteTapeDir(struct Disk *Dsk, struct TapeIO *WrtTIO, short DiskNr);
- static void RemoveRequests(void);
- static void RemoveTapeRequests(void);
- static void WaitForDisk(BOOL AnyChange);
- static enum TestDiskResult CheckAppendDisk(short unit);
- static short ReadDir(struct DiskLabel *Label, short unit);
- static void newdisk(BOOL append, BOOL SameDiskNr);
- static short ReadQFALabel(struct DiskFlags *Dsk, struct DiskLabel *Label);
- static short ReadTapeLabel(struct DiskFlags *Dsk, struct DiskLabel *Label);
- static void ShowCyl(const struct IOExtTD *Req, short DiskNr);
- static short OpenDisks(void);
- static unsigned long ComputeDirChecksum(const struct Disk *Dsk, unsigned long DirLen);
- static BOOL CheckWriterTxPort(void);
- static void SendWriterRx(unsigned short Class);
-
-
- // aus Backup.c
- extern struct BackupDevInfo globDrvDat; // globale Disk-Parameter
- extern struct Window *aktWindow;
- extern struct BackupOptions myOptions;
- extern struct DiskFlags __far *Disks;
- extern unsigned short NDisk; // Anzahl Einträge in Disks[]
- extern short DiskUnit; // aktuelles Laufwerk für Backup
- extern struct Buffer __far CylBuff[]; // Schreib-/Lese-Buffer (für je einen Cylinder)
- extern unsigned short ReadBuffNr, WriteBuffNr, OldestWriteBuffNr;
- extern BOOL toTape; // Backup erfolgt auf Tape
- extern unsigned char disknr; // laufende Nummer der Backup-Diskette
- extern short BuffersFull; // Anzahl gefüllter Buffer
- extern BOOL AllFilesRead; // Backup-Ende (lesen) erreicht
- extern unsigned long FilesProcessed; // Anzahl Files
- extern unsigned long BytesProcessed; // Anzahl Bytes
- extern char StartZeit[8];
- extern struct Disk ReadDisk;
- extern struct Disk WriteDisk;
- extern unsigned short CurrentSessionNr;
- extern short BuffCount; // tatsächliche Anzahl Buffer
- extern long readoffset; // Offset innerhalb des aktuellen Lese-Buffers
- extern struct NameField *aktName;
- extern struct Task *BackupTask;
-
-
- // aus Protocol.c
- extern FILE *ProtFileHandle; // File Handle für Protokoll-File
- extern BOOL ProtFileValid; // Flag: Protfile enthält sinnvolle Daten (wird am Ende von NamenSchreiben gesetzt)
-
- // aus Revision.c
- extern short Version; // aktuelle Versionsnummer
-
- // aus ProcStart.asm
- extern APTR __far WriterSeg; // SegList für CreateProc
-
-
- static short ReqsInUse = 0; // Anzahl IORequests, die z.Z. beim Trackdisk.device anstehen
-
- static char __far zeile[129];
-
- static struct Task *WriterTask; // Prozeß "BackupWriter"
- static struct MsgPort *WriterProcPort; // Prozeß-Port "BackupWriter"
- static struct MsgPort *WriterRxPort; // Port für Nachrichten Writer -> main
- static struct MsgPort *WriterRxReplyPort; // Reply-Port für Nachrichten Writer -> main
- static struct MsgPort *WriterTxPort; // Port für Nachrichten main -> Writer
- static struct MsgPort *WriterTxReplyPort; // Reply-Port für Nachrichten main -> Writer
- static BOOL WriterRunning; // Flag: Writer soll laufen
- static BOOL WriterWarten; // Flag: warten vor dem Beginn des Schreibens
- static BOOL WriterAbort = FALSE; // Flag: Writer wird abgebrochen
- static BOOL CloseWriter = FALSE; // Flag: letzte Disk wird geschlossen
- static BOOL NewDiskOkFlag = FALSE; // Flag: WMR_NEWDISKOK ist angekommen
- static BOOL WMDownFlag = FALSE; // Flag: WMR_DOWN ist angekommen
- static short WriterSigBit = -1; // Signal-Bit für "Buffer full"
- static unsigned long WriterSigMask; // Signal-Maske für "Buffer full"-Signalisierung
- static unsigned long WriterIOMask; // Signal-Maske für IOExtTD's
- static unsigned long WriterTxPortMask; // Signal-Maske für WriterTxPort
- static unsigned long SignalsGot; // erhaltene Signale während Warten auf Eingabe
- static jmp_buf AbortJumpBuf; // jmp_buf zum Abbrechen des Writers
-
- static struct BInputHandler *WriterInput = NULL;
-
-
- // return TRUE wenn OK, nach Fehler FALSE
- BOOL StartWriter(void)
- {
- BOOL Success = FALSE;
- struct WriterMessage *Msg;
-
- WriterRxPort = CreateMsgPort();
- if (NULL == WriterRxPort)
- {
- alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterRxPort");
- return FALSE;
- }
- WriterTxReplyPort = CreateMsgPort();
- if (NULL == WriterTxReplyPort)
- {
- alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterTxReplyPort");
- return FALSE;
- }
-
- WriterProcPort = CreateProc((STRPTR) "BackupWriter", 0L, MKBADDR(&WriterSeg),
- WRITEPROC_STACK);
- if (WriterProcPort == NULL)
- {
- alarm(GetString(MSG_CREATEPROC_FAILED), __FUNC__, "BackupWriter");
- return FALSE;
- }
-
- // auf Init.-Quittung warten
- WaitPort(WriterRxPort);
- Msg = (struct WriterMessage *) GetMsg(WriterRxPort); // Quittung holen
- if (Msg)
- {
- d(kprintf("%s %ld: Msg=%08lx Class=%lx\n", __FUNC__, __LINE__, Msg, Msg->wm_Class);)
- Success = WMR_INITOK == Msg->wm_Class;
-
- ReplyMsg((struct Message *) Msg);
- }
-
- if (Success)
- WriterInput = AddBInputHandler(1 << WriterRxPort->mp_SigBit, WriterRxPortHandler);
-
- return Success;
- }
-
-
- void StopWriter(BOOL abnormalAbort)
- {
- if (WriterRxPort == NULL)
- return;
-
- if (WriterProcPort)
- {
- struct WriterMessage *Msg;
-
- while (Msg = (struct WriterMessage *) GetMsg(WriterRxPort))
- {
- ReplyMsg((struct Message *) Msg);
- }
-
- SendWriter(abnormalAbort ? WM_ABORT : WM_SHUTDOWN);
- WriterRunning = FALSE;
-
- WMDownFlag = FALSE;
-
- do {
- // warten auf Ende-Quittung
- eingabe(0l);
- } while (!WMDownFlag);
- }
-
- d(kprintf("%s %ld\n", __FUNC__, __LINE__);)
-
- RemBInputHandler(&WriterInput);
-
- if (WriterRxPort)
- {
- DeleteMsgPort(WriterRxPort);
- WriterRxPort = NULL;
- }
- if (WriterTxReplyPort)
- {
- DeleteMsgPort(WriterTxReplyPort);
- WriterTxReplyPort = NULL;
- }
- }
-
-
- void SignalBufferFull(void)
- {
- Signal(WriterTask, WriterSigMask);
- }
-
-
- void SignalBeginWriting(void)
- {
- static BOOL First = TRUE;
-
- d(kprintf("%s %ld\n", __FUNC__, __LINE__);)
- if (First)
- {
- d(kprintf("%s %ld\n", __FUNC__, __LINE__);)
- SendWriter(WM_BEGINWRITE);
- First = FALSE;
- }
- }
-
-
- // Neue Disk anfordern und warten bis bereit
- void SignalNewDisk(void)
- {
- SendWriter(WM_NEWDISK);
-
- NewDiskOkFlag = FALSE;
-
- do {
- // warten auf WMR_NEWDISKOK
- eingabe(0l);
- } while (!NewDiskOkFlag);
- }
-
-
- // Letzte Disk schließen
- void SignalDiskClose(void)
- {
- SendWriter(WM_CLOSEDISK);
- }
-
-
- // DiskChanger meldet: Neue Disk ist Ok
- void SignalNewDiskOk(void)
- {
- if (WriterTask)
- Signal(WriterTask, WriterSigMask);
- }
-
-
- void SignalUnIconifyMainWindow(void)
- {
- struct MsgPort *ReplyPort;
- struct WriterMessage *Msg;
-
- if (FindTask(NULL) == BackupTask)
- {
- UnIconifyMainWindow();
- }
- else
- {
- ReplyPort = CreateMsgPort();
- if (ReplyPort)
- {
- Msg = malloc(sizeof(struct WriterMessage));
- if (Msg)
- {
- Msg->wm_Msg.mn_ReplyPort = ReplyPort;
- Msg->wm_Msg.mn_Length = sizeof(struct WriterMessage);
- Msg->wm_Class = WMR_OPENMAINWINDOW;
-
- d(kprintf(">>%s %ld: send %lx\n", __FUNC__, __LINE__, (long) Msg->wm_Class);)
- PutMsg(WriterRxPort, (struct Message *) Msg);
-
- d(kprintf(">>%s %ld vor WaitPort\n", __FUNC__, __LINE__);)
- WaitPort(ReplyPort);
- Msg = (struct WriterMessage *) GetMsg(ReplyPort);
-
- free(Msg);
- d(kprintf(">>%s %ld nach WaitPort\n", __FUNC__, __LINE__);)
- }
- DeleteMsgPort(ReplyPort);
- }
- }
- }
-
-
- // Message an Writer-Prozeß senden
- static void SendWriter(unsigned short Class)
- {
- struct WriterMessage *Msg;
-
- Msg = malloc(sizeof(struct WriterMessage));
- if (Msg)
- {
- Msg->wm_Msg.mn_ReplyPort = WriterTxReplyPort;
- Msg->wm_Msg.mn_Length = sizeof(struct WriterMessage);
- Msg->wm_Class = Class;
-
- d(kprintf("%ld: send %lx\n", __LINE__, (long) Class);)
- PutMsg(WriterTxPort, (struct Message *) Msg);
-
- WaitPort(WriterTxReplyPort); // Warten auf Reply
- Msg = (struct WriterMessage *) GetMsg(WriterTxReplyPort); // Reply-Port leeren
- free(Msg);
-
- d(kprintf("%ld: send %lx nach WaitPort()\n", __LINE__, (long) Class);)
- }
- }
-
-
- static int WriterRxPortHandler(void)
- {
- struct WriterMessage *Msg;
-
- do {
- Msg = (struct WriterMessage *) GetMsg(WriterRxPort);
- if (Msg)
- {
- switch (Msg->wm_Class)
- {
- case WMR_ABORTMAIN:
- // Hauptprogramm abbrechen
- myabort(10);
- break;
-
- case WMR_OPENMAINWINDOW:
- // Sicherstellen, daß aktWindow offen ist!
- SignalUnIconifyMainWindow();
- break;
-
- case WMR_BUFFEREMPTY:
- // ein Buffer ist leer geworden
- break;
-
- case WMR_NEWDISKOK:
- NewDiskOkFlag = TRUE;
- break;
-
- case WMR_DOWN:
- WMDownFlag = TRUE;
- break;
- }
-
- ReplyMsg((struct Message *) Msg);
- }
- } while (Msg);
-
- return 0;
- }
-
-
- // ======================================================
- // ab hier läuft der Code als eigener Prozeß !
-
- // main() des BackupWriter
- void __saveds BackupWriter(void)
- {
- unsigned long RcvdSig;
-
- d(kprintf("%ld vor WriterInit\n", __LINE__);)
- WriterInit();
-
- setjmp(AbortJumpBuf);
-
- d(kprintf("%ld vor WriterInitDisks\n", __LINE__);)
- if (WriterRunning && WriterInitDisks())
- {
- // Prozeß-Start quittieren
- SendWriterRx(WMR_INITOK);
- d(kprintf("%ld WriterInit ok\n", __LINE__);)
-
- WriterWarten = TRUE;
- while (WriterRunning && WriterWarten)
- {
- d(kprintf("%ld vor WaitPort\n", __LINE__);)
- WaitPort(WriterTxPort);
- d(kprintf("%ld nach WaitPort\n", __LINE__);)
-
- CheckWriterTxPort();
- }
-
- d(kprintf("%ld nach while {}\n", __LINE__);)
- if (WriterRunning && Disks[myOptions.bo_FirstUnit].TapeReq)
- TapeInitProperties(Disks[myOptions.bo_FirstUnit].TapeReq);
-
- while (WriterRunning)
- {
- d(kprintf("%ld in While {}\n", __LINE__);)
-
- SignalsGot = 0l;
- if (Schreiben())
- RcvdSig = SetSignal(0l, 0l) | SignalsGot;
- else if (WriterRunning)
- {
- // im Moment ist kein Puffer frei.
- // jetzt warten bis 2/3 aller Puffer gefüllt sind
- do {
- RcvdSig = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask) | SignalsGot;
- } while (!AllFilesRead && !(RcvdSig & ~WriterSigMask)
- && BuffersFull < 2*BuffCount/3);
- }
-
- d(kprintf("%ld in While {}\n", __LINE__);)
- if (RcvdSig & WriterTxPortMask)
- CheckWriterTxPort();
-
- d(kprintf("%ld in While {}\n", __LINE__);)
- if (RcvdSig & WriterIOMask)
- SchreibStatus();
- d(kprintf("%ld in While {}\n", __LINE__);)
-
- // Backup-Medium schließen: Directory + Label schreiben
- if (CloseWriter && !DB_EMPTY(WriteDisk) && WriteReady())
- NamenSchreiben(TRUE);
- }
-
- d(kprintf("%ld CloseWriter=%ld WriterAbort=%ld\n", __LINE__, CloseWriter, WriterAbort);)
-
- // Backup-Medium schließen: Directory + Label schreiben
- if (CloseWriter && !WriterAbort && !DB_EMPTY(WriteDisk))
- NamenSchreiben(TRUE);
-
- d(kprintf("%ld nach While {}\n", __LINE__);)
- }
- else
- {
- SendWriterRx(WMR_INITBAD);
- }
-
- WriterShutdown();
-
- // Prozeß-Ende quittieren
- Forbid();
- SendWriterRx(WMR_DOWN);
-
- WriterProcPort = NULL;
- WriterTask = NULL;
- }
-
-
- static BOOL __interrupt WriterInit(void)
- {
- WriterTask = FindTask(NULL);
-
- WriterTxPort = CreateMsgPort();
- if (WriterTxPort == NULL)
- {
- alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterTxPort");
- return FALSE;
- }
- WriterRxReplyPort = CreateMsgPort();
- if (WriterRxReplyPort == NULL)
- {
- alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterRxReplyPort");
- return FALSE;
- }
-
- WriterSigBit = AllocSignal(-1);
- if (WriterSigBit == -1)
- {
- alarm("%s: %s WriterSigBit", __FUNC__, GetString(MSG_CANNOT_GET_SIGNAL));
- return FALSE;
- }
-
- WriterTxPortMask = 1 << WriterTxPort->mp_SigBit;
- WriterSigMask = 1 << WriterSigBit;
-
- WriterRunning = TRUE;
- return TRUE;
- }
-
-
- static BOOL WriterInitDisks(void)
- {
- if (!OpenDisks())
- return FALSE; // Fehler bei OpenDevice
-
- WriterIOMask = 1 << Disks[myOptions.bo_FirstUnit].diskreq->iotd_Req.io_Message.mn_ReplyPort->mp_SigBit;
- if (myOptions.bo_SecondUnit != NO_DRIVE)
- WriterIOMask |= 1 << Disks[myOptions.bo_SecondUnit].diskreq->iotd_Req.io_Message.mn_ReplyPort->mp_SigBit;
-
- return TRUE;
- }
-
-
- static short WriterShutdown(void)
- {
- d(kprintf("Removing Writer Requests\n");)
- RemoveRequests();
-
- CloseDisk(&Disks[myOptions.bo_FirstUnit], CDP_UnloadTape);
- if (myOptions.bo_SecondUnit != NO_DRIVE)
- CloseDisk(&Disks[myOptions.bo_SecondUnit], CDP_UnloadTape);
-
- if (WriterTxPort)
- {
- DeleteMsgPort(WriterTxPort);
- WriterTxPort = NULL;
- }
- if (WriterRxReplyPort)
- {
- DeleteMsgPort(WriterRxReplyPort);
- WriterRxReplyPort = NULL;
- }
- if (WriterSigBit != -1)
- {
- FreeSignal(WriterSigBit);
- WriterSigBit = -1;
- }
- return 0;
- }
-
-
- static void TapeFull(struct TapeIO *TapeReq)
- {
- unsigned long LastByte, MissingBytes;
- struct NameField *nf;
- short error;
-
- ASSERT_VALID(TapeReq);
-
- alarm("Band ist voll !!!\nAlles weitere passiert ohne Gewähr!");
-
- LastByte = TapeReq->Req->iotd_Req.io_Offset + TapeReq->Req->iotd_Req.io_Actual;
- MissingBytes = TapeReq->Req->iotd_Req.io_Length - TapeReq->Req->iotd_Req.io_Actual;
-
- nf = LookupFile(LastByte, LastByte);
-
- nf->isComplete = 0;
- ComputeNfChecksum(aktName); // Prüfsumme in NameField korrigieren!
-
- FixupDir(disknr+1, LastByte); // Directory korrigieren
-
- // Ende der Daten mit SetMark kennzeichnen
- error = TapeWriteFileMarks(TapeReq, 1, TRUE);
-
- while (error)
- error = TapeError(TapeReq, &Disks[DiskUnit], GetString(MSG_WRITING_LABEL), error, FALSE, TRUE);
-
- NamenSchreiben(FALSE); // Label und QFA-Directory schreiben
-
- disknr++;
-
- newdisk(FALSE, FALSE); // neues Band anfordern
-
- // Neues Tape-Label schreiben
- WriteLabel(0l, 0l, 0l, 0l, 0l, 0l, disknr, FALSE);
-
- // fehlende Daten jetzt auf das neue Band schreiben
- error = TapeWrite(TapeReq, TapeReq->Req->iotd_Req.io_Data, MissingBytes);
- while (error)
- error = TapeError(TapeReq, &Disks[DiskUnit], GetString(MSG_WRITING), error, FALSE, TRUE);
- }
-
-
- static short ErrorCheck(struct IOExtTD *req, struct IOExtTD *verreq, BOOL bufwrite)
- {
- short error, result;
-
- ASSERT_VALID(req);
-
- error = result = WriteTrackStatus(req, verreq);
- while (result)
- {
- if (req->iotd_Req.io_Error)
- result = DiskError(req, GetString(MSG_WRITING), error, bufwrite);
- else if (myOptions.bo_Verify)
- {
- ASSERT_VALID(verreq);
- result = DiskError(verreq, GetString(MSG_VERIFYING), error, bufwrite);
- }
- }
- return error;
- }
-
-
- static short TapeErrorCheck(struct TapeIO *TapeReq, BOOL bufwrite)
- {
- long error, result;
-
- ASSERT_VALID(TapeReq);
- d(kprintf("%ld Beginn TapeErrorCheck\n", __LINE__);)
-
- error = result = TapeIOStatus(TapeReq);
- d(kprintf("%ld in TapeErrorCheck, result=%08lx\n", __LINE__, result);)
-
- while (result)
- {
- d(kprintf("%ld in TapeErrorCheck, result=%08lx\n", __LINE__, result);)
- d(kprintf("Status=%02lx SK=%02lx ASC=%02lx ASCQ=%02lx\n",
- TapeReq->Cmd.scsi_Status,
- TapeReq->Sense[2] & 0x0f,
- TapeReq->Cmd.scsi_SenseLength > 12 ? TapeReq->Sense[12] : 0,
- TapeReq->Cmd.scsi_SenseLength > 13 ? TapeReq->Sense[13] : 0
- );)
-
- if (error)
- result = TapeError(TapeReq, &Disks[DiskUnit], GetString(MSG_WRITING), error, bufwrite, TRUE);
- }
-
- d(kprintf("%ld Ende TapeErrorCheck\n", __LINE__);)
-
- return (short) error;
- }
-
-
- short TapeError(struct TapeIO *TapeReq, struct DiskFlags *Dsk, const char *text, short errno,
- BOOL bufwrite, BOOL BlockNrValid)
- {
- static const long SKMessages[] =
- {
- MSG_SK_NOSENSE, MSG_SK_RECOVEREDERROR, MSG_SK_NOTREADY, MSG_SK_MEDIUMERROR,
- MSG_SK_HARDWAREERROR, MSG_SK_ILLEGALREQUEST, MSG_SK_UNITATTENTION, MSG_SK_DATAPROTECT,
- MSG_SK_BLANKCHECK, MSG_SK_VENDORSPECIFIC, MSG_SK_COPYABORTED,
- MSG_SK_ABORTEDCOMMAND, MSG_SK_EQUAL, MSG_SK_VOLUMEOVERFLOW, MSG_SK_MISCOMPARE,
- MSG_SK_RESERVED
- };
- unsigned char SenseKey, ASC, ASCQ;
- struct NameField *nf;
- const char *DOSName;
- unsigned long Offset, MaxOffset;
- short result = 0;
- short EoM, c;
-
- ASSERT_VALID(TapeReq);
- ASSERT_VALID(text);
-
- d(kprintf("%ld Beginn TapeError\n", __LINE__);)
-
- DOSName = Dsk ? Dsk->DOSName : "";
-
- SenseKey = TapeReq->Sense[2] & 0x0f;
- EoM = TapeReq->Sense[2] & 0x40;
- ASC = TapeReq->Cmd.scsi_SenseLength > 12 ? TapeReq->Sense[12] : 0;
- ASCQ = TapeReq->Cmd.scsi_SenseLength > 13 ? TapeReq->Sense[13] : 0;
-
- d(kprintf("%ld in TapeError\n", __LINE__);)
- if (bufwrite)
- RemoveTapeRequests(); // Device anhalten
-
- d(kprintf("%ld in TapeError\n", __LINE__);)
-
- if (EoM && SenseKey == 0 && (TapeReq->DrvDat->SCSILevel < 2 ||
- (ASC == 0 && ASCQ == 2)))
- {
- // Band ist zu Ende
- TapeFull(TapeReq);
- return FALSE;
- }
-
- SetBusyPointer(aktWindow, FALSE);
-
- if (TapeReq->IOError)
- {
- sprintf(zeile, GetString(BlockNrValid ? MSG_TAPE_IOERROR_BLOCK : MSG_TAPE_IOERROR),
- DOSName, ErrorText((short) TapeReq->IOError),
- text, globDrvDat.BlockSize ? (TapeReq->Req->iotd_Req.io_Offset / globDrvDat.BlockSize) : 0);
- }
- else
- {
- sprintf(zeile, GetString(BlockNrValid ? MSG_TAPE_ERROR_BLOCK : MSG_TAPE_ERROR),
- DOSName, TapeReq->Cmd.scsi_Status,
- SenseKey, GetString(SKMessages[SenseKey]), ASC, ASCQ,
- text, globDrvDat.BlockSize ? (TapeReq->Req->iotd_Req.io_Offset / globDrvDat.BlockSize) : 0);
- }
- d(kprintf("%ld in TapeError\n", __LINE__);)
- PostError(TRUE, MSGPRI_Error, zeile);
- d(kprintf("%ld in TapeError\n", __LINE__);)
-
- SendWriterRx(WMR_OPENMAINWINDOW);
- c = askRetryWindow(aktWindow, WriterTxPortMask, &SignalsGot, zeile);
- // InfoLine("");
-
- // Prüfen ob Prozeß abgebrochen werden muß
- CheckWriterTxPort();
-
- if (c == *GetString(MSG_ABORT_SHORT))
- {
- // Abbrechen
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
- else if (c == *GetString(MSG_IGNORE_SHORT) && bufwrite)
- {
- // Ignorieren
- Offset = TapeReq->Req->iotd_Req.io_Offset + TapeReq->Cmd.scsi_Actual;
- MaxOffset = TapeReq->Req->iotd_Req.io_Offset + TapeReq->Cmd.scsi_Length;
-
- while (Offset < MaxOffset && (nf = LookupFile(Offset, MaxOffset))
- && !CheckWriterTxPort())
- {
- // Namen der beschädigten Files melden
- PostError(FALSE, MSGPRI_Warning, GetString(MSG_FILE_DAMAGED), NurName(nf->Name));
- Offset = nf->Offset + nf->RecordedLen + 1;
- }
-
- // Der Request mit dem Fehler wird abgehakt
- SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
- SendWriterRx(WMR_BUFFEREMPTY);
- NextBuffNr(&OldestWriteBuffNr);
- }
- if (c == *GetString(MSG_IGNORE_SHORT) ||
- c == *GetString(MSG_RETRY_SHORT) )
- {
- // Retry
- // Noch ausstehende Requests wieder absenden
- if (bufwrite)
- {
- RetryRequests();
- }
- else if (c == *GetString(MSG_RETRY_SHORT))
- {
- result = TapeDoIO(TapeReq);
- }
- }
- d(kprintf("%ld Ende TapeError\n", __LINE__);)
-
- return result;
- }
-
-
- static short DiskError(struct IOExtTD *req, const char *text, short errno, BOOL bufwrite)
- {
- struct NameField *nf;
- unsigned long Offset, MaxOffset;
- short c;
- short Error = 0;
-
- ASSERT_VALID(req);
- ASSERT_VALID(text);
-
- sprintf(zeile, GetString(MSG_DISK_ERROR),
- Disks[DiskUnit].DOSName,
- errno, ErrorText((short) errno), text,
- sectotrack(req->iotd_Req.io_Offset / globDrvDat.BlockSize),
- req->iotd_Req.io_Offset / globDrvDat.BlockSize);
-
- if (bufwrite)
- RemoveRequests(); // Device anhalten
-
- SendWriterRx(WMR_OPENMAINWINDOW);
- c = askRetryWindow(aktWindow, WriterTxPortMask, &SignalsGot, zeile);
- // InfoLine("");
-
- // Prüfen ob Prozeß abgebrochen werden muß
- CheckWriterTxPort();
-
- if (c == *GetString(MSG_RETRYNEWDISK_SHORT))
- {
- struct IOExtTD RetryReq;
- unsigned long Cyl = 0;
- APTR CylBuffer;
- int Error;
-
- RetryReq = *req;
- Clear(&RetryReq);
-
- newdisk(FALSE, TRUE); // neue Disk anfordern
-
- // Alle Cylinder zurückschreiben auf die neue Disk
- do {
- CylBuffer = RetrieveSaveInfo(Cyl);
- if (CylBuffer)
- {
- unsigned long Sector = Cyl * globDrvDat.NumSecs
- * globDrvDat.NumHeads;
-
- Error = TFormat(&RetryReq, Sector, CylBuffer, globDrvDat.CylSize);
- ShowCyl(&RetryReq, disknr);
-
- if (!Error && myOptions.bo_Verify)
- Error = TRead(&RetryReq, Sector, CylBuffer, globDrvDat.CylSize);
-
- Cyl++;
- }
- } while(!Error && CylBuffer);
- }
- else if (c == *GetString(MSG_ABORT_SHORT))
- {
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
- else if (c == *GetString(MSG_IGNORE_SHORT))
- {
- PostError(TRUE, MSGPRI_Error, zeile);
-
- Offset = req->iotd_Req.io_Offset + req->iotd_Req.io_Actual;
- MaxOffset = req->iotd_Req.io_Offset + req->iotd_Req.io_Length;
- while (Offset < MaxOffset && (nf = LookupFile(Offset, MaxOffset)) && !CheckWriterTxPort())
- {
- PostError(FALSE, MSGPRI_Warning, GetString(MSG_FILE_DAMAGED), NurName(nf->Name));
- Offset = nf->Offset + nf->RecordedLen + 1;
- }
-
- if (bufwrite)
- {
- // Der Request mit dem Fehler wird abgehakt
- SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
- SendWriterRx(WMR_BUFFEREMPTY);
- NextBuffNr(&OldestWriteBuffNr);
- }
- }
- if (!Error && (c == *GetString(MSG_IGNORE_SHORT) || c == *GetString(MSG_RETRY_SHORT)
- || c == *GetString(MSG_RETRYNEWDISK_SHORT)))
- {
- // Noch ausstehende Requests wieder absenden
- if (bufwrite)
- {
- RetryRequests();
- }
- else if (c != *GetString(MSG_IGNORE_SHORT))
- {
- Error = DoIO((struct IORequest *) req);
- }
- }
-
- return Error;
- }
-
-
- static void RetryRequests(void)
- {
- unsigned short n;
-
- n = OldestWriteBuffNr;
- do {
- if (GetBuffStatus(&CylBuff[n]) == VOLL)
- {
- d(kprintf("%ld in RetryRequests n=%ld LN_TYPE=%ld\n",
- __LINE__, n, CylBuff[n].BufIOReq.iotd_Req.io_Message.mn_Node.ln_Type);)
-
- if (toTape)
- {
- d(kprintf("%ld in RetryRequests n=%ld LN_TYPE=%ld\n",
- __LINE__, n, CylBuff[n].TapeReq->Req->iotd_Req.io_Message.mn_Node.ln_Type);)
-
- TapeBeginWrite(CylBuff[n].TapeReq, CylBuff[n].dbp, globDrvDat.CylSize,
- CylBuff[n].TapeReq->Req->iotd_Req.io_Offset);
- }
- else
- {
- unsigned long sector;
-
- d(kprintf("%ld in RetryRequests n=%ld LN_TYPE=%ld\n",
- __LINE__, n, CylBuff[n].BufIOReq.iotd_Req.io_Message.mn_Node.ln_Type);)
-
- sector = CylBuff[n].BufIOReq.iotd_Req.io_Offset / globDrvDat.BlockSize;
-
- CylBuff[n].BufferCheckSum = ComputeBufferCheckSum(&CylBuff[n]);
- StartWriteTrack( &CylBuff[n].BufIOReq, sector, CylBuff[n].dbp, globDrvDat.CylSize);
-
- if (myOptions.bo_Verify)
- {
- StartReadTrack( &CylBuff[n].VerifyReq, sector, CylBuff[n].dbp, globDrvDat.CylSize);
- ReqsInUse++;
- }
- }
- ReqsInUse++;
-
- SetBuffStatus(&CylBuff[n], LEEREN);
- }
-
- NextBuffNr(&n);
- } while (n != WriteBuffNr && (ReqsInUse <= MAXBUFFUSE));
- }
-
-
- // Header in Sektor 0 der Diskette schreiben.
- // liefert TRUE wenn Ok, sonst nach Fehler FALSE
- static short WriteLabel(unsigned long diranf, unsigned long LogicalDirAnf, unsigned long dirlen,
- unsigned long diranz, long lastoffset, unsigned long DirCks,
- short DiskNr, BOOL QFA)
- {
- struct DiskLabel *Label;
- long error;
- InfoLineHandle Pil;
-
- Pil = PushInfoLine(GetString(QFA ? MSG_WRITING_QFA_LABEL : MSG_WRITING_LABEL1));
-
- Label = (struct DiskLabel *) AllocVec(sizeof(struct DiskLabel), globDrvDat.BufMemType|MEMF_CLEAR);
- if (Label == NULL)
- {
- PopInfoLine(&Pil);
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "Label", sizeof(struct DiskLabel));
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- BuildDiskLabel(Label, DiskNr);
-
- Label->lastdisk = (!AllFilesRead || !WriteReady()) ? 0 : 0xff; // Markierung ob letzte Disk
- Label->DirAnf = diranf;
- Label->DirLen = dirlen;
- Label->DirAnz = diranz;
- Label->EndOfData = lastoffset;
- Label->RealDirAnf = LogicalDirAnf;
- Label->withQFA = Disks[DiskUnit].TapeReq ? Disks[DiskUnit].TapeReq->withQFA : 0;
-
- Label->LabelCheckSum = 0l;
- Label->DirCheckSum = DirCks;
-
- Label->LabelCheckSum = -ComputeLabelCheckSum(Label);
-
- if (toTape)
- {
- error = TapeWrite(Disks[DiskUnit].TapeReq, (char *) Label, globDrvDat.BlockSize);
-
- if (!error && !QFA)
- {
- // bei QFA keine FileMark nach dem Label!
- error = TapeWriteFileMarks(Disks[DiskUnit].TapeReq, 0, FALSE);
- }
-
- while (error)
- {
- error = TapeError(Disks[DiskUnit].TapeReq, &Disks[DiskUnit],
- GetString(MSG_WRITING_LABEL), error, FALSE, TRUE);
- }
- }
- else
- {
- error = TWrite(Disks[DiskUnit].diskreq, 0, (char *) Label, globDrvDat.BlockSize);
-
- while (error)
- error = DiskError(Disks[DiskUnit].diskreq, GetString(MSG_WRITING_LABEL), error, FALSE);
- }
-
- if (!toTape)
- Update(Disks[DiskUnit].diskreq);
-
- if (!toTape && myOptions.bo_Verify)
- {
- Clear(Disks[DiskUnit].diskreq);
-
- error = TRead(Disks[DiskUnit].diskreq, 0, (char *) Label, globDrvDat.BlockSize);
- while (error)
- error = DiskError(Disks[DiskUnit].diskreq, GetString(MSG_VERIFYING_LABEL), error, FALSE);
- }
- FreeVec(Label);
- PopInfoLine(&Pil);
-
- return (short) (!error);
- }
-
-
- // liefert TRUE wenn neuer Buffer zum Schreiben gefunden
- static BOOL Schreiben(void)
- {
- struct Buffer *buf;
- BOOL result = FALSE;
- short DiskNr;
- unsigned long Offset;
-
- LockWriteDisk();
- DiskNr = WriteDisk.nr;
- Offset = WriteDisk.Offset;
- UnlockWriteDisk();
-
- buf = &CylBuff[WriteBuffNr];
- if ( GetBuffStatus(buf) == VOLL && (ReqsInUse <= MAXBUFFUSE))
- {
- result = TRUE;
-
- if (buf->disknr != DiskNr)
- {
- // Achtung: WriteDisk ändert sich !
- NamenSchreiben(TRUE);
- newdisk(FALSE, FALSE);
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- // ********* if (!WriterAbort)
- // ich bin nicht sicher was das sollte, hier abzubrechen wenn KEIN WriterAbort
- // Im Zuge einer Fehlerbehebung habe ich die Bedingung umgekehrt (26 Jul 1996 21:32:03),
- // (Backup hing nach dem Einlegen der 2. Disk)
- // Der Abbruch beim Warten auf eine Neue Disk sowie das Weiterschreiben auf
- // eine neue Disk scheinen immer noch/wieder zu klappen.
-
- if (WriterAbort)
- return FALSE;
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- LockWriteDisk();
- Offset = WriteDisk.Offset;
- UnlockWriteDisk();
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- }
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- SetBuffStatus(buf, LEEREN);
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- if (toTape)
- TapeBeginWrite(buf->TapeReq, buf->dbp, globDrvDat.CylSize, Offset);
- else
- {
- buf->BufferCheckSum = ComputeBufferCheckSum(buf);
- StartWriteTrack( &(buf->BufIOReq), Offset/globDrvDat.BlockSize,
- buf->dbp, globDrvDat.CylSize);
-
- if (myOptions.bo_Verify)
- {
- StartReadTrack( &(buf->VerifyReq), Offset/globDrvDat.BlockSize,
- buf->dbp, globDrvDat.CylSize);
- ReqsInUse++;
- }
- }
- ReqsInUse++;
-
- NextBuffNr(&WriteBuffNr);
-
- LockWriteDisk();
- WriteDisk.Offset += globDrvDat.CylSize;
- UnlockWriteDisk();
- }
-
- return result;
- }
-
-
- // Liefert TRUE, wenn noch Schreib-Buffer in Bearbeitung sind
- // ..und FALSE, wenn alle Schreibvorgänge fertig sind.
- static short SchreibStatus(void)
- {
- short erg;
-
- d(kprintf("%ld Beginn Schreibstatus \n", __LINE__);)
- while ( erg = (GetBuffStatus(&CylBuff[OldestWriteBuffNr]) == LEEREN) )
- {
- d(kprintf("%ld in Schreibstatus \n", __LINE__);)
-
- if (toTape)
- {
- d(kprintf("%ld in Schreibstatus \n", __LINE__);)
-
- if ( TapeIOReady(CylBuff[OldestWriteBuffNr].TapeReq))
- {
- d(kprintf("%ld in Schreibstatus \n", __LINE__);)
-
- ShowCyl( &CylBuff[OldestWriteBuffNr].BufIOReq,
- CylBuff[OldestWriteBuffNr].disknr);
-
- d(kprintf("%ld in Schreibstatus \n", __LINE__);)
-
- if (TapeErrorCheck(CylBuff[OldestWriteBuffNr].TapeReq, TRUE) == 0)
- {
- ReqsInUse--;
-
- d(kprintf("%ld in Schreibstatus \n", __LINE__);)
- SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
- SendWriterRx(WMR_BUFFEREMPTY);
- NextBuffNr(&OldestWriteBuffNr);
- }
- d(kprintf("%ld in Schreibstatus \n", __LINE__);)
- }
- else
- break;
- }
- else
- {
- if ( WriteTrackReady(&CylBuff[OldestWriteBuffNr].BufIOReq,
- myOptions.bo_Verify ? &CylBuff[OldestWriteBuffNr].VerifyReq : NULL) )
- {
- ShowCyl( &CylBuff[OldestWriteBuffNr].BufIOReq,
- CylBuff[OldestWriteBuffNr].disknr);
-
- if (ErrorCheck(&CylBuff[OldestWriteBuffNr].BufIOReq,
- &CylBuff[OldestWriteBuffNr].VerifyReq, TRUE) == 0)
- {
- ReqsInUse--;
- if (myOptions.bo_Verify)
- {
- unsigned long Cks;
-
- Cks = ComputeBufferCheckSum(&CylBuff[OldestWriteBuffNr]);
- if (CylBuff[OldestWriteBuffNr].BufferCheckSum != Cks)
- {
- // Buffer-Prüfsumme stimmt nicht nach Rücklesen
- PostError(TRUE, MSGPRI_Warning,
- GetString(MSG_VERIFY_CHECKSUMERROR),
- sectotrack(CylBuff[OldestWriteBuffNr].BufIOReq.iotd_Req.io_Offset / globDrvDat.BlockSize),
- CylBuff[OldestWriteBuffNr].BufferCheckSum,
- Cks
- );
- }
- ReqsInUse--;
- }
-
- SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
- SendWriterRx(WMR_BUFFEREMPTY);
- NextBuffNr(&OldestWriteBuffNr);
- }
- }
- else
- break;
- }
- }
-
- d(kprintf("%ld Ende Schreibstatus \n", __LINE__);)
-
- return erg;
- }
-
-
- static short NamenSchreiben(BOOL WriteOutDir)
- {
- struct IOExtTD NameReq;
- struct TapeIO *NameTapeReq = NULL;
- struct Disk aktWriteDisk;
- unsigned long DirSektor, DirLen;
- long DirCheckSum;
- short error = 0;
-
- d(kprintf(__FUNC__ ": %ld\n", __LINE__);)
-
- LockWriteDisk();
- aktWriteDisk = WriteDisk;
- MoveDirBuff(&aktWriteDisk, &WriteDisk);
- UnlockWriteDisk();
-
- if (aktWriteDisk.dirlength == 0)
- return FALSE;
-
- if (DB_EMPTY(aktWriteDisk))
- {
- alarm(GetString(MSG_INTERNALERROR_NAMSCHR_1), __FUNC__);
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- NameReq = *Disks[DiskUnit].diskreq;
-
- if (toTape)
- {
- if (myOptions.bo_Append && Disks[DiskUnit].TapeReq->withQFA &&
- !Disks[DiskUnit].TapeReq->DrvDat->Properties.AppendQFA)
- {
- // Beim meinem TDC3820 klappt das Schreiben
- // von QFA-Label und -Directory nach Append nicht.
- // Deshalb Weiterarbeit ohne QFA
- Disks[DiskUnit].TapeReq->withQFA = FALSE;
- TapeInitQFA(Disks[DiskUnit].TapeReq, 0);
- }
-
- NameTapeReq = (struct TapeIO *) AllocVec(sizeof(struct TapeIO), globDrvDat.BufMemType);
- if (NameTapeReq == NULL)
- {
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "NameTapeReq", sizeof(struct TapeIO));
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
- *NameTapeReq = *Disks[DiskUnit].TapeReq;
- NameTapeReq->Req = &NameReq;
- }
-
- if (aktWriteDisk.Offset < aktWriteDisk.MaxOffset)
- {
- if (NameTapeReq)
- FreeVec(NameTapeReq);
-
- alarm(GetString(MSG_INTERNALERROR_NAMSCHR_2), __FUNC__);
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- if (WriteOutDir)
- {
- // Directory fängt mit neuem Sektor an
- DirSektor = ceildiv(aktWriteDisk.Offset, globDrvDat.BlockSize);
- if (NameTapeReq)
- DirSektor++; // Platz lassen für zusätzliches Label
- DirLen = ceildiv(aktWriteDisk.dirlength, globDrvDat.BlockSize);
-
- DirCheckSum = ComputeDirChecksum(&aktWriteDisk, DirLen);
-
- // Label vor Directory schreiben (nur bei TAPE)
- if (!error && NameTapeReq)
- {
- error = !WriteLabel(DirSektor, DirSektor, DirLen,
- aktWriteDisk.diranz, aktWriteDisk.MaxOffset,
- DirCheckSum, aktWriteDisk.nr, FALSE);
- }
-
- if (!error)
- {
- InfoLineHandle Pil;
-
- Pil = PushInfoLine(GetString(MSG_WRITING_DIRECTORY));
-
- // Directory schreiben ans Medien-Ende
- error = WriteDir(&aktWriteDisk, &NameReq, NameTapeReq, toTape, DirSektor);
- PopInfoLine(&Pil);
- }
- }
-
- // Label am Aufzeichnungsende schreiben
- if (!error)
- {
- error = !WriteLabel(DirSektor, DirSektor, DirLen,
- aktWriteDisk.diranz, aktWriteDisk.MaxOffset,
- DirCheckSum, aktWriteDisk.nr, FALSE);
- }
-
- // Jetzt bei QFA Directory und Label nochmal schreiben
- // nur bei TAPE
- if (NameTapeReq && NameTapeReq->withQFA && !error)
- {
- InfoLineHandle Pil;
-
- Pil = PushInfoLine(GetString(MSG_REWINDING));
-
- error = TapeRewind(NameTapeReq);
- if (error)
- TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), error, FALSE, FALSE);
-
- if (!error)
- {
- error = TapeSetDirectoryPartition(NameTapeReq);
- if (error)
- TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_CHANGEPARTITION), error, FALSE, FALSE);
- }
- if (!error)
- error = !WriteLabel(1, DirSektor, DirLen, aktWriteDisk.diranz, aktWriteDisk.MaxOffset,
- DirCheckSum, aktWriteDisk.nr, TRUE);
-
- if (!error)
- {
- // Jetzt QFA-Directory schreiben
- PopInfoLine(&Pil);
- Pil = PushInfoLine(GetString(MSG_WRITING_QFA_DIRECTORY));
-
- if (WriteOutDir)
- error = WriteDir(&aktWriteDisk, &NameReq, NameTapeReq, toTape, 0l);
- else
- error = WriteTapeDir(&aktWriteDisk, NameTapeReq, disknr);
- }
-
- if (!error)
- {
- // Directory-Aufzeichnung mit FileMarks beenden
- error = TapeWriteFileMarks(NameTapeReq, 0, FALSE);
-
- while (error)
- error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_WRITING_LABEL), error, FALSE, TRUE);
- }
- PopInfoLine(&Pil);
- }
-
- if (!error && WriteOutDir && ProtFileHandle && !aktWriteDisk.dirwritten)
- {
- WriteProtFile(FIRST_NF(aktWriteDisk), disknr);
- aktWriteDisk.dirwritten = 1;
- }
-
- // Fehler melden wenn hier die Directory-Checksumme nicht mehr stimmt!!
- if (DirCheckSum != ComputeDirChecksum(&aktWriteDisk, DirLen))
- {
- PostError(TRUE, MSGPRI_Warning,
- GetString(MSG_CHECKSUMERROR_DIRECTORY), Disks[DiskUnit].DOSName);
- }
-
- #ifdef XYZ_DEBUG
- {
- FILE *fd;
- struct DirBlock *aktBlock;
-
- fd = fopen("HD1:Backup.dir", "wb");
-
- for (aktBlock = (struct DirBlock *) aktWriteDisk.DirBuffers.mlh_Head;
- aktBlock != (struct DirBlock *) &(aktWriteDisk.DirBuffers.mlh_Tail);
- aktBlock = (struct DirBlock *) aktBlock->db_Node.mln_Succ)
- {
- fwrite(aktBlock->Data, aktBlock->DataLength, 1, fd);
- }
-
- fclose(fd);
- }
- #endif
-
- if (WriteOutDir)
- CleanupRWDisk(&aktWriteDisk);
-
- if (NameTapeReq && !error)
- {
- if (myOptions.bo_Verify)
- {
- InfoLineHandle Pil;
-
- // Verify-Lauf bei Bändern
- SetBusyPointer(aktWindow, TRUE);
- Pil = PushInfoLine(GetString(MSG_VERIFYING_TAPE));
-
- error = TapeRewind(NameTapeReq);
- if (error)
- error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), error, FALSE, FALSE);
-
- if (!error && NameTapeReq->withQFA)
- {
- // Wieder zurück zu Data Partition wechseln
- error = TapeSetDataPartition(NameTapeReq);
- if (error)
- {
- error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_CHANGEPARTITION),
- error, FALSE, FALSE);
- }
- }
-
- if (!error)
- {
- // Verify Data
- error = TapeVerify(NameTapeReq, (DirSektor+DirLen+1)*globDrvDat.BlockSize);
- if (error)
- {
- error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_VERIFYING),
- error, FALSE, TRUE);
- }
- }
- if (!error && NameTapeReq->withQFA)
- {
- // Verify QFA Label & Directory
- PopInfoLine(&Pil);
- Pil = PushInfoLine(GetString(MSG_VERIFYING_QFA));
-
- error = TapeRewind(NameTapeReq);
- if (error)
- {
- error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND),
- error, FALSE, FALSE);
- }
-
- TapeSetDataPartition(NameTapeReq);
-
- if (!error)
- {
- error = TapeVerify(NameTapeReq, (DirLen+1)*globDrvDat.BlockSize);
- if (error)
- {
- TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_VERIFYING),
- error, FALSE, TRUE);
- }
- }
- PopInfoLine(&Pil);
- }
-
- SetBusyPointer(aktWindow, FALSE);
- PopInfoLine(&Pil);
- }
-
- // Band zurückspulen
- error = TapeRewind(NameTapeReq);
- if (error)
- TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), error, FALSE, FALSE);
- }
-
- if (!NameTapeReq)
- {
- Update(Disks[DiskUnit].diskreq);
- Eject(Disks[DiskUnit].diskreq);
- }
-
- ResetDiskSave();
-
- if (NameTapeReq)
- FreeVec(NameTapeReq);
-
- ProtFileValid = TRUE;
-
- return TRUE;
- }
-
-
- static short WriteDir(struct Disk *Dsk, struct IOExtTD *WrtIO,
- struct TapeIO *WrtTIO, BOOL toTape, unsigned long DirSektor)
- {
- struct IOExtTD DirWrtReq;
- struct TapeIO *DirWrtTIO = NULL;
- struct IOExtTD VerifyReq;
- struct DirBlock *aktBlock;
- short error = 0;
-
- ASSERT_VALID(Dsk);
- ASSERT_VALID(WrtIO);
-
- DirWrtReq = VerifyReq = *WrtIO;
- if (toTape)
- {
- ASSERT_VALID(WrtTIO);
-
- DirWrtTIO = (struct TapeIO *) AllocVec(sizeof(struct TapeIO),
- globDrvDat.BufMemType);
- if (DirWrtTIO == NULL)
- {
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirWrtTIO", sizeof(struct TapeIO));
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- *DirWrtTIO = *WrtTIO;
- }
-
- for (aktBlock = (struct DirBlock *) Dsk->DirBuffers.mlh_Head;
- !error && aktBlock != (struct DirBlock *) &(Dsk->DirBuffers.mlh_Tail);
- aktBlock = (struct DirBlock *) aktBlock->db_Node.mln_Succ)
- {
- if (toTape)
- {
- TapeBeginWrite(DirWrtTIO, aktBlock->Data, aktBlock->DataLength,
- DirSektor * globDrvDat.BlockSize);
- }
- else
- {
- StartWriteTrack(&DirWrtReq, DirSektor, aktBlock->Data, aktBlock->DataLength);
- }
-
- if (!toTape && myOptions.bo_Verify)
- {
- StartReadTrack(&VerifyReq, DirSektor, aktBlock->Data, aktBlock->DataLength);
- }
-
- // Warten bis Directory fertig geschrieben
- if (toTape)
- {
- while ( SchreibStatus() && !TapeIOReady(DirWrtTIO) && !CheckWriterTxPort())
- SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
-
- TapeErrorCheck(DirWrtTIO, TRUE);
- }
- else
- {
- while ( SchreibStatus() && !WriteTrackReady(&DirWrtReq,
- myOptions.bo_Verify ? &VerifyReq : NULL) && !CheckWriterTxPort())
- {
- SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
- }
-
- ErrorCheck(&DirWrtReq, &VerifyReq, FALSE);
- }
-
- ShowCyl(&DirWrtReq, Dsk->nr);
-
- DirSektor += aktBlock->DataLength / globDrvDat.BlockSize;
- }
-
- if (DirWrtTIO)
- FreeVec(DirWrtTIO);
-
- return error;
- }
-
-
- // Korrektur des Directory am Anfang eines Folgebandes (Band ist voll).
- // - alle Einträge nach <LastByte> erhalten die neue <NewDisknr>
- // - bei allen Einträgen auf dem neuen Band wird Offset korrigiert
- // (neue Zählung ab 0 auf den Folgeband)
- static void FixupDir(short NewDiskNr, unsigned long LastByte)
- {
- struct NameField *nf;
-
- LockNFList();
-
- nf = FIRST_NF(WriteDisk);
- while (nf && (nf->DiskNr < NewDiskNr))
- {
- if (nf->Offset >= LastByte)
- {
- nf->DiskNr = NewDiskNr;
- nf->Offset = nf->Offset + sizeof(struct DiskLabel)
- - LastByte;
- }
-
- nf = nf->NextName;
- }
-
- UnlockNFList();
- }
-
-
- // aus dem aktuellen Directory werden alle Einträge für <DiskNr> herausgesucht
- // und geschrieben.
- //
- //*** irgendetwas muß noch für DirCheckSum und DirLen getan werden!
- static short WriteTapeDir(struct Disk *Dsk, struct TapeIO *WrtTIO, short DiskNr)
- {
- unsigned char *DirBuffer, *DirBuffPtr;
- struct TapeIO *DirWrtTIO;
- struct NameField *nf;
- short error = 0;
- size_t BufferSpace, WriteLen;
-
- ASSERT_VALID(Dsk);
- ASSERT_VALID(WrtTIO);
-
- DirBuffer = AllocVec(globDrvDat.CylSize, globDrvDat.BufMemType);
- if (DirBuffer == NULL)
- {
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirBuffer", globDrvDat.CylSize);
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- DirWrtTIO = (struct TapeIO *) AllocVec(sizeof(struct TapeIO),
- globDrvDat.BufMemType);
- if (DirWrtTIO == NULL)
- {
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirWrtTIO", sizeof(struct TapeIO));
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- *DirWrtTIO = *WrtTIO;
-
- nf = (struct NameField *) ((struct DirBlock *) Dsk->DirBuffers.mlh_Head)->Data;
- BufferSpace = globDrvDat.CylSize;
- DirBuffPtr = DirBuffer;
- WriteLen = 0;
-
- while (nf)
- {
- if (nf->DiskNr == DiskNr)
- {
- size_t NfLen, CopyLen;
-
- NfLen = NF_LEN(nf);
- CopyLen = min(NfLen, BufferSpace);
-
- CopyMem(nf, DirBuffPtr, CopyLen);
- BufferSpace -= CopyLen;
- DirBuffPtr += CopyLen;
- WriteLen += CopyLen;
-
- if (BufferSpace == 0)
- {
- // Buffer ist voll
- TapeBeginWrite(DirWrtTIO, DirBuffer, WriteLen, 0l);
-
- // Warten bis Directory fertig geschrieben
- while ( SchreibStatus() && !TapeIOReady(DirWrtTIO) && !CheckWriterTxPort())
- SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
-
- TapeErrorCheck(DirWrtTIO, TRUE);
-
- BufferSpace = globDrvDat.CylSize;
- DirBuffPtr = DirBuffer;
- WriteLen = 0;
-
- if (CopyLen < NfLen)
- {
- // Rest des <nf> in neuen Buffer kopieren
- CopyLen = NfLen - CopyLen;
- CopyMem(nf, DirBuffPtr, CopyLen);
- BufferSpace -= CopyLen;
- DirBuffPtr += CopyLen;
- WriteLen += CopyLen;
- }
- }
- }
-
- nf = nf->NextName;
- }
-
- if (WriteLen > 0)
- {
- // letzten, nur teilweise gefüllten Buffer schreiben
- TapeBeginWrite(DirWrtTIO, DirBuffer, WriteLen, 0l);
-
- // Warten bis Directory fertig geschrieben
- while ( SchreibStatus() && !TapeIOReady(DirWrtTIO) && !CheckWriterTxPort())
- SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
-
- TapeErrorCheck(DirWrtTIO, TRUE);
- }
-
- if (DirWrtTIO)
- FreeVec(DirWrtTIO);
- if (DirBuffer)
- FreeVec(DirBuffer);
-
- return error;
- }
-
-
- static void RemoveRequests(void)
- {
- unsigned short n;
-
- if (OldestWriteBuffNr == ~0)
- return;
-
- if (DiskFlush(&CylBuff[OldestWriteBuffNr].BufIOReq))
- {
- // Notlösung wenn FLUSH nicht geht
- Forbid();
- n = OldestWriteBuffNr;
- do {
- CylBuff[n].BufIOReq.iotd_Req.io_Command = CMD_INVALID;
- if (myOptions.bo_Verify)
- CylBuff[n].VerifyReq.iotd_Req.io_Command = CMD_INVALID;
- NextBuffNr(&n);
- } while (n != WriteBuffNr);
- Permit();
- }
-
- n = OldestWriteBuffNr;
- do {
- if (GetBuffStatus(&CylBuff[n]) == LEEREN)
- {
- WaitIO((struct IORequest *) &CylBuff[n].BufIOReq);
-
- if (myOptions.bo_Verify)
- {
- WaitIO((struct IORequest *) &CylBuff[n].VerifyReq);
- ReqsInUse--;
- }
-
- SetBuffStatus(&CylBuff[n], VOLL); // noch voll !
- ReqsInUse--;
- }
- NextBuffNr(&n);
- } while (ReqsInUse);
- }
-
-
- static void RemoveTapeRequests(void)
- {
- unsigned short n;
-
- if (DiskFlush(CylBuff[OldestWriteBuffNr].TapeReq->Req))
- {
- // Notlösung wenn FLUSH nicht geht
- Forbid();
- n = OldestWriteBuffNr;
- do {
- CylBuff[n].TapeReq->Req->iotd_Req.io_Command = CMD_INVALID;
- NextBuffNr(&n);
- } while (n != WriteBuffNr);
- Permit();
- }
-
- n = OldestWriteBuffNr;
- do {
- if (GetBuffStatus(&CylBuff[n]) == LEEREN)
- {
- d(kprintf("%ld in RemoveTapeRequests n=%ld LN_TYPE=%ld\n",
- __LINE__, n, CylBuff[n].TapeReq->Req->iotd_Req.io_Message.mn_Node.ln_Type);)
-
- WaitIO((struct IORequest *) CylBuff[n].TapeReq->Req);
-
- SetBuffStatus(&CylBuff[n], VOLL); // noch voll !
- ReqsInUse--;
- }
-
- NextBuffNr(&n);
- } while (ReqsInUse);
- }
-
-
- // Liefert TRUE wenn alle Puffer leer sind
- BOOL WriteReady(void)
- {
- BOOL erg = TRUE;
- unsigned short i;
-
- if ( ReqsInUse > 0 || GetBuffStatus(&CylBuff[OldestWriteBuffNr]) != LEER )
- return FALSE;
-
- for (i=0; erg && i<BuffCount; i++)
- erg &= (GetBuffStatus(&CylBuff[i]) == LEER);
-
- return erg;
- }
-
-
- // Warten auf neue Diskette
- static void WaitForDisk(BOOL AnyChange)
- {
- d(kprintf("%s %ld: AnyChange=%ld\n", __FUNC__, __LINE__, AnyChange);)
-
- while ( Disks[DiskUnit].DcI->DiskStatus != DiskOk && !CheckWriterTxPort())
- {
- d(kprintf(__FUNC__ "/%ld DiskStatus=%ld\n", __LINE__, Disks[DiskUnit].DcI->DiskStatus);)
-
- SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
- d(kprintf(__FUNC__ "/%ld SignalsGot=%08lx\n", __LINE__, SignalsGot);)
-
- if (AnyChange)
- return;
- }
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- }
-
-
- static void newdisk(BOOL append, BOOL SameDiskNr)
- {
- struct SignalSemaphore *Sema;
-
- assert(DiskUnit == NO_DRIVE || (DiskUnit >= 0 && DiskUnit < NDisk));
-
- if (DiskUnit != NO_DRIVE && Disks[DiskUnit].TapeReq == NULL)
- MotorOff(Disks[DiskUnit].diskreq);
-
- // immer mit myOptions.bo_FirstUnit anfangen !
- if (disknr == 0)
- DiskUnit = myOptions.bo_FirstUnit;
-
- if (!SameDiskNr && disknr+1 == UCHAR_MAX)
- {
- alarm(GetString(MSG_ERROR_MAXDISK), UCHAR_MAX);
- SendWriterRx(WMR_ABORTMAIN);
- return;
- }
-
- if (append && Disks[DiskUnit].TapeReq &&
- !(Disks[DiskUnit].TapeReq->DrvDat->Properties.canLocate
- || Disks[DiskUnit].TapeReq->DrvDat->Properties.SpaceBack))
- {
- // mit diesem Laufwerk geht kein APPEND
- alarm(GetString(MSG_NOAPPEND));
- SendWriterRx(WMR_ABORTMAIN);
- return;
- }
-
- if (!SameDiskNr)
- {
- if (disknr)
- {
- // Laufwerk wechseln wenn möglich
- Sema = &Disks[DiskUnit].DcI->Sema;
- ObtainSemaphore(Sema);
- if (myOptions.bo_SecondUnit != NO_DRIVE)
- {
- Disks[DiskUnit].DcI->DiskStatus = DiskObsolete;
- if (disknr)
- Disks[DiskUnit].DcI->NextDiskNr += 2;
-
- // ausgebrauchtes Medium markieren
- sprintf(zeile, "%s: %s #%-3d",
- Disks[DiskUnit].DOSName,
- GetString(toTape ? MSG_TAPE : MSG_DISK), disknr);
- DiskText(zeile, 2, 0, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
-
- DiskUnit = (DiskUnit == myOptions.bo_FirstUnit) ? myOptions.bo_SecondUnit : myOptions.bo_FirstUnit;
-
- if (Disks[DiskUnit].TapeReq)
- Disks[DiskUnit].TapeReq->Medium = Disks[DiskUnit].DcI->TapeReq->Medium;
- }
- else
- {
- Disks[DiskUnit].DcI->NextDiskNr++;
- }
- ReleaseSemaphore(Sema);
- }
-
- LockWriteDisk();
- WriteDisk.Offset = 0;
- UnlockWriteDisk();
-
- if (InitBufReq())
- {
- SendWriterRx(WMR_ABORTMAIN);
- return;
- }
-
- disknr++;
- }
-
- SetBusyPointer(aktWindow, TRUE);
- do {
- while (Disks[DiskUnit].DcI->DiskStatus == CheckingDisk)
- WaitForDisk(TRUE); // Warten bis Check des Laufwerks beendet
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- if (Disks[DiskUnit].DcI->DiskStatus != DiskOk)
- // Wenn keine neue Diskette bereit
- {
- SendWriterRx(WMR_OPENMAINWINDOW);
- DisplayBeep(aktWindow->WScreen);
-
- ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
- if (Disks[DiskUnit].DcI->DiskStatus != WaitingForDisk)
- {
- if (Disks[DiskUnit].TapeReq)
- {
- sprintf(zeile, GetString(append ? MSG_INSERT_LASTTAPE :
- MSG_INSERT_TAPE_N),
- Disks[DiskUnit].DOSName,
- Disks[DiskUnit].DcI->NextDiskNr);
- }
- else
- {
- sprintf(zeile, GetString(append ? MSG_INSERT_LASTDISK :
- MSG_INSERT_DISK_N),
- Disks[DiskUnit].DOSName,
- Disks[DiskUnit].DcI->NextDiskNr);
- }
-
- Disks[DiskUnit].DcI->DiskStatus = WaitingForDisk;
-
- // Eingabe-Aufforderung anzeigen
- DiskText(zeile, 3, 2, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
- }
- ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
-
- WaitForDisk(FALSE); // Warten bis neue Diskette bereit
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- }
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- CheckWriterTxPort();
-
- CheckOldProtFile(&Disks[DiskUnit]);
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- if (append)
- {
- switch (CheckAppendDisk(DiskUnit))
- {
- case NOBACKUPDISK:
- sprintf(zeile, GetString(Disks[DiskUnit].TapeReq
- ? MSG_NO_BACKUPTAPE
- : MSG_NO_BACKUPDISK),
- Disks[DiskUnit].DOSName);
-
- ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
- Disks[DiskUnit].DcI->DiskStatus = DiskObsolete;
- ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
- break;
- case NOTLASTDISK:
- sprintf(zeile, GetString(Disks[DiskUnit].TapeReq
- ? MSG_NOTLASTTAPE
- : MSG_NOTLASTDISK),
- Disks[DiskUnit].DOSName);
-
- ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
- Disks[DiskUnit].DcI->DiskStatus = DiskObsolete;
- ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
- case OK:
- break;
- }
- }
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- } while (Disks[DiskUnit].DcI->DiskStatus != DiskOk && !CheckWriterTxPort());
-
- SetBusyPointer(aktWindow, FALSE);
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- LockWriteDisk();
- WriteDisk.nr = disknr;
- UnlockWriteDisk();
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
- Disks[DiskUnit].DcI->DiskStatus = DiskInUse;
- if (Disks[DiskUnit].DcI->isTape)
- Disks[DiskUnit].TapeReq->withQFA = Disks[DiskUnit].DcI->withQFA;
- ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
-
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
-
- if (!append && Disks[DiskUnit].TapeReq)
- {
- // Band zurückspulen (steht nach CheckOldProtFile auf Block 1!
- TapeRewind(Disks[DiskUnit].TapeReq); // ###
-
- if (Disks[DiskUnit].TapeReq->withQFA)
- {
- // Select Data Partition
- TapeSetDataPartition(Disks[DiskUnit].TapeReq);
- }
- }
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- }
-
-
- // Disk/Tape-Label prüfen: wenn ein Backupmedium (von einer älteren Sicherung)
- // eingelegt ist, dann ggf. das alte Protokollfile löschen!
- void CheckOldProtFile(struct DiskFlags *Dsk)
- {
- short error = 0;
- static struct DiskLabel Label;
-
- ASSERT_VALID(Dsk);
-
- SetBusyPointer(aktWindow, TRUE);
-
- if (Dsk->TapeReq)
- {
- if (Dsk->DcI)
- Dsk->TapeReq->withQFA = Dsk->DcI->withQFA;
-
- error = TapeRewind(Dsk->TapeReq) ||
- TapeSetDataPartition(Dsk->TapeReq) ||
- TapeRead(Dsk->TapeReq, (char *) &Label, sizeof(Label));
- }
- else
- Label = Dsk->DcI->Label;
-
- if (!error && (strcmp(Label.Id, DISKID) == 0) &&
- ComputeLabelCheckSum(&Label) == 0l &&
- Label.ProtFileName[0] )
- {
- if (0 == access(Label.ProtFileName, F_OK) &&
- DeleteFile(Label.ProtFileName))
- {
- // Info: altes Protofile wurde gelöscht
- PostError(TRUE, MSGPRI_Info, GetString(MSG_DELETED_FILE), Label.ProtFileName);
- }
- }
-
- SetBusyPointer(aktWindow, FALSE);
- }
-
-
- static short ReadQFALabel(struct DiskFlags *Dsk, struct DiskLabel *Label)
- {
- short error;
-
- ASSERT_VALID(Dsk);
- ASSERT_VALID(Label);
-
- (error = TapeRewind(Dsk->TapeReq)) ||
- (error = TapeSetDirectoryPartition(Dsk->TapeReq)) ||
- (error = TapeRead(Dsk->TapeReq, (char *) Label, Dsk->DrvDat.BlockSize));
-
- if (error || !Label->withQFA)
- {
- // nochmal probieren ohne QFA !
- InfoLineHandle Pil;
-
- Pil = PushInfoLine(GetString(MSG_READINGTAPELABEL));
-
- TapeRewind(Dsk->TapeReq);
- TapeSetDataPartition(Dsk->TapeReq);
- TapeInitQFA(Dsk->TapeReq, FALSE);
-
- Dsk->TapeReq->withQFA = FALSE;
- PopInfoLine(&Pil);
- }
-
- // Bandposition direkt am Directory-Anfang
-
- return error;
- }
-
-
- static short ReadTapeLabel(struct DiskFlags *Dsk, struct DiskLabel *Label)
- {
- short error;
-
- ASSERT_VALID(Dsk);
- ASSERT_VALID(Label);
-
- error = TapeRewind(Dsk->TapeReq);
- if (Dsk->TapeReq->DrvDat->Properties.SpaceBack)
- {
- // Label schnell lesen (zum Bandende und dann 1 Sektor zurück),
- // geht aber nur wenn das Bandlaufwerk SPACE zurück kann
- if (!error)
- error = TapeSpace(Dsk->TapeReq, 0l, 3); // zum Bandende
- if (!error)
- {
- do {
- // wenn beim SPACE(-1) eine Filemark erreicht wird,
- // steht danach das Band VOR der FileMark, dann wird
- // der SPACE(-1) einfach wiederholt
-
- error = TapeSpace(Dsk->TapeReq, -1l, 0); // 1 Block zurück zum Anfang Label
- } while (error && Dsk->TapeReq->Cmd.scsi_Status == 2
- && Dsk->TapeReq->Cmd.scsi_SenseActual
- && Dsk->TapeReq->Sense[2] & 0x80);
- }
-
- // Label lesen
- if (!error)
- error = TapeRead(Dsk->TapeReq, (char *) Label, Dsk->DrvDat.BlockSize);
-
- // Bandposition 2 Blöcke nach Directory-Ende
- if (!error)
- {
- // das Directory wird immer in <CylSize> langen Blöcken aufgezeichnet!
- long DirLen;
-
- DirLen = ceildiv(Label->DirLen, globDrvDat.CylSize / globDrvDat.BlockSize)
- * globDrvDat.CylSize / globDrvDat.BlockSize;
-
- error = TapeSpace(Dsk->TapeReq, -DirLen - 1, 0); // zum Directory-Anfang
- }
- }
- else
- {
- TapeSpace(Dsk->TapeReq, 1, 0); // Dummy-Label auf Block 0 überspringen
- TapeWaitNotBusy(Dsk->TapeReq);
-
- do {
- // hier hilft alles nichts....
- // sequentiell alles lesen bis wir auf das Label stoßen.
- // Bei diesem dummen Bandlaufwerk geht sowieso kein Append
-
- error = TapeRead(Dsk->TapeReq, (char *) Label, Dsk->DrvDat.BlockSize);
-
- } while (!error && !((strcmp(Label->Id, "BACKUP") == 0)
- && ComputeLabelCheckSum(Label) != 0l
- && Label->DirLen) && !CheckWriterTxPort());
-
- // Bandposition direkt am Directory-Anfang
- }
-
- return error;
- }
-
-
- // Prüft Diskette (nur für Append).
- // return OK, wenn Disk Ok (letzte Backup-Disk)
- // return NOBACKUPDISK, wenn Append und keine Backup-Disk.
- // return NOTLASTDISK, wenn Append und nicht die letzte Disk
- static enum TestDiskResult CheckAppendDisk(short unit)
- {
- struct IOExtTD req;
- short error;
- enum TestDiskResult erg = OK;
- struct DiskLabel *Label;
-
- assert(unit >= 0 && unit < NDisk);
-
- if (Disks[unit].TapeReq)
- {
- InfoLineHandle Pil;
- static struct DiskLabel TapeLabel;
-
- Disks[unit].TapeReq->withQFA = Disks[unit].DcI->withQFA;
-
- SetBusyPointer(aktWindow, TRUE);
- Pil = PushInfoLine(GetString(Disks[unit].TapeReq->withQFA ?
- MSG_READING_QFA_TAPELABEL : MSG_READINGTAPELABEL));
-
- if (Disks[unit].TapeReq->withQFA)
- {
- // QFA Tape Label lesen
- error = ReadQFALabel(&Disks[unit], &TapeLabel);
- }
-
- if (!Disks[unit].TapeReq->withQFA)
- {
- // Tape Label lesen ohne QFA
- error = ReadTapeLabel(&Disks[unit], &TapeLabel);
- }
-
- if (error)
- erg = UNREADABLE;
-
- PopInfoLine(&Pil);
- Label = &TapeLabel;
- }
- else
- Label = &Disks[unit].DcI->Label;
-
- req = *Disks[unit].diskreq;
-
- if (Label->LabelCheckSum != 0L && ComputeLabelCheckSum(Label) != 0l)
- {
- PostError(TRUE, MSGPRI_Warning, GetString(MSG_CHECKSUMERROR_DISKLABEL), Disks[unit].DOSName);
- erg = NOBACKUPDISK;
- }
- else if (!Label->lastdisk)
- {
- erg = NOTLASTDISK; // Nicht die letzte Disk
- }
- else if (strcmp(Label->Id, DISKID) == 0)
- {
- // Letzte Backup-Disk gefunden, jetzt altes Directory lesen
- LockWriteDisk();
-
- // richtige Disk-Nummer anzeigen (aus Label)
- if (Disks[unit].TapeReq)
- {
- char Msg2[80];
-
- sprintf(Msg2, "%s: %s #%-3d",
- Disks[unit].DOSName,
- GetString(MSG_TAPE_LABEL),
- Label->diskno);
-
- // "TAPE: Tape #999 abcdefgh"
- sprintf(zeile, "%s %*s", Msg2, 63-37 - strlen(Msg2),
- TapeFormat(Disks[unit].TapeReq));
-
- // sprintf(zeile, "%s: %s #%-3d %-8.8s",
- // Disks[unit].DOSName,
- // GetString(MSG_TAPE_LABEL),
- // Label->diskno,
- // TapeFormat(Disks[unit].TapeReq));
- }
- else
- {
- sprintf(zeile, "%s: %s #%-3d",
- Disks[unit].DOSName,
- GetString(MSG_DISK_LABEL),
- Label->diskno);
- }
- DiskText(zeile, ~0, ~0, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
-
- if (Label->ProtFileName[0])
- strcpy(myOptions.bo_ProtFileName, Label->ProtFileName);
-
- ReadDisk.Offset = WriteDisk.Offset = Label->EndOfData;
-
- if (!ReadDir(Label, unit))
- {
- UnlockWriteDisk();
-
- SetBusyPointer(aktWindow, FALSE);
- return NOBACKUPDISK;
- }
-
- ReadDisk.nr = disknr = Label->diskno;
- Disks[unit].DcI->NextDiskNr = disknr;
-
- // Startzeit von altem Satz übernehmen !
- CopyMem(Label->BackupZeit, StartZeit, sizeof(StartZeit) );
- ShowBackupTime();
-
- if (Disks[unit].TapeReq)
- {
- // Neue Sicherung wird nach dem alten Directory und dem
- // alten Label angehängt !
- InfoLineHandle Pil;
-
- // das Directory wird immer in <CylSize> langen Blöcken aufgezeichnet!
- long DirLen;
-
- if (Disks[unit].TapeReq->withQFA)
- Label->DirAnf = Label->RealDirAnf;
-
- DirLen = ceildiv(Label->DirLen, globDrvDat.CylSize / globDrvDat.BlockSize)
- * globDrvDat.CylSize / globDrvDat.BlockSize;
-
- ReadDisk.Offset = WriteDisk.Offset =
- (Label->DirAnf + DirLen + 1) * globDrvDat.BlockSize;
-
- Pil = PushInfoLine(GetString(MSG_POSITIONING_EOT));
-
- if (Disks[unit].TapeReq->withQFA)
- {
- // Select Data Partition
- TapeRewind(Disks[unit].TapeReq);
- TapeSetDataPartition(Disks[unit].TapeReq);
- }
- // Positionieren ans Bandende
- TapeSpace(Disks[unit].TapeReq, 0l, 3);
-
- readoffset = 0;
- PopInfoLine(&Pil);
- }
- else
- {
- readoffset = ReadDisk.Offset % globDrvDat.CylSize;
- if (readoffset)
- {
- // Jetzt muß der erste Buffer teilweise gefüllt werden
- // damit die neuen Files nahtlos anschließen können
- struct Buffer *buff;
- long StartCyl;
-
- if (CylBuff[0].dbp == NULL)
- AllocDiskBuffer();
-
- buff = GetBuffer(); // ersten Buffer holen
- SetBuffStatus(buff, FUELLEN);
-
- StartCyl = sectotrack(ReadDisk.Offset / globDrvDat.BlockSize);
- WriteDisk.Offset = StartCyl*globDrvDat.CylSize;
-
- error = TRead(&(buff->BufIOReq),
- WriteDisk.Offset/globDrvDat.BlockSize, buff->dbp, globDrvDat.CylSize);
-
- while (error)
- error = DiskError(&(buff->BufIOReq), GetString(MSG_READING), error, FALSE);
- }
- }
-
- UnlockWriteDisk();
- }
-
- SetBusyPointer(aktWindow, FALSE);
-
- return erg;
- }
-
-
- // Liest das Directory von der aktuellen Diskette
- // und hängt alle gefundenen Einträge an die aktuelle File-Liste an.
- // Return: Success, TRUE wenn Ok, FALSE nach Fehler
- static short ReadDir(struct DiskLabel *Label, short unit)
- {
- char *DirBuff;
- unsigned long DirBuffLen;
- struct NameField *akt_nf;
- struct OldNameField *old_nf;
- long error;
- short i;
- long n, DirCks, *DirPtr;
-
- ASSERT_VALID(Label);
- assert(unit >= 0 && unit < NDisk);
-
- DirBuffLen = Label->DirLen * globDrvDat.BlockSize;
- DirBuff = (char *) AllocVec(DirBuffLen, globDrvDat.BufMemType|MEMF_CLEAR);
- if (DirBuff == NULL)
- {
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirBuff", DirBuffLen);
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- if (Disks[unit].TapeReq)
- {
- InfoLineHandle Pil;
-
- Pil = PushInfoLine(GetString(Disks[unit].TapeReq->withQFA
- ? MSG_READING_QFA_TAPEDIR : MSG_READINGTAPEDIR));
-
- // Band steht am immer am Directory-Anfang
- error = TapeRead(Disks[unit].TapeReq, DirBuff, Label->DirLen*globDrvDat.BlockSize);
-
- while (error)
- {
- error = TapeError(Disks[unit].TapeReq, &Disks[unit], GetString(MSG_READING_DIRECTORY),
- error, FALSE, TRUE);
- }
- PopInfoLine(&Pil);
- }
- else
- {
- error = TRead(Disks[unit].diskreq, Label->DirAnf, DirBuff, DirBuffLen);
-
- while (error)
- error = DiskError(Disks[unit].diskreq, GetString(MSG_READING), error, FALSE);
- }
-
- if (error)
- {
- FreeVec(DirBuff);
- return FALSE;
- }
-
- // Directory-Prüfsumme nachrechnen
- for (n=DirBuffLen/sizeof(long), DirPtr=(long *) DirBuff, DirCks=0L;
- n; n--)
- {
- DirCks += *DirPtr++;
- }
-
- if (Label->DirCheckSum != 0L && DirCks != Label->DirCheckSum)
- {
- PostError(TRUE, MSGPRI_Warning, GetString(MSG_CHECKSUMERROR_DIRECTORY), Disks[unit].DOSName);
- FreeVec(DirBuff);
- return FALSE;
- }
-
- // Wenn das letzte File auf der Diskette das alte Protokollfile
- // ist, wird es weggelassen. Dabei wird der ehemalige Anfang des
- // Protokollfiles als Startpunkt für die Zusatzsicherung gemerkt.
- // Ist das alte Protokollfile nicht komplett auf dieser Diskette
- // (Extension > 0), wird es einfach mit übernommen, weil es mir
- // zu mühsam ist, dann die Diskette mit dem Anfang vom
- // Protokollfile anzufordern und zu verifizieren.
-
- switch (Label->RecordedFormat)
- {
- case 0:
- old_nf=(struct OldNameField *) DirBuff;
-
- for (i=0; i<Label->DirAnz; i++)
- {
- // Alle Filenamen eintragen
- long len;
-
- if (Label->Version < VERS_OFFSET)
- old_nf->Offset *= globDrvDat.BlockSize;
-
- if (i != Label->DirAnz-1 || stricmp(old_nf->Name, myOptions.bo_ProtFileName) != 0
- || old_nf->Extension != 0)
- {
- struct NameField *NewName;
-
- NewName = calloc(NF_LEN(old_nf), 1);
- if (NewName == NULL)
- {
- FreeVec(DirBuff);
- alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "NewName", NF_LEN(old_nf));
- SendWriterRx(WMR_ABORTMAIN);
- return FALSE;
- }
-
- NewName->NextName = NULL;
- NewName->isComplete = old_nf->Complete;
- NewName->CompressionType = (old_nf->Flags & FIBF_COMPRESS) ?
- COMPRESS_INTERNAL : COMPRESS_NONE;
- NewName->isHardLink = (old_nf->Flags & FIBF_HARDLINK) ? 1 : 0;
- NewName->isSoftLink = (old_nf->Flags & FIBF_SOFTLINK) ? 1 : 0;
- NewName->isDir = 0;
- NewName->Extension = old_nf->Extension;
- NewName->SessionNr = 1;
- NewName->Offset = old_nf->Offset;
- NewName->FileLen = old_nf->FileLen;
- NewName->RecordedLen = 0l; // wird später getrennt bestimmt
- NewName->FileDate = old_nf->FileDate;
- NewName->Protection = old_nf->Flags & FILEPROT;
- NewName->NameLen = old_nf->NameLen;
- memcpy(NewName->Name, old_nf->Name, old_nf->NameLen+1);
-
- // nur wegen der Rückwärts-Kompatibilität
- NewName->isCompressed = NewName->CompressionType == COMPRESS_INTERNAL;
-
- EnterName(NULL, old_nf->Offset, "", NewName);
- aktNameDone();
-
- free(NewName);
- }
- else
- {
- Label->EndOfData = ReadDisk.Offset = WriteDisk.Offset = old_nf->Offset;
- }
-
- len = sizeof(struct OldNameField) + old_nf->NameLen;
-
- aktName->isComplete = 1;
-
- old_nf = (struct OldNameField *) ((char *) old_nf + 2 * ceildiv(len, 2));
- }
-
- CurrentSessionNr = 2;
-
- // jetzt alle physikalischen Filelängen bestimmen
- for (akt_nf=(struct NameField *) ReadDisk.DirBuffers.mlh_Head;
- akt_nf; akt_nf=akt_nf->NextName)
- {
- akt_nf->RecordedLen = FileLength(Label, akt_nf);
- ComputeNfChecksum(akt_nf); // Prüfsumme in NameField korrigieren!
- }
- break;
- case 1:
- akt_nf=(struct NameField *) DirBuff;
-
- for (i=0; i<Label->DirAnz; i++)
- {
- // Alle Filenamen eintragen
- unsigned long len;
-
- if (i != Label->DirAnz-1 || stricmp(akt_nf->Name, myOptions.bo_ProtFileName) != 0
- || akt_nf->Extension != 0)
- {
- if (akt_nf->CompressionType == COMPRESS_NONE &&
- akt_nf->isCompressed)
- akt_nf->CompressionType = COMPRESS_INTERNAL;
-
- EnterName(NULL, akt_nf->Offset, "", akt_nf);
- aktNameDone();
- }
- else
- {
- ReadDisk.Offset = WriteDisk.Offset = akt_nf->Offset;
- }
-
- len = NF_LEN(akt_nf);
-
- if (aktName->NameLen > FMSIZE)
- {
- FreeVec(DirBuff);
- alarm("%s (1): %s NameLen=%ld", __FUNC__, aktName->Name, aktName->NameLen);
- return FALSE;
- }
-
- if (aktName->SessionNr == 0)
- aktName->SessionNr = 1;
-
- aktName->isComplete = 1;
- ComputeNfChecksum(aktName); // Prüfsumme in NameField korrigieren!
-
- akt_nf = (struct NameField *) ((char *) akt_nf + 2 * ceildiv(len, 2));
- }
-
- CurrentSessionNr = aktName->SessionNr + 1;
- break;
- default:
- alarm(GetString(MSG_UNKNOWN_DIRECTORY_FORMAT));
- SendWriterRx(WMR_ABORTMAIN);
- break;
- }
-
- FilesProcessed = BytesProcessed = 0; // Zähler rückstellen
-
- FreeVec(DirBuff);
-
- return TRUE;
- }
-
-
- static void ShowCyl(const struct IOExtTD *Req, short DiskNr)
- {
- char zeile[40];
- long sektor;
-
- ASSERT_VALID(Req);
-
- if (!toTape)
- {
- sektor = Req->iotd_Req.io_Offset / globDrvDat.BlockSize;
-
- sprintf(zeile, "%s: %s #%-3d Cyl #%-3d",
- Disks[DiskUnit].DOSName, GetString(MSG_DISK_LABEL),
- DiskNr, sectotrack(sektor) );
- DiskText(zeile, ~0, ~0, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
- }
- }
-
-
- // Öffnen der belegten Devices.
- // liefert TRUE wenn alles Ok, FALSE nach Fehler.
- static short OpenDisks(void)
- {
- Disks[myOptions.bo_FirstUnit].diskreq = OpenDisk(&Disks[myOptions.bo_FirstUnit], TRUE);
- if (Disks[myOptions.bo_FirstUnit].diskreq == NULL)
- return FALSE;
-
- if (Disks[myOptions.bo_FirstUnit].TapeReq)
- {
- Disks[myOptions.bo_FirstUnit].TapeReq->Req = Disks[myOptions.bo_FirstUnit].diskreq;
- myOptions.bo_SecondUnit = NO_DRIVE; // nur eine Unit bei TAPE
- }
-
- if (myOptions.bo_SecondUnit != NO_DRIVE)
- {
- Disks[myOptions.bo_SecondUnit].diskreq = OpenDisk(&Disks[myOptions.bo_SecondUnit], TRUE);
- if (Disks[myOptions.bo_SecondUnit].diskreq == NULL)
- return FALSE;
- }
- return TRUE;
- }
-
-
- // Lesen von Daten aus der Partition <pInfo>
- // liefert die Anzahl gelesene Bytes zurück.
- ULONG ReadPartition(struct PartitionInfo *pInfo, ULONG ReadLen, APTR Buffer)
- {
- ULONG Result = 0;
- ULONG cLen;
-
- while (ReadLen)
- {
- if (0 == pInfo->BytesInTrackBuff)
- {
- short error;
-
-
- cLen = min(pInfo->PartSize, pInfo->TrackBuffSize);
-
- error = TRead0(pInfo->PartIO, pInfo->CurrentOffset, pInfo->TrackBuff, cLen);
- while (error)
- error = DiskError(pInfo->PartIO, GetString(MSG_READING), error, FALSE);
-
- pInfo->BytesInTrackBuff = cLen;
- pInfo->CurrentOffset += cLen;
- pInfo->PartSize -= cLen;
- pInfo->TBOffset = 0;
- }
-
- cLen = min(ReadLen, pInfo->BytesInTrackBuff);
- CopyMem((char *) pInfo->TrackBuff + pInfo->TBOffset, Buffer, cLen);
-
- ReadLen -= cLen;
- pInfo->BytesInTrackBuff -= cLen;
- pInfo->TBOffset += cLen;
- Result += cLen;
- Buffer = ((char *) Buffer) + cLen;
- }
-
- return Result;
- }
-
-
- // Directory-Prüfsumme berechnen
- static unsigned long ComputeDirChecksum(const struct Disk *Dsk, unsigned long DirLen)
- {
- unsigned long l, DirCheckSum;
- struct DirBlock *aktblock;
-
- for (l = DirLen * globDrvDat.BlockSize / sizeof(long), DirCheckSum=0l,
- aktblock = (struct DirBlock *) Dsk->DirBuffers.mlh_Head;
- l && aktblock != (struct DirBlock *) &(Dsk->DirBuffers.mlh_Tail);
- aktblock = (struct DirBlock *) aktblock->db_Node.mln_Succ)
- {
- unsigned long Len;
- long *DirPtr;
-
- DirPtr = (long *) aktblock->Data;
- Len = aktblock->DataLength / sizeof(long);
-
- while (l && Len)
- {
- DirCheckSum += *DirPtr++;
- l--;
- Len--;
- }
- }
-
- return DirCheckSum;
- }
-
-
- // Ergebnis: TRUE wenn abgebrochen werden muß
- static BOOL CheckWriterTxPort(void)
- {
- struct WriterMessage *Msg;
-
- if (NULL == WriterTxPort)
- return FALSE;
-
- while (Msg = (struct WriterMessage *) GetMsg(WriterTxPort))
- {
- unsigned short Class;
-
- Class = Msg->wm_Class;
-
- ReplyMsg((struct Message *) Msg);
-
- switch (Class)
- {
- case WM_ABORT:
- WriterAbort = TRUE;
- case WM_SHUTDOWN:
- d(kprintf(">>received WM_ABORT oder WM_SHUTDOWN\n");)
- WriterRunning = FALSE;
- if (WriterAbort)
- longjmp(AbortJumpBuf, 0);
- break;
- case WM_BEGINWRITE:
- d(kprintf(">>received WM_BEGINWRITE\n");)
- WriterWarten = FALSE;
- break;
- case WM_NEWDISK:
- d(kprintf(">>received WM_NEWDISK\n");)
- newdisk(myOptions.bo_Append, FALSE);
- d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
- if (!WriterAbort)
- SendWriterRx(WMR_NEWDISKOK);
- break;
- case WM_CLOSEDISK:
- d(kprintf(">>received WM_CLOSEDISK\n");)
- CloseWriter = TRUE;
- break;
- default:
- d(kprintf(">>received unknown %ld\n", (long) Class);)
- break;
- }
- }
-
- return (BOOL) !WriterRunning;
- }
-
-
- // Message vom Writer-Prozeß an Hauptprozeß senden
- static void SendWriterRx(unsigned short Class)
- {
- struct WriterMessage *Msg;
-
- Msg = malloc(sizeof(struct WriterMessage));
- if (Msg)
- {
- Msg->wm_Msg.mn_ReplyPort = WriterRxReplyPort;
- Msg->wm_Msg.mn_Length = sizeof(struct WriterMessage);
- Msg->wm_Class = Class;
- d(kprintf(">>%s %ld: send %lx\n", __FUNC__, __LINE__, (long) Class);)
- PutMsg(WriterRxPort, (struct Message *) Msg);
-
- if (WriterRxReplyPort)
- {
- ULONG Signals;
-
- d(kprintf(">>%s %ld vor WaitPort\n", __FUNC__, __LINE__);)
-
- do {
- Signals = Wait(WriterTxPortMask | (1 << WriterRxReplyPort->mp_SigBit));
-
- if (Signals & WriterTxPortMask)
- CheckWriterTxPort();
-
- Msg = (struct WriterMessage *) GetMsg(WriterRxReplyPort);
- } while (NULL == Msg);
-
- free(Msg);
- d(kprintf(">>%s %ld nach WaitPort\n", __FUNC__, __LINE__);)
- }
- }
- }
-
-
-