1 /* HETLIB.C (c) Copyright Leland Lucius, 2000-2009 */
2 /* Library for managing Hercules Emulated Tapes */
3
4 /*
5 || ----------------------------------------------------------------------------
6 ||
7 || HETLIB.C (c) Copyright Leland Lucius, 2000-2009
8 || Released under terms of the Q Public License.
9 ||
10 || Library for managing Hercules Emulated Tapes.
11 ||
12 || ----------------------------------------------------------------------------
13 */
14
15 #include "hstdinc.h"
16
17 #define _HETLIB_C_
18 #define _HTAPE_DLL_
19
20 #include "hercules.h"
21 #include "hetlib.h"
22
23 #undef HETDEBUGR
24 #undef HETDEBUGW
25
26 /*
27 || Local constant data
28 */
29 static const char *het_errstr[] =
30 {
31 "No error",
32 "File error",
33 "Tapemark read",
34 "Beginning of tape",
35 "End of tape",
36 "BOR not found",
37 "EOR not found",
38 "Unexpected tapemark",
39 "Buffer not big enough",
40 "Premature EOF",
41 "Decompression error",
42 "Unknown compression method",
43 "Compression error",
44 "Specified length to big",
45 "Write protected",
46 "Bad function code passed",
47 "Bad compression method",
48 "Bad compression level",
49 "Bad write chunk size",
50 "Invalid direction specified",
51 "Insufficient memory",
52 "Couldn't read block header",
53 "Inconsistent compression flags",
54 "Invalid error code",
55 };
56 #define HET_ERRSTR_MAX ( sizeof( het_errstr) / sizeof( het_errstr[ 0 ] ) )
57
58 /*==DOC==
59
60 NAME
61 het_open - Open an HET format file
62
63 SYNOPSIS
64 #include "hetlib.h"
65
66 int het_open( HETB **hetb, char *filename, int flags )
67
68 DESCRIPTION
69 The het_open() function opens the file indicated by the "filename"
70 parameter and, if successful, places the address of an HETB at
71 the location pointed to by the "hetb" parameter.
72
73 Currently, "HETOPEN_CREATE" is the only flag available and has
74 the same function as the O_CREAT flag of the open(3) function.
75
76 @ISW@ Added flag HETOPEN_READONLY
77
78 HETOPEN_CREATE and HETOPEN_READONLY are mutually exclusive.
79
80 When HETOPEN_READONLY is set, the het file must exist.
81 It is opened read only. Any attempt to write will fail.
82
83 RETURN VALUE
84 If no errors are detected then the return value will be >= 0
85 and the address of the newly allocated HETB will be place at the
86 "hetb" location.
87
88 If an error occurs, then the return value will be < 0 and will be
89 one of the following:
90
91 HETE_NOMEM Insufficient memory to allocate an HETB
92
93 HETE_ERROR File system error - check errno(3)
94
95 For other possible errors, see:
96 het_read_header()
97 het_tapemark()
98 het_rewind()
99
100 NOTES
101 Even if het_open() fails, you should still call het_close().
102
103 EXAMPLE
104 //
105 // Create an NL tape
106 //
107
108 #include "hetlib.h"
109
110 int main( int argc, char *argv[] )
111 {
112 HETB *hetb;
113 int rc;
114
115 rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE );
116 if( rc < 0 )
117 {
118 printf( "het_open() returned: %d\n", rc );
119 }
120 else
121 {
122 printf( "%s successfully created\n", argv[ 1 ] );
123 }
124
125 het_close( &hetb );
126
127 return( 0 );
128 }
129
130 SEE ALSO
131 het_read_header(), het_tapemark(), het_rewind(), het_close()
132
133 ==DOC==*/
134
135 DLL_EXPORT int
het_open(HETB ** hetb,char * filename,int flags)136 het_open( HETB **hetb, char *filename, int flags )
137 {
138 HETB *thetb;
139 char *omode;
140 int rc;
141 int fd;
142 int oflags;
143 char pathname[MAX_PATH];
144
145 /*
146 || Initialize
147 */
148 *hetb = NULL;
149 hostpath(pathname, filename, sizeof(pathname));
150
151 /*
152 || Allocate a new HETB
153 */
154 thetb = calloc( 1, sizeof( HETB ) );
155 if( thetb == NULL )
156 {
157 return( HETE_NOMEM );
158 }
159
160 /*
161 || Set defaults
162 */
163 thetb->compress = HETDFLT_COMPRESS;
164 thetb->decompress = HETDFLT_DECOMPRESS;
165 thetb->method = HETDFLT_METHOD;
166 thetb->level = HETDFLT_LEVEL;
167 thetb->chksize = HETDFLT_CHKSIZE;
168
169 /*
170 || clear HETOPEN_CREATE if HETOPEN_READONLY is specified
171 */
172 if(flags & HETOPEN_READONLY)
173 {
174 flags&=~HETOPEN_CREATE;
175 }
176 /*
177 || Translate HET create flag to filesystem flag
178 */
179 oflags = ( ( flags & HETOPEN_CREATE ) ? O_CREAT : 0 );
180
181 /*
182 || Open the tape file
183 */
184 omode = "r+b";
185 if(!(flags & HETOPEN_READONLY))
186 {
187 fd = hopen( pathname, O_RDWR | O_BINARY | oflags, S_IRUSR | S_IWUSR | S_IRGRP );
188 }
189 if( (flags & HETOPEN_READONLY) || (fd == -1 && (errno == EROFS || errno == EACCES) ) )
190 {
191 /*
192 || Retry open if file resides on readonly file system
193 */
194 omode = "rb";
195 thetb->writeprotect = TRUE;
196 fd = hopen( pathname, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP );
197 }
198
199 /*
200 || Error out if both opens failed
201 */
202 if( fd == -1 )
203 {
204 free( thetb );
205 return( HETE_ERROR );
206 }
207
208 /*
209 || Associate stream with file descriptor
210 */
211 thetb->fd = fdopen( fd, omode );
212 if( thetb->fd == NULL )
213 {
214 rc = errno;
215 close( fd );
216 errno = rc;
217 free( thetb );
218 return( HETE_ERROR );
219 }
220
221 /*
222 || If uninitialized tape, write 2 tapemarks to make it a valid NL tape
223 */
224 rc = het_read_header( thetb );
225 if( rc < 0 && rc != HETE_TAPEMARK )
226 {
227 if( rc != HETE_EOT )
228 {
229 return( rc );
230 }
231
232 rc = het_tapemark( thetb );
233 if( rc < 0 )
234 {
235 return( rc );
236 }
237
238 rc = het_tapemark( thetb );
239 if( rc < 0 )
240 {
241 return( rc );
242 }
243 }
244
245 /*
246 || Reposition tape to load point
247 */
248 rc = het_rewind( thetb );
249 if( rc < 0 )
250 {
251 return( rc );
252 }
253
254 /*
255 || Give the caller the new HETB
256 */
257 *hetb = thetb;
258
259 return( 0 );
260
261 }
262
263 /*==DOC==
264
265 NAME
266 het_close - Close an HET file
267
268 SYNOPSIS
269 #include "hetlib.h"
270
271 int het_close( HETB **hetb )
272
273 DESCRIPTION
274 The het_close() function closes an HET file and releases the
275 HETB.
276
277 RETURN VALUE
278 If no errors are detected then the return value will be >= 0
279 and the location specified by the "hetb" parameter will be set
280 to NULL.
281
282 If an error occurs, then the return value will be < 0. At this
283 time, no errors will be returned.
284
285 EXAMPLE
286 //
287 // Create an NL tape
288 //
289
290 #include "hetlib.h"
291
292 int main( int argc, char *argv[] )
293 {
294 HETB *hetb;
295 int rc;
296
297 rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE );
298 if( rc < 0 )
299 {
300 printf( "het_open() returned: %d\n", rc );
301 }
302 else
303 {
304 printf( "%s successfully created\n", argv[ 1 ] );
305 }
306
307 het_close( &hetb );
308
309 return( 0 );
310 }
311
312 SEE ALSO
313 het_open()
314
315 ==DOC==*/
316
317 DLL_EXPORT int
het_close(HETB ** hetb)318 het_close( HETB **hetb )
319 {
320
321 /*
322 || Only free the HETB if we have one
323 */
324 if( *(hetb) != NULL )
325 {
326 /*
327 || Only close the file if opened
328 */
329 if( (*hetb)->fd != NULL )
330 {
331 fclose( (*hetb)->fd );
332 }
333 free( *(hetb) );
334 }
335
336 /*
337 || Reinitialize pointer
338 */
339 *hetb = NULL;
340
341 return( 0 );
342 }
343
344 /*==DOC==
345
346 NAME
347 het_cntl - Control HET file behavior
348
349 SYNOPSIS
350 #include "hetlib.h"
351
352 int het_cntl( HETB *hetb, int func, unsigned long val )
353
354 DESCRIPTION
355 The het_cntl() function allows you to get/set several values
356 that control how an HET file behaves. The value of the "val"
357 parameter depends on the function code.
358
359 The possible modes are:
360
361 HETCNTL_GET Should be ORed (|) with the function codes
362 to retrieve the current setting. (Default)
363
364 HETCNTL_SET Should be ORed (|) with the function codes
365 to set a new value.
366
367 The possible function codes are:
368
369 HETCNTL_COMPRESS val=TRUE to enable write compression (see notes)
370 Values: FALSE (disable)
371 TRUE (enable)
372 Default: HETDFLT_COMPRESS (TRUE)
373
374 HETCNTL_DECOMPRESS val=TRUE to enable read decompression
375 Values: FALSE (disable)
376 TRUE (enable)
377 Default: HETDFLT_DECOMPRESS (TRUE)
378
379 HETCNTL_METHOD val=Compression method to use
380 Values: HETMETH_ZLIB (1)
381 HETMETH_BZLIB (2)
382 Default: HETDFLT_METHOD (HETMETH_ZLIB)
383
384 HETCNTL_LEVEL val=Level of compression
385 Min: HETMIN_LEVEL (1)
386 Max: HETMAX_LEVEL (9)
387 Default: HETDFLT_LEVEL (4)
388
389 HETCNTL_CHUNKSIZE val=Size of output chunks (see notes)
390 Min: HETMIN_CHUNKSIZE (4096)
391 Max: HETMAX_CHUNKSIZE (65535)
392 Default: HETDFLT_CHUNKSIZE (65535)
393
394 RETURN VALUE
395 If no errors are detected then the return value will be either
396 the current setting for a "get" request or >= 0 for a "set"
397 request.
398
399 If an error occurs, then the return value will be < 0 and can be
400 one of the following:
401
402 HETE_BADMETHOD Specified method out of range
403
404 HETE_BADLEVEL Specified level out of range
405
406 HETE_BADCHUNKSIZE Specified chunk size out of range
407
408 HETE_BADFUNC Unrecognized function code
409
410 NOTES
411 Each block on an HET file is made up of "HETCNTL_CHUNKSIZE" sized
412 chunks. There can be 1 or many chunks per block.
413
414 If you wish to create an AWSTAPE compatible file, specify a chunk
415 size of 4096 and disable write compression.
416
417 EXAMPLE
418 //
419 // Create an NL tape and write an uncompressed string to it
420 //
421
422 #include "hetlib.h"
423
424 char data[] = "This is a test";
425
426 int main( int argc, char *argv[] )
427 {
428 HETB *hetb;
429 int rc;
430
431 rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE );
432 if( rc >= 0 )
433 {
434 rc = het_cntl( hetb, HETCNTL_SET | HETCNTL_COMPRESS, FALSE );
435 if( rc >= 0 )
436 {
437 rc = het_write( hetb, data, sizeof( data ) );
438 if( rc >= 0 )
439 {
440 printf( "Data successfully written\n" );
441 }
442 }
443 }
444
445 if( rc < 0 )
446 {
447 printf( "HETLIB error: %d\n", rc );
448 }
449
450 het_close( &hetb );
451
452 return( 0 );
453 }
454
455 SEE ALSO
456 het_open(), het_cntl(), het_write(), het_close()
457
458 ==DOC==*/
459
460 DLL_EXPORT int
het_cntl(HETB * hetb,int func,unsigned long val)461 het_cntl( HETB *hetb, int func, unsigned long val )
462 {
463 int mode;
464
465 /*
466 || Isolate the mode
467 */
468 mode = func & HETCNTL_SET;
469
470 /*
471 || Process the requested function
472 */
473 switch( func & ( ~( HETCNTL_GET | HETCNTL_SET ) ) )
474 {
475 case HETCNTL_COMPRESS:
476 if( mode == HETCNTL_GET )
477 {
478 return( hetb->compress );
479 }
480
481 hetb->compress = ( val ? TRUE : FALSE );
482 break;
483
484 case HETCNTL_DECOMPRESS:
485 if( mode == HETCNTL_GET )
486 {
487 return( hetb->decompress );
488 }
489
490 hetb->decompress = ( val ? TRUE : FALSE );
491 break;
492
493 case HETCNTL_METHOD:
494 if( mode == HETCNTL_GET )
495 {
496 return( hetb->method );
497 }
498
499 if( val < HETMIN_METHOD || val > HETMAX_METHOD )
500 {
501 return( HETE_BADMETHOD );
502 }
503
504 hetb->method = val;
505 break;
506
507 case HETCNTL_LEVEL:
508 if( mode == HETCNTL_GET )
509 {
510 return( hetb->level );
511 }
512
513 if( val < HETMIN_LEVEL || val > HETMAX_LEVEL )
514 {
515 return( HETE_BADLEVEL );
516 }
517
518 hetb->level = val;
519 break;
520
521 case HETCNTL_CHUNKSIZE:
522 if( mode == HETCNTL_GET )
523 {
524 return( hetb->chksize );
525 }
526
527 if( val < HETMIN_CHUNKSIZE || val > HETMAX_CHUNKSIZE )
528 {
529 return( HETE_BADSIZE );
530 }
531
532 hetb->chksize = val;
533 break;
534
535 default:
536 return( HETE_BADFUNC );
537 break;
538 }
539
540 /*
541 || Success
542 */
543
544 return( 0 );
545 }
546
547 /*==DOC==
548
549 NAME
550 het_read_header - Retrieve the next chunk header from an HET file
551
552 SYNOPSIS
553 #include "hetlib.h"
554
555 int het_read_header( HETB *hetb )
556
557 DESCRIPTION
558 Retrieves the next chunk header and stores it in the HETB.
559
560 RETURN VALUE
561 If no errors are detected then the return value will be >= 0
562 and the current block count will be incremented.
563
564 If an error occurs, then the return value will be < 0 and can be
565 one of the following:
566
567 HETE_EOT End of tape encountered
568
569 HETE_ERROR File system error - check errno(3)
570
571 HETE_TAPEMARK Tape mark encountered
572
573 NOTES
574 This function is not normally called from user programs and its
575 behavior may change.
576
577 EXAMPLE
578 //
579 // Read a chunk header from an HET file.
580 //
581
582 #include "hetlib.h"
583
584 int main( int argc, char *argv[] )
585 {
586 HETB *hetb;
587 int rc;
588
589 rc = het_open( &hetb, argv[ 1 ], 0 );
590 if( rc >= 0 )
591 {
592 rc = het_read_header( hetb );
593 if( rc >= 0 )
594 {
595 printf( "Header read:\n" );
596 printf( " Current length: %d\n", HETHDR_CLEN( hetb ) );
597 printf( " Previous length: %d\n", HETHDR_PLEN( hetb ) );
598 printf( " Flags1: %x\n", hetb->flags1 );
599 printf( " Flags2: %x\n", hetb->flags2 );
600 }
601 }
602
603 if( rc < 0 )
604 {
605 printf( "HETLIB error: %d\n", rc );
606 }
607
608 het_close( &hetb );
609
610 return( 0 );
611 }
612
613 SEE ALSO
614 het_open(), het_close()
615
616 ==DOC==*/
617
618 DLL_EXPORT int
het_read_header(HETB * hetb)619 het_read_header( HETB *hetb )
620 {
621 int rc;
622
623 /*
624 || Read in a headers worth of data
625 */
626 rc = fread( &hetb->chdr, sizeof( HETHDR ), 1, hetb->fd );
627 if( rc != 1 )
628 {
629 /*
630 || Return EOT if at end of physical file
631 */
632 if( feof( hetb->fd ) )
633 {
634 return( HETE_EOT );
635 }
636
637 /*
638 || Something else must've happened
639 */
640 return( HETE_ERROR );
641 }
642
643 #if defined( HETDEBUGR )
644 printf("read hdr: pl=%d, cl=%d, f1=%02x, f2=%02x\n",
645 HETHDR_PLEN( hetb ), HETHDR_CLEN( hetb ),
646 hetb->chdr.flags1, hetb->chdr.flags2);
647 #endif
648
649 /*
650 || Bump block number if done with entire block
651 */
652 if( hetb->chdr.flags1 & ( HETHDR_FLAGS1_EOR | HETHDR_FLAGS1_TAPEMARK ) )
653 {
654 hetb->cblk++;
655 }
656
657 /*
658 || Check for tape marks
659 */
660 if( hetb->chdr.flags1 & HETHDR_FLAGS1_TAPEMARK )
661 {
662 return( HETE_TAPEMARK );
663 }
664
665 /*
666 || Success
667 */
668 return( 0 );
669 }
670
671 /*==DOC==
672
673 NAME
674 het_read - Retrieve the next block from an HET file
675
676 SYNOPSIS
677 #include "hetlib.h"
678
679 int het_read( HETB *hetb, void *sbuf )
680
681 DESCRIPTION
682 Read the next block of data into the "sbuf" memory location. The
683 length of "sbuf" should be at least HETMAX_BLOCKSIZE bytes.
684
685 RETURN VALUE
686 If no errors are detected then the return value will be the
687 size of the block read. This will be either the compressed or
688 uncompressed length depending on the current AWSCNTL_DECOMPRESS
689 setting.
690
691 If an error occurs, then the return value will be < 0 and can be
692 one of the following:
693
694 HETE_ERROR File system error - check errno(3)
695
696 HETE_BADBOR Beginning of record expected but not found
697
698 HETE_BADCOMPRESS Compression mismatch between related chunks
699
700 HETE_OVERFLOW Record too large for buffer
701
702 HETE_PREMEOF Premature EOF on file
703
704 HETE_DECERR Decompression error (stored in errno(3))
705
706 HETE_UNKMETH Unknown compression method encountered
707
708 For other possible errors, see:
709 het_read_header()
710
711 EXAMPLE
712 //
713 // Read a block from an HET file.
714 //
715
716 #include "hetlib.h"
717
718 char buffer[ HETMAX_BLOCKSIZE ];
719
720 int main( int argc, char *argv[] )
721 {
722 HETB *hetb;
723 int rc;
724
725 rc = het_open( &hetb, argv[ 1 ], 0 );
726 if( rc >= 0 )
727 {
728 rc = het_read( hetb, buffer );
729 if( rc >= 0 )
730 {
731 printf( "Block read - length: %d\n", rc );
732 }
733 }
734
735 if( rc < 0 )
736 {
737 printf( "HETLIB error: %d\n", rc );
738 }
739
740 het_close( &hetb );
741
742 return( 0 );
743 }
744
745 SEE ALSO
746 het_open(), het_read_header(), het_close()
747
748 ==DOC==*/
749
750 DLL_EXPORT int
het_read(HETB * hetb,void * sbuf)751 het_read( HETB *hetb, void *sbuf )
752 {
753 char *tptr;
754 int rc;
755 unsigned long slen;
756 int flags1, flags2;
757 unsigned long tlen;
758 char tbuf[ HETMAX_BLOCKSIZE ];
759
760 /*
761 || Initialize
762 */
763 flags1 = flags2 = 0;
764 tlen = 0;
765 tptr = sbuf;
766
767 /*
768 || Read chunks until entire block has been read
769 */
770 do
771 {
772 /*
773 || Get a header
774 */
775 rc = het_read_header( hetb );
776 if( rc < 0 )
777 {
778 return( rc );
779 }
780
781 /*
782 || Have we seen a BOR chunk yet?
783 */
784 if( !( flags1 & HETHDR_FLAGS1_BOR ) )
785 {
786 /*
787 || Nope, so this chunk MUST have the BOR set
788 */
789 if( !( hetb->chdr.flags1 & HETHDR_FLAGS1_BOR ) )
790 {
791 return( HETE_BADBOR );
792 }
793
794 /*
795 || If block is compressed (and decompression is desired), set
796 || destination pointer.
797 */
798 if( hetb->decompress )
799 {
800 if( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS ||
801 hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS )
802 {
803 if( ( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS ) &&
804 ( hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS ) )
805 {
806 return( HETE_BADCOMPRESS );
807 }
808 tptr = tbuf;
809 }
810 }
811
812 /*
813 || Save flags for later validation
814 */
815 flags1 = hetb->chdr.flags1;
816 flags2 = hetb->chdr.flags2;
817 }
818 else
819 {
820 /*
821 || Yep, so this chunk MUST NOT have the BOR flag set
822 */
823 if( hetb->chdr.flags1 & HETHDR_FLAGS1_BOR )
824 {
825 return( HETE_BADBOR );
826 }
827 }
828
829 /*
830 || Compression flags from related chunks must match
831 */
832 if( ( flags1 & HETHDR_FLAGS1_COMPRESS ) !=
833 ( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS ) )
834 {
835 return( HETE_BADCOMPRESS );
836 }
837 if( ( flags2 & HETHDR_FLAGS2_COMPRESS ) !=
838 ( hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS ) )
839 {
840 return( HETE_BADCOMPRESS );
841 }
842
843 /*
844 || Calculate running length
845 */
846 slen = HETHDR_CLEN( hetb );
847 tlen += slen;
848
849 /*
850 || Can't be bigger than HETMAX_BLOCKSIZE
851 */
852 if( tlen > HETMAX_BLOCKSIZE )
853 {
854 return( HETE_OVERFLOW );
855 }
856
857 /*
858 || Finally read in the chunk data
859 */
860 rc = fread( tptr, 1, slen, hetb->fd );
861 if( rc != (int)slen )
862 {
863 if( feof( hetb->fd ) )
864 {
865 return( HETE_PREMEOF );
866 }
867
868 return( HETE_ERROR );
869 }
870
871 /*
872 || Bump destination pointer to next possible location
873 */
874 tptr += slen;
875 }
876 while( !( hetb->chdr.flags1 & HETHDR_FLAGS1_EOR ) );
877
878 /*
879 || Save compressed length (means cblksize size and ublksize will be the
880 || same for uncompressed data)
881 */
882 hetb->cblksize = tlen;
883
884 /*
885 || Decompress data if requested
886 */
887 if( hetb->decompress )
888 {
889 switch( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS )
890 {
891 case 0:
892 switch( hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS )
893 {
894 case 0:
895 break;
896 #if defined( HAVE_LIBZ )
897 case HETHDR_FLAGS2_ZLIB_BUSTECH:
898 slen = HETMAX_BLOCKSIZE;
899
900 rc = uncompress( sbuf, &slen, (unsigned char *)tbuf, tlen );
901 if( rc != Z_OK )
902 {
903 errno = rc;
904 return( HETE_DECERR );
905 }
906
907 tlen = slen;
908 break;
909 #endif /* defined( HAVE_LIBZ ) */
910 default:
911 return( HETE_UNKMETH );
912 break;
913 }
914 break;
915
916 #if defined( HAVE_LIBZ )
917 case HETHDR_FLAGS1_ZLIB:
918 slen = HETMAX_BLOCKSIZE;
919
920 rc = uncompress( sbuf, &slen, (unsigned char *)tbuf, tlen );
921 if( rc != Z_OK )
922 {
923 errno = rc;
924 return( HETE_DECERR );
925 }
926
927 tlen = slen;
928 break;
929 #endif /* defined( HAVE_LIBZ ) */
930
931 #if defined( HET_BZIP2 )
932 case HETHDR_FLAGS1_BZLIB:
933 slen = HETMAX_BLOCKSIZE;
934
935 rc = BZ2_bzBuffToBuffDecompress( sbuf,
936 (void *) &slen,
937 tbuf,
938 tlen,
939 0,
940 0 );
941 if (rc != BZ_OK)
942 {
943 errno = rc;
944 return( HETE_DECERR );
945 }
946
947 tlen = slen;
948 break;
949 #endif /* defined( HET_BZIP2 ) */
950
951 default:
952 return( HETE_UNKMETH );
953 break;
954 }
955 }
956
957 /*
958 || Save uncompressed length
959 */
960 hetb->ublksize = tlen;
961
962 /*
963 || Success
964 */
965 return( tlen );
966 }
967
968 /*==DOC==
969
970 NAME
971 het_write_header - Write a chunk header to an HET file
972
973 SYNOPSIS
974 #include "hetlib.h"
975
976 int het_write_header( HETB *hetb, int len, int flags1, int flags2 )
977
978 DESCRIPTION
979 Constructs and writes a chunk header to an HET file.
980
981 RETURN VALUE
982 If no errors are detected then the return value will be >= 0
983 and the current block count will be incremented.
984
985 If an error occurs, then the return value will be < 0 and can be
986 one of the following:
987
988 HETE_BADLEN "len" parameter out of range
989
990 HETE_PROTECTED File is write protected
991
992 HETE_ERROR File system error - check errno(3)
993
994 NOTES
995 This function is not normally called from user programs and its
996 behavior may change.
997
998 If this function is called and the tape is not positioned at the
999 end, then the file will be truncated to the current position. This
1000 means that rewriting blocks is not currently possible.
1001
1002 EXAMPLE
1003 //
1004 // Write a chunk header to an HET file.
1005 //
1006
1007 #include "hetlib.h"
1008
1009 int main( int argc, char *argv[] )
1010 {
1011 HETB *hetb;
1012 int rc;
1013
1014 rc = het_open( &hetb, argv[ 1 ], 0 );
1015 if( rc >= 0 )
1016 {
1017 rc = het_write_header( hetb, 0, HETHDR_TAPEMARK, 0 );
1018 if( rc >= 0 )
1019 {
1020 printf( "Header written\n" );
1021 }
1022 }
1023
1024 if( rc < 0 )
1025 {
1026 printf( "HETLIB error: %d\n", rc );
1027 }
1028
1029 het_close( &hetb );
1030
1031 return( 0 );
1032 }
1033
1034 SEE ALSO
1035 het_open(), het_close()
1036
1037 ==DOC==*/
1038
1039 int
het_write_header(HETB * hetb,int len,int flags1,int flags2)1040 het_write_header( HETB *hetb, int len, int flags1, int flags2 )
1041 {
1042 int rc;
1043 off_t rcoff;
1044
1045 #if defined( HETDEBUGW )
1046 printf("write hdr: pl=%d, cl=%d, f1=%02x, f2=%02x\n",
1047 HETHDR_PLEN( hetb ), HETHDR_CLEN( hetb ),
1048 hetb->chdr.flags1, hetb->chdr.flags2);
1049 #endif
1050
1051 /*
1052 || Validate length
1053 */
1054 if( len > HETMAX_CHUNKSIZE )
1055 {
1056 return( HETE_BADLEN );
1057 }
1058
1059 /*
1060 || Can't write anything on readonly media
1061 */
1062 if( hetb->writeprotect )
1063 {
1064 return( HETE_PROTECTED );
1065 }
1066
1067 /*
1068 || For tapemarks, length must be zero.
1069 */
1070 if( flags1 & HETHDR_FLAGS1_TAPEMARK )
1071 {
1072 len = 0;
1073 }
1074
1075 /*
1076 || According to Linux fopen() man page, a positioning function is required
1077 || between reads and writes. Is this REALLY necessary???
1078 */
1079 if( !hetb->readlast )
1080 {
1081 fseek( hetb->fd, 0, SEEK_CUR );
1082 hetb->readlast = FALSE;
1083 }
1084
1085 /*
1086 || If this is the first write, truncate the file
1087 */
1088 if( !hetb->truncated )
1089 {
1090 rcoff = ftell( hetb->fd );
1091 if( rcoff == -1 )
1092 {
1093 return( HETE_ERROR );
1094 }
1095
1096 rc = ftruncate( fileno( hetb->fd ), rcoff );
1097 if( rc == -1 )
1098 {
1099 return( HETE_ERROR );
1100 }
1101
1102 hetb->truncated = TRUE;
1103 }
1104
1105 /*
1106 || Construct the header
1107 */
1108 hetb->chdr.plen[ 0 ] = hetb->chdr.clen[ 0 ];
1109 hetb->chdr.plen[ 1 ] = hetb->chdr.clen[ 1 ];
1110 hetb->chdr.clen[ 0 ] = len & 0xFF;
1111 hetb->chdr.clen[ 1 ] = ( len >> 8 ) & 0xFF;
1112 hetb->chdr.flags1 = flags1;
1113 hetb->chdr.flags2 = flags2;
1114
1115 /*
1116 || Write it out
1117 */
1118 rc = fwrite( &hetb->chdr, sizeof( HETHDR ), 1, hetb->fd );
1119 if( rc != 1 )
1120 {
1121 return( HETE_ERROR );
1122 }
1123
1124 /*
1125 || Bump block count if done with entire block
1126 */
1127 if( hetb->chdr.flags1 & ( HETHDR_FLAGS1_EOR | HETHDR_FLAGS1_TAPEMARK ) )
1128 {
1129 hetb->cblk++;
1130 }
1131
1132 /*
1133 || Success
1134 */
1135 return 0;
1136 }
1137
1138 /*==DOC==
1139
1140 NAME
1141 het_write - Write a block to an HET file
1142
1143 SYNOPSIS
1144 #include "hetlib.h"
1145
1146 int het_write( HETB *hetb, void *sbuf, int slen )
1147
1148 DESCRIPTION
1149 Writes a block of data specified by "sbuf" with a length of "slen"
1150 to an HET file. Depending on the current HETCNTL_COMPRESS setting,
1151 the data may be compressed prior to writing.
1152
1153 RETURN VALUE
1154 If no errors are detected then the return value will be the
1155 size of the block written. This will be either the compressed or
1156 uncompressed length depending on the current AWSCNTL_COMPRESS
1157 setting.
1158
1159 If an error occurs, then the return value will be < 0 and can be
1160 one of the following:
1161
1162 HETE_ERROR File system error - check errno(3)
1163
1164 HETE_BADLEN "slen" parameter out of range
1165
1166 HETE_BADCOMPRESS Compression mismatch between related chunks
1167
1168 For other possible errors, see:
1169 het_write_header()
1170
1171 EXAMPLE
1172 //
1173 // Create an NL tape and write a string to it
1174 //
1175
1176 #include "hetlib.h"
1177
1178 char data[] = "This is a test";
1179
1180 int main( int argc, char *argv[] )
1181 {
1182 HETB *hetb;
1183 int rc;
1184
1185 rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE );
1186 if( rc >= 0 )
1187 {
1188 rc = het_write( hetb, data, sizeof( data ) );
1189 if( rc >= 0 )
1190 {
1191 printf( "Block written - length: %d\n", rc );
1192 }
1193 }
1194
1195 if( rc < 0 )
1196 {
1197 printf( "HETLIB error: %d\n", rc );
1198 }
1199
1200 het_close( &hetb );
1201
1202 return( 0 );
1203 }
1204
1205 SEE ALSO
1206 het_open(), het_write_header(), het_close()
1207
1208 ==DOC==*/
1209
1210 DLL_EXPORT int
het_write(HETB * hetb,void * sbuf,int slen)1211 het_write( HETB *hetb, void *sbuf, int slen )
1212 {
1213 int rc;
1214 int flags;
1215 unsigned long tlen;
1216 #if defined(HAVE_LIBZ) || defined( HET_BZIP2 )
1217 char tbuf[ ((((HETMAX_BLOCKSIZE * 1001) + 999) / 1000) + 12) ];
1218 #endif
1219
1220 /*
1221 || Validate
1222 */
1223 if( slen > HETMAX_BLOCKSIZE )
1224 {
1225 return( HETE_BADLEN );
1226 }
1227
1228 /*
1229 || Initialize
1230 */
1231 flags = HETHDR_FLAGS1_BOR;
1232
1233 /*
1234 || Save uncompressed length
1235 */
1236 hetb->ublksize = slen;
1237
1238 /*
1239 || Compress data if requested
1240 */
1241 if( hetb->compress )
1242 {
1243 switch( hetb->method )
1244 {
1245 #if defined(HAVE_LIBZ)
1246 case HETHDR_FLAGS1_ZLIB:
1247 tlen = sizeof( tbuf );
1248
1249 rc = compress2( (unsigned char *)tbuf, &tlen, sbuf, slen, hetb->level );
1250 if( rc != Z_OK )
1251 {
1252 errno = rc;
1253 return( HETE_COMPERR );
1254 }
1255
1256 if( (int)tlen < slen )
1257 {
1258 sbuf = tbuf;
1259 slen = tlen;
1260 flags |= HETHDR_FLAGS1_ZLIB;
1261 }
1262 break;
1263 #endif
1264
1265 #if defined( HET_BZIP2 )
1266 case HETHDR_FLAGS1_BZLIB:
1267 tlen = sizeof( tbuf );
1268
1269 rc = BZ2_bzBuffToBuffCompress( tbuf,
1270 (void *) &tlen,
1271 sbuf,
1272 slen,
1273 hetb->level,
1274 0,
1275 0 );
1276 if( rc != BZ_OK )
1277 {
1278 errno = rc;
1279 return( HETE_COMPERR );
1280 }
1281
1282 if( (int)tlen < slen )
1283 {
1284 sbuf = tbuf;
1285 slen = tlen;
1286 flags |= HETHDR_FLAGS1_BZLIB;
1287 }
1288 break;
1289 #endif /* defined( HET_BZIP2 ) */
1290 }
1291 }
1292
1293 /*
1294 || Save compressed length
1295 */
1296 hetb->cblksize = slen;
1297
1298 /*
1299 || Write block, breaking it into "chksize" chunks
1300 */
1301 do
1302 {
1303 /*
1304 || Last chunk for this block?
1305 */
1306 if( slen <= (int)hetb->chksize )
1307 {
1308 flags |= HETHDR_FLAGS1_EOR;
1309 tlen = slen;
1310 }
1311 else
1312 {
1313 tlen = hetb->chksize;
1314 }
1315
1316 /*
1317 || Write the header
1318 */
1319 rc = het_write_header( hetb, tlen, flags, 0 );
1320 if( rc < 0 )
1321 {
1322 return( rc );
1323 }
1324
1325 /*
1326 || Write the block
1327 */
1328 rc = fwrite( sbuf, 1, tlen, hetb->fd );
1329 if( rc != (int)tlen )
1330 {
1331 return( HETE_ERROR );
1332 }
1333
1334 /*
1335 || Bump pointers and turn off BOR flag
1336 */
1337 {
1338 char *csbuf;
1339 csbuf=(char *)sbuf;
1340 csbuf+=tlen;
1341 sbuf=(void *)csbuf;
1342 }
1343 slen -= tlen;
1344 flags &= (~HETHDR_FLAGS1_BOR);
1345 }
1346 while( slen > 0 );
1347
1348 /*
1349 || Set new physical EOF
1350 */
1351 do rc = ftruncate( fileno( hetb->fd ), ftell( hetb->fd ) );
1352 while (EINTR == rc);
1353 if (rc != 0)
1354 {
1355 return( HETE_ERROR );
1356 }
1357
1358 /*
1359 || Success
1360 */
1361 return( hetb->cblksize );
1362 }
1363
1364 /*==DOC==
1365
1366 NAME
1367 het_tapemark - Write a tape mark to an HET file
1368
1369 SYNOPSIS
1370 #include "hetlib.h"
1371
1372 int het_tapemark( HETB *hetb )
1373
1374 DESCRIPTION
1375 Writes a special chunk header to an HET file to simulate a tape
1376 mark.
1377
1378 RETURN VALUE
1379 If no errors are detected then the return value will be >= 0.
1380
1381 If an error occurs, then the return value will be < 0 and will be
1382 the same as those returned by het_write_header().
1383
1384 EXAMPLE
1385 //
1386 // Write a tapemark to an HET file
1387 //
1388
1389 #include "hetlib.h"
1390
1391 int main( int argc, char *argv[] )
1392 {
1393 HETB *hetb;
1394 int rc;
1395
1396 rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE );
1397 if( rc >= 0 )
1398 {
1399 rc = het_tapemark( hetb );
1400 if( rc >= 0 )
1401 {
1402 printf( "Tape mark written\n" );
1403 }
1404 }
1405
1406 if( rc < 0 )
1407 {
1408 printf( "HETLIB error: %d\n", rc );
1409 }
1410
1411 het_close( &hetb );
1412
1413 return( 0 );
1414 }
1415
1416 SEE ALSO
1417 het_open(), het_write_header(), het_close()
1418
1419 ==DOC==*/
1420
1421 DLL_EXPORT int
het_tapemark(HETB * hetb)1422 het_tapemark( HETB *hetb )
1423 {
1424 int rc;
1425
1426 /*
1427 || Just write a tapemark header
1428 */
1429 rc = het_write_header( hetb, 0, HETHDR_FLAGS1_TAPEMARK, 0 );
1430 if( rc < 0 )
1431 {
1432 return( rc );
1433 }
1434
1435 /*
1436 || Set new physical EOF
1437 */
1438 do rc = ftruncate( fileno( hetb->fd ), ftell( hetb->fd ) );
1439 while (EINTR == rc);
1440 if (rc != 0)
1441 {
1442 return( HETE_ERROR );
1443 }
1444
1445 /*
1446 || Success
1447 */
1448 return( 0 );
1449 }
1450
1451 /*==DOC==
1452
1453 NAME
1454 het_sync - commit/flush a HET file's buffers to disk
1455
1456 SYNOPSIS
1457 #include "hetlib.h"
1458
1459 int het_sync( HETB *hetb )
1460
1461 DESCRIPTION
1462 Calls the file system's "fdatasync" (or fsync) function to cause
1463 all data for the HET file to be transferred to disk by forcing a
1464 physical write of all data from the file's buffers or the file-
1465 system's cache, to the disk, thereby assuring that after a system
1466 crash or other failure, that all data up to the time of the call
1467 is thus recorded on the disk.
1468
1469 RETURN VALUE
1470 If no errors are detected then the return value will be >= 0.
1471
1472 If an error occurs, then the return value will be < 0 and will be
1473 one of the following:
1474
1475 HETE_PROTECTED File is write protected
1476
1477 HETE_ERROR File system error - check errno(3)
1478
1479 EXAMPLE
1480 //
1481 // Flush a HET file's buffers to disk
1482 //
1483
1484 #include "hetlib.h"
1485
1486 char data[] = "This is a test";
1487
1488 int main( int argc, char *argv[] )
1489 {
1490 HETB *hetb;
1491 int rc;
1492
1493 rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE );
1494 if( rc >= 0 )
1495 {
1496 rc = het_write( hetb, data, sizeof( data ) );
1497 if( rc >= 0 )
1498 {
1499 printf( "Block successfully written\n" );
1500
1501 rc = het_sync( &hetb );
1502 if( rc >= 0 )
1503 {
1504 printf( "Block successfully committed\n" );
1505 }
1506 }
1507 }
1508
1509 if( rc < 0 )
1510 {
1511 printf( "HETLIB error: %d\n", rc );
1512 }
1513
1514 het_close( &hetb );
1515
1516 return( 0 );
1517 }
1518
1519 SEE ALSO
1520 het_open(), het_write(), het_close()
1521
1522 ==DOC==*/
1523
1524 DLL_EXPORT int
het_sync(HETB * hetb)1525 het_sync( HETB *hetb )
1526 {
1527 int rc;
1528
1529 /*
1530 || Can't sync to readonly media
1531 */
1532 if( hetb->writeprotect )
1533 {
1534 return( HETE_PROTECTED );
1535 }
1536
1537 /*
1538 || Perform the sync
1539 */
1540 do rc = fdatasync( fileno( hetb->fd ) );
1541 while (EINTR == rc);
1542 if (rc != 0)
1543 {
1544 return( HETE_ERROR );
1545 }
1546
1547 /*
1548 || Success
1549 */
1550 return( 0 );
1551 }
1552
1553 /*==DOC==
1554
1555 NAME
1556 het_locate - Locate a block within an HET file
1557
1558 SYNOPSIS
1559 #include "hetlib.h"
1560
1561 int het_locate( HETB *hetb, int block )
1562
1563 DESCRIPTION
1564 Repositions the HET file to the start of the block specified by
1565 the "block" parameter.
1566
1567 RETURN VALUE
1568 If no errors are detected then the return value will be >= 0 and
1569 represents the new current block number.
1570
1571 If an error occurs, then the return value will be < 0 and will
1572 the same as those returned by:
1573 het_rewind()
1574 het_fsb()
1575
1576 NOTES
1577 Block numbers start at 0.
1578
1579 EXAMPLE
1580 //
1581 // Seek to block #4 in HET file
1582 //
1583
1584 #include "hetlib.h"
1585
1586 int main( int argc, char *argv[] )
1587 {
1588 HETB *hetb;
1589 int rc;
1590
1591 rc = het_open( &hetb, argv[ 1 ], 0 );
1592 if( rc >= 0 )
1593 {
1594 rc = het_locate( hetb, 4 );
1595 if( rc >= 0 )
1596 {
1597 printf( "New tape position: %d\n", rc );
1598 }
1599 }
1600
1601 if( rc < 0 )
1602 {
1603 printf( "HETLIB error: %d\n", rc );
1604 }
1605
1606 het_close( &hetb );
1607
1608 return( 0 );
1609 }
1610
1611 SEE ALSO
1612 het_open(), het_rewind(), het_fsb(), het_close()
1613
1614 ==DOC==*/
1615
1616 DLL_EXPORT int
het_locate(HETB * hetb,int block)1617 het_locate( HETB *hetb, int block )
1618 {
1619 int rc;
1620
1621 /*
1622 || Start the search from the beginning
1623 */
1624 rc = het_rewind( hetb );
1625 if( rc < 0 )
1626 {
1627 return( rc );
1628 }
1629
1630 /*
1631 || Forward space until we reach the desired block
1632 */
1633 while( (int)hetb->cblk < block )
1634 {
1635 rc = het_fsb( hetb );
1636 if( rc < 0 && HETE_TAPEMARK != rc )
1637 {
1638 return( rc );
1639 }
1640 }
1641
1642 return( hetb->cblk );
1643 }
1644
1645 /*==DOC==
1646
1647 NAME
1648 het_bsb - Backspace a block in an HET file
1649
1650 SYNOPSIS
1651 #include "hetlib.h"
1652
1653 int het_bsb( HETB *hetb )
1654
1655 DESCRIPTION
1656 Repositions the current block pointer in an HET file to the
1657 previous block.
1658
1659 RETURN VALUE
1660 If no errors are detected then the return value will be >= 0 and
1661 will be the new block number.
1662
1663 If an error occurs, then the return value will be < 0 and can be
1664 one of the following:
1665
1666 HETE_ERROR File system error - check errno(3)
1667
1668 HETE_BOT Beginning of tape
1669
1670 HETE_TAPEMARK Tape mark encountered
1671
1672 For other possible errors, see:
1673 het_rewind()
1674 het_read_header()
1675
1676 EXAMPLE
1677 //
1678 // Backspace a block in an HET file
1679 //
1680
1681 #include "hetlib.h"
1682
1683 int main( int argc, char *argv[] )
1684 {
1685 HETB *hetb;
1686 int rc;
1687
1688 rc = het_open( &hetb, argv[ 1 ], 0 );
1689 if( rc >= 0 )
1690 {
1691 rc = het_fsb( hetb );
1692 if( rc >= 0 )
1693 {
1694 rc = het_bsb( hetb );
1695 if( rc >= 0 )
1696 {
1697 printf( "New block number = %d\n", rc );
1698 }
1699 }
1700 }
1701
1702 if( rc < 0 )
1703 {
1704 printf( "HETLIB error: %d\n", rc );
1705 }
1706
1707 het_close( &hetb );
1708
1709 return( 0 );
1710 }
1711
1712 SEE ALSO
1713 het_open(), het_rewind(), het_read_header(), het_fsb(), het_close()
1714
1715 ==DOC==*/
1716
1717 DLL_EXPORT int
het_bsb(HETB * hetb)1718 het_bsb( HETB *hetb )
1719 {
1720 int rc;
1721 int newblk;
1722 int offset; // (note: safe to use 'int' as offset here
1723 // since we only ever seek from SEEK_CUR)
1724 int tapemark = FALSE;
1725
1726 /*
1727 || Error if at BOT
1728 */
1729 if( hetb->cblk == 0 )
1730 {
1731 return( HETE_BOT );
1732 }
1733
1734 /*
1735 || Get new block number
1736 */
1737 newblk = hetb->cblk - 1;
1738
1739 /*
1740 || If new block is first on, then just rewind
1741 */
1742 if( newblk == 0 )
1743 {
1744 return( het_rewind( hetb ) );
1745 }
1746
1747 /*
1748 || Calculate offset to get back to beginning of current block
1749 */
1750 offset = -((int)( HETHDR_CLEN( hetb ) + sizeof( HETHDR ) ));
1751
1752 /*
1753 || Search backwards an entire block. If the block is a tapemark, we can't
1754 || just return to caller since we must load the chunk header preceding it
1755 || to maintain the chdr in the HET.
1756 */
1757 do
1758 {
1759 /*
1760 || Reposition to start of chunk
1761 */
1762 rc = fseek( hetb->fd,
1763 offset,
1764 SEEK_CUR );
1765 if( rc == -1 )
1766 {
1767 return( HETE_ERROR );
1768 }
1769
1770 /*
1771 || Read header, ignoring tapemarks
1772 */
1773 rc = het_read_header( hetb );
1774 if( rc < 0 && rc != HETE_TAPEMARK )
1775 {
1776 return( rc );
1777 }
1778
1779 /*
1780 || Recalculate offset
1781 */
1782 offset = -((int)( HETHDR_PLEN( hetb ) + ( sizeof( HETHDR ) * 2 ) ));
1783 }
1784 while( hetb->chdr.flags1 & !( HETHDR_FLAGS1_BOR | HETHDR_FLAGS1_TAPEMARK ) );
1785
1786 /*
1787 || Remember whether it's a tapemark or not
1788 */
1789 tapemark = ( hetb->chdr.flags1 & HETHDR_FLAGS1_TAPEMARK );
1790
1791 /*
1792 || Reposition to chunk header preceding this one so we can load keep the
1793 || chdr in the HET current.
1794 */
1795 rc = fseek( hetb->fd,
1796 offset,
1797 SEEK_CUR );
1798 if( rc == -1 )
1799 {
1800 return( HETE_ERROR );
1801 }
1802
1803 /*
1804 || Read header (ignore tapemarks)
1805 */
1806 rc = het_read_header( hetb );
1807 if( rc < 0 && ( rc != HETE_TAPEMARK ) )
1808 {
1809 return( rc );
1810 }
1811
1812 /*
1813 || Finally reposition back to the where we should be
1814 */
1815 rc = fseek( hetb->fd,
1816 HETHDR_CLEN( hetb ),
1817 SEEK_CUR );
1818 if( rc == -1 )
1819 {
1820 return( HETE_ERROR );
1821 }
1822
1823 /*
1824 || Store new block number
1825 */
1826 hetb->cblk = newblk;
1827
1828 /*
1829 || Was it a tapemark?
1830 */
1831 if( tapemark )
1832 {
1833 return( HETE_TAPEMARK );
1834 }
1835
1836 /*
1837 || Reset flag to force truncation if a write occurs
1838 */
1839 hetb->truncated = FALSE;
1840
1841 /*
1842 || Return block number
1843 */
1844 return( hetb->cblk );
1845 }
1846
1847 /*==DOC==
1848
1849 NAME
1850 het_fsb - Foward space a block in an HET file
1851
1852 SYNOPSIS
1853 #include "hetlib.h"
1854
1855 int het_fsb( HETB *hetb )
1856
1857 DESCRIPTION
1858 Repositions the current block pointer in an HET file to the
1859 next block.
1860
1861 RETURN VALUE
1862 If no errors are detected then the return value will be >= 0 and
1863 will be the new block number.
1864
1865 If an error occurs, then the return value will be < 0 and can be
1866 one of the following:
1867
1868 HETE_ERROR File system error - check errno(3)
1869
1870 For other possible errors, see:
1871 het_read_header()
1872
1873 EXAMPLE
1874 //
1875 // Forward space a block in an HET file
1876 //
1877
1878 #include "hetlib.h"
1879
1880 int main( int argc, char *argv[] )
1881 {
1882 HETB *hetb;
1883 int rc;
1884
1885 rc = het_open( &hetb, argv[ 1 ], 0 );
1886 if( rc >= 0 )
1887 {
1888 rc = het_fsb( hetb );
1889 if( rc >= 0 )
1890 {
1891 printf( "New block number = %d\n", rc );
1892 }
1893 }
1894
1895 if( rc < 0 )
1896 {
1897 printf( "HETLIB error: %d\n", rc );
1898 }
1899
1900 het_close( &hetb );
1901
1902 return( 0 );
1903 }
1904
1905 SEE ALSO
1906 het_open(), het_read_header(), het_close()
1907
1908 ==DOC==*/
1909
1910 DLL_EXPORT int
het_fsb(HETB * hetb)1911 het_fsb( HETB *hetb )
1912 {
1913 int rc;
1914
1915 /*
1916 || Loop until we've processed an entire block
1917 */
1918 do
1919 {
1920 /*
1921 || Read header to get length of next chunk
1922 */
1923 rc = het_read_header( hetb );
1924 if( rc < 0 )
1925 {
1926 return( rc );
1927 }
1928
1929 /*
1930 || Seek to next chunk
1931 */
1932 rc = fseek( hetb->fd,
1933 HETHDR_CLEN( hetb ),
1934 SEEK_CUR );
1935 if( rc == -1 )
1936 {
1937 return( HETE_ERROR );
1938 }
1939 }
1940 while( !( hetb->chdr.flags1 & HETHDR_FLAGS1_EOR ) );
1941
1942 /*
1943 || Reset flag to force truncation if a write occurs
1944 */
1945 hetb->truncated = FALSE;
1946
1947 /*
1948 || Return block number
1949 */
1950 return( hetb->cblk );
1951 }
1952
1953 /*==DOC==
1954
1955 NAME
1956 het_bsf - Backspace a file in an HET file
1957
1958 SYNOPSIS
1959 #include "hetlib.h"
1960
1961 int het_bsf( HETB *hetb )
1962
1963 DESCRIPTION
1964 Repositions the current block pointer in an HET file to the
1965 previous tapemark.
1966
1967 RETURN VALUE
1968 If no errors are detected then the return value will be >= 0 and
1969 will be the new block number.
1970
1971 If an error occurs, then the return value will be < 0 and will be
1972 the same as those returned by het_bsb() with the exception that
1973 HETE_TAPEMARK and HETE_BOT will not occur.
1974
1975 EXAMPLE
1976 //
1977 // Backspace a file in an HET file
1978 //
1979
1980 #include "hetlib.h"
1981
1982 int main( int argc, char *argv[] )
1983 {
1984 HETB *hetb;
1985 int rc;
1986
1987 rc = het_open( &hetb, argv[ 1 ], 0 );
1988 if( rc >= 0 )
1989 {
1990 rc = het_fsf( hetb );
1991 if( rc >= 0 )
1992 {
1993 rc = het_bsf( hetb );
1994 if( rc >= 0 )
1995 {
1996 printf( "Backspaced (sort of :-))\n" );
1997 }
1998 }
1999 }
2000
2001 if( rc < 0 )
2002 {
2003 printf( "HETLIB error: %d\n", rc );
2004 }
2005
2006 het_close( &hetb );
2007
2008 return( 0 );
2009 }
2010
2011 SEE ALSO
2012 het_open(), het_bsb(), het_fsf(), het_close()
2013
2014 ==DOC==*/
2015
2016 DLL_EXPORT int
het_bsf(HETB * hetb)2017 het_bsf( HETB *hetb )
2018 {
2019 int rc;
2020
2021 /*
2022 || Backspace until we hit a tapemark
2023 */
2024 do
2025 {
2026 rc = het_bsb( hetb );
2027 }
2028 while( rc >= 0 );
2029
2030 /*
2031 || Success
2032 */
2033 if( ( rc == HETE_BOT ) || ( rc == HETE_TAPEMARK ) )
2034 {
2035 return( hetb->cblk );
2036 }
2037
2038 /*
2039 || Failure
2040 */
2041 return( rc );
2042 }
2043
2044 /*==DOC==
2045
2046 NAME
2047 het_fsf - Forward space a file in an HET file
2048
2049 SYNOPSIS
2050 #include "hetlib.h"
2051
2052 int het_fsf( HETB *hetb )
2053
2054 DESCRIPTION
2055 Repositions the current block pointer in an HET file to the
2056 next tapemark.
2057
2058 RETURN VALUE
2059 If no errors are detected then the return value will be >= 0 and
2060 will be the new block number.
2061
2062 If an error occurs, then the return value will be < 0 and will be
2063 the same as those returned by het_fsb() with the exception that
2064 HETE_TAPEMARK will not occur.
2065
2066 EXAMPLE
2067 //
2068 // Forward space a file in an HET file
2069 //
2070
2071 #include "hetlib.h"
2072
2073 int main( int argc, char *argv[] )
2074 {
2075 HETB *hetb;
2076 int rc;
2077
2078 rc = het_open( &hetb, argv[ 1 ], 0 );
2079 if( rc >= 0 )
2080 {
2081 rc = het_fsf( hetb );
2082 if( rc >= 0 )
2083 {
2084 printf( "Forward spaced\n" );
2085 }
2086 }
2087
2088 if( rc < 0 )
2089 {
2090 printf( "HETLIB error: %d\n", rc );
2091 }
2092
2093 het_close( &hetb );
2094
2095 return( 0 );
2096 }
2097
2098 SEE ALSO
2099 het_open(), het_fsb(), het_close()
2100
2101 ==DOC==*/
2102
2103 DLL_EXPORT int
het_fsf(HETB * hetb)2104 het_fsf( HETB *hetb )
2105 {
2106 int rc;
2107
2108 /*
2109 || Forward space until we hit a tapemark
2110 */
2111 do
2112 {
2113 rc = het_fsb( hetb );
2114 }
2115 while( rc >= 0 );
2116
2117 /*
2118 || Success
2119 */
2120 if( rc == HETE_TAPEMARK )
2121 {
2122 return( hetb->cblk );
2123 }
2124
2125 /*
2126 || Failure
2127 */
2128 return( rc );
2129 }
2130
2131 /*==DOC==
2132
2133 NAME
2134 het_rewind - Rewind an HET file
2135
2136 SYNOPSIS
2137 #include "hetlib.h"
2138
2139 int het_rewind( HETB *hetb )
2140
2141 DESCRIPTION
2142 Repositions the current block pointer in an HET file to the
2143 load point.
2144
2145 RETURN VALUE
2146 If no errors are detected then the return value will be >= 0 and
2147 represents the new block number (always 0).
2148
2149 If an error occurs, then the return value will be < 0 and will be
2150 one of the following:
2151
2152 HETE_ERROR File system error - check errno(3)
2153
2154 EXAMPLE
2155 //
2156 // Rewind an HET file to the load point.
2157 //
2158
2159 #include "hetlib.h"
2160
2161 int main( int argc, char *argv[] )
2162 {
2163 HETB *hetb;
2164 int rc;
2165
2166 rc = het_open( &hetb, argv[ 1 ], 0 );
2167 if( rc >= 0 )
2168 {
2169 rc = het_rewind( hetb );
2170 if( rc >= 0 )
2171 {
2172 printf( "Tape rewound\n" );
2173 }
2174 }
2175
2176 if( rc < 0 )
2177 {
2178 printf( "HETLIB error: %d\n", rc );
2179 }
2180
2181 het_close( &hetb );
2182
2183 return( 0 );
2184 }
2185
2186 SEE ALSO
2187 het_open(), het_close()
2188
2189 ==DOC==*/
2190
2191 DLL_EXPORT int
het_rewind(HETB * hetb)2192 het_rewind( HETB *hetb )
2193 {
2194 int rc;
2195
2196 /*
2197 || Just seek to the beginning of the file
2198 */
2199 rc = fseek( hetb->fd,
2200 0,
2201 SEEK_SET );
2202 if( rc == -1 )
2203 {
2204 return( HETE_ERROR );
2205 }
2206
2207 /*
2208 || Reset current block
2209 */
2210 hetb->cblk = 0;
2211
2212 /*
2213 || Clear header for the heck of it
2214 */
2215 memset( &hetb->chdr, 0, sizeof( hetb->chdr ) );
2216
2217 /*
2218 || Reset flag to force truncation if a write occurs
2219 */
2220 hetb->truncated = FALSE;
2221
2222 /*
2223 || Return block number
2224 */
2225 return( hetb->cblk );
2226 }
2227
2228 /*==DOC==
2229
2230 NAME
2231 het_error - Returns a text message for an HET error code
2232
2233 SYNOPSIS
2234 #include "hetlib.h"
2235
2236 char *het_error( int rc )
2237
2238 DESCRIPTION
2239 Simply returns a pointer to a string that describes the error
2240 code passed in the "rc" parameter.
2241
2242 RETURN VALUE
2243 The return value is always valid and no errors are returned.
2244
2245 EXAMPLE
2246 //
2247 // Print text of HETE_BADLEN.
2248 //
2249
2250 #include "hetlib.h"
2251
2252 int main( int argc, char *argv[] )
2253 {
2254 printf( "HETLIB error: %d = %s\n",
2255 HETE_BADLEN,
2256 het_error( HETE_BADLEN ) );
2257
2258 return( 0 );
2259 }
2260
2261 SEE ALSO
2262
2263 ==DOC==*/
2264
2265 DLL_EXPORT const char *
het_error(int rc)2266 het_error( int rc )
2267 {
2268 /*
2269 || If not an error just return the "OK" string
2270 */
2271 if( rc >= 0 )
2272 {
2273 rc = 0;
2274 }
2275
2276 /*
2277 || Turn it into an index
2278 */
2279 rc = -rc;
2280
2281 /*
2282 || Within range?
2283 */
2284 if( rc >= (int)HET_ERRSTR_MAX )
2285 {
2286 rc = HET_ERRSTR_MAX - 1;
2287 }
2288
2289 /*
2290 || Return string
2291 */
2292 return( het_errstr[ rc ] );
2293 }
2294 /*==DOC==
2295
2296 NAME
2297 het_tell - Returns the current read/write pointer offset
2298
2299 SYNOPSIS
2300 #include "hetlib.h"
2301
2302 off_t het_tell( HETB *hetb )
2303
2304 DESCRIPTION
2305 Returns a off_t describing the actual read/write cursor
2306 within the HET file
2307
2308 RETURN VALUE
2309 >=0 The actual cursor offset
2310 <0 An error occured.
2311 Possible errors are :
2312 HETE_ERROR - File system error occured
2313
2314 EXAMPLE
2315 //
2316 // Get the current HET pointer
2317 //
2318
2319 #include "hetlib.h"
2320
2321 int main( int argc, char *argv[] )
2322 {
2323 HETB *hetb;
2324 int rc;
2325 off_t rwptr;
2326
2327 rc = het_open( &hetb, argv[ 1 ], 0 );
2328 if( rc >= 0 )
2329 {
2330 rwptr = het_tell( hetb );
2331 if( rwptr >= 0 )
2332 {
2333 printf( "Current offset is %" I64_FMT "d\n" , (U64)rwptr);
2334 }
2335 }
2336
2337 if( rc < 0 )
2338 {
2339 printf( "HETLIB error: %d\n", rc );
2340 }
2341
2342 het_close( &hetb );
2343
2344 return( 0 );
2345 }
2346
2347 SEE ALSO
2348
2349 ==DOC==*/
2350
2351 DLL_EXPORT
2352 off_t
het_tell(HETB * hetb)2353 het_tell( HETB *hetb )
2354 {
2355 off_t rwptr = ftell( hetb->fd );
2356 if ( rwptr < 0 )
2357 {
2358 return HETE_ERROR;
2359 }
2360 return rwptr;
2361 }
2362