home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / disk utilities / backup / backup_restore / backup_src_v3.20.lha / Schreiben.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-06  |  65.0 KB  |  2,610 lines

  1. // Schreiben.c
  2. // 06 Dec 1996 11:24:07
  3.  
  4. #ifndef    BACKUP_INCLUDE
  5. #include "IncludeAll.c"
  6. #endif
  7. #include "Backup.h"
  8. #include "FileSelect.h"
  9. #include "Backup_proto.h"
  10. #include "BackupStrings.h"
  11. #include "Writer.h"
  12.  
  13. #define    d(x)        ;
  14.  
  15. #define    WRITEPROC_STACK    8192l    // Stack für Writer-Prozeß
  16.  
  17. #define    MAXBUFFUSE    3    // maximale Anzahl gleichzeitige Requests an Device
  18.  
  19.  
  20. #define    TXPORTSIG(Sig)    ((Sig) & WriterTxPortMask)
  21.  
  22.  
  23. static int WriterRxPortHandler(void);
  24. static void SendWriter(unsigned short Class);
  25. static BOOL WriterInit(void);
  26. static BOOL WriterInitDisks(void);
  27. static short WriterShutdown(void);
  28. static void  TapeFull(struct TapeIO *TapeReq);
  29. static short ErrorCheck(struct IOExtTD *req, struct IOExtTD *verreq, BOOL bufwrite);
  30. static short TapeErrorCheck(struct TapeIO *TapeReq,  BOOL bufwrite);
  31. static short DiskError(struct IOExtTD *req, const char *text, short errno, BOOL bufwrite);
  32. static void  RetryRequests(void);
  33. static short WriteLabel(unsigned long diranf, unsigned long LogicalDirAnf, unsigned long dirlen,
  34.         unsigned long diranz, long lastoffset, unsigned long DirCks,
  35.         short DiskNr, BOOL QFA);
  36. static BOOL Schreiben(void);
  37. static short SchreibStatus(void);
  38. static short NamenSchreiben(BOOL WriteOutDir);
  39. static short WriteDir(struct Disk *Dsk, struct IOExtTD *WrtIO,
  40.         struct TapeIO *WrtTIO, BOOL toTape, unsigned long DirSektor);
  41. static void FixupDir(short NewDiskNr, unsigned long LastByte);
  42. static short WriteTapeDir(struct Disk *Dsk, struct TapeIO *WrtTIO, short DiskNr);
  43. static void  RemoveRequests(void);
  44. static void  RemoveTapeRequests(void);
  45. static void  WaitForDisk(BOOL AnyChange);
  46. static enum TestDiskResult CheckAppendDisk(short unit);
  47. static short ReadDir(struct DiskLabel *Label, short unit);
  48. static void  newdisk(BOOL append, BOOL SameDiskNr);
  49. static short ReadQFALabel(struct DiskFlags *Dsk, struct DiskLabel *Label);
  50. static short ReadTapeLabel(struct DiskFlags *Dsk, struct DiskLabel *Label);
  51. static void ShowCyl(const struct IOExtTD *Req, short DiskNr);
  52. static short OpenDisks(void);
  53. static unsigned long ComputeDirChecksum(const struct Disk *Dsk, unsigned long DirLen);
  54. static BOOL CheckWriterTxPort(void);
  55. static void SendWriterRx(unsigned short Class);
  56.  
  57.  
  58. // aus Backup.c
  59. extern struct BackupDevInfo globDrvDat;        // globale Disk-Parameter
  60. extern struct Window *aktWindow;
  61. extern struct BackupOptions myOptions;
  62. extern struct DiskFlags __far *Disks;
  63. extern unsigned short NDisk;            // Anzahl Einträge in Disks[]
  64. extern short DiskUnit;                // aktuelles Laufwerk für Backup
  65. extern struct Buffer __far CylBuff[];        // Schreib-/Lese-Buffer (für je einen Cylinder)
  66. extern unsigned short ReadBuffNr, WriteBuffNr, OldestWriteBuffNr;
  67. extern BOOL toTape;                // Backup erfolgt auf Tape
  68. extern unsigned char disknr;            // laufende Nummer der Backup-Diskette
  69. extern short BuffersFull;            // Anzahl gefüllter Buffer
  70. extern BOOL AllFilesRead;            // Backup-Ende (lesen) erreicht
  71. extern unsigned long FilesProcessed;        // Anzahl Files
  72. extern unsigned long BytesProcessed;        // Anzahl Bytes
  73. extern char StartZeit[8];
  74. extern struct Disk ReadDisk;
  75. extern struct Disk WriteDisk;
  76. extern unsigned short CurrentSessionNr;
  77. extern short BuffCount;                // tatsächliche Anzahl Buffer
  78. extern long readoffset;                // Offset innerhalb des aktuellen Lese-Buffers
  79. extern struct NameField *aktName;
  80. extern struct Task *BackupTask;
  81.  
  82.  
  83. // aus Protocol.c
  84. extern FILE *ProtFileHandle;            // File Handle für Protokoll-File
  85. extern BOOL ProtFileValid;            // Flag: Protfile enthält sinnvolle Daten (wird am Ende von NamenSchreiben gesetzt)
  86.  
  87. // aus Revision.c
  88. extern short Version;                // aktuelle Versionsnummer
  89.  
  90. // aus ProcStart.asm
  91. extern APTR __far WriterSeg;            // SegList für CreateProc
  92.  
  93.  
  94. static short  ReqsInUse = 0;            // Anzahl IORequests, die z.Z. beim Trackdisk.device anstehen
  95.  
  96. static char __far zeile[129];
  97.  
  98. static struct Task *WriterTask;            // Prozeß "BackupWriter"
  99. static struct MsgPort *WriterProcPort;        // Prozeß-Port "BackupWriter"
  100. static struct MsgPort *WriterRxPort;        // Port für Nachrichten Writer -> main
  101. static struct MsgPort *WriterRxReplyPort;    // Reply-Port für Nachrichten Writer -> main
  102. static struct MsgPort *WriterTxPort;        // Port für Nachrichten main -> Writer
  103. static struct MsgPort *WriterTxReplyPort;    // Reply-Port für Nachrichten main -> Writer
  104. static BOOL WriterRunning;            // Flag: Writer soll laufen
  105. static BOOL WriterWarten;            // Flag: warten vor dem Beginn des Schreibens
  106. static BOOL WriterAbort = FALSE;        // Flag: Writer wird abgebrochen
  107. static BOOL CloseWriter = FALSE;        // Flag: letzte Disk wird geschlossen
  108. static BOOL NewDiskOkFlag = FALSE;        // Flag: WMR_NEWDISKOK ist angekommen
  109. static BOOL WMDownFlag = FALSE;            // Flag: WMR_DOWN ist angekommen
  110. static short WriterSigBit = -1;            // Signal-Bit für "Buffer full"
  111. static unsigned long WriterSigMask;        // Signal-Maske für "Buffer full"-Signalisierung
  112. static unsigned long WriterIOMask;        // Signal-Maske für IOExtTD's
  113. static unsigned long WriterTxPortMask;        // Signal-Maske für WriterTxPort
  114. static unsigned long SignalsGot;        // erhaltene Signale während Warten auf Eingabe
  115. static jmp_buf AbortJumpBuf;            // jmp_buf zum Abbrechen des Writers
  116.  
  117. static struct BInputHandler *WriterInput = NULL;
  118.  
  119.  
  120. // return TRUE wenn OK, nach Fehler FALSE
  121. BOOL StartWriter(void)
  122. {
  123.     BOOL Success = FALSE;
  124.     struct WriterMessage *Msg;
  125.  
  126.     WriterRxPort = CreateMsgPort();
  127.     if (NULL == WriterRxPort)
  128.         {
  129.         alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterRxPort");
  130.         return FALSE;
  131.         }
  132.     WriterTxReplyPort = CreateMsgPort();
  133.     if (NULL == WriterTxReplyPort)
  134.         {
  135.         alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterTxReplyPort");
  136.         return FALSE;
  137.         }
  138.  
  139.     WriterProcPort = CreateProc((STRPTR) "BackupWriter", 0L, MKBADDR(&WriterSeg),
  140.         WRITEPROC_STACK);
  141.     if (WriterProcPort == NULL)
  142.         {
  143.         alarm(GetString(MSG_CREATEPROC_FAILED), __FUNC__, "BackupWriter");
  144.         return FALSE;
  145.         }
  146.  
  147.     // auf Init.-Quittung warten
  148.     WaitPort(WriterRxPort);
  149.     Msg = (struct WriterMessage *) GetMsg(WriterRxPort);    // Quittung holen
  150.     if (Msg)
  151.         {
  152.         d(kprintf("%s %ld: Msg=%08lx  Class=%lx\n", __FUNC__, __LINE__, Msg, Msg->wm_Class);)
  153.         Success = WMR_INITOK == Msg->wm_Class;
  154.  
  155.         ReplyMsg((struct Message *) Msg);
  156.         }
  157.  
  158.     if (Success)
  159.         WriterInput = AddBInputHandler(1 << WriterRxPort->mp_SigBit, WriterRxPortHandler);
  160.  
  161.     return Success;
  162. }
  163.  
  164.  
  165. void StopWriter(BOOL abnormalAbort)
  166. {
  167.     if (WriterRxPort == NULL)
  168.         return;
  169.  
  170.     if (WriterProcPort)
  171.         {
  172.         struct WriterMessage *Msg;
  173.  
  174.         while (Msg = (struct WriterMessage *) GetMsg(WriterRxPort))
  175.             {
  176.             ReplyMsg((struct Message *) Msg);
  177.             }
  178.  
  179.         SendWriter(abnormalAbort ? WM_ABORT : WM_SHUTDOWN);
  180.         WriterRunning = FALSE;
  181.  
  182.         WMDownFlag = FALSE;
  183.  
  184.         do    {
  185.             // warten auf Ende-Quittung
  186.             eingabe(0l);
  187.             } while (!WMDownFlag);
  188.         }
  189.  
  190.     d(kprintf("%s %ld\n", __FUNC__, __LINE__);)
  191.  
  192.     RemBInputHandler(&WriterInput);
  193.  
  194.     if (WriterRxPort)
  195.         {
  196.         DeleteMsgPort(WriterRxPort);
  197.         WriterRxPort = NULL;
  198.         }
  199.     if (WriterTxReplyPort)
  200.         {
  201.         DeleteMsgPort(WriterTxReplyPort);
  202.         WriterTxReplyPort = NULL;
  203.         }
  204. }
  205.  
  206.  
  207. void SignalBufferFull(void)
  208. {
  209.     Signal(WriterTask, WriterSigMask);
  210. }
  211.  
  212.  
  213. void SignalBeginWriting(void)
  214. {
  215.     static BOOL First = TRUE;
  216.  
  217.     d(kprintf("%s %ld\n", __FUNC__, __LINE__);)
  218.     if (First)
  219.         {
  220.         d(kprintf("%s %ld\n", __FUNC__, __LINE__);)
  221.         SendWriter(WM_BEGINWRITE);
  222.         First = FALSE;
  223.         }
  224. }
  225.  
  226.  
  227. // Neue Disk anfordern und warten bis bereit
  228. void SignalNewDisk(void)
  229. {
  230.     SendWriter(WM_NEWDISK);
  231.  
  232.     NewDiskOkFlag = FALSE;
  233.  
  234.     do    {
  235.         // warten auf WMR_NEWDISKOK
  236.         eingabe(0l);
  237.         } while (!NewDiskOkFlag);
  238. }
  239.  
  240.  
  241. // Letzte Disk schließen
  242. void SignalDiskClose(void)
  243. {
  244.     SendWriter(WM_CLOSEDISK);
  245. }
  246.  
  247.  
  248. // DiskChanger meldet: Neue Disk ist Ok
  249. void SignalNewDiskOk(void)
  250. {
  251.     if (WriterTask)
  252.         Signal(WriterTask, WriterSigMask);
  253. }
  254.  
  255.  
  256. void SignalUnIconifyMainWindow(void)
  257. {
  258.     struct MsgPort *ReplyPort;
  259.     struct WriterMessage *Msg;
  260.  
  261.     if (FindTask(NULL) == BackupTask)
  262.         {
  263.         UnIconifyMainWindow();
  264.         }
  265.     else
  266.         {
  267.         ReplyPort = CreateMsgPort();
  268.         if (ReplyPort)
  269.             {
  270.             Msg = malloc(sizeof(struct WriterMessage));
  271.             if (Msg)
  272.                 {
  273.                 Msg->wm_Msg.mn_ReplyPort = ReplyPort;
  274.                 Msg->wm_Msg.mn_Length = sizeof(struct WriterMessage);
  275.                 Msg->wm_Class = WMR_OPENMAINWINDOW;
  276.  
  277.                 d(kprintf(">>%s %ld: send %lx\n", __FUNC__, __LINE__, (long) Msg->wm_Class);)
  278.                 PutMsg(WriterRxPort, (struct Message *) Msg);
  279.  
  280.                 d(kprintf(">>%s %ld vor WaitPort\n", __FUNC__, __LINE__);)
  281.                 WaitPort(ReplyPort);
  282.                 Msg = (struct WriterMessage *) GetMsg(ReplyPort);
  283.  
  284.                 free(Msg);
  285.                 d(kprintf(">>%s %ld nach WaitPort\n", __FUNC__, __LINE__);)
  286.                 }
  287.             DeleteMsgPort(ReplyPort);
  288.             }
  289.         }
  290. }
  291.  
  292.  
  293. // Message an Writer-Prozeß senden
  294. static void SendWriter(unsigned short Class)
  295. {
  296.     struct WriterMessage *Msg;
  297.  
  298.     Msg = malloc(sizeof(struct WriterMessage));
  299.     if (Msg)
  300.         {
  301.         Msg->wm_Msg.mn_ReplyPort = WriterTxReplyPort;
  302.         Msg->wm_Msg.mn_Length = sizeof(struct WriterMessage);
  303.         Msg->wm_Class = Class;
  304.  
  305.         d(kprintf("%ld: send %lx\n", __LINE__, (long) Class);)
  306.         PutMsg(WriterTxPort, (struct Message *) Msg);
  307.  
  308.         WaitPort(WriterTxReplyPort);        // Warten auf Reply
  309.         Msg = (struct WriterMessage *) GetMsg(WriterTxReplyPort);    // Reply-Port leeren
  310.         free(Msg);
  311.  
  312.         d(kprintf("%ld: send %lx nach WaitPort()\n", __LINE__, (long) Class);)
  313.         }
  314. }
  315.  
  316.  
  317. static int WriterRxPortHandler(void)
  318. {
  319.     struct WriterMessage *Msg;
  320.  
  321.     do    {
  322.         Msg = (struct WriterMessage *) GetMsg(WriterRxPort);
  323.         if (Msg)
  324.             {
  325.             switch (Msg->wm_Class)
  326.                 {
  327.             case WMR_ABORTMAIN:
  328.                 // Hauptprogramm abbrechen
  329.                 myabort(10);
  330.                 break;
  331.  
  332.             case WMR_OPENMAINWINDOW:
  333.                 // Sicherstellen, daß aktWindow offen ist!
  334.                 SignalUnIconifyMainWindow();
  335.                 break;
  336.  
  337.             case WMR_BUFFEREMPTY:
  338.                 // ein Buffer ist leer geworden
  339.                 break;
  340.  
  341.             case WMR_NEWDISKOK:
  342.                 NewDiskOkFlag = TRUE;
  343.                 break;
  344.  
  345.             case WMR_DOWN:
  346.                 WMDownFlag = TRUE;
  347.                 break;
  348.                 }
  349.  
  350.             ReplyMsg((struct Message *) Msg);
  351.             }
  352.         } while (Msg);
  353.  
  354.     return 0;
  355. }
  356.  
  357.  
  358. // ======================================================
  359. // ab hier läuft der Code als eigener Prozeß !
  360.  
  361. // main() des BackupWriter
  362. void __saveds BackupWriter(void)
  363. {
  364.     unsigned long RcvdSig;
  365.  
  366.     d(kprintf("%ld vor WriterInit\n", __LINE__);)
  367.     WriterInit();
  368.  
  369.     setjmp(AbortJumpBuf);
  370.  
  371.     d(kprintf("%ld vor WriterInitDisks\n", __LINE__);)
  372.     if (WriterRunning && WriterInitDisks())
  373.         {
  374.         // Prozeß-Start quittieren
  375.         SendWriterRx(WMR_INITOK);
  376.         d(kprintf("%ld WriterInit ok\n", __LINE__);)
  377.  
  378.         WriterWarten = TRUE;
  379.         while (WriterRunning && WriterWarten)
  380.             {
  381.             d(kprintf("%ld vor WaitPort\n", __LINE__);)
  382.             WaitPort(WriterTxPort);
  383.             d(kprintf("%ld nach WaitPort\n", __LINE__);)
  384.  
  385.             CheckWriterTxPort();
  386.             }
  387.  
  388.         d(kprintf("%ld nach while {}\n", __LINE__);)
  389.         if (WriterRunning && Disks[myOptions.bo_FirstUnit].TapeReq)
  390.             TapeInitProperties(Disks[myOptions.bo_FirstUnit].TapeReq);
  391.  
  392.         while (WriterRunning)
  393.             {
  394.             d(kprintf("%ld in While {}\n", __LINE__);)
  395.  
  396.             SignalsGot = 0l;
  397.             if (Schreiben())
  398.                 RcvdSig = SetSignal(0l, 0l) | SignalsGot;
  399.             else if (WriterRunning)
  400.                 {
  401.                 // im Moment ist kein Puffer frei.
  402.                 // jetzt warten bis 2/3 aller Puffer gefüllt sind
  403.                 do    {
  404.                     RcvdSig = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask) | SignalsGot;
  405.                     } while (!AllFilesRead && !(RcvdSig & ~WriterSigMask)
  406.                         && BuffersFull < 2*BuffCount/3);
  407.                 }
  408.  
  409.             d(kprintf("%ld in While {}\n", __LINE__);)
  410.             if (RcvdSig & WriterTxPortMask)
  411.                 CheckWriterTxPort();
  412.  
  413.             d(kprintf("%ld in While {}\n", __LINE__);)
  414.             if (RcvdSig & WriterIOMask)
  415.                 SchreibStatus();
  416.             d(kprintf("%ld in While {}\n", __LINE__);)
  417.  
  418.             // Backup-Medium schließen: Directory + Label schreiben
  419.             if (CloseWriter && !DB_EMPTY(WriteDisk) && WriteReady())
  420.                 NamenSchreiben(TRUE);
  421.             }
  422.  
  423.         d(kprintf("%ld CloseWriter=%ld  WriterAbort=%ld\n", __LINE__, CloseWriter, WriterAbort);)
  424.  
  425.         // Backup-Medium schließen: Directory + Label schreiben
  426.         if (CloseWriter && !WriterAbort && !DB_EMPTY(WriteDisk))
  427.             NamenSchreiben(TRUE);
  428.  
  429.         d(kprintf("%ld nach While {}\n", __LINE__);)
  430.         }
  431.     else
  432.         {
  433.         SendWriterRx(WMR_INITBAD);
  434.         }
  435.  
  436.     WriterShutdown();
  437.  
  438.     // Prozeß-Ende quittieren
  439.     Forbid();
  440.     SendWriterRx(WMR_DOWN);
  441.  
  442.     WriterProcPort = NULL;
  443.     WriterTask = NULL;
  444. }
  445.  
  446.  
  447. static BOOL __interrupt WriterInit(void)
  448. {
  449.     WriterTask = FindTask(NULL);
  450.  
  451.     WriterTxPort = CreateMsgPort();
  452.     if (WriterTxPort == NULL)
  453.         {
  454.         alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterTxPort");
  455.         return FALSE;
  456.         }
  457.     WriterRxReplyPort = CreateMsgPort();
  458.     if (WriterRxReplyPort == NULL)
  459.         {
  460.         alarm(GetString(MSG_CREATEPORT_FAILED), __FUNC__, "WriterRxReplyPort");
  461.         return FALSE;
  462.         }
  463.  
  464.     WriterSigBit = AllocSignal(-1);
  465.     if (WriterSigBit == -1)
  466.         {
  467.         alarm("%s: %s WriterSigBit", __FUNC__, GetString(MSG_CANNOT_GET_SIGNAL));
  468.         return FALSE;
  469.         }
  470.  
  471.     WriterTxPortMask = 1 << WriterTxPort->mp_SigBit;
  472.     WriterSigMask = 1 << WriterSigBit;
  473.  
  474.     WriterRunning = TRUE;
  475.     return TRUE;
  476. }
  477.  
  478.  
  479. static BOOL WriterInitDisks(void)
  480. {
  481.     if (!OpenDisks())
  482.         return FALSE;        // Fehler bei OpenDevice
  483.  
  484.     WriterIOMask = 1 << Disks[myOptions.bo_FirstUnit].diskreq->iotd_Req.io_Message.mn_ReplyPort->mp_SigBit;
  485.     if (myOptions.bo_SecondUnit != NO_DRIVE)
  486.         WriterIOMask |= 1 << Disks[myOptions.bo_SecondUnit].diskreq->iotd_Req.io_Message.mn_ReplyPort->mp_SigBit;
  487.  
  488.     return TRUE;
  489. }
  490.  
  491.  
  492. static short WriterShutdown(void)
  493. {
  494.     d(kprintf("Removing Writer Requests\n");)
  495.     RemoveRequests();
  496.  
  497.     CloseDisk(&Disks[myOptions.bo_FirstUnit], CDP_UnloadTape);
  498.     if (myOptions.bo_SecondUnit != NO_DRIVE)
  499.         CloseDisk(&Disks[myOptions.bo_SecondUnit], CDP_UnloadTape);
  500.  
  501.     if (WriterTxPort)
  502.         {
  503.         DeleteMsgPort(WriterTxPort);
  504.         WriterTxPort = NULL;
  505.         }
  506.     if (WriterRxReplyPort)
  507.         {
  508.         DeleteMsgPort(WriterRxReplyPort);
  509.         WriterRxReplyPort = NULL;
  510.         }
  511.     if (WriterSigBit != -1)
  512.         {
  513.         FreeSignal(WriterSigBit);
  514.         WriterSigBit = -1;
  515.         }
  516.     return 0;
  517. }
  518.  
  519.  
  520. static void TapeFull(struct TapeIO *TapeReq)
  521. {
  522.     unsigned long LastByte, MissingBytes;
  523.     struct NameField *nf;
  524.     short error;
  525.  
  526.     ASSERT_VALID(TapeReq);
  527.  
  528.     alarm("Band ist voll !!!\nAlles weitere passiert ohne Gewähr!");
  529.  
  530.     LastByte = TapeReq->Req->iotd_Req.io_Offset + TapeReq->Req->iotd_Req.io_Actual;
  531.     MissingBytes = TapeReq->Req->iotd_Req.io_Length - TapeReq->Req->iotd_Req.io_Actual;
  532.  
  533.     nf = LookupFile(LastByte, LastByte);
  534.  
  535.     nf->isComplete = 0;
  536.     ComputeNfChecksum(aktName);        // Prüfsumme in NameField korrigieren!
  537.  
  538.     FixupDir(disknr+1, LastByte);    // Directory korrigieren
  539.  
  540.     // Ende der Daten mit SetMark kennzeichnen
  541.     error = TapeWriteFileMarks(TapeReq, 1, TRUE);
  542.  
  543.     while (error)
  544.         error = TapeError(TapeReq, &Disks[DiskUnit], GetString(MSG_WRITING_LABEL), error, FALSE, TRUE);
  545.  
  546.     NamenSchreiben(FALSE);        // Label und QFA-Directory schreiben
  547.  
  548.     disknr++;
  549.  
  550.     newdisk(FALSE, FALSE);        // neues Band anfordern
  551.  
  552.     // Neues Tape-Label schreiben
  553.     WriteLabel(0l, 0l, 0l, 0l, 0l, 0l, disknr, FALSE);
  554.  
  555.     // fehlende Daten jetzt auf das neue Band schreiben
  556.     error = TapeWrite(TapeReq, TapeReq->Req->iotd_Req.io_Data, MissingBytes);
  557.     while (error)
  558.         error = TapeError(TapeReq, &Disks[DiskUnit], GetString(MSG_WRITING), error, FALSE, TRUE);
  559. }
  560.  
  561.  
  562. static short ErrorCheck(struct IOExtTD *req, struct IOExtTD *verreq, BOOL bufwrite)
  563. {
  564.     short error, result;
  565.  
  566.     ASSERT_VALID(req);
  567.  
  568.     error = result = WriteTrackStatus(req, verreq);
  569.     while (result)
  570.         {
  571.         if (req->iotd_Req.io_Error)
  572.             result = DiskError(req, GetString(MSG_WRITING), error, bufwrite);
  573.         else if (myOptions.bo_Verify)
  574.             {
  575.             ASSERT_VALID(verreq);
  576.             result = DiskError(verreq, GetString(MSG_VERIFYING), error, bufwrite);
  577.             }
  578.         }
  579.     return error;
  580. }
  581.  
  582.  
  583. static short TapeErrorCheck(struct TapeIO *TapeReq,  BOOL bufwrite)
  584. {
  585.     long error, result;
  586.  
  587.     ASSERT_VALID(TapeReq);
  588.     d(kprintf("%ld Beginn TapeErrorCheck\n", __LINE__);)
  589.  
  590.     error = result = TapeIOStatus(TapeReq);
  591.     d(kprintf("%ld in TapeErrorCheck, result=%08lx\n", __LINE__, result);)
  592.  
  593.     while (result)
  594.         {
  595.         d(kprintf("%ld in TapeErrorCheck, result=%08lx\n", __LINE__, result);)
  596.         d(kprintf("Status=%02lx SK=%02lx ASC=%02lx ASCQ=%02lx\n",
  597.                 TapeReq->Cmd.scsi_Status,
  598.                 TapeReq->Sense[2] & 0x0f,
  599.                 TapeReq->Cmd.scsi_SenseLength > 12 ? TapeReq->Sense[12] : 0,
  600.                 TapeReq->Cmd.scsi_SenseLength > 13 ? TapeReq->Sense[13] : 0
  601.                 );)
  602.  
  603.         if (error)
  604.             result = TapeError(TapeReq, &Disks[DiskUnit], GetString(MSG_WRITING), error, bufwrite, TRUE);
  605.         }
  606.  
  607.     d(kprintf("%ld Ende TapeErrorCheck\n", __LINE__);)
  608.  
  609.     return (short) error;
  610. }
  611.  
  612.  
  613. short TapeError(struct TapeIO *TapeReq, struct DiskFlags *Dsk, const char *text, short errno, 
  614.             BOOL bufwrite, BOOL BlockNrValid)
  615. {
  616.     static const long SKMessages[] =
  617.         {
  618.         MSG_SK_NOSENSE, MSG_SK_RECOVEREDERROR, MSG_SK_NOTREADY, MSG_SK_MEDIUMERROR,
  619.         MSG_SK_HARDWAREERROR, MSG_SK_ILLEGALREQUEST, MSG_SK_UNITATTENTION, MSG_SK_DATAPROTECT,
  620.         MSG_SK_BLANKCHECK, MSG_SK_VENDORSPECIFIC, MSG_SK_COPYABORTED,
  621.         MSG_SK_ABORTEDCOMMAND, MSG_SK_EQUAL, MSG_SK_VOLUMEOVERFLOW, MSG_SK_MISCOMPARE,
  622.         MSG_SK_RESERVED
  623.         };
  624.     unsigned char SenseKey, ASC, ASCQ;
  625.     struct NameField *nf;
  626.     const char *DOSName;
  627.     unsigned long Offset, MaxOffset;
  628.     short result = 0;
  629.     short EoM, c;
  630.  
  631.     ASSERT_VALID(TapeReq);
  632.     ASSERT_VALID(text);
  633.  
  634.     d(kprintf("%ld Beginn TapeError\n", __LINE__);)
  635.  
  636.     DOSName = Dsk ? Dsk->DOSName : "";
  637.  
  638.     SenseKey = TapeReq->Sense[2] & 0x0f;
  639.     EoM  = TapeReq->Sense[2] & 0x40;
  640.     ASC  = TapeReq->Cmd.scsi_SenseLength > 12 ? TapeReq->Sense[12] : 0;
  641.     ASCQ = TapeReq->Cmd.scsi_SenseLength > 13 ? TapeReq->Sense[13] : 0;
  642.  
  643.     d(kprintf("%ld in TapeError\n", __LINE__);)
  644.     if (bufwrite)
  645.         RemoveTapeRequests();        // Device anhalten
  646.  
  647.     d(kprintf("%ld in TapeError\n", __LINE__);)
  648.  
  649.     if (EoM && SenseKey == 0 && (TapeReq->DrvDat->SCSILevel < 2 ||
  650.                  (ASC == 0 && ASCQ == 2)))
  651.         {
  652.         // Band ist zu Ende
  653.         TapeFull(TapeReq);
  654.         return FALSE;
  655.         }
  656.  
  657.     SetBusyPointer(aktWindow, FALSE);
  658.  
  659.     if (TapeReq->IOError)
  660.         {
  661.         sprintf(zeile, GetString(BlockNrValid ? MSG_TAPE_IOERROR_BLOCK : MSG_TAPE_IOERROR),
  662.             DOSName, ErrorText((short) TapeReq->IOError),
  663.             text, globDrvDat.BlockSize ? (TapeReq->Req->iotd_Req.io_Offset / globDrvDat.BlockSize) : 0);
  664.         }
  665.     else
  666.         {
  667.         sprintf(zeile, GetString(BlockNrValid ? MSG_TAPE_ERROR_BLOCK : MSG_TAPE_ERROR),
  668.             DOSName, TapeReq->Cmd.scsi_Status,
  669.             SenseKey, GetString(SKMessages[SenseKey]), ASC, ASCQ,
  670.             text, globDrvDat.BlockSize ? (TapeReq->Req->iotd_Req.io_Offset / globDrvDat.BlockSize) : 0);
  671.         }
  672.     d(kprintf("%ld in TapeError\n", __LINE__);)
  673.     PostError(TRUE, MSGPRI_Error, zeile);
  674.     d(kprintf("%ld in TapeError\n", __LINE__);)
  675.  
  676.     SendWriterRx(WMR_OPENMAINWINDOW);
  677.     c = askRetryWindow(aktWindow, WriterTxPortMask, &SignalsGot, zeile);
  678. //    InfoLine("");
  679.  
  680.     // Prüfen ob Prozeß abgebrochen werden muß
  681.     CheckWriterTxPort();
  682.  
  683.     if (c == *GetString(MSG_ABORT_SHORT))
  684.         {
  685.         // Abbrechen
  686.         SendWriterRx(WMR_ABORTMAIN);
  687.         return FALSE;
  688.         }
  689.     else if (c == *GetString(MSG_IGNORE_SHORT) && bufwrite)
  690.         {
  691.         // Ignorieren
  692.         Offset = TapeReq->Req->iotd_Req.io_Offset + TapeReq->Cmd.scsi_Actual;
  693.         MaxOffset = TapeReq->Req->iotd_Req.io_Offset + TapeReq->Cmd.scsi_Length;
  694.  
  695.         while (Offset < MaxOffset && (nf = LookupFile(Offset, MaxOffset))
  696.                 && !CheckWriterTxPort())
  697.             {
  698.             // Namen der beschädigten Files melden
  699.             PostError(FALSE, MSGPRI_Warning, GetString(MSG_FILE_DAMAGED), NurName(nf->Name));
  700.             Offset = nf->Offset + nf->RecordedLen + 1;
  701.             }
  702.  
  703.         // Der Request mit dem Fehler wird abgehakt
  704.         SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
  705.         SendWriterRx(WMR_BUFFEREMPTY);
  706.         NextBuffNr(&OldestWriteBuffNr);
  707.         }
  708.     if (c == *GetString(MSG_IGNORE_SHORT) ||
  709.         c == *GetString(MSG_RETRY_SHORT) )
  710.         {
  711.         // Retry
  712.         // Noch ausstehende Requests wieder absenden
  713.         if (bufwrite)
  714.             {
  715.             RetryRequests();
  716.             }
  717.         else if (c == *GetString(MSG_RETRY_SHORT))
  718.             {
  719.             result = TapeDoIO(TapeReq);
  720.             }
  721.         }
  722.     d(kprintf("%ld Ende TapeError\n", __LINE__);)
  723.  
  724.     return result;
  725. }
  726.  
  727.  
  728. static short DiskError(struct IOExtTD *req, const char *text, short errno, BOOL bufwrite)
  729. {
  730.     struct NameField *nf;
  731.     unsigned long Offset, MaxOffset;
  732.     short c;
  733.     short Error = 0;
  734.  
  735.     ASSERT_VALID(req);
  736.     ASSERT_VALID(text);
  737.  
  738.     sprintf(zeile, GetString(MSG_DISK_ERROR),
  739.         Disks[DiskUnit].DOSName,
  740.         errno, ErrorText((short) errno), text, 
  741.         sectotrack(req->iotd_Req.io_Offset / globDrvDat.BlockSize),
  742.         req->iotd_Req.io_Offset / globDrvDat.BlockSize);
  743.  
  744.     if (bufwrite)
  745.         RemoveRequests();        // Device anhalten
  746.  
  747.     SendWriterRx(WMR_OPENMAINWINDOW);
  748.     c = askRetryWindow(aktWindow, WriterTxPortMask, &SignalsGot, zeile);
  749. //    InfoLine("");
  750.  
  751.     // Prüfen ob Prozeß abgebrochen werden muß
  752.     CheckWriterTxPort();
  753.  
  754.     if (c == *GetString(MSG_RETRYNEWDISK_SHORT))
  755.         {
  756.         struct IOExtTD RetryReq;
  757.         unsigned long Cyl = 0;
  758.         APTR CylBuffer;
  759.         int Error;
  760.  
  761.         RetryReq = *req;
  762.         Clear(&RetryReq);
  763.  
  764.         newdisk(FALSE, TRUE);        // neue Disk anfordern
  765.  
  766.         // Alle Cylinder zurückschreiben auf die neue Disk
  767.         do    {
  768.             CylBuffer = RetrieveSaveInfo(Cyl);
  769.             if (CylBuffer)
  770.                 {
  771.                 unsigned long Sector = Cyl * globDrvDat.NumSecs
  772.                         * globDrvDat.NumHeads;
  773.  
  774.                 Error = TFormat(&RetryReq, Sector, CylBuffer, globDrvDat.CylSize);
  775.                 ShowCyl(&RetryReq, disknr);
  776.  
  777.                 if (!Error && myOptions.bo_Verify)
  778.                     Error = TRead(&RetryReq, Sector, CylBuffer, globDrvDat.CylSize);
  779.  
  780.                 Cyl++;
  781.                 }
  782.             } while(!Error && CylBuffer);
  783.         }
  784.     else if (c == *GetString(MSG_ABORT_SHORT))
  785.         {
  786.         SendWriterRx(WMR_ABORTMAIN);
  787.         return FALSE;
  788.         }
  789.     else if (c == *GetString(MSG_IGNORE_SHORT))
  790.         {
  791.         PostError(TRUE, MSGPRI_Error, zeile);
  792.  
  793.         Offset = req->iotd_Req.io_Offset + req->iotd_Req.io_Actual;
  794.         MaxOffset = req->iotd_Req.io_Offset + req->iotd_Req.io_Length;
  795.         while (Offset < MaxOffset && (nf = LookupFile(Offset, MaxOffset)) && !CheckWriterTxPort())
  796.             {
  797.             PostError(FALSE, MSGPRI_Warning, GetString(MSG_FILE_DAMAGED), NurName(nf->Name));
  798.             Offset = nf->Offset + nf->RecordedLen + 1;
  799.             }
  800.  
  801.         if (bufwrite)
  802.             {
  803.             // Der Request mit dem Fehler wird abgehakt
  804.             SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
  805.             SendWriterRx(WMR_BUFFEREMPTY);
  806.             NextBuffNr(&OldestWriteBuffNr);
  807.             }
  808.         }
  809.     if (!Error && (c == *GetString(MSG_IGNORE_SHORT) || c == *GetString(MSG_RETRY_SHORT)
  810.             || c == *GetString(MSG_RETRYNEWDISK_SHORT)))
  811.         {
  812.         // Noch ausstehende Requests wieder absenden
  813.         if (bufwrite)
  814.             {
  815.             RetryRequests();
  816.             }
  817.         else if (c != *GetString(MSG_IGNORE_SHORT))
  818.             {
  819.             Error = DoIO((struct IORequest *) req);
  820.             }
  821.         }
  822.  
  823.     return Error;
  824. }
  825.  
  826.  
  827. static void RetryRequests(void)
  828. {
  829.     unsigned short n;
  830.  
  831.     n = OldestWriteBuffNr;
  832.     do    {
  833.         if (GetBuffStatus(&CylBuff[n]) == VOLL)
  834.             {
  835.             d(kprintf("%ld in RetryRequests n=%ld LN_TYPE=%ld\n",
  836.                 __LINE__, n, CylBuff[n].BufIOReq.iotd_Req.io_Message.mn_Node.ln_Type);)
  837.  
  838.             if (toTape)
  839.                 {
  840.                 d(kprintf("%ld in RetryRequests n=%ld LN_TYPE=%ld\n",
  841.                     __LINE__, n, CylBuff[n].TapeReq->Req->iotd_Req.io_Message.mn_Node.ln_Type);)
  842.  
  843.                 TapeBeginWrite(CylBuff[n].TapeReq, CylBuff[n].dbp, globDrvDat.CylSize,
  844.                     CylBuff[n].TapeReq->Req->iotd_Req.io_Offset);
  845.                 }
  846.             else
  847.                 {
  848.                 unsigned long sector;
  849.  
  850.                 d(kprintf("%ld in RetryRequests n=%ld LN_TYPE=%ld\n",
  851.                     __LINE__, n, CylBuff[n].BufIOReq.iotd_Req.io_Message.mn_Node.ln_Type);)
  852.  
  853.                 sector = CylBuff[n].BufIOReq.iotd_Req.io_Offset / globDrvDat.BlockSize;
  854.  
  855.                 CylBuff[n].BufferCheckSum = ComputeBufferCheckSum(&CylBuff[n]);
  856.                 StartWriteTrack( &CylBuff[n].BufIOReq, sector, CylBuff[n].dbp, globDrvDat.CylSize);
  857.  
  858.                 if (myOptions.bo_Verify)
  859.                     {
  860.                     StartReadTrack( &CylBuff[n].VerifyReq, sector, CylBuff[n].dbp, globDrvDat.CylSize);
  861.                     ReqsInUse++;
  862.                     }
  863.                 }
  864.             ReqsInUse++;
  865.  
  866.             SetBuffStatus(&CylBuff[n], LEEREN);
  867.             }
  868.  
  869.         NextBuffNr(&n);
  870.         } while (n != WriteBuffNr && (ReqsInUse <= MAXBUFFUSE));
  871. }
  872.  
  873.  
  874. // Header in Sektor 0 der Diskette schreiben.
  875. // liefert TRUE wenn Ok, sonst nach Fehler FALSE
  876. static short WriteLabel(unsigned long diranf, unsigned long LogicalDirAnf, unsigned long dirlen,
  877.         unsigned long diranz, long lastoffset, unsigned long DirCks,
  878.         short DiskNr, BOOL QFA)
  879. {
  880.     struct DiskLabel *Label;
  881.     long error;
  882.     InfoLineHandle Pil;
  883.  
  884.     Pil = PushInfoLine(GetString(QFA ? MSG_WRITING_QFA_LABEL : MSG_WRITING_LABEL1));
  885.  
  886.     Label = (struct DiskLabel *) AllocVec(sizeof(struct DiskLabel), globDrvDat.BufMemType|MEMF_CLEAR);
  887.     if (Label == NULL)
  888.         {
  889.         PopInfoLine(&Pil);
  890.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "Label", sizeof(struct DiskLabel));
  891.         SendWriterRx(WMR_ABORTMAIN);
  892.         return FALSE;
  893.         }
  894.  
  895.     BuildDiskLabel(Label, DiskNr);
  896.  
  897.     Label->lastdisk = (!AllFilesRead || !WriteReady()) ? 0 : 0xff;        // Markierung ob letzte Disk
  898.     Label->DirAnf = diranf;
  899.     Label->DirLen = dirlen;
  900.     Label->DirAnz = diranz;
  901.     Label->EndOfData = lastoffset;
  902.     Label->RealDirAnf = LogicalDirAnf;
  903.     Label->withQFA = Disks[DiskUnit].TapeReq ? Disks[DiskUnit].TapeReq->withQFA : 0;
  904.  
  905.     Label->LabelCheckSum = 0l;
  906.     Label->DirCheckSum = DirCks;
  907.  
  908.     Label->LabelCheckSum = -ComputeLabelCheckSum(Label);
  909.  
  910.     if (toTape)
  911.         {
  912.         error = TapeWrite(Disks[DiskUnit].TapeReq, (char *) Label, globDrvDat.BlockSize);
  913.  
  914.         if (!error && !QFA)
  915.             {
  916.             // bei QFA keine FileMark nach dem Label!
  917.             error = TapeWriteFileMarks(Disks[DiskUnit].TapeReq, 0, FALSE);
  918.             }
  919.  
  920.         while (error)
  921.             {
  922.             error = TapeError(Disks[DiskUnit].TapeReq, &Disks[DiskUnit], 
  923.                     GetString(MSG_WRITING_LABEL), error, FALSE, TRUE);
  924.             }
  925.         }
  926.     else
  927.         {
  928.         error = TWrite(Disks[DiskUnit].diskreq, 0, (char *) Label, globDrvDat.BlockSize);
  929.  
  930.         while (error)
  931.             error = DiskError(Disks[DiskUnit].diskreq, GetString(MSG_WRITING_LABEL), error, FALSE);
  932.         }
  933.  
  934.     if (!toTape)
  935.         Update(Disks[DiskUnit].diskreq);
  936.  
  937.     if (!toTape && myOptions.bo_Verify)
  938.         {
  939.         Clear(Disks[DiskUnit].diskreq);
  940.  
  941.         error = TRead(Disks[DiskUnit].diskreq, 0, (char *) Label, globDrvDat.BlockSize);
  942.         while (error)
  943.             error = DiskError(Disks[DiskUnit].diskreq, GetString(MSG_VERIFYING_LABEL), error, FALSE);
  944.         }
  945.     FreeVec(Label);
  946.     PopInfoLine(&Pil);
  947.  
  948.     return (short) (!error);
  949. }
  950.  
  951.  
  952. // liefert TRUE wenn neuer Buffer zum Schreiben gefunden
  953. static BOOL Schreiben(void)
  954. {
  955.     struct Buffer *buf;
  956.     BOOL result = FALSE;
  957.     short DiskNr;
  958.     unsigned long Offset;
  959.  
  960.     LockWriteDisk();
  961.     DiskNr = WriteDisk.nr;
  962.     Offset = WriteDisk.Offset;
  963.     UnlockWriteDisk();
  964.  
  965.     buf = &CylBuff[WriteBuffNr];
  966.     if ( GetBuffStatus(buf) == VOLL && (ReqsInUse <= MAXBUFFUSE))
  967.         {
  968.         result = TRUE;
  969.  
  970.         if (buf->disknr != DiskNr)
  971.             {
  972.             // Achtung: WriteDisk ändert sich !
  973.             NamenSchreiben(TRUE);
  974.             newdisk(FALSE, FALSE);
  975.             d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  976.  
  977. // *********        if (!WriterAbort)
  978. // ich bin nicht sicher was das sollte, hier abzubrechen wenn KEIN WriterAbort
  979. // Im Zuge einer Fehlerbehebung habe ich die Bedingung umgekehrt (26 Jul 1996 21:32:03),
  980. //     (Backup hing nach dem Einlegen der 2. Disk)
  981. // Der Abbruch beim Warten auf eine Neue Disk sowie das Weiterschreiben auf
  982. // eine neue Disk scheinen immer noch/wieder zu klappen.
  983.  
  984.             if (WriterAbort)
  985.                 return FALSE;
  986.  
  987.             d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  988.             LockWriteDisk();
  989.             Offset = WriteDisk.Offset;
  990.             UnlockWriteDisk();
  991.             d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  992.             }
  993.  
  994.         d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  995.         SetBuffStatus(buf, LEEREN);
  996.  
  997.         d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  998.  
  999.         if (toTape)
  1000.             TapeBeginWrite(buf->TapeReq, buf->dbp, globDrvDat.CylSize, Offset);
  1001.         else
  1002.             {
  1003.             buf->BufferCheckSum = ComputeBufferCheckSum(buf);
  1004.             StartWriteTrack( &(buf->BufIOReq), Offset/globDrvDat.BlockSize,
  1005.                 buf->dbp, globDrvDat.CylSize);
  1006.  
  1007.             if (myOptions.bo_Verify)
  1008.                 {
  1009.                 StartReadTrack( &(buf->VerifyReq), Offset/globDrvDat.BlockSize,
  1010.                     buf->dbp, globDrvDat.CylSize);
  1011.                 ReqsInUse++;
  1012.                 }
  1013.             }
  1014.         ReqsInUse++;
  1015.  
  1016.         NextBuffNr(&WriteBuffNr);
  1017.  
  1018.         LockWriteDisk();
  1019.         WriteDisk.Offset += globDrvDat.CylSize;
  1020.         UnlockWriteDisk();
  1021.         }
  1022.  
  1023.     return result;
  1024. }
  1025.  
  1026.  
  1027. // Liefert TRUE, wenn noch Schreib-Buffer in Bearbeitung sind
  1028. // ..und FALSE, wenn alle Schreibvorgänge fertig sind.
  1029. static short SchreibStatus(void)
  1030. {
  1031.     short erg;
  1032.  
  1033.     d(kprintf("%ld Beginn Schreibstatus \n", __LINE__);)
  1034.     while ( erg = (GetBuffStatus(&CylBuff[OldestWriteBuffNr]) == LEEREN) )
  1035.         {
  1036.         d(kprintf("%ld in Schreibstatus \n", __LINE__);)
  1037.  
  1038.         if (toTape)
  1039.             {
  1040.             d(kprintf("%ld in Schreibstatus \n", __LINE__);)
  1041.  
  1042.             if ( TapeIOReady(CylBuff[OldestWriteBuffNr].TapeReq))
  1043.                 {
  1044.                 d(kprintf("%ld in Schreibstatus \n", __LINE__);)
  1045.  
  1046.                 ShowCyl( &CylBuff[OldestWriteBuffNr].BufIOReq,
  1047.                     CylBuff[OldestWriteBuffNr].disknr);
  1048.  
  1049.                 d(kprintf("%ld in Schreibstatus \n", __LINE__);)
  1050.  
  1051.                 if (TapeErrorCheck(CylBuff[OldestWriteBuffNr].TapeReq, TRUE) == 0)
  1052.                     {
  1053.                     ReqsInUse--;
  1054.  
  1055.                     d(kprintf("%ld in Schreibstatus \n", __LINE__);)
  1056.                     SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
  1057.                     SendWriterRx(WMR_BUFFEREMPTY);
  1058.                     NextBuffNr(&OldestWriteBuffNr);
  1059.                     }
  1060.                 d(kprintf("%ld in Schreibstatus \n", __LINE__);)
  1061.                 }
  1062.             else
  1063.                 break;
  1064.             }
  1065.         else
  1066.             {
  1067.             if ( WriteTrackReady(&CylBuff[OldestWriteBuffNr].BufIOReq,
  1068.                     myOptions.bo_Verify ? &CylBuff[OldestWriteBuffNr].VerifyReq : NULL) )
  1069.                 {
  1070.                 ShowCyl( &CylBuff[OldestWriteBuffNr].BufIOReq, 
  1071.                     CylBuff[OldestWriteBuffNr].disknr);
  1072.  
  1073.                 if (ErrorCheck(&CylBuff[OldestWriteBuffNr].BufIOReq,
  1074.                         &CylBuff[OldestWriteBuffNr].VerifyReq, TRUE) == 0)
  1075.                     {
  1076.                     ReqsInUse--;
  1077.                     if (myOptions.bo_Verify)
  1078.                         {
  1079.                         unsigned long Cks;
  1080.  
  1081.                         Cks = ComputeBufferCheckSum(&CylBuff[OldestWriteBuffNr]);
  1082.                         if (CylBuff[OldestWriteBuffNr].BufferCheckSum != Cks)
  1083.                             {
  1084.                             // Buffer-Prüfsumme stimmt nicht nach Rücklesen
  1085.                             PostError(TRUE, MSGPRI_Warning, 
  1086.                                 GetString(MSG_VERIFY_CHECKSUMERROR), 
  1087.                                 sectotrack(CylBuff[OldestWriteBuffNr].BufIOReq.iotd_Req.io_Offset / globDrvDat.BlockSize),
  1088.                                 CylBuff[OldestWriteBuffNr].BufferCheckSum, 
  1089.                                 Cks
  1090.                                 );
  1091.                             }
  1092.                         ReqsInUse--;
  1093.                         }
  1094.  
  1095.                     SetBuffStatus(&CylBuff[OldestWriteBuffNr], LEER);
  1096.                     SendWriterRx(WMR_BUFFEREMPTY);
  1097.                     NextBuffNr(&OldestWriteBuffNr);
  1098.                     }
  1099.                 }
  1100.             else
  1101.                 break;
  1102.             }
  1103.         }
  1104.  
  1105.     d(kprintf("%ld Ende Schreibstatus \n", __LINE__);)
  1106.  
  1107.     return erg;
  1108. }
  1109.  
  1110.  
  1111. static short NamenSchreiben(BOOL WriteOutDir)
  1112. {
  1113.     struct IOExtTD NameReq;
  1114.     struct TapeIO *NameTapeReq = NULL;
  1115.     struct Disk aktWriteDisk;
  1116.     unsigned long DirSektor, DirLen;
  1117.     long DirCheckSum;
  1118.     short error = 0;
  1119.  
  1120.     d(kprintf(__FUNC__ ": %ld\n", __LINE__);)
  1121.  
  1122.     LockWriteDisk();
  1123.     aktWriteDisk = WriteDisk;
  1124.     MoveDirBuff(&aktWriteDisk, &WriteDisk);
  1125.     UnlockWriteDisk();
  1126.  
  1127.     if (aktWriteDisk.dirlength == 0)
  1128.         return FALSE;
  1129.  
  1130.     if (DB_EMPTY(aktWriteDisk))
  1131.         {
  1132.         alarm(GetString(MSG_INTERNALERROR_NAMSCHR_1), __FUNC__);
  1133.         SendWriterRx(WMR_ABORTMAIN);
  1134.         return FALSE;
  1135.         }
  1136.  
  1137.     NameReq = *Disks[DiskUnit].diskreq;
  1138.  
  1139.     if (toTape)
  1140.         {
  1141.         if (myOptions.bo_Append && Disks[DiskUnit].TapeReq->withQFA &&
  1142.                 !Disks[DiskUnit].TapeReq->DrvDat->Properties.AppendQFA)
  1143.             {
  1144.             // Beim meinem TDC3820 klappt das Schreiben
  1145.             // von QFA-Label und -Directory nach Append nicht.
  1146.             // Deshalb Weiterarbeit ohne QFA
  1147.             Disks[DiskUnit].TapeReq->withQFA = FALSE;
  1148.             TapeInitQFA(Disks[DiskUnit].TapeReq, 0);
  1149.             }
  1150.  
  1151.         NameTapeReq = (struct TapeIO *) AllocVec(sizeof(struct TapeIO), globDrvDat.BufMemType);
  1152.         if (NameTapeReq == NULL)
  1153.             {
  1154.             alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "NameTapeReq", sizeof(struct TapeIO));
  1155.             SendWriterRx(WMR_ABORTMAIN);
  1156.             return FALSE;
  1157.             }
  1158.         *NameTapeReq = *Disks[DiskUnit].TapeReq;
  1159.         NameTapeReq->Req = &NameReq;
  1160.         }
  1161.  
  1162.     if (aktWriteDisk.Offset < aktWriteDisk.MaxOffset)
  1163.         {
  1164.         if (NameTapeReq)
  1165.             FreeVec(NameTapeReq);
  1166.  
  1167.         alarm(GetString(MSG_INTERNALERROR_NAMSCHR_2), __FUNC__);
  1168.         SendWriterRx(WMR_ABORTMAIN);
  1169.         return FALSE;
  1170.         }
  1171.  
  1172.     if (WriteOutDir)
  1173.         {
  1174.         // Directory fängt mit neuem Sektor an
  1175.         DirSektor = ceildiv(aktWriteDisk.Offset, globDrvDat.BlockSize);
  1176.         if (NameTapeReq)
  1177.             DirSektor++;    // Platz lassen für zusätzliches Label
  1178.         DirLen = ceildiv(aktWriteDisk.dirlength, globDrvDat.BlockSize);
  1179.  
  1180.         DirCheckSum = ComputeDirChecksum(&aktWriteDisk, DirLen);
  1181.  
  1182.         // Label vor Directory schreiben (nur bei TAPE)
  1183.         if (!error && NameTapeReq)
  1184.             {
  1185.             error = !WriteLabel(DirSektor, DirSektor, DirLen, 
  1186.                 aktWriteDisk.diranz, aktWriteDisk.MaxOffset,
  1187.                 DirCheckSum, aktWriteDisk.nr, FALSE);
  1188.             }
  1189.  
  1190.         if (!error)
  1191.             {
  1192.             InfoLineHandle Pil;
  1193.  
  1194.             Pil = PushInfoLine(GetString(MSG_WRITING_DIRECTORY));
  1195.  
  1196.             // Directory schreiben ans Medien-Ende
  1197.             error = WriteDir(&aktWriteDisk, &NameReq, NameTapeReq, toTape, DirSektor);
  1198.             PopInfoLine(&Pil);
  1199.             }
  1200.         }
  1201.  
  1202.     // Label am Aufzeichnungsende schreiben
  1203.     if (!error)
  1204.         {
  1205.         error = !WriteLabel(DirSektor, DirSektor, DirLen, 
  1206.                 aktWriteDisk.diranz, aktWriteDisk.MaxOffset,
  1207.                 DirCheckSum, aktWriteDisk.nr, FALSE);
  1208.         }
  1209.  
  1210.     // Jetzt bei QFA Directory und Label nochmal schreiben
  1211.     // nur bei TAPE
  1212.     if (NameTapeReq && NameTapeReq->withQFA && !error)
  1213.         {
  1214.         InfoLineHandle Pil;
  1215.  
  1216.         Pil = PushInfoLine(GetString(MSG_REWINDING));
  1217.  
  1218.         error = TapeRewind(NameTapeReq);
  1219.         if (error)
  1220.             TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), error, FALSE, FALSE);
  1221.  
  1222.         if (!error)
  1223.             {
  1224.             error = TapeSetDirectoryPartition(NameTapeReq);
  1225.             if (error)
  1226.                 TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_CHANGEPARTITION), error, FALSE, FALSE);
  1227.             }
  1228.         if (!error)
  1229.             error = !WriteLabel(1, DirSektor, DirLen, aktWriteDisk.diranz, aktWriteDisk.MaxOffset,
  1230.                     DirCheckSum, aktWriteDisk.nr, TRUE);
  1231.  
  1232.         if (!error)
  1233.             {
  1234.             // Jetzt QFA-Directory schreiben
  1235.             PopInfoLine(&Pil);
  1236.             Pil = PushInfoLine(GetString(MSG_WRITING_QFA_DIRECTORY));
  1237.  
  1238.             if (WriteOutDir)
  1239.                 error = WriteDir(&aktWriteDisk, &NameReq, NameTapeReq, toTape, 0l);
  1240.             else
  1241.                 error = WriteTapeDir(&aktWriteDisk, NameTapeReq, disknr);
  1242.             }
  1243.  
  1244.         if (!error)
  1245.             {
  1246.             // Directory-Aufzeichnung mit FileMarks beenden
  1247.             error = TapeWriteFileMarks(NameTapeReq, 0, FALSE);
  1248.  
  1249.             while (error)
  1250.                 error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_WRITING_LABEL), error, FALSE, TRUE);
  1251.             }
  1252.         PopInfoLine(&Pil);
  1253.         }
  1254.  
  1255.     if (!error && WriteOutDir && ProtFileHandle && !aktWriteDisk.dirwritten)
  1256.         {
  1257.         WriteProtFile(FIRST_NF(aktWriteDisk), disknr);
  1258.         aktWriteDisk.dirwritten = 1;
  1259.         }
  1260.  
  1261.     // Fehler melden wenn hier die Directory-Checksumme nicht mehr stimmt!!
  1262.     if (DirCheckSum != ComputeDirChecksum(&aktWriteDisk, DirLen))
  1263.         {
  1264.         PostError(TRUE, MSGPRI_Warning, 
  1265.             GetString(MSG_CHECKSUMERROR_DIRECTORY), Disks[DiskUnit].DOSName);
  1266.         }
  1267.  
  1268. #ifdef XYZ_DEBUG
  1269.     {
  1270.     FILE *fd;
  1271.     struct DirBlock *aktBlock;
  1272.  
  1273.     fd = fopen("HD1:Backup.dir", "wb");
  1274.  
  1275.     for (aktBlock = (struct DirBlock *) aktWriteDisk.DirBuffers.mlh_Head;
  1276.         aktBlock != (struct DirBlock *) &(aktWriteDisk.DirBuffers.mlh_Tail);
  1277.         aktBlock = (struct DirBlock *) aktBlock->db_Node.mln_Succ)
  1278.         {
  1279.         fwrite(aktBlock->Data, aktBlock->DataLength, 1, fd);
  1280.         }
  1281.  
  1282.     fclose(fd);
  1283.     }
  1284. #endif
  1285.  
  1286.     if (WriteOutDir)
  1287.         CleanupRWDisk(&aktWriteDisk);
  1288.  
  1289.     if (NameTapeReq && !error)
  1290.         {
  1291.         if (myOptions.bo_Verify)
  1292.             {
  1293.             InfoLineHandle Pil;
  1294.  
  1295.             // Verify-Lauf bei Bändern
  1296.             SetBusyPointer(aktWindow, TRUE);
  1297.             Pil = PushInfoLine(GetString(MSG_VERIFYING_TAPE));
  1298.  
  1299.             error = TapeRewind(NameTapeReq);
  1300.             if (error)
  1301.                 error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), error, FALSE, FALSE);
  1302.  
  1303.             if (!error && NameTapeReq->withQFA)
  1304.                 {
  1305.                 // Wieder zurück zu Data Partition wechseln
  1306.                 error = TapeSetDataPartition(NameTapeReq);
  1307.                 if (error)
  1308.                     {
  1309.                     error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_CHANGEPARTITION), 
  1310.                             error, FALSE, FALSE);
  1311.                     }
  1312.                 }
  1313.  
  1314.             if (!error)
  1315.                 {
  1316.                 // Verify Data
  1317.                 error = TapeVerify(NameTapeReq, (DirSektor+DirLen+1)*globDrvDat.BlockSize);
  1318.                 if (error)
  1319.                     {
  1320.                     error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_VERIFYING), 
  1321.                             error, FALSE, TRUE);
  1322.                     }
  1323.                 }
  1324.             if (!error && NameTapeReq->withQFA)
  1325.                 {
  1326.                 // Verify QFA Label & Directory
  1327.                 PopInfoLine(&Pil);
  1328.                 Pil = PushInfoLine(GetString(MSG_VERIFYING_QFA));
  1329.  
  1330.                 error = TapeRewind(NameTapeReq);
  1331.                 if (error)
  1332.                     {
  1333.                     error = TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), 
  1334.                             error, FALSE, FALSE);
  1335.                     }
  1336.  
  1337.                 TapeSetDataPartition(NameTapeReq);
  1338.  
  1339.                 if (!error)
  1340.                     {
  1341.                     error = TapeVerify(NameTapeReq, (DirLen+1)*globDrvDat.BlockSize);
  1342.                     if (error)
  1343.                         {
  1344.                         TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_VERIFYING), 
  1345.                             error, FALSE, TRUE);
  1346.                         }
  1347.                     }
  1348.                 PopInfoLine(&Pil);
  1349.                 }
  1350.  
  1351.             SetBusyPointer(aktWindow, FALSE);
  1352.             PopInfoLine(&Pil);
  1353.             }
  1354.  
  1355.         // Band zurückspulen
  1356.         error = TapeRewind(NameTapeReq);
  1357.         if (error)
  1358.             TapeError(NameTapeReq, &Disks[DiskUnit], GetString(MSG_REWIND), error, FALSE, FALSE);
  1359.         }
  1360.  
  1361.     if (!NameTapeReq)
  1362.         {
  1363.         Update(Disks[DiskUnit].diskreq);
  1364.         Eject(Disks[DiskUnit].diskreq);
  1365.         }
  1366.  
  1367.     ResetDiskSave();
  1368.  
  1369.     if (NameTapeReq)
  1370.         FreeVec(NameTapeReq);
  1371.  
  1372.     ProtFileValid = TRUE;
  1373.  
  1374.     return TRUE;
  1375. }
  1376.  
  1377.  
  1378. static short WriteDir(struct Disk *Dsk, struct IOExtTD *WrtIO,
  1379.     struct TapeIO *WrtTIO, BOOL toTape, unsigned long DirSektor)
  1380. {
  1381.     struct IOExtTD DirWrtReq;
  1382.     struct TapeIO *DirWrtTIO = NULL;
  1383.     struct IOExtTD VerifyReq;
  1384.     struct DirBlock *aktBlock;
  1385.     short error = 0;
  1386.  
  1387.     ASSERT_VALID(Dsk);
  1388.     ASSERT_VALID(WrtIO);
  1389.  
  1390.     DirWrtReq = VerifyReq = *WrtIO;
  1391.     if (toTape)
  1392.         {
  1393.         ASSERT_VALID(WrtTIO);
  1394.  
  1395.         DirWrtTIO = (struct TapeIO *) AllocVec(sizeof(struct TapeIO),
  1396.             globDrvDat.BufMemType);
  1397.         if (DirWrtTIO == NULL)
  1398.             {
  1399.             alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirWrtTIO", sizeof(struct TapeIO));
  1400.             SendWriterRx(WMR_ABORTMAIN);
  1401.             return FALSE;
  1402.             }
  1403.  
  1404.         *DirWrtTIO = *WrtTIO;
  1405.         }
  1406.  
  1407.     for (aktBlock = (struct DirBlock *) Dsk->DirBuffers.mlh_Head;
  1408.         !error && aktBlock != (struct DirBlock *) &(Dsk->DirBuffers.mlh_Tail);
  1409.         aktBlock = (struct DirBlock *) aktBlock->db_Node.mln_Succ)
  1410.         {
  1411.         if (toTape)
  1412.             {
  1413.             TapeBeginWrite(DirWrtTIO, aktBlock->Data, aktBlock->DataLength,
  1414.                 DirSektor * globDrvDat.BlockSize);
  1415.             }
  1416.         else
  1417.             {
  1418.             StartWriteTrack(&DirWrtReq, DirSektor, aktBlock->Data, aktBlock->DataLength);
  1419.             }
  1420.  
  1421.         if (!toTape && myOptions.bo_Verify)
  1422.             {
  1423.             StartReadTrack(&VerifyReq, DirSektor, aktBlock->Data, aktBlock->DataLength);
  1424.             }
  1425.  
  1426.         // Warten bis Directory fertig geschrieben
  1427.         if (toTape)
  1428.             {
  1429.             while ( SchreibStatus() && !TapeIOReady(DirWrtTIO) && !CheckWriterTxPort())
  1430.                 SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
  1431.  
  1432.             TapeErrorCheck(DirWrtTIO, TRUE);
  1433.             }
  1434.         else
  1435.             {
  1436.             while ( SchreibStatus() && !WriteTrackReady(&DirWrtReq,
  1437.                     myOptions.bo_Verify ? &VerifyReq : NULL)  && !CheckWriterTxPort())
  1438.                 {
  1439.                 SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
  1440.                 }
  1441.  
  1442.             ErrorCheck(&DirWrtReq, &VerifyReq, FALSE);
  1443.             }
  1444.  
  1445.         ShowCyl(&DirWrtReq, Dsk->nr);
  1446.  
  1447.         DirSektor += aktBlock->DataLength / globDrvDat.BlockSize;
  1448.         }
  1449.  
  1450.     if (DirWrtTIO)
  1451.         FreeVec(DirWrtTIO);
  1452.  
  1453.     return error;
  1454. }
  1455.  
  1456.  
  1457. // Korrektur des Directory am Anfang eines Folgebandes (Band ist voll).
  1458. // - alle Einträge nach <LastByte> erhalten die neue <NewDisknr>
  1459. // - bei allen Einträgen auf dem neuen Band wird Offset korrigiert
  1460. //   (neue Zählung ab 0 auf den Folgeband)
  1461. static void FixupDir(short NewDiskNr, unsigned long LastByte)
  1462. {
  1463.     struct NameField *nf;
  1464.  
  1465.     LockNFList();
  1466.  
  1467.     nf = FIRST_NF(WriteDisk);
  1468.     while (nf && (nf->DiskNr < NewDiskNr))
  1469.         {
  1470.         if (nf->Offset >= LastByte)
  1471.             {
  1472.             nf->DiskNr = NewDiskNr;
  1473.             nf->Offset = nf->Offset + sizeof(struct DiskLabel)
  1474.                     - LastByte;
  1475.             }
  1476.  
  1477.         nf = nf->NextName;
  1478.         }
  1479.  
  1480.     UnlockNFList();
  1481. }
  1482.  
  1483.  
  1484. // aus dem aktuellen Directory werden alle Einträge für <DiskNr> herausgesucht
  1485. // und geschrieben.
  1486. //
  1487. //*** irgendetwas muß noch für DirCheckSum und DirLen getan werden!
  1488. static short WriteTapeDir(struct Disk *Dsk, struct TapeIO *WrtTIO, short DiskNr)
  1489. {
  1490.     unsigned char *DirBuffer, *DirBuffPtr;
  1491.     struct TapeIO *DirWrtTIO;
  1492.     struct NameField *nf;
  1493.     short error = 0;
  1494.     size_t BufferSpace, WriteLen;
  1495.  
  1496.     ASSERT_VALID(Dsk);
  1497.     ASSERT_VALID(WrtTIO);
  1498.  
  1499.     DirBuffer = AllocVec(globDrvDat.CylSize, globDrvDat.BufMemType);
  1500.     if (DirBuffer == NULL)
  1501.         {
  1502.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirBuffer", globDrvDat.CylSize);
  1503.         SendWriterRx(WMR_ABORTMAIN);
  1504.         return FALSE;
  1505.         }
  1506.  
  1507.     DirWrtTIO = (struct TapeIO *) AllocVec(sizeof(struct TapeIO),
  1508.         globDrvDat.BufMemType);
  1509.     if (DirWrtTIO == NULL)
  1510.         {
  1511.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirWrtTIO", sizeof(struct TapeIO));
  1512.         SendWriterRx(WMR_ABORTMAIN);
  1513.         return FALSE;
  1514.         }
  1515.  
  1516.     *DirWrtTIO = *WrtTIO;
  1517.  
  1518.     nf = (struct NameField *) ((struct DirBlock *) Dsk->DirBuffers.mlh_Head)->Data;
  1519.     BufferSpace = globDrvDat.CylSize;
  1520.     DirBuffPtr = DirBuffer;
  1521.     WriteLen = 0;
  1522.  
  1523.     while (nf)
  1524.         {
  1525.         if (nf->DiskNr == DiskNr)
  1526.             {
  1527.             size_t NfLen, CopyLen;
  1528.  
  1529.             NfLen = NF_LEN(nf);
  1530.             CopyLen = min(NfLen, BufferSpace);
  1531.  
  1532.             CopyMem(nf, DirBuffPtr, CopyLen);
  1533.             BufferSpace -= CopyLen;
  1534.             DirBuffPtr += CopyLen;
  1535.             WriteLen += CopyLen;
  1536.  
  1537.             if (BufferSpace == 0)
  1538.                 {
  1539.                 // Buffer ist voll
  1540.                 TapeBeginWrite(DirWrtTIO, DirBuffer, WriteLen, 0l);
  1541.  
  1542.                 // Warten bis Directory fertig geschrieben
  1543.                 while ( SchreibStatus() && !TapeIOReady(DirWrtTIO) && !CheckWriterTxPort())
  1544.                     SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
  1545.  
  1546.                 TapeErrorCheck(DirWrtTIO, TRUE);
  1547.  
  1548.                 BufferSpace = globDrvDat.CylSize;
  1549.                 DirBuffPtr = DirBuffer;
  1550.                 WriteLen = 0;
  1551.  
  1552.                 if (CopyLen < NfLen)
  1553.                     {
  1554.                     // Rest des <nf> in neuen Buffer kopieren
  1555.                     CopyLen = NfLen - CopyLen;
  1556.                     CopyMem(nf, DirBuffPtr, CopyLen);
  1557.                     BufferSpace -= CopyLen;
  1558.                     DirBuffPtr += CopyLen;
  1559.                     WriteLen += CopyLen;
  1560.                     }
  1561.                 }
  1562.             }
  1563.  
  1564.         nf = nf->NextName;
  1565.         }
  1566.  
  1567.     if (WriteLen > 0)
  1568.         {
  1569.         // letzten, nur teilweise gefüllten Buffer schreiben
  1570.         TapeBeginWrite(DirWrtTIO, DirBuffer, WriteLen, 0l);
  1571.  
  1572.         // Warten bis Directory fertig geschrieben
  1573.         while ( SchreibStatus() && !TapeIOReady(DirWrtTIO) && !CheckWriterTxPort())
  1574.             SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
  1575.  
  1576.         TapeErrorCheck(DirWrtTIO, TRUE);
  1577.         }
  1578.  
  1579.     if (DirWrtTIO)
  1580.         FreeVec(DirWrtTIO);
  1581.     if (DirBuffer)
  1582.         FreeVec(DirBuffer);
  1583.  
  1584.     return error;
  1585. }
  1586.  
  1587.  
  1588. static void RemoveRequests(void)
  1589. {
  1590.     unsigned short n;
  1591.  
  1592.     if (OldestWriteBuffNr == ~0)
  1593.         return;
  1594.  
  1595.     if (DiskFlush(&CylBuff[OldestWriteBuffNr].BufIOReq))
  1596.         {
  1597.         // Notlösung wenn FLUSH nicht geht
  1598.         Forbid();
  1599.         n = OldestWriteBuffNr;
  1600.         do    {
  1601.             CylBuff[n].BufIOReq.iotd_Req.io_Command = CMD_INVALID;
  1602.             if (myOptions.bo_Verify)
  1603.                 CylBuff[n].VerifyReq.iotd_Req.io_Command = CMD_INVALID;
  1604.             NextBuffNr(&n);
  1605.             } while (n != WriteBuffNr);
  1606.         Permit();
  1607.         }
  1608.  
  1609.     n = OldestWriteBuffNr;
  1610.     do    {
  1611.         if (GetBuffStatus(&CylBuff[n]) == LEEREN)
  1612.             {
  1613.             WaitIO((struct IORequest *) &CylBuff[n].BufIOReq);
  1614.  
  1615.             if (myOptions.bo_Verify)
  1616.                 {
  1617.                 WaitIO((struct IORequest *) &CylBuff[n].VerifyReq);
  1618.                 ReqsInUse--;
  1619.                 }
  1620.  
  1621.             SetBuffStatus(&CylBuff[n], VOLL);    // noch voll !
  1622.             ReqsInUse--;
  1623.             }
  1624.         NextBuffNr(&n);
  1625.         } while (ReqsInUse);
  1626. }
  1627.  
  1628.  
  1629. static void RemoveTapeRequests(void)
  1630. {
  1631.     unsigned short n;
  1632.  
  1633.     if (DiskFlush(CylBuff[OldestWriteBuffNr].TapeReq->Req))
  1634.         {
  1635.         // Notlösung wenn FLUSH nicht geht
  1636.         Forbid();
  1637.         n = OldestWriteBuffNr;
  1638.         do    {
  1639.             CylBuff[n].TapeReq->Req->iotd_Req.io_Command = CMD_INVALID;
  1640.             NextBuffNr(&n);
  1641.             } while (n != WriteBuffNr);
  1642.         Permit();
  1643.         }
  1644.  
  1645.     n = OldestWriteBuffNr;
  1646.     do    {
  1647.         if (GetBuffStatus(&CylBuff[n]) == LEEREN)
  1648.             {
  1649.             d(kprintf("%ld in RemoveTapeRequests n=%ld LN_TYPE=%ld\n",
  1650.                 __LINE__, n, CylBuff[n].TapeReq->Req->iotd_Req.io_Message.mn_Node.ln_Type);)
  1651.  
  1652.             WaitIO((struct IORequest *) CylBuff[n].TapeReq->Req);
  1653.  
  1654.             SetBuffStatus(&CylBuff[n], VOLL);    // noch voll !
  1655.             ReqsInUse--;
  1656.             }
  1657.  
  1658.         NextBuffNr(&n);
  1659.         } while (ReqsInUse);
  1660. }
  1661.  
  1662.  
  1663. // Liefert TRUE wenn alle Puffer leer sind
  1664. BOOL WriteReady(void)
  1665. {
  1666.     BOOL erg = TRUE;
  1667.     unsigned short i;
  1668.  
  1669.     if ( ReqsInUse > 0 || GetBuffStatus(&CylBuff[OldestWriteBuffNr]) != LEER )
  1670.         return FALSE;
  1671.  
  1672.     for (i=0; erg && i<BuffCount; i++)
  1673.         erg &= (GetBuffStatus(&CylBuff[i]) == LEER);
  1674.  
  1675.     return erg;
  1676. }
  1677.  
  1678.  
  1679. // Warten auf neue Diskette
  1680. static void WaitForDisk(BOOL AnyChange)
  1681. {
  1682.     d(kprintf("%s %ld: AnyChange=%ld\n", __FUNC__, __LINE__, AnyChange);)
  1683.  
  1684.     while ( Disks[DiskUnit].DcI->DiskStatus != DiskOk && !CheckWriterTxPort())
  1685.         {
  1686.         d(kprintf(__FUNC__ "/%ld  DiskStatus=%ld\n", __LINE__, Disks[DiskUnit].DcI->DiskStatus);)
  1687.  
  1688.         SignalsGot = Wait(WriterSigMask | WriterIOMask | WriterTxPortMask);
  1689.         d(kprintf(__FUNC__ "/%ld  SignalsGot=%08lx\n", __LINE__, SignalsGot);)
  1690.  
  1691.         if (AnyChange)
  1692.             return;
  1693.         }
  1694.  
  1695.     d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1696. }
  1697.  
  1698.  
  1699. static void newdisk(BOOL append, BOOL SameDiskNr)
  1700. {
  1701.     struct SignalSemaphore *Sema;
  1702.  
  1703.     assert(DiskUnit == NO_DRIVE || (DiskUnit >= 0 && DiskUnit < NDisk));
  1704.  
  1705.     if (DiskUnit != NO_DRIVE && Disks[DiskUnit].TapeReq == NULL)
  1706.          MotorOff(Disks[DiskUnit].diskreq);
  1707.  
  1708.     // immer mit myOptions.bo_FirstUnit anfangen !
  1709.     if (disknr == 0)
  1710.         DiskUnit = myOptions.bo_FirstUnit;
  1711.  
  1712.     if (!SameDiskNr && disknr+1 == UCHAR_MAX)
  1713.         {
  1714.         alarm(GetString(MSG_ERROR_MAXDISK), UCHAR_MAX);
  1715.         SendWriterRx(WMR_ABORTMAIN);
  1716.         return;
  1717.         }
  1718.  
  1719.     if (append && Disks[DiskUnit].TapeReq &&
  1720.         !(Disks[DiskUnit].TapeReq->DrvDat->Properties.canLocate
  1721.         || Disks[DiskUnit].TapeReq->DrvDat->Properties.SpaceBack))
  1722.         {
  1723.         // mit diesem Laufwerk geht kein APPEND
  1724.         alarm(GetString(MSG_NOAPPEND));
  1725.         SendWriterRx(WMR_ABORTMAIN);
  1726.         return;
  1727.         }
  1728.  
  1729.     if (!SameDiskNr)
  1730.         {
  1731.         if (disknr)
  1732.             {
  1733.             // Laufwerk wechseln wenn möglich
  1734.             Sema = &Disks[DiskUnit].DcI->Sema;
  1735.             ObtainSemaphore(Sema);
  1736.             if (myOptions.bo_SecondUnit != NO_DRIVE)
  1737.                 {
  1738.                 Disks[DiskUnit].DcI->DiskStatus = DiskObsolete;
  1739.                 if (disknr)
  1740.                     Disks[DiskUnit].DcI->NextDiskNr += 2;
  1741.  
  1742.                 // ausgebrauchtes Medium markieren
  1743.                 sprintf(zeile, "%s: %s #%-3d",
  1744.                     Disks[DiskUnit].DOSName,
  1745.                     GetString(toTape ? MSG_TAPE : MSG_DISK), disknr);
  1746.                 DiskText(zeile, 2, 0, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
  1747.  
  1748.                 DiskUnit = (DiskUnit == myOptions.bo_FirstUnit) ? myOptions.bo_SecondUnit : myOptions.bo_FirstUnit;
  1749.  
  1750.                 if (Disks[DiskUnit].TapeReq)
  1751.                     Disks[DiskUnit].TapeReq->Medium = Disks[DiskUnit].DcI->TapeReq->Medium;
  1752.                 }
  1753.             else
  1754.                 {
  1755.                 Disks[DiskUnit].DcI->NextDiskNr++;
  1756.                 }
  1757.             ReleaseSemaphore(Sema);
  1758.             }
  1759.  
  1760.         LockWriteDisk();
  1761.         WriteDisk.Offset = 0;
  1762.         UnlockWriteDisk();
  1763.  
  1764.         if (InitBufReq())
  1765.             {
  1766.             SendWriterRx(WMR_ABORTMAIN);
  1767.             return;
  1768.             }
  1769.  
  1770.         disknr++;
  1771.         }
  1772.  
  1773.     SetBusyPointer(aktWindow, TRUE);
  1774.     do    {
  1775.         while (Disks[DiskUnit].DcI->DiskStatus == CheckingDisk)
  1776.             WaitForDisk(TRUE);        // Warten bis Check des Laufwerks beendet
  1777.  
  1778.         d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1779.  
  1780.         if (Disks[DiskUnit].DcI->DiskStatus != DiskOk)
  1781.             // Wenn keine neue Diskette bereit
  1782.             {
  1783.             SendWriterRx(WMR_OPENMAINWINDOW);
  1784.             DisplayBeep(aktWindow->WScreen);
  1785.  
  1786.             ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
  1787.             if (Disks[DiskUnit].DcI->DiskStatus != WaitingForDisk)
  1788.                 {
  1789.                 if (Disks[DiskUnit].TapeReq)
  1790.                     {
  1791.                     sprintf(zeile, GetString(append ? MSG_INSERT_LASTTAPE :
  1792.                             MSG_INSERT_TAPE_N),
  1793.                         Disks[DiskUnit].DOSName,
  1794.                         Disks[DiskUnit].DcI->NextDiskNr);
  1795.                     }
  1796.                 else
  1797.                     {
  1798.                     sprintf(zeile, GetString(append ? MSG_INSERT_LASTDISK :
  1799.                             MSG_INSERT_DISK_N),
  1800.                         Disks[DiskUnit].DOSName,
  1801.                         Disks[DiskUnit].DcI->NextDiskNr);
  1802.                     }
  1803.  
  1804.                 Disks[DiskUnit].DcI->DiskStatus = WaitingForDisk;
  1805.  
  1806.                 // Eingabe-Aufforderung anzeigen
  1807.                 DiskText(zeile, 3, 2, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
  1808.                 }
  1809.             ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
  1810.  
  1811.             WaitForDisk(FALSE);        // Warten bis neue Diskette bereit
  1812.             d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1813.             }
  1814.  
  1815.         d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1816.  
  1817.         CheckWriterTxPort();
  1818.  
  1819.         CheckOldProtFile(&Disks[DiskUnit]);
  1820.  
  1821.         d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1822.  
  1823.         if (append)
  1824.             {
  1825.             switch (CheckAppendDisk(DiskUnit))
  1826.                 {
  1827.             case NOBACKUPDISK:
  1828.                 sprintf(zeile, GetString(Disks[DiskUnit].TapeReq 
  1829.                         ? MSG_NO_BACKUPTAPE
  1830.                         : MSG_NO_BACKUPDISK),
  1831.                     Disks[DiskUnit].DOSName);
  1832.  
  1833.                 ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
  1834.                 Disks[DiskUnit].DcI->DiskStatus = DiskObsolete;
  1835.                 ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
  1836.                 break;
  1837.             case NOTLASTDISK:
  1838.                 sprintf(zeile, GetString(Disks[DiskUnit].TapeReq
  1839.                         ? MSG_NOTLASTTAPE
  1840.                         : MSG_NOTLASTDISK),
  1841.                     Disks[DiskUnit].DOSName);
  1842.  
  1843.                 ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
  1844.                 Disks[DiskUnit].DcI->DiskStatus = DiskObsolete;
  1845.                 ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
  1846.             case OK:
  1847.                 break;
  1848.                 }
  1849.             }
  1850.  
  1851.         d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1852.         } while (Disks[DiskUnit].DcI->DiskStatus != DiskOk && !CheckWriterTxPort());
  1853.  
  1854.     SetBusyPointer(aktWindow, FALSE);
  1855.  
  1856.     d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1857.  
  1858.     LockWriteDisk();
  1859.     WriteDisk.nr = disknr;
  1860.     UnlockWriteDisk();
  1861.  
  1862.     d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1863.  
  1864.     ObtainSemaphore(&Disks[DiskUnit].DcI->Sema);
  1865.     Disks[DiskUnit].DcI->DiskStatus = DiskInUse;
  1866.     if (Disks[DiskUnit].DcI->isTape)
  1867.         Disks[DiskUnit].TapeReq->withQFA = Disks[DiskUnit].DcI->withQFA;
  1868.     ReleaseSemaphore(&Disks[DiskUnit].DcI->Sema);
  1869.  
  1870.     d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1871.  
  1872.     if (!append && Disks[DiskUnit].TapeReq)
  1873.         {
  1874.         // Band zurückspulen (steht nach CheckOldProtFile auf Block 1!
  1875.         TapeRewind(Disks[DiskUnit].TapeReq); // ###
  1876.  
  1877.         if (Disks[DiskUnit].TapeReq->withQFA)
  1878.             {
  1879.             // Select Data Partition
  1880.             TapeSetDataPartition(Disks[DiskUnit].TapeReq);
  1881.             }
  1882.         }
  1883.     d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  1884. }
  1885.  
  1886.  
  1887. // Disk/Tape-Label prüfen: wenn ein Backupmedium (von einer älteren Sicherung)
  1888. // eingelegt ist, dann ggf. das alte Protokollfile löschen!
  1889. void CheckOldProtFile(struct DiskFlags *Dsk)
  1890. {
  1891.     short error = 0;
  1892.     static struct DiskLabel Label;
  1893.  
  1894.     ASSERT_VALID(Dsk);
  1895.  
  1896.     SetBusyPointer(aktWindow, TRUE);
  1897.  
  1898.     if (Dsk->TapeReq)
  1899.         {
  1900.         if (Dsk->DcI)
  1901.             Dsk->TapeReq->withQFA = Dsk->DcI->withQFA;
  1902.  
  1903.         error = TapeRewind(Dsk->TapeReq) ||
  1904.             TapeSetDataPartition(Dsk->TapeReq) ||
  1905.             TapeRead(Dsk->TapeReq, (char *) &Label, sizeof(Label));
  1906.         }
  1907.     else
  1908.         Label = Dsk->DcI->Label;
  1909.  
  1910.     if (!error && (strcmp(Label.Id, DISKID) == 0) && 
  1911.             ComputeLabelCheckSum(&Label) == 0l &&
  1912.             Label.ProtFileName[0] )
  1913.         {
  1914.         if (0 == access(Label.ProtFileName, F_OK) &&
  1915.                 DeleteFile(Label.ProtFileName))
  1916.             {
  1917.             // Info: altes Protofile wurde gelöscht
  1918.             PostError(TRUE, MSGPRI_Info, GetString(MSG_DELETED_FILE), Label.ProtFileName);
  1919.             }
  1920.         }
  1921.  
  1922.     SetBusyPointer(aktWindow, FALSE);
  1923. }
  1924.  
  1925.  
  1926. static short ReadQFALabel(struct DiskFlags *Dsk, struct DiskLabel *Label)
  1927. {
  1928.     short error;
  1929.  
  1930.     ASSERT_VALID(Dsk);
  1931.     ASSERT_VALID(Label);
  1932.  
  1933.     (error = TapeRewind(Dsk->TapeReq)) ||
  1934.       (error = TapeSetDirectoryPartition(Dsk->TapeReq)) ||
  1935.       (error = TapeRead(Dsk->TapeReq, (char *) Label, Dsk->DrvDat.BlockSize));
  1936.  
  1937.     if (error || !Label->withQFA)
  1938.         {
  1939.         // nochmal probieren ohne QFA !
  1940.         InfoLineHandle Pil;
  1941.  
  1942.         Pil = PushInfoLine(GetString(MSG_READINGTAPELABEL));
  1943.  
  1944.         TapeRewind(Dsk->TapeReq);
  1945.         TapeSetDataPartition(Dsk->TapeReq);
  1946.         TapeInitQFA(Dsk->TapeReq, FALSE);
  1947.  
  1948.         Dsk->TapeReq->withQFA = FALSE;
  1949.         PopInfoLine(&Pil);
  1950.         }
  1951.  
  1952.     // Bandposition direkt am Directory-Anfang
  1953.  
  1954.     return error;
  1955. }
  1956.  
  1957.  
  1958. static short ReadTapeLabel(struct DiskFlags *Dsk, struct DiskLabel *Label)
  1959. {
  1960.     short error;
  1961.  
  1962.     ASSERT_VALID(Dsk);
  1963.     ASSERT_VALID(Label);
  1964.  
  1965.     error = TapeRewind(Dsk->TapeReq);
  1966.     if (Dsk->TapeReq->DrvDat->Properties.SpaceBack)
  1967.         {
  1968.         // Label schnell lesen (zum Bandende und dann 1 Sektor zurück),
  1969.         // geht aber nur wenn das Bandlaufwerk SPACE zurück kann
  1970.         if (!error)
  1971.             error = TapeSpace(Dsk->TapeReq, 0l, 3);    // zum Bandende
  1972.         if (!error)
  1973.             {
  1974.             do    {
  1975.                 // wenn beim SPACE(-1) eine Filemark erreicht wird,
  1976.                 // steht danach das Band VOR der FileMark, dann wird
  1977.                 // der SPACE(-1) einfach wiederholt
  1978.  
  1979.                 error = TapeSpace(Dsk->TapeReq, -1l, 0);    // 1 Block zurück zum Anfang Label
  1980.                 } while (error && Dsk->TapeReq->Cmd.scsi_Status == 2
  1981.                     && Dsk->TapeReq->Cmd.scsi_SenseActual
  1982.                     && Dsk->TapeReq->Sense[2] & 0x80);
  1983.             }
  1984.  
  1985.         // Label lesen
  1986.         if (!error)
  1987.             error = TapeRead(Dsk->TapeReq, (char *) Label, Dsk->DrvDat.BlockSize);
  1988.  
  1989.         // Bandposition 2 Blöcke nach Directory-Ende
  1990.         if (!error)
  1991.             {
  1992.             // das Directory wird immer in <CylSize> langen Blöcken aufgezeichnet!
  1993.             long DirLen;
  1994.  
  1995.             DirLen = ceildiv(Label->DirLen, globDrvDat.CylSize / globDrvDat.BlockSize)
  1996.                 * globDrvDat.CylSize / globDrvDat.BlockSize;
  1997.  
  1998.             error = TapeSpace(Dsk->TapeReq, -DirLen - 1, 0);    // zum Directory-Anfang
  1999.             }
  2000.         }
  2001.     else
  2002.         {
  2003.         TapeSpace(Dsk->TapeReq, 1, 0);    // Dummy-Label auf Block 0 überspringen
  2004.         TapeWaitNotBusy(Dsk->TapeReq);
  2005.  
  2006.         do    {
  2007.             // hier hilft alles nichts....
  2008.             // sequentiell alles lesen bis wir auf das Label stoßen.
  2009.             // Bei diesem dummen Bandlaufwerk geht sowieso kein Append
  2010.  
  2011.             error = TapeRead(Dsk->TapeReq, (char *) Label, Dsk->DrvDat.BlockSize);
  2012.  
  2013.             } while (!error && !((strcmp(Label->Id, "BACKUP") == 0)
  2014.                 && ComputeLabelCheckSum(Label) != 0l
  2015.                 && Label->DirLen) && !CheckWriterTxPort());
  2016.  
  2017.         // Bandposition direkt am Directory-Anfang
  2018.         }
  2019.  
  2020.     return error;
  2021. }
  2022.  
  2023.  
  2024. // Prüft Diskette (nur für Append).
  2025. // return OK,  wenn Disk Ok (letzte Backup-Disk)
  2026. // return NOBACKUPDISK, wenn Append und keine Backup-Disk.
  2027. // return NOTLASTDISK, wenn Append und nicht die letzte Disk
  2028. static enum TestDiskResult CheckAppendDisk(short unit)
  2029. {
  2030.     struct IOExtTD req;
  2031.     short error;
  2032.     enum TestDiskResult erg = OK;
  2033.     struct DiskLabel *Label;
  2034.  
  2035.     assert(unit >= 0 && unit < NDisk);
  2036.  
  2037.     if (Disks[unit].TapeReq)
  2038.         {
  2039.         InfoLineHandle Pil;
  2040.         static struct DiskLabel TapeLabel;
  2041.  
  2042.         Disks[unit].TapeReq->withQFA = Disks[unit].DcI->withQFA;
  2043.  
  2044.         SetBusyPointer(aktWindow, TRUE);
  2045.         Pil = PushInfoLine(GetString(Disks[unit].TapeReq->withQFA ?
  2046.             MSG_READING_QFA_TAPELABEL : MSG_READINGTAPELABEL));
  2047.  
  2048.         if (Disks[unit].TapeReq->withQFA)
  2049.             {
  2050.             // QFA Tape Label lesen
  2051.             error = ReadQFALabel(&Disks[unit], &TapeLabel);
  2052.             }
  2053.  
  2054.         if (!Disks[unit].TapeReq->withQFA)
  2055.             {
  2056.             // Tape Label lesen ohne QFA
  2057.             error = ReadTapeLabel(&Disks[unit], &TapeLabel);
  2058.             }
  2059.  
  2060.         if (error)
  2061.             erg = UNREADABLE;
  2062.  
  2063.         PopInfoLine(&Pil);
  2064.         Label = &TapeLabel;
  2065.         }
  2066.     else
  2067.         Label = &Disks[unit].DcI->Label;
  2068.  
  2069.     req = *Disks[unit].diskreq;
  2070.  
  2071.     if (Label->LabelCheckSum != 0L && ComputeLabelCheckSum(Label) != 0l)
  2072.         {
  2073.         PostError(TRUE, MSGPRI_Warning, GetString(MSG_CHECKSUMERROR_DISKLABEL), Disks[unit].DOSName);
  2074.         erg = NOBACKUPDISK;
  2075.         }
  2076.     else if (!Label->lastdisk)
  2077.         {
  2078.         erg = NOTLASTDISK;    // Nicht die letzte Disk
  2079.         }
  2080.     else if (strcmp(Label->Id, DISKID) == 0)
  2081.         {
  2082.         // Letzte Backup-Disk gefunden, jetzt altes Directory lesen
  2083.         LockWriteDisk();
  2084.  
  2085.         // richtige Disk-Nummer anzeigen (aus Label)
  2086.         if (Disks[unit].TapeReq)
  2087.             {
  2088.             char Msg2[80];
  2089.  
  2090.             sprintf(Msg2, "%s: %s #%-3d",
  2091.                 Disks[unit].DOSName,
  2092.                 GetString(MSG_TAPE_LABEL),
  2093.                 Label->diskno);
  2094.  
  2095.             // "TAPE: Tape #999   abcdefgh"
  2096.             sprintf(zeile, "%s %*s", Msg2, 63-37 - strlen(Msg2),
  2097.                 TapeFormat(Disks[unit].TapeReq));
  2098.  
  2099.         //    sprintf(zeile, "%s: %s #%-3d    %-8.8s",
  2100.         //        Disks[unit].DOSName,
  2101.         //        GetString(MSG_TAPE_LABEL),
  2102.         //        Label->diskno,
  2103.         //        TapeFormat(Disks[unit].TapeReq));
  2104.             }
  2105.         else
  2106.             {
  2107.             sprintf(zeile, "%s: %s #%-3d",
  2108.                 Disks[unit].DOSName,
  2109.                 GetString(MSG_DISK_LABEL),
  2110.                 Label->diskno);
  2111.             }
  2112.         DiskText(zeile, ~0, ~0, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
  2113.  
  2114.         if (Label->ProtFileName[0])
  2115.             strcpy(myOptions.bo_ProtFileName, Label->ProtFileName);
  2116.  
  2117.         ReadDisk.Offset = WriteDisk.Offset = Label->EndOfData;
  2118.  
  2119.         if (!ReadDir(Label, unit))
  2120.             {
  2121.             UnlockWriteDisk();
  2122.  
  2123.             SetBusyPointer(aktWindow, FALSE);
  2124.             return NOBACKUPDISK;
  2125.             }
  2126.  
  2127.         ReadDisk.nr = disknr = Label->diskno;
  2128.         Disks[unit].DcI->NextDiskNr = disknr;
  2129.  
  2130.         // Startzeit von altem Satz übernehmen !
  2131.         CopyMem(Label->BackupZeit, StartZeit, sizeof(StartZeit) );
  2132.         ShowBackupTime();
  2133.  
  2134.         if (Disks[unit].TapeReq)
  2135.             {
  2136.             // Neue Sicherung wird nach dem alten Directory und dem
  2137.             // alten Label angehängt !
  2138.             InfoLineHandle Pil;
  2139.  
  2140.             // das Directory wird immer in <CylSize> langen Blöcken aufgezeichnet!
  2141.             long DirLen;
  2142.  
  2143.             if (Disks[unit].TapeReq->withQFA)
  2144.                 Label->DirAnf = Label->RealDirAnf;
  2145.  
  2146.             DirLen = ceildiv(Label->DirLen, globDrvDat.CylSize / globDrvDat.BlockSize)
  2147.                 * globDrvDat.CylSize / globDrvDat.BlockSize;
  2148.  
  2149.             ReadDisk.Offset = WriteDisk.Offset =
  2150.                 (Label->DirAnf + DirLen + 1) * globDrvDat.BlockSize;
  2151.  
  2152.             Pil = PushInfoLine(GetString(MSG_POSITIONING_EOT));
  2153.  
  2154.             if (Disks[unit].TapeReq->withQFA)
  2155.                 {
  2156.                 // Select Data Partition
  2157.                 TapeRewind(Disks[unit].TapeReq);
  2158.                 TapeSetDataPartition(Disks[unit].TapeReq);
  2159.                 }
  2160.             // Positionieren ans Bandende
  2161.             TapeSpace(Disks[unit].TapeReq, 0l, 3);
  2162.  
  2163.             readoffset = 0;
  2164.             PopInfoLine(&Pil);
  2165.             }
  2166.         else
  2167.             {
  2168.             readoffset = ReadDisk.Offset % globDrvDat.CylSize;
  2169.             if (readoffset)
  2170.                 {
  2171.                 // Jetzt muß der erste Buffer teilweise gefüllt werden
  2172.                 // damit die neuen Files nahtlos anschließen können
  2173.                 struct Buffer *buff;
  2174.                 long StartCyl;
  2175.  
  2176.                 if (CylBuff[0].dbp == NULL)
  2177.                     AllocDiskBuffer();
  2178.  
  2179.                 buff = GetBuffer();    // ersten Buffer holen
  2180.                 SetBuffStatus(buff, FUELLEN);
  2181.  
  2182.                 StartCyl = sectotrack(ReadDisk.Offset / globDrvDat.BlockSize);
  2183.                 WriteDisk.Offset = StartCyl*globDrvDat.CylSize;
  2184.  
  2185.                 error = TRead(&(buff->BufIOReq),
  2186.                     WriteDisk.Offset/globDrvDat.BlockSize, buff->dbp, globDrvDat.CylSize);
  2187.  
  2188.                 while (error)
  2189.                     error = DiskError(&(buff->BufIOReq), GetString(MSG_READING), error, FALSE);
  2190.                 }
  2191.             }
  2192.  
  2193.         UnlockWriteDisk();
  2194.         }
  2195.  
  2196.     SetBusyPointer(aktWindow, FALSE);
  2197.  
  2198.     return erg;
  2199. }
  2200.  
  2201.  
  2202. // Liest das Directory von der aktuellen Diskette 
  2203. // und hängt alle gefundenen Einträge an die aktuelle File-Liste an.
  2204. // Return: Success, TRUE wenn Ok, FALSE nach Fehler
  2205. static short ReadDir(struct DiskLabel *Label, short unit)
  2206. {
  2207.     char *DirBuff;
  2208.     unsigned long DirBuffLen;
  2209.     struct NameField *akt_nf;
  2210.     struct OldNameField *old_nf;
  2211.     long error;
  2212.     short i;
  2213.     long n, DirCks, *DirPtr;
  2214.  
  2215.     ASSERT_VALID(Label);
  2216.     assert(unit >= 0 && unit < NDisk);
  2217.  
  2218.     DirBuffLen = Label->DirLen * globDrvDat.BlockSize;
  2219.     DirBuff = (char *) AllocVec(DirBuffLen, globDrvDat.BufMemType|MEMF_CLEAR);
  2220.     if (DirBuff == NULL)
  2221.         {
  2222.         alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "DirBuff", DirBuffLen);
  2223.         SendWriterRx(WMR_ABORTMAIN);
  2224.         return FALSE;
  2225.         }
  2226.  
  2227.     if (Disks[unit].TapeReq)
  2228.         {
  2229.         InfoLineHandle Pil;
  2230.  
  2231.         Pil = PushInfoLine(GetString(Disks[unit].TapeReq->withQFA
  2232.             ? MSG_READING_QFA_TAPEDIR : MSG_READINGTAPEDIR));
  2233.  
  2234.         // Band steht am immer am Directory-Anfang
  2235.         error = TapeRead(Disks[unit].TapeReq, DirBuff, Label->DirLen*globDrvDat.BlockSize);
  2236.  
  2237.         while (error)
  2238.             {
  2239.             error = TapeError(Disks[unit].TapeReq, &Disks[unit], GetString(MSG_READING_DIRECTORY), 
  2240.                     error, FALSE, TRUE);
  2241.             }
  2242.         PopInfoLine(&Pil);
  2243.         }
  2244.     else
  2245.         {
  2246.         error = TRead(Disks[unit].diskreq, Label->DirAnf, DirBuff, DirBuffLen);
  2247.  
  2248.         while (error)
  2249.             error = DiskError(Disks[unit].diskreq, GetString(MSG_READING), error, FALSE);
  2250.         }
  2251.  
  2252.     if (error)
  2253.         {
  2254.         FreeVec(DirBuff);
  2255.         return FALSE;
  2256.         }
  2257.  
  2258.     // Directory-Prüfsumme nachrechnen
  2259.     for (n=DirBuffLen/sizeof(long), DirPtr=(long *) DirBuff, DirCks=0L;
  2260.             n; n--)
  2261.         {
  2262.         DirCks += *DirPtr++;
  2263.         }
  2264.  
  2265.     if (Label->DirCheckSum != 0L && DirCks != Label->DirCheckSum)
  2266.         {
  2267.         PostError(TRUE, MSGPRI_Warning, GetString(MSG_CHECKSUMERROR_DIRECTORY), Disks[unit].DOSName);
  2268.         FreeVec(DirBuff);
  2269.         return FALSE;
  2270.         }
  2271.  
  2272.     // Wenn das letzte File auf der Diskette das alte Protokollfile
  2273.     // ist, wird es weggelassen. Dabei wird der ehemalige Anfang des
  2274.     // Protokollfiles als Startpunkt für die Zusatzsicherung gemerkt.
  2275.     // Ist das alte Protokollfile nicht komplett auf dieser Diskette
  2276.     // (Extension > 0), wird es einfach mit übernommen, weil es mir
  2277.     // zu mühsam ist, dann die Diskette mit dem Anfang vom
  2278.     // Protokollfile anzufordern und zu verifizieren.
  2279.  
  2280.     switch (Label->RecordedFormat)
  2281.         {
  2282.     case 0:
  2283.         old_nf=(struct OldNameField *) DirBuff;
  2284.  
  2285.         for (i=0; i<Label->DirAnz; i++)
  2286.             {
  2287.             // Alle Filenamen eintragen
  2288.             long len;
  2289.  
  2290.             if (Label->Version < VERS_OFFSET)
  2291.                 old_nf->Offset *= globDrvDat.BlockSize;
  2292.         
  2293.             if (i != Label->DirAnz-1 || stricmp(old_nf->Name, myOptions.bo_ProtFileName) != 0
  2294.                       || old_nf->Extension != 0)
  2295.                 {
  2296.                 struct NameField *NewName;
  2297.  
  2298.                 NewName = calloc(NF_LEN(old_nf), 1);
  2299.                 if (NewName == NULL)
  2300.                     {
  2301.                     FreeVec(DirBuff);
  2302.                     alarm(GetString(MSG_OUTOFMEMORY), __FUNC__, "NewName", NF_LEN(old_nf));
  2303.                     SendWriterRx(WMR_ABORTMAIN);
  2304.                     return FALSE;
  2305.                     }
  2306.  
  2307.                 NewName->NextName = NULL;
  2308.                 NewName->isComplete = old_nf->Complete;
  2309.                 NewName->CompressionType = (old_nf->Flags & FIBF_COMPRESS) ?
  2310.                     COMPRESS_INTERNAL : COMPRESS_NONE;
  2311.                 NewName->isHardLink = (old_nf->Flags & FIBF_HARDLINK) ? 1 : 0;
  2312.                 NewName->isSoftLink = (old_nf->Flags & FIBF_SOFTLINK) ? 1 : 0;
  2313.                 NewName->isDir = 0;
  2314.                 NewName->Extension = old_nf->Extension;
  2315.                 NewName->SessionNr = 1;
  2316.                 NewName->Offset = old_nf->Offset;
  2317.                 NewName->FileLen = old_nf->FileLen;
  2318.                 NewName->RecordedLen = 0l;        // wird später getrennt bestimmt
  2319.                 NewName->FileDate = old_nf->FileDate;
  2320.                 NewName->Protection = old_nf->Flags & FILEPROT;
  2321.                 NewName->NameLen = old_nf->NameLen;
  2322.                 memcpy(NewName->Name, old_nf->Name, old_nf->NameLen+1);
  2323.  
  2324.                 // nur wegen der Rückwärts-Kompatibilität
  2325.                 NewName->isCompressed = NewName->CompressionType == COMPRESS_INTERNAL;
  2326.  
  2327.                 EnterName(NULL, old_nf->Offset, "", NewName);
  2328.                 aktNameDone();
  2329.  
  2330.                 free(NewName);
  2331.                 }
  2332.             else
  2333.                 {
  2334.                 Label->EndOfData = ReadDisk.Offset = WriteDisk.Offset = old_nf->Offset;
  2335.                 }
  2336.  
  2337.             len = sizeof(struct OldNameField) + old_nf->NameLen;
  2338.  
  2339.             aktName->isComplete = 1;
  2340.  
  2341.             old_nf = (struct OldNameField *) ((char *) old_nf + 2 * ceildiv(len, 2));
  2342.             }
  2343.  
  2344.         CurrentSessionNr = 2;
  2345.  
  2346.         // jetzt alle physikalischen Filelängen bestimmen
  2347.         for (akt_nf=(struct NameField *) ReadDisk.DirBuffers.mlh_Head;
  2348.                 akt_nf; akt_nf=akt_nf->NextName)
  2349.             {
  2350.             akt_nf->RecordedLen = FileLength(Label, akt_nf);
  2351.             ComputeNfChecksum(akt_nf);        // Prüfsumme in NameField korrigieren!
  2352.             }
  2353.         break;
  2354.     case 1:
  2355.         akt_nf=(struct NameField *) DirBuff;
  2356.  
  2357.         for (i=0; i<Label->DirAnz; i++)
  2358.             {
  2359.             // Alle Filenamen eintragen
  2360.             unsigned long len;
  2361.  
  2362.             if (i != Label->DirAnz-1 || stricmp(akt_nf->Name, myOptions.bo_ProtFileName) != 0
  2363.                       || akt_nf->Extension != 0)
  2364.                 {
  2365.                 if (akt_nf->CompressionType == COMPRESS_NONE &&
  2366.                         akt_nf->isCompressed)
  2367.                     akt_nf->CompressionType = COMPRESS_INTERNAL;
  2368.  
  2369.                 EnterName(NULL, akt_nf->Offset, "", akt_nf);
  2370.                 aktNameDone();
  2371.                 }
  2372.             else
  2373.                 {
  2374.                 ReadDisk.Offset = WriteDisk.Offset = akt_nf->Offset;
  2375.                 }
  2376.  
  2377.             len = NF_LEN(akt_nf);
  2378.  
  2379.             if (aktName->NameLen > FMSIZE)
  2380.                 {
  2381.                 FreeVec(DirBuff);
  2382.                 alarm("%s (1): %s NameLen=%ld", __FUNC__, aktName->Name, aktName->NameLen);
  2383.                 return FALSE;
  2384.                 }
  2385.  
  2386.             if (aktName->SessionNr == 0)
  2387.                 aktName->SessionNr = 1;
  2388.  
  2389.             aktName->isComplete = 1;
  2390.             ComputeNfChecksum(aktName);        // Prüfsumme in NameField korrigieren!
  2391.  
  2392.             akt_nf = (struct NameField *) ((char *) akt_nf + 2 * ceildiv(len, 2));
  2393.             }
  2394.  
  2395.         CurrentSessionNr = aktName->SessionNr + 1;
  2396.         break;
  2397.     default:
  2398.         alarm(GetString(MSG_UNKNOWN_DIRECTORY_FORMAT));
  2399.         SendWriterRx(WMR_ABORTMAIN);
  2400.         break;
  2401.         }
  2402.  
  2403.     FilesProcessed = BytesProcessed = 0;            // Zähler rückstellen
  2404.  
  2405.     FreeVec(DirBuff);
  2406.  
  2407.     return TRUE;
  2408. }
  2409.  
  2410.  
  2411. static void ShowCyl(const struct IOExtTD *Req, short DiskNr)
  2412. {
  2413.     char zeile[40];
  2414.     long sektor;
  2415.  
  2416.     ASSERT_VALID(Req);
  2417.  
  2418.     if (!toTape)
  2419.         {
  2420.         sektor = Req->iotd_Req.io_Offset / globDrvDat.BlockSize;
  2421.  
  2422.         sprintf(zeile, "%s: %s #%-3d Cyl #%-3d",
  2423.                 Disks[DiskUnit].DOSName, GetString(MSG_DISK_LABEL),
  2424.                 DiskNr, sectotrack(sektor) );
  2425.         DiskText(zeile, ~0, ~0, (DiskUnit == myOptions.bo_FirstUnit) ? 1 : 2);
  2426.         }
  2427. }
  2428.  
  2429.  
  2430. // Öffnen der belegten Devices.
  2431. // liefert TRUE wenn alles Ok, FALSE nach Fehler.
  2432. static short OpenDisks(void)
  2433. {
  2434.     Disks[myOptions.bo_FirstUnit].diskreq = OpenDisk(&Disks[myOptions.bo_FirstUnit], TRUE);
  2435.     if (Disks[myOptions.bo_FirstUnit].diskreq == NULL)
  2436.         return FALSE;
  2437.  
  2438.     if (Disks[myOptions.bo_FirstUnit].TapeReq)
  2439.         {
  2440.         Disks[myOptions.bo_FirstUnit].TapeReq->Req = Disks[myOptions.bo_FirstUnit].diskreq;
  2441.         myOptions.bo_SecondUnit = NO_DRIVE;        // nur eine Unit bei TAPE
  2442.         }
  2443.  
  2444.     if (myOptions.bo_SecondUnit != NO_DRIVE)
  2445.         {
  2446.         Disks[myOptions.bo_SecondUnit].diskreq = OpenDisk(&Disks[myOptions.bo_SecondUnit], TRUE);
  2447.         if (Disks[myOptions.bo_SecondUnit].diskreq == NULL)
  2448.             return FALSE;
  2449.         }
  2450.     return TRUE;
  2451. }
  2452.  
  2453.  
  2454. // Lesen von Daten aus der Partition <pInfo>
  2455. // liefert die Anzahl gelesene Bytes zurück.
  2456. ULONG ReadPartition(struct PartitionInfo *pInfo, ULONG ReadLen, APTR Buffer)
  2457. {
  2458.     ULONG Result = 0;
  2459.     ULONG cLen;
  2460.  
  2461.     while (ReadLen)
  2462.         {
  2463.         if (0 == pInfo->BytesInTrackBuff)
  2464.             {
  2465.             short error;
  2466.  
  2467.  
  2468.             cLen = min(pInfo->PartSize, pInfo->TrackBuffSize);
  2469.  
  2470.             error = TRead0(pInfo->PartIO, pInfo->CurrentOffset, pInfo->TrackBuff, cLen);
  2471.             while (error)
  2472.                 error = DiskError(pInfo->PartIO, GetString(MSG_READING), error, FALSE);
  2473.  
  2474.             pInfo->BytesInTrackBuff = cLen;
  2475.             pInfo->CurrentOffset += cLen;
  2476.             pInfo->PartSize -= cLen;
  2477.             pInfo->TBOffset = 0;
  2478.             }
  2479.  
  2480.         cLen = min(ReadLen, pInfo->BytesInTrackBuff);
  2481.         CopyMem((char *) pInfo->TrackBuff + pInfo->TBOffset, Buffer, cLen);
  2482.  
  2483.         ReadLen -= cLen;
  2484.         pInfo->BytesInTrackBuff -= cLen;
  2485.         pInfo->TBOffset += cLen;
  2486.         Result += cLen;
  2487.         Buffer = ((char *) Buffer) + cLen;
  2488.         }
  2489.  
  2490.     return Result;
  2491. }
  2492.  
  2493.  
  2494. // Directory-Prüfsumme berechnen
  2495. static unsigned long ComputeDirChecksum(const struct Disk *Dsk, unsigned long DirLen)
  2496. {
  2497.     unsigned long l, DirCheckSum;
  2498.     struct DirBlock *aktblock;
  2499.  
  2500.     for (l = DirLen * globDrvDat.BlockSize / sizeof(long), DirCheckSum=0l,
  2501.         aktblock = (struct DirBlock *) Dsk->DirBuffers.mlh_Head;
  2502.         l && aktblock != (struct DirBlock *) &(Dsk->DirBuffers.mlh_Tail);
  2503.         aktblock = (struct DirBlock *) aktblock->db_Node.mln_Succ)
  2504.         {
  2505.         unsigned long Len;
  2506.         long *DirPtr;
  2507.  
  2508.         DirPtr = (long *) aktblock->Data;
  2509.         Len = aktblock->DataLength / sizeof(long);
  2510.  
  2511.         while (l && Len)
  2512.             {
  2513.             DirCheckSum += *DirPtr++;
  2514.             l--;
  2515.             Len--;
  2516.             }
  2517.         }
  2518.  
  2519.     return DirCheckSum;
  2520. }
  2521.  
  2522.  
  2523. // Ergebnis: TRUE wenn abgebrochen werden muß
  2524. static BOOL CheckWriterTxPort(void)
  2525. {
  2526.     struct WriterMessage *Msg;
  2527.  
  2528.     if (NULL == WriterTxPort)
  2529.         return FALSE;
  2530.  
  2531.     while (Msg = (struct WriterMessage *) GetMsg(WriterTxPort))
  2532.         {
  2533.         unsigned short Class;
  2534.  
  2535.         Class = Msg->wm_Class;
  2536.  
  2537.         ReplyMsg((struct Message *) Msg);
  2538.  
  2539.         switch (Class)
  2540.             {
  2541.         case WM_ABORT:
  2542.             WriterAbort = TRUE;
  2543.         case WM_SHUTDOWN:
  2544.             d(kprintf(">>received WM_ABORT oder WM_SHUTDOWN\n");)
  2545.             WriterRunning = FALSE;
  2546.             if (WriterAbort)
  2547.                 longjmp(AbortJumpBuf, 0);
  2548.             break;
  2549.         case WM_BEGINWRITE:
  2550.             d(kprintf(">>received WM_BEGINWRITE\n");)
  2551.             WriterWarten = FALSE;
  2552.             break;
  2553.         case WM_NEWDISK:
  2554.             d(kprintf(">>received WM_NEWDISK\n");)
  2555.             newdisk(myOptions.bo_Append, FALSE);
  2556.             d(kprintf(__FUNC__ "/%ld\n", __LINE__);)
  2557.             if (!WriterAbort)
  2558.                 SendWriterRx(WMR_NEWDISKOK);
  2559.             break;
  2560.         case WM_CLOSEDISK:
  2561.             d(kprintf(">>received WM_CLOSEDISK\n");)
  2562.             CloseWriter = TRUE;
  2563.             break;
  2564.         default:
  2565.             d(kprintf(">>received unknown %ld\n", (long) Class);)
  2566.             break;
  2567.             }
  2568.         }
  2569.  
  2570.     return (BOOL) !WriterRunning;
  2571. }
  2572.  
  2573.  
  2574. // Message vom Writer-Prozeß an Hauptprozeß senden
  2575. static void SendWriterRx(unsigned short Class)
  2576. {
  2577.     struct WriterMessage *Msg;
  2578.  
  2579.     Msg = malloc(sizeof(struct WriterMessage));
  2580.     if (Msg)
  2581.         {
  2582.         Msg->wm_Msg.mn_ReplyPort = WriterRxReplyPort;
  2583.         Msg->wm_Msg.mn_Length = sizeof(struct WriterMessage);
  2584.         Msg->wm_Class = Class;
  2585.         d(kprintf(">>%s %ld: send %lx\n", __FUNC__, __LINE__, (long) Class);)
  2586.         PutMsg(WriterRxPort, (struct Message *) Msg);
  2587.  
  2588.         if (WriterRxReplyPort)
  2589.             {
  2590.             ULONG Signals;
  2591.  
  2592.             d(kprintf(">>%s %ld vor WaitPort\n", __FUNC__, __LINE__);)
  2593.  
  2594.             do    {
  2595.                 Signals = Wait(WriterTxPortMask | (1 << WriterRxReplyPort->mp_SigBit));
  2596.  
  2597.                 if (Signals & WriterTxPortMask)
  2598.                     CheckWriterTxPort();
  2599.  
  2600.                 Msg = (struct WriterMessage *) GetMsg(WriterRxReplyPort);
  2601.                 } while (NULL == Msg);
  2602.  
  2603.             free(Msg);
  2604.             d(kprintf(">>%s %ld nach WaitPort\n", __FUNC__, __LINE__);)
  2605.             }
  2606.         }
  2607. }
  2608.  
  2609.  
  2610.