1 /* AWSTAPE.C    (c) Copyright Roger Bowler, 1999-2009                */
2 /*              Hercules Tape Device Handler for AWSTAPE             */
3 
4 /* Original Author: Roger Bowler                                     */
5 /* Prime Maintainer: Ivan Warren                                     */
6 /* Secondary Maintainer: "Fish" (David B. Trout)                     */
7 
8 /*-------------------------------------------------------------------*/
9 /* This module contains the AWSTAPE emulated tape format support.    */
10 /*                                                                   */
11 /* The subroutines in this module are called by the general tape     */
12 /* device handler (tapedev.c) when the tape format is AWSTAPE.       */
13 /*                                                                   */
14 /* Messages issued by this module are prefixed HHCTA1nn              */
15 /*-------------------------------------------------------------------*/
16 
17 #include "hstdinc.h"
18 #include "hercules.h"  /* need Hercules control blocks               */
19 #include "tapedev.h"   /* Main tape handler header file              */
20 
21 //#define  ENABLE_TRACING_STMTS     // (Fish: DEBUGGING)
22 
23 #ifdef ENABLE_TRACING_STMTS
24   #if !defined(DEBUG)
25     #warning DEBUG required for ENABLE_TRACING_STMTS
26   #endif
27   // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h)
28 #else
29   #undef  TRACE
30   #undef  ASSERT
31   #undef  VERIFY
32   #define TRACE       1 ? ((void)0) : logmsg
33   #define ASSERT(a)
34   #define VERIFY(a)   ((void)(a))
35 #endif
36 
37 /*********************************************************************/
38 /* START OF ORIGINAL AWS FUNCTIONS   (ISW Additions)                 */
39 /*********************************************************************/
40 
41 /*-------------------------------------------------------------------*/
42 /* Close an AWSTAPE format file                                      */
43 /* New Function added by ISW for consistency with other medias       */
44 /*-------------------------------------------------------------------*/
close_awstape(DEVBLK * dev)45 void close_awstape (DEVBLK *dev)
46 {
47     if(dev->fd>=0)
48     {
49         logmsg (_("HHCTA101I %4.4X: AWS Tape %s closed\n"),
50                 dev->devnum, dev->filename);
51         close(dev->fd);
52     }
53     strcpy(dev->filename, TAPE_UNLOADED);
54     dev->fd=-1;
55     dev->blockid = 0;
56     dev->fenced = 0;
57     return;
58 }
59 
60 /*-------------------------------------------------------------------*/
61 /* Rewinds an AWS Tape format file                                   */
62 /* New Function added by ISW for consistency with other medias       */
63 /*-------------------------------------------------------------------*/
rewind_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)64 int rewind_awstape (DEVBLK *dev,BYTE *unitstat,BYTE code)
65 {
66     off_t rcoff;
67     rcoff=lseek(dev->fd,0,SEEK_SET);
68     if(rcoff<0)
69     {
70         build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code);
71         return -1;
72     }
73     dev->nxtblkpos=0;
74     dev->prvblkpos=-1;
75     dev->curfilen=1;
76     dev->blockid=0;
77     dev->fenced = 0;
78     return 0;
79 }
80 
81 /*-------------------------------------------------------------------*/
82 /* Determines if a tape has passed a virtual EOT marker              */
83 /* New Function added by ISW for consistency with other medias       */
84 /*-------------------------------------------------------------------*/
passedeot_awstape(DEVBLK * dev)85 int passedeot_awstape (DEVBLK *dev)
86 {
87     if(dev->nxtblkpos==0)
88     {
89         dev->eotwarning = 0;
90         return 0;
91     }
92     if(dev->tdparms.maxsize==0)
93     {
94         dev->eotwarning = 0;
95         return 0;
96     }
97     if(dev->nxtblkpos+dev->eotmargin > dev->tdparms.maxsize)
98     {
99         dev->eotwarning = 1;
100         return 1;
101     }
102     dev->eotwarning = 0;
103     return 0;
104 }
105 
106 /*********************************************************************/
107 /* START OF ORIGINAL RB AWS FUNCTIONS                                */
108 /*********************************************************************/
109 
110 /*-------------------------------------------------------------------*/
111 /* Open an AWSTAPE format file                                       */
112 /*                                                                   */
113 /* If successful, the file descriptor is stored in the device block  */
114 /* and the return value is zero.  Otherwise the return value is -1.  */
115 /*-------------------------------------------------------------------*/
open_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)116 int open_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code)
117 {
118 int             rc = -1;                /* Return code               */
119 char            pathname[MAX_PATH];     /* file path in host format  */
120 
121     /* Check for no tape in drive */
122     if (!strcmp (dev->filename, TAPE_UNLOADED))
123     {
124         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
125         return -1;
126     }
127 
128     /* Open the AWSTAPE file */
129     hostpath(pathname, dev->filename, sizeof(pathname));
130     if(!dev->tdparms.logical_readonly)
131     {
132         rc = hopen(pathname, O_RDWR | O_BINARY);
133     }
134 
135     /* If file is read-only, attempt to open again */
136     if (dev->tdparms.logical_readonly || (rc < 0 && (EROFS == errno || EACCES == errno)))
137     {
138         dev->readonly = 1;
139         rc = hopen(pathname, O_RDONLY | O_BINARY);
140     }
141 
142     /* Check for successful open */
143     if (rc < 0)
144     {
145         logmsg (_("HHCTA102E %4.4X: Error opening %s: %s\n"),
146                 dev->devnum, dev->filename, strerror(errno));
147 
148         strcpy(dev->filename, TAPE_UNLOADED);
149         build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code);
150         return -1;
151     }
152 
153     /* Store the file descriptor in the device block */
154     dev->fd = rc;
155     rc=rewind_awstape(dev,unitstat,code);
156     return rc;
157 
158 } /* end function open_awstape */
159 
160 /*-------------------------------------------------------------------*/
161 /* Read an AWSTAPE block header                                      */
162 /*                                                                   */
163 /* If successful, return value is zero, and buffer contains header.  */
164 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
165 /*-------------------------------------------------------------------*/
readhdr_awstape(DEVBLK * dev,off_t blkpos,AWSTAPE_BLKHDR * buf,BYTE * unitstat,BYTE code)166 int readhdr_awstape (DEVBLK *dev, off_t blkpos,
167                         AWSTAPE_BLKHDR *buf, BYTE *unitstat,BYTE code)
168 {
169 int             rc;                     /* Return code               */
170 off_t           rcoff;                  /* Return code from lseek()  */
171 
172     /* Reposition file to the requested block header */
173     rcoff = lseek (dev->fd, blkpos, SEEK_SET);
174     if (rcoff < 0)
175     {
176         /* Handle seek error condition */
177         logmsg (_("HHCTA103E %4.4X: Error seeking to offset "I64_FMTX" "
178                 "in file %s: %s\n"),
179                 dev->devnum, blkpos, dev->filename, strerror(errno));
180 
181         /* Set unit check with equipment check */
182         build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
183         return -1;
184     }
185 
186     /* Read the 6-byte block header */
187     rc = read (dev->fd, buf, sizeof(AWSTAPE_BLKHDR));
188 
189     /* Handle read error condition */
190     if (rc < 0)
191     {
192         logmsg (_("HHCTA104E %4.4X: Error reading block header "
193                 "at offset "I64_FMTX" in file %s: %s\n"),
194                 dev->devnum, blkpos, dev->filename, strerror(errno));
195 
196         /* Set unit check with equipment check */
197         build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
198         return -1;
199     }
200 
201     /* Handle end of file (uninitialized tape) condition */
202     if (rc == 0)
203     {
204         logmsg (_("HHCTA105E %4.4X: End of file (end of tape) "
205                 "at offset "I64_FMTX" in file %s\n"),
206                 dev->devnum, blkpos, dev->filename);
207 
208         /* Set unit exception with tape indicate (end of tape) */
209         build_senseX(TAPE_BSENSE_EMPTYTAPE,dev,unitstat,code);
210         return -1;
211     }
212 
213     /* Handle end of file within block header */
214     if (rc < (int)sizeof(AWSTAPE_BLKHDR))
215     {
216         logmsg (_("HHCTA106E %4.4X: Unexpected end of file in block header "
217                 "at offset "I64_FMTX" in file %s\n"),
218                 dev->devnum, blkpos, dev->filename);
219 
220         build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
221         return -1;
222     }
223 
224     /* Successful return */
225     return 0;
226 
227 } /* end function readhdr_awstape */
228 
229 /*-------------------------------------------------------------------*/
230 /* Read a block from an AWSTAPE format file                          */
231 /*                                                                   */
232 /* The block may be formed of one or more block segments each        */
233 /* preceded by an AWSTAPE block header. The ENDREC flag in the       */
234 /* block header indicates the final segment of the block.            */
235 /*                                                                   */
236 /* If successful, return value is block length read.                 */
237 /* If a tapemark was read, the return value is zero, and the         */
238 /* current file number in the device block is incremented.           */
239 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
240 /*-------------------------------------------------------------------*/
read_awstape(DEVBLK * dev,BYTE * buf,BYTE * unitstat,BYTE code)241 int read_awstape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code)
242 {
243 int             rc;                     /* Return code               */
244 AWSTAPE_BLKHDR  awshdr;                 /* AWSTAPE block header      */
245 off_t           blkpos;                 /* Offset of block header    */
246 int             blklen = 0;             /* Total length of block     */
247 U16             seglen;                 /* Data length of segment    */
248 
249     /* Initialize current block position */
250     blkpos = dev->nxtblkpos;
251 
252     /* Read block segments until end of block */
253     do
254     {
255         /* Read the 6-byte block header */
256         rc = readhdr_awstape (dev, blkpos, &awshdr, unitstat,code);
257         if (rc < 0) return -1;
258 
259         /* Extract the segment length from the block header */
260         seglen = ((U16)(awshdr.curblkl[1]) << 8)
261                     | awshdr.curblkl[0];
262 
263         /* Calculate the offset of the next block segment */
264         blkpos += sizeof(awshdr) + seglen;
265 
266         /* Check that block length will not exceed buffer size */
267         if (blklen + seglen > MAX_BLKLEN)
268         {
269             logmsg (_("HHCTA107E %4.4X: Block length exceeds %d "
270                     "at offset "I64_FMTX" in file %s\n"),
271                     dev->devnum,
272                     (int)MAX_BLKLEN, blkpos, dev->filename);
273 
274             /* Set unit check with data check */
275             build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
276             return -1;
277         }
278 
279         /* Check that tapemark blocksize is zero */
280         if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK)
281             && blklen + seglen > 0)
282         {
283             logmsg (_("HHCTA108E %4.4X: Invalid tapemark "
284                     "at offset "I64_FMTX" in file %s\n"),
285                     dev->devnum, blkpos, dev->filename);
286 
287             /* Set unit check with data check */
288             build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
289             return -1;
290         }
291 
292         /* Exit loop if this is a tapemark */
293         if (awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK)
294             break;
295 
296         /* Read data block segment from tape file */
297         rc = read (dev->fd, buf+blklen, seglen);
298 
299         /* Handle read error condition */
300         if (rc < 0)
301         {
302             logmsg (_("HHCTA109E %4.4X: Error reading data block "
303                     "at offset "I64_FMTX" in file %s: %s\n"),
304                     dev->devnum, blkpos, dev->filename, strerror(errno));
305 
306             /* Set unit check with equipment check */
307             build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
308             return -1;
309         }
310 
311         /* Handle end of file within data block */
312         if (rc < seglen)
313         {
314             logmsg (_("HHCTA110E %4.4X: Unexpected end of file in data block "
315                     "at offset "I64_FMTX" in file %s\n"),
316                     dev->devnum, blkpos, dev->filename);
317 
318             /* Set unit check with data check and partial record */
319             build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code);
320             return -1;
321         }
322 
323         /* Accumulate the total block length */
324         blklen += seglen;
325 
326     } while ((awshdr.flags1 & AWSTAPE_FLAG1_ENDREC) == 0);
327 
328     /* Calculate the offsets of the next and previous blocks */
329     dev->prvblkpos = dev->nxtblkpos;
330     dev->nxtblkpos = blkpos;
331 
332     /* Increment the block number */
333     dev->blockid++;
334 
335     /* Increment file number and return zero if tapemark was read */
336     if (blklen == 0)
337     {
338         dev->curfilen++;
339         return 0; /* UX will be set by caller */
340     }
341 
342     /* Return block length */
343     return blklen;
344 
345 } /* end function read_awstape */
346 
347 /*-------------------------------------------------------------------*/
348 /* Write a block to an AWSTAPE format file                           */
349 /*                                                                   */
350 /* If successful, return value is zero.                              */
351 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
352 /*-------------------------------------------------------------------*/
write_awstape(DEVBLK * dev,BYTE * buf,U16 blklen,BYTE * unitstat,BYTE code)353 int write_awstape (DEVBLK *dev, BYTE *buf, U16 blklen,
354                         BYTE *unitstat,BYTE code)
355 {
356 int             rc;                     /* Return code               */
357 off_t           rcoff;                  /* Return code from lseek()  */
358 AWSTAPE_BLKHDR  awshdr;                 /* AWSTAPE block header      */
359 off_t           blkpos;                 /* Offset of block header    */
360 U16             prvblkl;                /* Length of previous block  */
361 
362     /* Initialize current block position and previous block length */
363     blkpos = dev->nxtblkpos;
364     prvblkl = 0;
365 
366     /* Determine previous block length if not at start of tape */
367     if (dev->nxtblkpos > 0)
368     {
369         /* Reread the previous block header */
370         rc = readhdr_awstape (dev, dev->prvblkpos, &awshdr, unitstat,code);
371         if (rc < 0) return -1;
372 
373         /* Extract the block length from the block header */
374         prvblkl = ((U16)(awshdr.curblkl[1]) << 8)
375                     | awshdr.curblkl[0];
376 
377         /* Recalculate the offset of the next block */
378         blkpos = dev->prvblkpos + sizeof(awshdr) + prvblkl;
379     }
380 
381     /* Reposition file to the new block header */
382     rcoff = lseek (dev->fd, blkpos, SEEK_SET);
383     if (rcoff < 0)
384     {
385         /* Handle seek error condition */
386         logmsg (_("HHCTA111E %4.4X: Error seeking to offset "I64_FMTX" "
387                 "in file %s: %s\n"),
388                 dev->devnum, blkpos, dev->filename, strerror(errno));
389 
390         /* Set unit check with equipment check */
391         build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
392         return -1;
393     }
394     /* ISW: Determine if we are passed maxsize */
395     if(dev->tdparms.maxsize>0)
396     {
397         if((off_t)(dev->nxtblkpos+blklen+sizeof(awshdr)) > dev->tdparms.maxsize)
398         {
399             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
400             return -1;
401         }
402     }
403     /* ISW: End of virtual physical EOT determination */
404 
405     /* Build the 6-byte block header */
406     awshdr.curblkl[0] = blklen & 0xFF;
407     awshdr.curblkl[1] = (blklen >> 8) & 0xFF;
408     awshdr.prvblkl[0] = prvblkl & 0xFF;
409     awshdr.prvblkl[1] = (prvblkl >>8) & 0xFF;
410     awshdr.flags1 = AWSTAPE_FLAG1_NEWREC | AWSTAPE_FLAG1_ENDREC;
411     awshdr.flags2 = 0;
412 
413     /* Write the block header */
414     rc = write (dev->fd, &awshdr, sizeof(awshdr));
415     if (rc < (int)sizeof(awshdr))
416     {
417         if(errno==ENOSPC)
418         {
419             /* Disk FULL */
420             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
421             logmsg (_("HHCTA112E %4.4X: Media full condition reached "
422                     "at offset "I64_FMTX" in file %s\n"),
423                     dev->devnum, blkpos, dev->filename);
424             return -1;
425         }
426 
427         /* Handle write error condition */
428         logmsg (_("HHCTA113E %4.4X: Error writing block header "
429                 "at offset "I64_FMTX" in file %s: %s\n"),
430                 dev->devnum, blkpos, dev->filename, strerror(errno));
431 
432         /* Set unit check with equipment check */
433         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
434         return -1;
435     }
436 
437     /* Calculate the offsets of the next and previous blocks */
438     dev->nxtblkpos = blkpos + sizeof(awshdr) + blklen;
439     dev->prvblkpos = blkpos;
440 
441     /* Write the data block */
442     rc = write (dev->fd, buf, blklen);
443     if (rc < blklen)
444     {
445         if(errno==ENOSPC)
446         {
447             /* Disk FULL */
448             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
449             logmsg (_("HHCTA114E %4.4X: Media full condition reached "
450                     "at offset "I64_FMTX" in file %s\n"),
451                     dev->devnum, blkpos, dev->filename);
452             return -1;
453         }
454 
455         /* Handle write error condition */
456         logmsg (_("HHCTA115E %4.4X: Error writing data block "
457                 "at offset "I64_FMTX" in file %s: %s\n"),
458                 dev->devnum, blkpos, dev->filename, strerror(errno));
459 
460         /* Set unit check with equipment check */
461         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
462         return -1;
463     }
464 
465     dev->blockid++;
466 
467     /* Set new physical EOF */
468     do rc = ftruncate( dev->fd, dev->nxtblkpos );
469     while (EINTR == rc);
470 
471     if (rc != 0)
472     {
473         /* Handle write error condition */
474         logmsg (_("HHCTA116E %4.4X: Error writing data block "
475                 "at offset "I64_FMTX" in file %s: %s\n"),
476                 dev->devnum, blkpos, dev->filename, strerror(errno));
477 
478         /* Set unit check with equipment check */
479         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
480         return -1;
481     }
482 
483     /* Return normal status */
484     return 0;
485 
486 } /* end function write_awstape */
487 
488 /*-------------------------------------------------------------------*/
489 /* Write a tapemark to an AWSTAPE format file                        */
490 /*                                                                   */
491 /* If successful, return value is zero.                              */
492 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
493 /*-------------------------------------------------------------------*/
write_awsmark(DEVBLK * dev,BYTE * unitstat,BYTE code)494 int write_awsmark (DEVBLK *dev, BYTE *unitstat,BYTE code)
495 {
496 int             rc;                     /* Return code               */
497 off_t           rcoff;                  /* Return code from lseek()  */
498 AWSTAPE_BLKHDR  awshdr;                 /* AWSTAPE block header      */
499 off_t           blkpos;                 /* Offset of block header    */
500 U16             prvblkl;                /* Length of previous block  */
501 
502     /* Initialize current block position and previous block length */
503     blkpos = dev->nxtblkpos;
504     prvblkl = 0;
505 
506     /* Determine previous block length if not at start of tape */
507     if (dev->nxtblkpos > 0)
508     {
509         /* Reread the previous block header */
510         rc = readhdr_awstape (dev, dev->prvblkpos, &awshdr, unitstat,code);
511         if (rc < 0) return -1;
512 
513         /* Extract the block length from the block header */
514         prvblkl = ((U16)(awshdr.curblkl[1]) << 8)
515                     | awshdr.curblkl[0];
516 
517         /* Recalculate the offset of the next block */
518         blkpos = dev->prvblkpos + sizeof(awshdr) + prvblkl;
519     }
520 
521     /* Reposition file to the new block header */
522     rcoff = lseek (dev->fd, blkpos, SEEK_SET);
523     if (rcoff < 0)
524     {
525         /* Handle seek error condition */
526         logmsg (_("HHCTA117E %4.4X: Error seeking to offset "I64_FMTX" "
527                 "in file %s: %s\n"),
528                 dev->devnum, blkpos, dev->filename, strerror(errno));
529 
530         build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
531         return -1;
532     }
533     /* ISW: Determine if we are passed maxsize */
534     if(dev->tdparms.maxsize>0)
535     {
536         if((off_t)(dev->nxtblkpos+sizeof(awshdr)) > dev->tdparms.maxsize)
537         {
538             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
539             return -1;
540         }
541     }
542     /* ISW: End of virtual physical EOT determination */
543 
544     /* Build the 6-byte block header */
545     awshdr.curblkl[0] = 0;
546     awshdr.curblkl[1] = 0;
547     awshdr.prvblkl[0] = prvblkl & 0xFF;
548     awshdr.prvblkl[1] = (prvblkl >>8) & 0xFF;
549     awshdr.flags1 = AWSTAPE_FLAG1_TAPEMARK;
550     awshdr.flags2 = 0;
551 
552     /* Write the block header */
553     rc = write (dev->fd, &awshdr, sizeof(awshdr));
554     if (rc < (int)sizeof(awshdr))
555     {
556         /* Handle write error condition */
557         logmsg (_("HHCTA118E %4.4X: Error writing block header "
558                 "at offset "I64_FMTX" in file %s: %s\n"),
559                 dev->devnum, blkpos, dev->filename, strerror(errno));
560 
561         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
562         return -1;
563     }
564 
565     dev->blockid++;
566 
567     /* Calculate the offsets of the next and previous blocks */
568     dev->nxtblkpos = blkpos + sizeof(awshdr);
569     dev->prvblkpos = blkpos;
570 
571     /* Set new physical EOF */
572     do rc = ftruncate( dev->fd, dev->nxtblkpos );
573     while (EINTR == rc);
574 
575     if (rc != 0)
576     {
577         /* Handle write error condition */
578         logmsg (_("HHCTA119E Error writing tape mark "
579                 "at offset "I64_FMTX" in file %s: %s\n"),
580                 blkpos, dev->filename, strerror(errno));
581 
582         /* Set unit check with equipment check */
583         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
584         return -1;
585     }
586 
587     /* Return normal status */
588     return 0;
589 
590 } /* end function write_awsmark */
591 
592 /*-------------------------------------------------------------------*/
593 /* Synchronize an AWSTAPE format file  (i.e. flush buffers to disk)  */
594 /*                                                                   */
595 /* If successful, return value is zero.                              */
596 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
597 /*-------------------------------------------------------------------*/
sync_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)598 int sync_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code)
599 {
600     /* Unit check if tape is write-protected */
601     if (dev->readonly)
602     {
603         build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
604         return -1;
605     }
606 
607     /* Perform sync. Return error on failure. */
608     if (fdatasync( dev->fd ) < 0)
609     {
610         /* Log the error */
611         logmsg (_("HHCTA120E %4.4X: Sync error on file %s: %s\n"),
612             dev->devnum, dev->filename, strerror(errno));
613         /* Set unit check with equipment check */
614         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
615         return -1;
616     }
617 
618     /* Return normal status */
619     return 0;
620 
621 } /* end function sync_awstape */
622 
623 /*-------------------------------------------------------------------*/
624 /* Forward space over next block of AWSTAPE format file              */
625 /*                                                                   */
626 /* If successful, return value is the length of the block skipped.   */
627 /* If the block skipped was a tapemark, the return value is zero,    */
628 /* and the current file number in the device block is incremented.   */
629 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
630 /*-------------------------------------------------------------------*/
fsb_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)631 int fsb_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code)
632 {
633 int             rc;                     /* Return code               */
634 AWSTAPE_BLKHDR  awshdr;                 /* AWSTAPE block header      */
635 off_t           blkpos;                 /* Offset of block header    */
636 int             blklen = 0;             /* Total length of block     */
637 U16             seglen;                 /* Data length of segment    */
638 
639     /* Initialize current block position */
640     blkpos = dev->nxtblkpos;
641 
642     /* Read block segments until end of block */
643     do
644     {
645         /* Read the 6-byte block header */
646         rc = readhdr_awstape (dev, blkpos, &awshdr, unitstat,code);
647         if (rc < 0) return -1;
648 
649         /* Extract the block length from the block header */
650         seglen = ((U16)(awshdr.curblkl[1]) << 8)
651                     | awshdr.curblkl[0];
652 
653         /* Calculate the offset of the next block segment */
654         blkpos += sizeof(awshdr) + seglen;
655 
656         /* Accumulate the total block length */
657         blklen += seglen;
658 
659         /* Exit loop if this is a tapemark */
660         if (awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK)
661             break;
662 
663     } while ((awshdr.flags1 & AWSTAPE_FLAG1_ENDREC) == 0);
664 
665     /* Calculate the offsets of the next and previous blocks */
666     dev->prvblkpos = dev->nxtblkpos;
667     dev->nxtblkpos = blkpos;
668 
669     /* Increment current file number if tapemark was skipped */
670     if (blklen == 0)
671         dev->curfilen++;
672 
673     dev->blockid++;
674 
675     /* Return block length or zero if tapemark */
676     return blklen;
677 
678 } /* end function fsb_awstape */
679 
680 /*-------------------------------------------------------------------*/
681 /* Backspace to previous block of AWSTAPE format file                */
682 /*                                                                   */
683 /* If successful, return value is the length of the block.           */
684 /* If the block is a tapemark, the return value is zero,             */
685 /* and the current file number in the device block is decremented.   */
686 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
687 /*-------------------------------------------------------------------*/
bsb_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)688 int bsb_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code)
689 {
690 int             rc;                     /* Return code               */
691 AWSTAPE_BLKHDR  awshdr;                 /* AWSTAPE block header      */
692 U16             curblkl;                /* Length of current block   */
693 U16             prvblkl;                /* Length of previous block  */
694 off_t           blkpos;                 /* Offset of block header    */
695 
696     /* Unit check if already at start of tape */
697     if (dev->nxtblkpos == 0)
698     {
699         build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
700         return -1;
701     }
702 
703     /* Backspace to previous block position */
704     blkpos = dev->prvblkpos;
705 
706     /* Read the 6-byte block header */
707     rc = readhdr_awstape (dev, blkpos, &awshdr, unitstat,code);
708     if (rc < 0) return -1;
709 
710     /* Extract the block lengths from the block header */
711     curblkl = ((U16)(awshdr.curblkl[1]) << 8)
712                 | awshdr.curblkl[0];
713     prvblkl = ((U16)(awshdr.prvblkl[1]) << 8)
714                 | awshdr.prvblkl[0];
715 
716     /* Calculate the offset of the previous block */
717     dev->prvblkpos = blkpos - sizeof(awshdr) - prvblkl;
718     dev->nxtblkpos = blkpos;
719 
720     /* Decrement current file number if backspaced over tapemark */
721     if (curblkl == 0)
722         dev->curfilen--;
723 
724     dev->blockid--;
725 
726     /* Return block length or zero if tapemark */
727     return curblkl;
728 
729 } /* end function bsb_awstape */
730 
731 /*-------------------------------------------------------------------*/
732 /* Forward space to next logical file of AWSTAPE format file         */
733 /*                                                                   */
734 /* For AWSTAPE files, the forward space file operation is achieved   */
735 /* by forward spacing blocks until positioned just after a tapemark. */
736 /*                                                                   */
737 /* If successful, return value is zero, and the current file number  */
738 /* in the device block is incremented by fsb_awstape.                */
739 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
740 /*-------------------------------------------------------------------*/
fsf_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)741 int fsf_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code)
742 {
743 int             rc;                     /* Return code               */
744 
745     while (1)
746     {
747         /* Forward space over next block */
748         rc = fsb_awstape (dev, unitstat,code);
749         if (rc < 0) return -1;
750 
751         /* Exit loop if spaced over a tapemark */
752         if (rc == 0) break;
753 
754     } /* end while */
755 
756     /* Return normal status */
757     return 0;
758 
759 } /* end function fsf_awstape */
760 
761 /*-------------------------------------------------------------------*/
762 /* Backspace to previous logical file of AWSTAPE format file         */
763 /*                                                                   */
764 /* For AWSTAPE files, the backspace file operation is achieved       */
765 /* by backspacing blocks until positioned just before a tapemark     */
766 /* or until positioned at start of tape.                             */
767 /*                                                                   */
768 /* If successful, return value is zero, and the current file number  */
769 /* in the device block is decremented by bsb_awstape.                */
770 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
771 /*-------------------------------------------------------------------*/
bsf_awstape(DEVBLK * dev,BYTE * unitstat,BYTE code)772 int bsf_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code)
773 {
774 int             rc;                     /* Return code               */
775 
776     while (1)
777     {
778         /* Exit if now at start of tape */
779         if (dev->nxtblkpos == 0)
780         {
781             build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
782             return -1;
783         }
784 
785         /* Backspace to previous block position */
786         rc = bsb_awstape (dev, unitstat,code);
787         if (rc < 0) return -1;
788 
789         /* Exit loop if backspaced over a tapemark */
790         if (rc == 0) break;
791 
792     } /* end while */
793 
794     /* Return normal status */
795     return 0;
796 
797 } /* end function bsf_awstape */
798 
799 /*********************************************************************/
800 /*  END OF ORIGINAL RB AWS FUNCTIONS                                 */
801 /*********************************************************************/
802