1 /* TAPESPLT.C (c) Copyright Jay Maynard, 2000-2009 */
2 /* Split AWSTAPE format tape image */
3
4 /*-------------------------------------------------------------------*/
5 /* This program reads an AWSTAPE format tape image file and produces */
6 /* output files containing pieces of it, controlled by command line */
7 /* options. */
8 /*-------------------------------------------------------------------*/
9
10 #include "hstdinc.h"
11
12 #include "hercules.h"
13
14 /*-------------------------------------------------------------------*/
15 /* Structure definition for AWSTAPE block header */
16 /*-------------------------------------------------------------------*/
17 typedef struct _AWSTAPE_BLKHDR {
18 HWORD curblkl; /* Length of this block */
19 HWORD prvblkl; /* Length of previous block */
20 BYTE flags1; /* Flags byte 1 */
21 BYTE flags2; /* Flags byte 2 */
22 } AWSTAPE_BLKHDR;
23
24 /* Definitions for AWSTAPE_BLKHDR flags byte 1 */
25 #define AWSTAPE_FLAG1_NEWREC 0x80 /* Start of new record */
26 #define AWSTAPE_FLAG1_TAPEMARK 0x40 /* Tape mark */
27 #define AWSTAPE_FLAG1_ENDREC 0x20 /* End of record */
28
29 /*-------------------------------------------------------------------*/
30 /* Static data areas */
31 /*-------------------------------------------------------------------*/
32 static BYTE vollbl[] = "\xE5\xD6\xD3"; /* EBCDIC characters "VOL" */
33 static BYTE hdrlbl[] = "\xC8\xC4\xD9"; /* EBCDIC characters "HDR" */
34 static BYTE eoflbl[] = "\xC5\xD6\xC6"; /* EBCDIC characters "EOF" */
35 static BYTE eovlbl[] = "\xC5\xD6\xE5"; /* EBCDIC characters "EOV" */
36 static BYTE buf[65536];
37
38 #ifdef EXTERNALGUI
39 /* Report progress every this many bytes */
40 #define PROGRESS_MASK (~0x3FFFF /* 256K */)
41 /* How many bytes we've read so far. */
42 long curpos = 0;
43 long prevpos = 0;
44 #endif /*EXTERNALGUI*/
45
46 /*-------------------------------------------------------------------*/
47 /* tapesplt main entry point */
48 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])49 int main (int argc, char *argv[])
50 {
51 int rc; /* Return code */
52 int i; /* Array subscript */
53 int len; /* Block length */
54 int prevlen; /* Previous block length */
55 char *infilename; /* -> Input file name */
56 char *outfilename; /* -> Current out file name */
57 int infd = -1; /* Input file descriptor */
58 int outfd = -1; /* Current out file desc */
59 int fileno; /* Tape file number */
60 int blkcount; /* Block count */
61 int curblkl; /* Current block length */
62 int minblksz; /* Minimum block size */
63 int maxblksz; /* Maximum block size */
64 int outfilenum; /* Current out file# in argv */
65 int outfilecount; /* Current # files copied */
66 int files2copy; /* Current # files to copy */
67 BYTE labelrec[81]; /* Standard label (ASCIIZ) */
68 AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */
69 char pathname[MAX_PATH]; /* file path in host format */
70
71 INITIALIZE_UTILITY("tapesplt");
72
73 /* Display the program identification message */
74 display_version (stderr, "Hercules tape split program ", FALSE);
75
76 /* The only argument is the tape image file name */
77 if (argc > 3 && argv[1] != NULL)
78 {
79 infilename = argv[1];
80 }
81 else
82 {
83 printf ("Usage: tapesplt infilename outfilename count [...]\n");
84 exit (1);
85 }
86
87 /* Open the tape device */
88 hostpath(pathname, infilename, sizeof(pathname));
89 infd = hopen(pathname, O_RDONLY | O_BINARY);
90 if (infd < 0)
91 {
92 printf ("tapesplt: error opening input file %s: %s\n",
93 infilename, strerror(errno));
94 exit (2);
95 }
96
97 /* Copy blocks from input to output files */
98 fileno = 1;
99 blkcount = 0;
100 minblksz = 0;
101 maxblksz = 0;
102 len = 0;
103
104 for (outfilenum = 2; outfilenum < argc; outfilenum += 2)
105 {
106 outfilename = argv[outfilenum];
107 printf ("Writing output file %s.\n", outfilename);
108 hostpath(pathname, outfilename, sizeof(pathname));
109 outfd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY,
110 S_IRUSR | S_IWUSR | S_IRGRP);
111
112 if (outfd < 0)
113 {
114 printf ("tapesplt: error opening output file %s: %s\n",
115 outfilename, strerror(errno));
116 exit (3);
117 }
118
119 if (outfilenum == argc)
120 {
121 /* count not specified for last file, so use big number */
122 files2copy = 32767;
123 }
124 else
125 {
126 files2copy = atoi(argv[outfilenum + 1]);
127 }
128
129 /* Copy just that many files */
130 for (outfilecount = 0; outfilecount < files2copy; )
131 {
132
133 /* Save previous block length */
134 prevlen = len;
135
136 /* Read a block from the tape */
137 len = read (infd, buf, sizeof(AWSTAPE_BLKHDR));
138 if (len < 0)
139 {
140 printf ("tapesplt: error reading header block from %s: %s\n",
141 infilename, strerror(errno));
142 exit (4);
143 }
144
145 /* Did we finish too soon? */
146 if ((len > 0) && (len < (int)sizeof(AWSTAPE_BLKHDR)))
147 {
148 printf ("tapesplt: incomplete block header on %s\n",
149 infilename);
150 exit(5);
151 }
152
153 #ifdef EXTERNALGUI
154 if (extgui)
155 {
156 curpos += len;
157 /* Report progress every nnnK */
158 if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) )
159 {
160 prevpos = curpos;
161 fprintf( stderr, "IPOS=%ld\n", curpos );
162 }
163 }
164 #endif /*EXTERNALGUI*/
165
166 /* Check for end of tape. */
167 if (len == 0)
168 {
169 printf ("End of input tape.\n");
170 break;
171 }
172
173 /* Copy the header to the output file. */
174 rc = write(outfd, buf, sizeof(AWSTAPE_BLKHDR));
175 if (rc < (int)sizeof(AWSTAPE_BLKHDR))
176 {
177 printf ("tapesplt: error writing block header to %s: %s\n",
178 outfilename, strerror(errno));
179 exit(6);
180 }
181
182 /* Parse the block header */
183 memcpy(&awshdr, buf, sizeof(AWSTAPE_BLKHDR));
184
185 /* Tapemark? */
186 if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) != 0)
187 {
188 /* Print summary of current file */
189 printf ("File %u: Blocks=%u, block size min=%u, max=%u\n",
190 fileno, blkcount, minblksz, maxblksz);
191
192 /* Reset counters for next file */
193 fileno++;
194 minblksz = 0;
195 maxblksz = 0;
196 blkcount = 0;
197
198 /* Count the file we just copied. */
199 outfilecount++;
200
201 }
202 else /* if(tapemark) */
203 {
204 /* Count blocks and block sizes */
205 blkcount++;
206 curblkl = awshdr.curblkl[0] + (awshdr.curblkl[1] << 8);
207 if (curblkl > maxblksz) maxblksz = curblkl;
208 if (minblksz == 0 || curblkl < minblksz) minblksz = curblkl;
209
210 /* Read the data block. */
211 len = read (infd, buf, curblkl);
212 if (len < 0)
213 {
214 printf ("tapesplt: error reading data block from %s: %s\n",
215 infilename, strerror(errno));
216 exit (7);
217 }
218
219 /* Did we finish too soon? */
220 if ((len > 0) && (len < curblkl))
221 {
222 printf ("tapesplt: incomplete final data block on %s: "
223 "expected %d bytes, got %d\n",
224 infilename, curblkl, len);
225 exit(8);
226 }
227
228 /* Check for end of tape */
229 if (len == 0)
230 {
231 printf ("tapesplt: header block with no data on %s\n",
232 infilename);
233 exit(9);
234 }
235
236 #ifdef EXTERNALGUI
237 if (extgui)
238 {
239 curpos += len;
240 /* Report progress every nnnK */
241 if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) )
242 {
243 prevpos = curpos;
244 fprintf( stderr, "IPOS=%ld\n", curpos );
245 }
246 }
247 #endif /*EXTERNALGUI*/
248
249 /* Copy the header to the output file. */
250 rc = write(outfd, buf, len);
251 if (rc < len)
252 {
253 printf ("tapesplt: error writing data block to %s: %s\n",
254 outfilename, strerror(errno));
255 exit(10);
256 }
257
258 /* Print standard labels */
259 if (len == 80 && blkcount < 4
260 && (memcmp(buf, vollbl, 3) == 0
261 || memcmp(buf, hdrlbl, 3) == 0
262 || memcmp(buf, eoflbl, 3) == 0
263 || memcmp(buf, eovlbl, 3) == 0))
264 {
265 for (i=0; i < 80; i++)
266 labelrec[i] = guest_to_host(buf[i]);
267 labelrec[i] = '\0';
268 printf ("%s\n", labelrec);
269 }
270
271 } /* end if(tapemark) */
272
273 } /* end for(outfilecount) */
274
275 close(outfd);
276
277 } /* end for(outfilenum) */
278
279 /* Close files and exit */
280 close (infd);
281
282 return 0;
283
284 } /* end function main */
285