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