1 /* CCKDUTIL.C (c) Copyright Greg Smith, 2000-2009 */
2 /* Compressed CKD Common routines */
3
4 /*-------------------------------------------------------------------*/
5 /* This module contains functions for compressed CKD devices */
6 /* used by more than 1 main program. */
7 /*-------------------------------------------------------------------*/
8
9 #include "hstdinc.h"
10
11 #define _CCKDUTIL_C_
12 #define _HDASD_DLL_
13
14 #include "hercules.h"
15 #include "opcode.h"
16
17 /*-------------------------------------------------------------------*/
18
19 typedef struct _SPCTAB { /* Space table */
20 BYTE typ; /* Type of space */
21 int val; /* Value for space */
22 U32 pos; /* Space offset */
23 U32 len; /* Space length */
24 U32 siz; /* Space size */
25 } SPCTAB;
26
27 #define SPCTAB_NONE 0 /* Ignore this space entry */
28 #define SPCTAB_DEVHDR 1 /* Space is device header */
29 #define SPCTAB_CDEVHDR 2 /* Space is compressed hdr */
30 #define SPCTAB_L1 3 /* Space is level 1 table */
31 #define SPCTAB_L2 4 /* Space is level 2 table */
32 #define SPCTAB_TRK 5 /* Space is track image */
33 #define SPCTAB_BLKGRP 6 /* Space is blkgrp image */
34 #define SPCTAB_FREE 7 /* Space is free block */
35 #define SPCTAB_EOF 8 /* Space is end-of-file */
36
37 /*-------------------------------------------------------------------*/
38 /* Internal functions */
39 /*-------------------------------------------------------------------*/
40 static int comp_spctab_sort(const void *a, const void *b);
41 static int cdsk_spctab_sort(const void *a, const void *b);
42 static int cdsk_build_free_space(SPCTAB *spctab, int s);
43 static int cdsk_valid_trk (int trk, BYTE *buf, int heads, int len);
44
45 /*-------------------------------------------------------------------*/
46 /* Static data areas */
47 /*-------------------------------------------------------------------*/
48 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
49 static char *spaces[] = { "none", "devhdr", "cdevhdr", "l1", "l2",
50 "trk", "blkgrp", "free", "eof" };
51 static char *comps[] = { "none", "zlib", "bzip2" };
52
53 /*-------------------------------------------------------------------*/
54 /* Change the endianess of a compressed file */
55 /*-------------------------------------------------------------------*/
cckd_swapend(DEVBLK * dev)56 DLL_EXPORT int cckd_swapend (DEVBLK *dev)
57 {
58 CCKDDASD_EXT *cckd; /* -> cckd extension */
59 int fd; /* File descriptor */
60 int rc; /* Return code */
61 struct stat fst; /* File status buffer */
62 int i; /* Index */
63 int swapend; /* 1=swap space */
64 int len; /* Length */
65 off_t off, lopos, hipos; /* File offsets */
66 CCKD_DEVHDR cdevhdr; /* Compressed ckd header */
67 CCKD_L1ENT *l1 = NULL; /* Level 1 table */
68 CCKD_L2ENT l2[256]; /* Level 2 table */
69 CCKD_FREEBLK freeblk; /* Free block */
70
71 /* Get fd */
72 cckd = dev->cckd_ext;
73 if (cckd == NULL)
74 fd = dev->fd;
75 else
76 fd = cckd->fd[cckd->sfn];
77
78 /* Get file size */
79 if (fstat (fd, &fst) < 0)
80 goto cswp_fstat_error;
81 hipos = fst.st_size;
82
83 /* Device header */
84 off = CCKD_DEVHDR_POS;
85 if (lseek (fd, off, SEEK_SET) < 0)
86 goto cswp_lseek_error;
87 len = CCKD_DEVHDR_SIZE;
88 if ((rc = read (fd, &cdevhdr, len)) != len)
89 goto cswp_read_error;
90 swapend = (cdevhdr.options & CCKD_BIGENDIAN) != cckd_endian();
91 cckd_swapend_chdr (&cdevhdr);
92 cdevhdr.options |= CCKD_ORDWR;
93 if (lseek (fd, off, SEEK_SET) < 0)
94 goto cswp_lseek_error;
95 if ((rc = write (fd, &cdevhdr, len)) != len)
96 goto cswp_write_error;
97 if (!swapend) cckd_swapend_chdr (&cdevhdr);
98
99 /* l1 table */
100 len = cdevhdr.numl1tab * CCKD_L1ENT_SIZE;
101 if ((l1 = malloc (len)) == NULL)
102 goto cswp_malloc_error;
103 off = CCKD_L1TAB_POS;
104 if (lseek (fd, off, SEEK_SET) < 0)
105 goto cswp_lseek_error;
106 if ((rc = read (fd, l1, len)) != len)
107 goto cswp_read_error;
108 cckd_swapend_l1 (l1, (int)cdevhdr.numl1tab);
109 if (lseek (fd, off, SEEK_SET) < 0)
110 goto cswp_lseek_error;
111 if ((rc = write (fd, l1, len)) != len)
112 goto cswp_write_error;
113 if (!swapend) cckd_swapend_l1 (l1, (int)cdevhdr.numl1tab);
114 lopos = CCKD_L1TAB_POS + len;
115
116 /* l2 tables */
117 for (i = 0; i < cdevhdr.numl1tab; i++)
118 {
119 if (l1[i] == 0 || l1[i] == 0xffffffff
120 || l1[i] < lopos || l1[i] > hipos - CCKD_L2TAB_SIZE)
121 continue;
122 off = (off_t)l1[i];
123 if (lseek (fd, off, SEEK_SET) < 0)
124 goto cswp_lseek_error;
125 len = CCKD_L2TAB_SIZE;
126 if ((rc = read (fd, l2, len)) != len)
127 goto cswp_read_error;
128 cckd_swapend_l2 (l2);
129 if (lseek (fd, off, SEEK_SET) < 0)
130 goto cswp_lseek_error;
131 if ((rc = write (fd, l2, len)) != len)
132 goto cswp_write_error;
133 }
134
135 free (l1);
136 l1 = NULL;
137
138 /* free space */
139 if (cdevhdr.free && cdevhdr.free >= lopos
140 && cdevhdr.free <= hipos - CCKD_FREEBLK_SIZE)
141 {
142 off = (off_t)cdevhdr.free;
143 if (lseek (fd, off, SEEK_SET) < 0)
144 goto cswp_lseek_error;
145 len = CCKD_FREEBLK_SIZE;
146 if ((rc = read (fd, &freeblk, len)) != len)
147 goto cswp_read_error;
148 if (memcmp(&freeblk, "FREE_BLK", 8) == 0)
149 {
150 /* New format free space */
151 for (i = 0; i < cdevhdr.free_number; i++)
152 {
153 off += CCKD_FREEBLK_SIZE;
154 if (off > hipos - CCKD_FREEBLK_SIZE)
155 break;
156 if (lseek (fd, off, SEEK_SET) < 0)
157 goto cswp_lseek_error;
158 if ((rc = read (fd, &freeblk, len)) != len)
159 goto cswp_read_error;
160 cckd_swapend_free (&freeblk);
161 if (lseek (fd, off, SEEK_SET) < 0)
162 goto cswp_lseek_error;
163 if ((rc = write (fd, &freeblk, len)) != len)
164 goto cswp_write_error;
165 } /* for each free space */
166 } /* if new format free space */
167 else
168 {
169 /* Old format free space */
170 for (i = 0; i < cdevhdr.free_number; i++)
171 {
172 if (off < lopos || off > hipos - CCKD_FREEBLK_SIZE)
173 break;
174 if (lseek (fd, off, SEEK_SET) < 0)
175 goto cswp_lseek_error;
176 if ((rc = read (fd, &freeblk, len)) != len)
177 goto cswp_read_error;
178 cckd_swapend_free (&freeblk);
179 if (lseek (fd, off, SEEK_SET) < 0)
180 goto cswp_lseek_error;
181 if ((rc = write (fd, &freeblk, len)) != len)
182 goto cswp_write_error;
183 if (!swapend) cckd_swapend_free (&freeblk);
184 off = (off_t)freeblk.pos;
185 } /* for each free space */
186 } /* else old format free space */
187 } /* if free space */
188
189 return 0;
190
191 /* error exits */
192 cswp_fstat_error:
193
194 cckdumsg (dev, 701, "fstat error: %s\n", strerror(errno));
195 goto cswp_error;
196
197 cswp_lseek_error:
198
199 cckdumsg (dev, 702, "lseek error, offset 0x%" I64_FMT "x: %s\n",
200 (long long)off, strerror(errno));
201 goto cswp_error;
202
203 cswp_read_error:
204
205 cckdumsg (dev, 703, "read error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n",
206 rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete");
207 goto cswp_error;
208
209 cswp_write_error:
210
211 cckdumsg (dev, 704, "write error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n",
212 rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete");
213 goto cswp_error;
214
215 cswp_malloc_error:
216
217 cckdumsg (dev, 705, "malloc error, size %d: %s\n",
218 len, strerror(errno));
219 goto cswp_error;
220
221 cswp_error:
222
223 if (l1) free(l1);
224 return -1;
225 }
226
227 /*-------------------------------------------------------------------*/
228 /* Swap endian - compressed device header */
229 /*-------------------------------------------------------------------*/
cckd_swapend_chdr(CCKD_DEVHDR * cdevhdr)230 DLL_EXPORT void cckd_swapend_chdr (CCKD_DEVHDR *cdevhdr)
231 {
232 /* fix the compressed ckd header */
233 cdevhdr->options ^= CCKD_BIGENDIAN;
234 cckd_swapend4 ((char *) &cdevhdr->numl1tab);
235 cckd_swapend4 ((char *) &cdevhdr->numl2tab);
236 cckd_swapend4 ((char *) &cdevhdr->size);
237 cckd_swapend4 ((char *) &cdevhdr->used);
238 cckd_swapend4 ((char *) &cdevhdr->free);
239 cckd_swapend4 ((char *) &cdevhdr->free_total);
240 cckd_swapend4 ((char *) &cdevhdr->free_largest);
241 cckd_swapend4 ((char *) &cdevhdr->free_number);
242 cckd_swapend4 ((char *) &cdevhdr->free_imbed);
243 cckd_swapend2 ((char *) &cdevhdr->compress_parm);
244 }
245
246 /*-------------------------------------------------------------------*/
247 /* Swap endian - level 1 table */
248 /*-------------------------------------------------------------------*/
cckd_swapend_l1(CCKD_L1ENT * l1,int n)249 DLL_EXPORT void cckd_swapend_l1 (CCKD_L1ENT *l1, int n)
250 {
251 int i; /* Index */
252
253 for (i = 0; i < n; i++)
254 cckd_swapend4 ((char *) &l1[i]);
255 }
256
257 /*-------------------------------------------------------------------*/
258 /* Swap endian - level 2 table */
259 /*-------------------------------------------------------------------*/
cckd_swapend_l2(CCKD_L2ENT * l2)260 DLL_EXPORT void cckd_swapend_l2 (CCKD_L2ENT *l2)
261 {
262 int i; /* Index */
263
264 for (i = 0; i < 256; i++)
265 {
266 cckd_swapend4 ((char *) &l2[i].pos);
267 cckd_swapend2 ((char *) &l2[i].len);
268 cckd_swapend2 ((char *) &l2[i].size);
269 }
270 }
271
272 /*-------------------------------------------------------------------*/
273 /* Swap endian - free space entry */
274 /*-------------------------------------------------------------------*/
cckd_swapend_free(CCKD_FREEBLK * fb)275 DLL_EXPORT void cckd_swapend_free (CCKD_FREEBLK *fb)
276 {
277 cckd_swapend4 ((char *) &fb->pos);
278 cckd_swapend4 ((char *) &fb->len);
279 }
280
281 /*-------------------------------------------------------------------*/
282 /* Swap endian - 4 bytes */
283 /*-------------------------------------------------------------------*/
cckd_swapend4(char * c)284 DLL_EXPORT void cckd_swapend4 (char *c)
285 {
286 char temp[4];
287
288 memcpy (&temp, c, 4);
289 c[0] = temp[3];
290 c[1] = temp[2];
291 c[2] = temp[1];
292 c[3] = temp[0];
293 }
294
295 /*-------------------------------------------------------------------*/
296 /* Swap endian - 2 bytes */
297 /*-------------------------------------------------------------------*/
cckd_swapend2(char * c)298 DLL_EXPORT void cckd_swapend2 (char *c)
299 {
300 char temp[2];
301
302 memcpy (&temp, c, 2);
303 c[0] = temp[1];
304 c[1] = temp[0];
305 }
306
307 /*-------------------------------------------------------------------*/
308 /* Are we little or big endian? From Harbison&Steele. */
309 /*-------------------------------------------------------------------*/
cckd_endian()310 DLL_EXPORT int cckd_endian()
311 {
312 union
313 {
314 long l;
315 char c[sizeof (long)];
316 } u;
317
318 u.l = 1;
319 return u.c[sizeof (long) - 1] == 1 ? CCKD_BIGENDIAN : 0;
320 }
321
322 /*-------------------------------------------------------------------
323 * Remove all free space from a compressed ckd file
324 *-------------------------------------------------------------------*/
cckd_comp(DEVBLK * dev)325 DLL_EXPORT int cckd_comp (DEVBLK *dev)
326 {
327 CCKDDASD_EXT *cckd; /* -> cckd extension */
328 int fd; /* File descriptor */
329 struct stat fst; /* File status buffer */
330 long long maxsize; /* Max cckd file size */
331 int rc; /* Return code */
332 off_t off; /* File offset */
333 off_t l2area; /* Boundary for l2 tables */
334 int len; /* Length */
335 int i, j, l, n; /* Work variables */
336 int relocate = 0; /* 1=spaces will be relocated*/
337 int l1size; /* l1 table size */
338 U32 next; /* offset of next space */
339 int s; /* space table index */
340 CKDDASD_DEVHDR devhdr; /* CKD device header */
341 CCKD_DEVHDR cdevhdr; /* CCKD device header */
342 CCKD_L1ENT *l1=NULL; /* -> l1 table */
343 CCKD_L2ENT **l2=NULL; /* -> l2 table array */
344 SPCTAB *spctab=NULL; /* -> space table */
345 BYTE *rbuf=NULL; /* Relocation buffer */
346 BYTE *p; /* -> relocation buffer */
347 int rlen=0; /* Relocation buffer length */
348 CCKD_L2ENT zero_l2[256]; /* Empty l2 table (zeros) */
349 CCKD_L2ENT ff_l2[256]; /* Empty l2 table (0xff's) */
350 BYTE buf[65536*4]; /* Buffer */
351
352 /*---------------------------------------------------------------
353 * Get fd
354 *---------------------------------------------------------------*/
355 cckd = dev->cckd_ext;
356 if (cckd == NULL)
357 fd = dev->fd;
358 else
359 fd = cckd->fd[cckd->sfn];
360
361 /*---------------------------------------------------------------
362 * Get file statistics
363 *---------------------------------------------------------------*/
364 if (fstat (fd, &fst) < 0)
365 goto comp_fstat_error;
366 maxsize = sizeof(off_t) == 4 ? 0x7fffffffll : 0xffffffffll;
367
368 /*---------------------------------------------------------------
369 * Read device header
370 *---------------------------------------------------------------*/
371 off = 0;
372 if (lseek (fd, off, SEEK_SET) < 0)
373 goto comp_lseek_error;
374 len = CKDDASD_DEVHDR_SIZE;
375 if ((rc = read (fd, &devhdr, len)) != len)
376 goto comp_read_error;
377 if (memcmp (devhdr.devid, "CKD_C370", 8) != 0
378 && memcmp (devhdr.devid, "CKD_S370", 8) != 0
379 && memcmp (devhdr.devid, "FBA_C370", 8) != 0
380 && memcmp (devhdr.devid, "FBA_S370", 8) != 0)
381 {
382 cckdumsg (dev, 999, "not a compressed dasd file\n");
383 goto comp_error;
384 }
385
386 comp_restart:
387
388 /*---------------------------------------------------------------
389 * Read compressed device header
390 *---------------------------------------------------------------*/
391 off = CCKD_DEVHDR_POS;
392 if (lseek (fd, off, SEEK_SET) < 0)
393 goto comp_lseek_error;
394 len = CCKD_DEVHDR_SIZE;
395 if ((rc = read (fd, &cdevhdr, len)) != len)
396 goto comp_read_error;
397
398 /*---------------------------------------------------------------
399 * Check the endianess of the file
400 *---------------------------------------------------------------*/
401 if ((cdevhdr.options & CCKD_BIGENDIAN) != cckd_endian())
402 {
403 cckdumsg (dev, 101, "converting to %s\n",
404 cckd_endian() ? "big-endian" : "little-endian");
405 if (cckd_swapend (dev) < 0)
406 goto comp_error;
407 else
408 goto comp_restart;
409 }
410
411 /*---------------------------------------------------------------
412 * Some header checks
413 *---------------------------------------------------------------*/
414 if ((off_t)cdevhdr.size != fst.st_size
415 || cdevhdr.size != cdevhdr.used || cdevhdr.free != 0
416 || cdevhdr.free_total != 0 || cdevhdr.free_largest != 0
417 || cdevhdr.free_number != 0 || cdevhdr.free_imbed != 0)
418 relocate = 1;
419
420 /*---------------------------------------------------------------
421 * Build empty l2 tables
422 *---------------------------------------------------------------*/
423 memset (&zero_l2, 0, CCKD_L2TAB_SIZE);
424 if (cdevhdr.nullfmt != 0)
425 for (i = 0; i < 256; i++)
426 zero_l2[i].len = zero_l2[i].size = cdevhdr.nullfmt;
427 memset (&ff_l2, 0xff, CCKD_L2TAB_SIZE);
428
429 /*---------------------------------------------------------------
430 * Read the l1 table
431 *---------------------------------------------------------------*/
432 l1size = len = cdevhdr.numl1tab * CCKD_L1ENT_SIZE;
433 if ((l1 = malloc (len)) == NULL)
434 goto comp_malloc_error;
435 off = CCKD_L1TAB_POS;
436 if (lseek (fd, off, SEEK_SET) < 0)
437 goto comp_lseek_error;
438 if ((rc = read (fd, l1, len)) != len)
439 goto comp_read_error;
440
441 /*---------------------------------------------------------------
442 * Build the space table
443 *---------------------------------------------------------------*/
444 n = 1 + 1 + 1 + cdevhdr.numl1tab + 1;
445 for (i = 0; i < cdevhdr.numl1tab; i++)
446 if (l1[i] != 0 && l1[i] != 0xffffffff)
447 n += 256;
448 len = sizeof(SPCTAB);
449 if ((spctab = calloc (n, len)) == NULL)
450 goto comp_calloc_error;
451 s = 0;
452 spctab[s].typ = SPCTAB_DEVHDR;
453 spctab[s].val = -1;
454 spctab[s].pos = 0;
455 spctab[s].len =
456 spctab[s].siz = CKDDASD_DEVHDR_SIZE;
457 s++;
458 spctab[s].typ = SPCTAB_CDEVHDR;
459 spctab[s].val = -1;
460 spctab[s].pos = CCKD_DEVHDR_POS;
461 spctab[s].len =
462 spctab[s].siz = CCKD_DEVHDR_SIZE;
463 s++;
464 spctab[s].typ = SPCTAB_L1;
465 spctab[s].val = -1;
466 spctab[s].pos = CCKD_L1TAB_POS;
467 spctab[s].len =
468 spctab[s].siz = l1size;
469 s++;
470 spctab[s].typ = SPCTAB_EOF;
471 spctab[s].val = -1;
472 spctab[s].pos = fst.st_size;
473 spctab[s].len =
474 spctab[s].siz = 0;
475 s++;
476
477 for (i = 0; i < cdevhdr.numl1tab; i++)
478 if (l1[i] != 0 && l1[i] != 0xffffffff)
479 {
480 spctab[s].typ = SPCTAB_L2;
481 spctab[s].val = i;
482 spctab[s].pos = l1[i];
483 spctab[s].len =
484 spctab[s].siz = CCKD_L2TAB_SIZE;
485 s++;
486 }
487 qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort);
488
489 /*---------------------------------------------------------------
490 * Read level 2 tables
491 *---------------------------------------------------------------*/
492 n = cdevhdr.numl1tab;
493 len = sizeof (void *);
494 if ((l2 = calloc (n, len)) == NULL)
495 goto comp_calloc_error;
496 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
497 {
498 if (spctab[i].typ != SPCTAB_L2) continue;
499 l = spctab[i].val;
500 len = CCKD_L2TAB_SIZE;
501 if ((l2[l] = malloc (len)) == NULL)
502 goto comp_malloc_error;
503 off = (off_t)spctab[i].pos;
504 if (lseek (fd, off, SEEK_SET) < 0)
505 goto comp_lseek_error;
506 if ((rc = read (fd, l2[l], len)) != len)
507 goto comp_read_error;
508 for (j = 0; j < 256; j++)
509 {
510 if (l2[l][j].pos == 0 || l2[l][j].pos == 0xffffffff)
511 continue;
512 spctab[s].typ = SPCTAB_TRK;
513 spctab[s].val = spctab[i].val*256 + j;
514 spctab[s].pos = l2[l][j].pos;
515 spctab[s].len = l2[l][j].len;
516 spctab[s].siz = l2[l][j].size;
517 s++;
518 } /* for each l2 entry */
519 /* check if empty l2 table */
520 if (memcmp (l2[l], &zero_l2, CCKD_L2TAB_SIZE) == 0
521 || memcmp (l2[l], &ff_l2, CCKD_L2TAB_SIZE) == 0)
522 {
523 l1[l] = l2[l][0].pos; /* 0x00000000 or 0xffffffff */
524 spctab[i].typ = SPCTAB_NONE;
525 free (l2[l]);
526 l2[l] = NULL;
527 relocate = 1;
528 }
529 } /* for each space */
530 qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort);
531 while (spctab[s-1].typ == SPCTAB_NONE) s--;
532 /* set relocate flag if last space is free space */
533 if (spctab[s-2].pos + spctab[s-2].len != spctab[s-1].pos)
534 relocate = 1;
535
536 /*---------------------------------------------------------------
537 * relocate l2 tables in order
538 *---------------------------------------------------------------*/
539
540 /* determine l2 area */
541 l2area = CCKD_L1TAB_POS + l1size;
542 for (i = 0; i < cdevhdr.numl1tab; i++)
543 {
544 if (l1[i] == 0 || l1[i] == 0xffffffff) continue;
545 if (l1[i] != l2area)
546 relocate = 1;
547 l2area += CCKD_L2TAB_SIZE;
548 }
549
550 /* quick return if all l2 tables are orderered and no free space */
551 if (!relocate)
552 {
553 for (i = 1; spctab[i].typ != SPCTAB_EOF; i++)
554 if (spctab[i-1].pos + spctab[i-1].len != spctab[i].pos)
555 break;
556 if (spctab[i].typ == SPCTAB_EOF)
557 {
558 cckdumsg (dev, 103, "file already compressed\n");
559 goto comp_return_ok;
560 }
561 }
562
563 /* file will be updated */
564 cdevhdr.options |= CCKD_ORDWR;
565
566 /* calculate track size within the l2 area */
567 for (i = rlen = 0; spctab[i].pos < l2area; i++)
568 if (spctab[i].typ == SPCTAB_TRK)
569 rlen += sizeof(spctab[i].val) + sizeof(spctab[i].len)
570 + spctab[i].len;
571
572 /* read any tracks in the l2area into rbuf */
573 if ((len = rlen) > 0)
574 {
575 if ((rbuf = malloc (len)) == NULL)
576 goto comp_malloc_error;
577 for (i = 0, p = rbuf; spctab[i].pos < l2area; i++)
578 {
579 if (spctab[i].typ != SPCTAB_TRK) continue;
580 memcpy (p, &spctab[i].val, sizeof(spctab[i].val));
581 p += sizeof(spctab[i].val);
582 memcpy (p, &spctab[i].len, sizeof(spctab[i].len));
583 p += sizeof(spctab[i].len);
584 off = (off_t)spctab[i].pos;
585 if (lseek (fd, off, SEEK_SET) < 0)
586 goto comp_lseek_error;
587 len = spctab[i].len;
588 if ((rc = read (fd, p, len)) != len)
589 goto comp_read_error;
590 p += len;
591 spctab[i].typ = SPCTAB_NONE;
592 } /* for each space in the l2 area */
593 qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort);
594 while (spctab[s-1].typ == SPCTAB_NONE) s--;
595 } /* if any tracks to relocate */
596
597 /* remove all l2 tables from the space table */
598 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
599 if (spctab[i].typ == SPCTAB_L2)
600 spctab[i].typ = SPCTAB_NONE;
601 qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort);
602 while (spctab[s-1].typ == SPCTAB_NONE) s--;
603
604 /* add all l2 tables at their ordered offsets */
605 off = CCKD_L1TAB_POS + l1size;
606 for (i = 0; i < cdevhdr.numl1tab; i++)
607 {
608 if (l1[i] == 0 || l1[i] == 0xffffffff) continue;
609 spctab[s].typ = SPCTAB_L2;
610 spctab[s].val = i;
611 spctab[s].pos = (U32)off;
612 spctab[s].len =
613 spctab[s].siz = CCKD_L2TAB_SIZE;
614 s++;
615 off += CCKD_L2TAB_SIZE;
616 }
617 qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort);
618 /* set end-of-file position */
619 spctab[s-1].pos = spctab[s-2].pos + spctab[s-2].len;
620
621 /*---------------------------------------------------------------
622 * Perform compression
623 *---------------------------------------------------------------*/
624
625 /* move spaces left */
626 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
627 {
628 /* ignore contiguous spaces */
629 if (spctab[i].pos + spctab[i].len == spctab[i+1].pos)
630 continue;
631
632 /* found a gap */
633 off = (off_t)spctab[i+1].pos;
634
635 /* figure out how much we can read */
636 for (len = 0, j = i + 1; spctab[j].typ != SPCTAB_EOF; j++)
637 {
638 if (len + spctab[j].len > sizeof(buf))
639 break;
640 next = spctab[j].pos + spctab[j].len;
641 spctab[j].pos = spctab[i].pos + spctab[i].len + len;
642 spctab[j].siz = spctab[j].len;
643 len += spctab[j].len;
644 if (next != spctab[j+1].pos)
645 break;
646 } /* search for contiguous spaces */
647
648 /* this can happen if the next space is end-of-file */
649 if (len == 0)
650 continue;
651
652 /* read the image(s) to be relocated */
653 if (lseek (fd, off, SEEK_SET) < 0)
654 goto comp_lseek_error;
655 if ((rc = read (fd, buf, len)) != len)
656 goto comp_write_error;
657
658 /* write the images */
659 off = (off_t)spctab[i].pos + spctab[i].len;
660 if (lseek (fd, off, SEEK_SET) < 0)
661 goto comp_lseek_error;
662 if ((rc = write (fd, buf, len)) != len)
663 goto comp_write_error;
664 }
665
666 /* adjust the size of the file */
667 spctab[s-1].pos = spctab[s-2].pos + spctab[s-2].len;
668
669 /*---------------------------------------------------------------
670 * Write spaces relocated from the l2area to the end of the file
671 *---------------------------------------------------------------*/
672 off = (off_t)spctab[s-1].pos;
673 p = rbuf;
674 while (rlen)
675 {
676 spctab[s].typ = SPCTAB_TRK;
677 spctab[s].pos = (U32)off;
678 memcpy (&spctab[s].val, p, sizeof(spctab[s].val));
679 p += sizeof(spctab[s].val);
680 memcpy (&spctab[s].len, p, sizeof(spctab[s].len));
681 spctab[s].siz = spctab[s].len;
682 p += sizeof(spctab[s].len);
683
684 if (lseek (fd, off, SEEK_SET) < 0)
685 goto comp_lseek_error;
686 len = spctab[s].len;
687 if ((rc = write (fd, p, len)) != len)
688 goto comp_write_error;
689
690 p += len;
691 off += len;
692 rlen -= len + sizeof(spctab[s].val) + sizeof(spctab[s].len);
693 s++;
694 } /* for each relocated space in l2area */
695
696 /* adjust the space table */
697 if (rbuf)
698 {
699 free (rbuf); rbuf = NULL;
700 qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort);
701 spctab[s-1].pos = spctab[s-2].pos + spctab[s-2].len;
702 }
703
704 /*---------------------------------------------------------------
705 * Update the device header
706 *---------------------------------------------------------------*/
707 cdevhdr.size =
708 cdevhdr.used = spctab[s-1].pos;
709 cdevhdr.free =
710 cdevhdr.free_total =
711 cdevhdr.free_largest =
712 cdevhdr.free_number =
713 cdevhdr.free_imbed = 0;
714 cdevhdr.vrm[0] = CCKD_VERSION;
715 cdevhdr.vrm[1] = CCKD_RELEASE;
716 cdevhdr.vrm[2] = CCKD_MODLVL;
717
718 /*---------------------------------------------------------------
719 * Update the lookup tables
720 *---------------------------------------------------------------*/
721 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
722 if (spctab[i].typ == SPCTAB_L2)
723 l1[spctab[i].val] = spctab[i].pos;
724 else if (spctab[i].typ == SPCTAB_TRK)
725 {
726 l = spctab[i].val / 256;
727 j = spctab[i].val % 256;
728 l2[l][j].pos = spctab[i].pos;
729 l2[l][j].len =
730 l2[l][j].size = spctab[i].len;
731 }
732
733 /*---------------------------------------------------------------
734 * Write the cdevhdr, l1 table and l2 tables
735 *---------------------------------------------------------------*/
736
737 /* write cdevhdr */
738 off = CCKD_DEVHDR_POS;
739 if (lseek (fd, off, SEEK_SET) < 0)
740 goto comp_lseek_error;
741 len = CCKD_DEVHDR_SIZE;
742 if ((rc = write (fd, &cdevhdr, len)) != len)
743 goto comp_write_error;
744
745 /* write l1 table */
746 off = CCKD_L1TAB_POS;
747 if (lseek (fd, off, SEEK_SET) < 0)
748 goto comp_lseek_error;
749 len = l1size;
750 if ((rc = write (fd, l1, len)) != len)
751 goto comp_write_error;
752
753 /* write l2 tables */
754 for (i = 0; i < cdevhdr.numl1tab; i++)
755 if (l1[i] != 0 && l1[i] != 0xffffffff)
756 {
757 off = (off_t)l1[i];
758 if (lseek (fd, off, SEEK_SET) < 0)
759 goto comp_lseek_error;
760 len = CCKD_L2TAB_SIZE;
761 if ((rc = write (fd, l2[i], len)) != len)
762 goto comp_lseek_error;
763 }
764
765 /* truncate the file */
766 off = (off_t)spctab[s-1].pos;
767 if (off < fst.st_size)
768 {
769 ftruncate (fd, off);
770 cckdumsg (dev, 102, "compress successful, %lld bytes released\n",
771 (long long)fst.st_size - off);
772 }
773 else
774 cckdumsg (dev, 102, "compress successful, L2 tables relocated\n");
775
776 /*---------------------------------------------------------------
777 * Return
778 *---------------------------------------------------------------*/
779
780 comp_return_ok:
781
782 rc = 0;
783
784 comp_return:
785
786 if (rbuf) free(rbuf);
787 if (l2)
788 {
789 for (i = 0; i < cdevhdr.numl1tab; i++)
790 if (l2[i])
791 free (l2[i]);
792 free (l2);
793 }
794 if (l1) free (l1);
795 if (spctab) free (spctab);
796
797 return rc;
798
799 /*---------------------------------------------------------------
800 * Error exits
801 *---------------------------------------------------------------*/
802
803 comp_fstat_error:
804
805 cckdumsg (dev, 701, "fstat error: %s\n",
806 strerror(errno));
807 goto comp_error;
808
809 comp_lseek_error:
810
811 cckdumsg (dev, 702, "lseek error, offset 0x%" I64_FMT "x: %s\n",
812 (long long)off, strerror(errno));
813 goto comp_error;
814
815 comp_read_error:
816
817 cckdumsg (dev, 703, "read error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n",
818 rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete");
819 goto comp_error;
820
821 comp_write_error:
822
823 cckdumsg (dev, 704, "write error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n",
824 rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete");
825 goto comp_error;
826
827 comp_malloc_error:
828
829 cckdumsg (dev, 705, "malloc error, size %d: %s\n",
830 len, strerror(errno));
831 goto comp_error;
832
833 comp_calloc_error:
834
835 cckdumsg (dev, 706, "calloc error, size %d: %s\n",
836 n*len, strerror(errno));
837 goto comp_error;
838
839 comp_error:
840
841 rc = -1;
842 goto comp_return;
843
844 } /* cckd_comp() */
845
846 /*-------------------------------------------------------------------
847 * cckd_comp() space table sort
848 *-------------------------------------------------------------------*/
comp_spctab_sort(const void * a,const void * b)849 static int comp_spctab_sort(const void *a, const void *b)
850 {
851 const SPCTAB *x = a, *y = b;
852
853 if (x->typ == SPCTAB_NONE) return 1;
854 else if (y->typ == SPCTAB_NONE) return -1;
855 else if (x->typ == SPCTAB_EOF) return 1;
856 else if (y->typ == SPCTAB_EOF) return -1;
857 else if (x->pos < y->pos) return -1;
858 else return 1;
859 }
860
861 /*-------------------------------------------------------------------
862 * Perform check function on a compressed ckd file
863 *
864 * check levels
865 * -1 devhdr, cdevhdr, l1 table
866 * 0 devhdr, cdevhdr, l1 table, l2 tables
867 * 1 devhdr, cdevhdr, l1 table, l2 tables, free spaces
868 * 2 devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkhdrs
869 * 3 devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkimgs
870 * 4 devhdr, cdevhdr. Build everything else from recovery
871 *-------------------------------------------------------------------*/
cckd_chkdsk(DEVBLK * dev,int level)872 DLL_EXPORT int cckd_chkdsk(DEVBLK *dev, int level)
873 {
874 CCKDDASD_EXT *cckd; /* -> ckd extension */
875 int fd; /* file descriptor */
876 struct stat fst; /* file status information */
877 int fdflags; /* file descriptor flags */
878 long long maxsize; /* max cckd file size */
879 int ro; /* 1=file opened read-only */
880 int f, i, j, l, n; /* work integers */
881 int l1x, l2x; /* l1, l2 table indexes */
882 BYTE compmask[256]; /* compression byte mask
883 00 - supported
884 0x - valid, not supported
885 ff - invalid */
886 off_t off; /* file offset */
887 int len; /* length to read */
888 int rc; /* function return code */
889 int comp; /* trkhdr compression byte[0]*/
890 int cyl; /* trkhdr cyl bytes[1-2]*/
891 int head; /* trkhdr head bytes[3-4]*/
892 int trk; /* trkhdr calculated trk */
893 int cyls; /* number cylinders */
894 int heads; /* number heads/cylinder */
895 int trks; /* number tracks */
896 unsigned int trksz; /* track size */
897 int blks; /* number fba blocks */
898 int blkgrp; /* current block group nbr */
899 int blkgrps; /* number fba block groups */
900 unsigned int blkgrpsz; /* fba block group size */
901 int trktyp; /* track type (TRK, BLKGRP) */
902 int ckddasd=0; /* 1=ckd */
903 int fbadasd=0; /* 1= fba */
904 int shadow=0; /* 0xff=shadow file */
905 int hdrerr=0; /* non-zero: header errors */
906 int fsperr=0; /* 1=rebuild free space */
907 int comperrs=0; /* 1=unsupported comp found */
908 int recovery=0; /* 1=perform track recovery */
909 int valid; /* 1=valid trk recovered */
910 int l1size; /* size of l1 table */
911 int swapend=0; /* 1=call cckd_swapend */
912 U32 lopos, hipos; /* low/high file positions */
913 int pass; /* recovery pass number (fba)*/
914 int s; /* space table index */
915 SPCTAB *spctab=NULL; /* -> space table */
916 BYTE *l2errs=NULL; /* l2 error table */
917 BYTE *rcvtab=NULL; /* recovered tracks */
918 CKDDASD_DEVHDR devhdr; /* device header */
919 CCKD_DEVHDR cdevhdr; /* compressed device header */
920 CCKD_DEVHDR cdevhdr2; /* compressed device header 2*/
921 CCKD_L1ENT *l1=NULL; /* -> level 1 table */
922 CCKD_L2ENT l2ent; /* level 2 entry */
923 CCKD_L2ENT l2tab[256]; /* level 2 table */
924 CCKD_L2ENT **l2=NULL; /* -> level 2 table array */
925 CCKD_L2ENT empty_l2[256]; /* Empty l2 table */
926 CCKD_FREEBLK freeblk; /* free block */
927 CCKD_FREEBLK *fsp=NULL; /* free blocks (new format) */
928 BYTE buf[4*65536]; /* buffer */
929
930 /* Get fd */
931 cckd = dev->cckd_ext;
932 if (cckd == NULL)
933 fd = dev->fd;
934 else
935 fd = cckd->fd[cckd->sfn];
936
937 /* Get some file information */
938 if ( fstat (fd, &fst) < 0 )
939 goto cdsk_fstat_error;
940 hipos = fst.st_size;
941 maxsize = sizeof(off_t) == 4 ? 0x7fffffffll : 0xffffffffll;
942 fdflags = get_file_accmode_flags(fd);
943 ro = (fdflags & O_RDWR) == 0;
944
945 /* Build table for compression byte test */
946 memset (compmask, 0xff, 256);
947 compmask[0] = 0;
948 #if defined(HAVE_LIBZ)
949 compmask[CCKD_COMPRESS_ZLIB] = 0;
950 #else
951 compmask[CCKD_COMPRESS_ZLIB] = 1;
952 #endif
953 #if defined(CCKD_BZIP2)
954 compmask[CCKD_COMPRESS_BZIP2] = 0;
955 #else
956 compmask[CCKD_COMPRESS_BZIP2] = 2;
957 #endif
958
959 /*---------------------------------------------------------------
960 * Header checks
961 *---------------------------------------------------------------*/
962
963 /* Read the device header */
964 off = 0;
965 if ( lseek (fd, off, SEEK_SET) < 0)
966 goto cdsk_lseek_error;
967
968 len = CKDDASD_DEVHDR_SIZE;
969 if ((rc = read (fd, &devhdr, len)) != len)
970 goto cdsk_read_error;
971
972 /* Device header checks */
973 if (memcmp(devhdr.devid, "CKD_C370", 8) == 0
974 || memcmp(devhdr.devid, "CKD_S370", 8) == 0
975 )
976 ckddasd = 1;
977 else if (memcmp(devhdr.devid, "FBA_C370", 8) == 0
978 || memcmp(devhdr.devid, "FBA_S370", 8) == 0
979 )
980 fbadasd = 1;
981 else
982 {
983 cckdumsg (dev, 999, "not a compressed dasd file\n");
984 goto cdsk_error;
985 }
986 if (memcmp(devhdr.devid, "CKD_S370", 8) == 0
987 || memcmp(devhdr.devid, "FBA_S370", 8) == 0
988 )
989 shadow = 0xff;
990
991 trktyp = ckddasd ? SPCTAB_TRK : SPCTAB_BLKGRP;
992
993 /* Read the cckd device header */
994 off = CCKD_DEVHDR_POS;
995 if ( lseek (fd, off, SEEK_SET) < 0)
996 goto cdsk_lseek_error;
997
998 len = CCKD_DEVHDR_SIZE;
999 if ((rc = read (fd, &cdevhdr, len)) != len)
1000 goto cdsk_read_error;
1001
1002 /* Endianess check */
1003 if ((cdevhdr.options & CCKD_BIGENDIAN) != cckd_endian())
1004 {
1005 if (!ro)
1006 {
1007 cckdumsg (dev, 101, "converting to %s\n",
1008 cckd_endian() ? "big-endian" : "little-endian");
1009 if (cckd_swapend (dev) < 0)
1010 goto cdsk_error;
1011 if (level < 0) level = 0;
1012 swapend = 0;
1013 }
1014 else
1015 swapend = 1;
1016 cckd_swapend_chdr (&cdevhdr);
1017 }
1018
1019 /* ckd checks */
1020 if (ckddasd)
1021 {
1022 CKDDEV *ckd;
1023
1024 heads = (devhdr.heads[3] << 24)
1025 + (devhdr.heads[2] << 16)
1026 + (devhdr.heads[1] << 8)
1027 + (devhdr.heads[0]);
1028 cyls = (cdevhdr.cyls[3] << 24)
1029 + (cdevhdr.cyls[2] << 16)
1030 + (cdevhdr.cyls[1] << 8)
1031 + (cdevhdr.cyls[0]);
1032 trks = heads * cyls;
1033 trksz = (devhdr.trksize[3] << 24)
1034 + (devhdr.trksize[2] << 16)
1035 + (devhdr.trksize[1] << 8)
1036 + (devhdr.trksize[0]);
1037
1038 /* ckd dasd lookup */
1039 ckd = dasd_lookup (DASD_CKDDEV, NULL, devhdr.devtype, cyls);
1040 if (ckd == NULL)
1041 {
1042 cckdumsg (dev, 900, "dasd lookup error type=%2.2X cyls=%d\n",
1043 devhdr.devtype, cyls);
1044 goto cdsk_error;
1045 }
1046
1047 /* track size check */
1048 n = sizeof(CKDDASD_TRKHDR)
1049 + sizeof(CKDDASD_RECHDR) + 8 /* r0 length */
1050 + sizeof(CKDDASD_RECHDR) + ckd->r1 /* max data length */
1051 + sizeof(eighthexFF);
1052 n = ((n+511)/512)*512;
1053 if ((int)trksz != n)
1054 {
1055 cckdumsg (dev, 901, "bad trksize: %d, expecting %d\n",
1056 trksz, n);
1057 goto cdsk_error;
1058 }
1059
1060 /* number of heads check */
1061 if (heads != ckd->heads)
1062 {
1063 cckdumsg (dev, 902, "bad number of heads: %d, expecting %d\n",
1064 heads, ckd->heads);
1065 goto cdsk_error;
1066 }
1067 } /* if (ckddasd) */
1068
1069 /* fba checks */
1070 else
1071 {
1072 /* Note: cyls & heads are setup for ckd type hdr checks */
1073 blks = (cdevhdr.cyls[3] << 24)
1074 + (cdevhdr.cyls[2] << 16)
1075 + (cdevhdr.cyls[1] << 8)
1076 + (cdevhdr.cyls[0]);
1077 trks = blks / CFBA_BLOCK_NUM;
1078 if (blks % CFBA_BLOCK_NUM) trks++;
1079 trksz = CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE;
1080 heads = 65536;
1081 cyls = trks / heads;
1082 if (trks % heads) cyls++;
1083 }
1084
1085 /* fba variables */
1086 blkgrps = trks;
1087 blkgrpsz = trksz;
1088
1089 /* `numl1tab' check */
1090 n = trks / 256;
1091 if (trks % 256) n++;
1092
1093 if (cdevhdr.numl1tab != n && cdevhdr.numl1tab != n + 1)
1094 {
1095 cckdumsg (dev, 903, "bad `numl1tab': %d, expecting %d\n",
1096 cdevhdr.numl1tab, n);
1097 goto cdsk_error;
1098 }
1099 l1size = cdevhdr.numl1tab * CCKD_L1ENT_SIZE;
1100 if (CCKD_L1TAB_POS + l1size > fst.st_size)
1101 {
1102 cckdumsg (dev, 904, "file too small to contain L1 table: %d, need %d",
1103 fst.st_size, CCKD_L1TAB_POS + l1size);
1104 goto cdsk_error;
1105 }
1106
1107 /* check level 2 if SPERRS bit on */
1108 if (!ro && level < 2 && (cdevhdr.options & CCKD_SPERRS))
1109 {
1110 level = 2;
1111 cckdumsg (dev, 600, "forcing check level %d; space error bit on\n", level);
1112 }
1113
1114 /* cdevhdr inconsistencies check */
1115 hdrerr = 0;
1116 hdrerr |= fst.st_size != (off_t)cdevhdr.size && cdevhdr.size != cdevhdr.free ? 0x0001 : 0;
1117 hdrerr |= cdevhdr.size != cdevhdr.used + cdevhdr.free_total ? 0x0002 : 0;
1118 hdrerr |= cdevhdr.free_largest > cdevhdr.free_total - cdevhdr.free_imbed ? 0x0004 : 0;
1119 hdrerr |= cdevhdr.free == 0 && cdevhdr.free_number != 0 ? 0x0008 : 0;
1120 hdrerr |= cdevhdr.free == 0 && cdevhdr.free_total != cdevhdr.free_imbed ? 0x0010 : 0;
1121 hdrerr |= cdevhdr.free != 0 && cdevhdr.free_total == 0 ? 0x0020 : 0;
1122 hdrerr |= cdevhdr.free != 0 && cdevhdr.free_number == 0 ? 0x0040 : 0;
1123 hdrerr |= cdevhdr.free_number == 0 && cdevhdr.free_total != cdevhdr.free_imbed ? 0x0080 : 0;
1124 hdrerr |= cdevhdr.free_number != 0 && cdevhdr.free_total <= cdevhdr.free_imbed ? 0x0100 : 0;
1125 hdrerr |= cdevhdr.free_imbed > cdevhdr.free_total ? 0x0200 : 0;
1126
1127 /* Additional checking if header errors */
1128 if (hdrerr != 0)
1129 {
1130 cckdumsg (dev, 601, "cdevhdr inconsistencies found, code=%4.4x\n", hdrerr);
1131 if (level < 1)
1132 {
1133 level = 1;
1134 cckdumsg (dev, 600, "forcing check level %d\n", level);
1135 }
1136 }
1137
1138 /* Additional checking if not properly closed */
1139 if (level < 1 && (cdevhdr.options & CCKD_OPENED))
1140 {
1141 level = 1;
1142 cckdumsg (dev, 600, "forcing check level %d; file not closed\n", level);
1143 }
1144
1145 /* Additional checking if last opened for read/write */
1146 if (level < 0 && (cdevhdr.options & CCKD_ORDWR))
1147 level = 0;
1148
1149 /* Set check level -1 */
1150 if (level == 0 && !dev->batch && !hdrerr
1151 && (cdevhdr.options & (CCKD_OPENED|CCKD_SPERRS)) == 0
1152 && ((cdevhdr.options & (CCKD_ORDWR)) == 0 || ro))
1153 level = -1;
1154
1155 /* Build empty l2 table */
1156 memset (&empty_l2, shadow, CCKD_L2TAB_SIZE);
1157 if (shadow == 0 && cdevhdr.nullfmt != 0)
1158 for (i = 0; i < 256; i++)
1159 empty_l2[i].len = empty_l2[i].size = cdevhdr.nullfmt;
1160
1161 /*---------------------------------------------------------------
1162 * read the level 1 table
1163 *---------------------------------------------------------------*/
1164
1165 len = l1size;
1166 if ((l1 = malloc (len)) == NULL)
1167 goto cdsk_error;
1168 off = CCKD_L1TAB_POS;
1169 if ( lseek (fd, off, SEEK_SET) < 0)
1170 goto cdsk_lseek_error;
1171 if ((rc = read (fd, l1, len)) != len)
1172 goto cdsk_read_error;
1173 if (swapend) cckd_swapend_l1 (l1, (int)cdevhdr.numl1tab);
1174 lopos = CCKD_L1TAB_POS + l1size;
1175
1176 /*---------------------------------------------------------------
1177 * initialize the space table
1178 *---------------------------------------------------------------*/
1179
1180 /* find number of non-null l1 entries */
1181 for (i = n = 0; i < cdevhdr.numl1tab; i++)
1182 if (l1[i] != 0 && l1[i] != 0xffffffff)
1183 n++;
1184
1185 if (level >= 4) n = cdevhdr.numl1tab;
1186
1187 /* calculate max possible space table entries */
1188 n = 1 + 1 + 1 // devhdr, cdevhdr, l1tab
1189 + n // l2tabs
1190 + (n * 256) // trk/blk images
1191 + (1 + n + (n * 256) + 1) // max possible free spaces
1192 + 1; // end-of-file
1193
1194 /* obtain the space table */
1195 len = sizeof(SPCTAB);
1196 if ((spctab = calloc (n, len)) == NULL)
1197 goto cdsk_calloc_error;
1198
1199 /* populate the table with what we have */
1200 s = 0;
1201
1202 /* devhdr */
1203 spctab[s].typ = SPCTAB_DEVHDR;
1204 spctab[s].val = -1;
1205 spctab[s].pos = 0;
1206 spctab[s].len =
1207 spctab[s].siz = CKDDASD_DEVHDR_SIZE;
1208 s++;
1209 /* cdevhdr */
1210 spctab[s].typ = SPCTAB_CDEVHDR;
1211 spctab[s].val = -1;
1212 spctab[s].pos = CCKD_DEVHDR_POS;
1213 spctab[s].len =
1214 spctab[s].siz = CCKD_DEVHDR_SIZE;
1215 s++;
1216 /* l1 table */
1217 spctab[s].typ = SPCTAB_L1;
1218 spctab[s].val = -1;
1219 spctab[s].pos = CCKD_L1TAB_POS;
1220 spctab[s].len =
1221 spctab[s].siz = l1size;
1222 s++;
1223 /* l2 tables */
1224 for (i = 0; i < cdevhdr.numl1tab && level < 4; i++)
1225 {
1226 if (l1[i] == 0 || l1[i] == 0xffffffff) continue;
1227 spctab[s].typ = SPCTAB_L2;
1228 spctab[s].val = i;
1229 spctab[s].pos = l1[i];
1230 spctab[s].len =
1231 spctab[s].siz = CCKD_L2TAB_SIZE;
1232 s++;
1233 }
1234 /* end-of-file */
1235 spctab[s].typ = SPCTAB_EOF;
1236 spctab[s].val = -1;
1237 spctab[s].pos = (U32)fst.st_size;
1238 spctab[s].len =
1239 spctab[s].siz = 0;
1240 s++;
1241
1242 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
1243
1244 /*---------------------------------------------------------------
1245 * Quick return if level -1
1246 *---------------------------------------------------------------*/
1247
1248 if (level < 0)
1249 {
1250 int err = 0;
1251 /* check for overlaps */
1252 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
1253 if (spctab[i].pos + spctab[i].siz > spctab[i+1].pos)
1254 err = 1;
1255 /* exit if no errors */
1256 if (!err) goto cdsk_return_ok;
1257 }
1258
1259 /*---------------------------------------------------------------
1260 * obtain the l2errs table and recovery table
1261 *---------------------------------------------------------------*/
1262
1263 len = sizeof(BYTE);
1264
1265 n = cdevhdr.numl1tab;
1266 if ((l2errs = calloc (n, len)) == NULL)
1267 goto cdsk_calloc_error;
1268
1269 n = trks;
1270 if ((rcvtab = calloc (n, len)) == NULL)
1271 goto cdsk_calloc_error;
1272
1273 /*---------------------------------------------------------------
1274 * Special processing for level 4 (recover everything)
1275 *---------------------------------------------------------------*/
1276
1277 if (level == 4)
1278 {
1279 memset (l2errs, 1, cdevhdr.numl1tab);
1280 memset (rcvtab, 1, trks);
1281 goto cdsk_recovery;
1282 }
1283
1284 /*---------------------------------------------------------------
1285 * Read the level 2 tables
1286 *---------------------------------------------------------------*/
1287
1288 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
1289 {
1290 if (spctab[i].typ != SPCTAB_L2
1291 || spctab[i].pos < lopos || spctab[i].pos > hipos)
1292 continue;
1293
1294 off = spctab[i].pos;
1295 if ( lseek (fd, off, SEEK_SET) < 0 )
1296 goto cdsk_lseek_error;
1297 len = CCKD_L2TAB_SIZE;
1298 if ((rc = read (fd, l2tab, len)) != len)
1299 goto cdsk_read_error;
1300 if (swapend) cckd_swapend_l2 (l2tab);
1301
1302 /* add trks/blkgrps to the space table */
1303 for (j = 0; j < 256; j++)
1304 {
1305 if (l2tab[j].pos != 0 && l2tab[j].pos != 0xffffffff)
1306 {
1307 spctab[s].typ = trktyp;
1308 spctab[s].val = spctab[i].val * 256 + j;
1309 spctab[s].pos = l2tab[j].pos;
1310 spctab[s].len = l2tab[j].len;
1311 spctab[s].siz = l2tab[j].size;
1312 s++;
1313 }
1314 }
1315 }
1316 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
1317
1318 /*---------------------------------------------------------------
1319 * Consistency checks.
1320 *
1321 * The space table is now populated with everything but free
1322 * space. Therefore we can infer what the free space should
1323 * be (ie gaps between allocated spaces).
1324 *---------------------------------------------------------------*/
1325
1326 lopos = CCKD_L1TAB_POS + l1size;
1327 hipos = fst.st_size;
1328
1329 /* Make adjustment if new format free space is at the end */
1330 len = spctab[s-1].pos - (spctab[s-2].pos + spctab[s-2].siz);
1331 if (len > 0
1332 && cdevhdr.size == cdevhdr.free
1333 && cdevhdr.size + len == spctab[s-1].pos)
1334 {
1335 spctab[s-1].pos -= len;
1336 hipos -= len;
1337 }
1338
1339 memset (&cdevhdr2, 0, CCKD_DEVHDR_SIZE);
1340 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
1341 {
1342 /* Calculate gap size */
1343 len = spctab[i+1].pos - (spctab[i].pos + spctab[i].siz);
1344
1345 /* Update space statistics */
1346 cdevhdr2.size += spctab[i].siz + len;
1347 cdevhdr2.used += spctab[i].len;
1348 if (len > 0)
1349 {
1350 cdevhdr2.free_number++;
1351 cdevhdr2.free_total += len;
1352 if (cdevhdr2.free_largest < (U32)len)
1353 cdevhdr2.free_largest = (U32)len;
1354 }
1355 if (spctab[i].typ == trktyp)
1356 {
1357 cdevhdr2.free_total += spctab[i].siz - spctab[i].len;
1358 cdevhdr2.free_imbed += spctab[i].siz - spctab[i].len;
1359 }
1360
1361 /* ignore devhdr, cdevhdr and l1 (these are `out of bounds') */
1362 if (spctab[i].typ == SPCTAB_DEVHDR
1363 || spctab[i].typ == SPCTAB_CDEVHDR
1364 || spctab[i].typ == SPCTAB_L1
1365 )
1366 continue;
1367
1368 /* check if the space is out of bounds */
1369 valid = (off_t)spctab[i].pos >= lopos
1370 && (off_t)spctab[i].pos + spctab[i].siz <= hipos;
1371
1372 /* Overlap check */
1373 if (len < 0 || !valid)
1374 {
1375 char space1[32], space2[32];
1376 recovery = 1;
1377
1378 /* issue error message */
1379 j = sprintf(space1, "%s", spaces[spctab[i].typ]);
1380 if (spctab[i].val >= 0)
1381 sprintf(space1+j, "[%d]", spctab[i].val);
1382 j = sprintf(space2, "%s", spaces[spctab[i+1].typ]);
1383 if (spctab[i+1].val >= 0)
1384 sprintf(space2+j, "[%d]", spctab[i+1].val);
1385
1386 if (!valid)
1387 cckdumsg(dev, 602, "%s offset 0x%" I32_FMT "x len %d is out of bounds\n",
1388 space1, spctab[i].pos, spctab[i].siz);
1389 else
1390 cckdumsg(dev, 603, "%s offset 0x%" I32_FMT "x len %d overlaps %s offset 0x%" I32_FMT "x\n",
1391 space1, spctab[i].pos, spctab[i].siz, space2, spctab[i+1].pos);
1392
1393 /* setup recovery */
1394 if (spctab[i].typ == SPCTAB_L2)
1395 {
1396 l2errs[spctab[i].val] = 1;
1397 /* Mark all tracks for the l2 for recovery */
1398 memset (rcvtab + (spctab[i].val*256), 1, 256);
1399 }
1400 else if (spctab[i].typ == trktyp)
1401 rcvtab[spctab[i].val] = 1;
1402
1403 if (spctab[i+1].typ == SPCTAB_L2 && valid)
1404 {
1405 l2errs[spctab[i+1].val] = 1;
1406 memset (rcvtab + (spctab[i+1].val*256), 1, 256);
1407 }
1408 else if (spctab[i+1].typ == trktyp && valid)
1409 rcvtab[spctab[i+1].val] = 1;
1410
1411 } /* if overlap or out of bounds */
1412
1413 /* Check image l2 entry consistency */
1414 else if (spctab[i].typ == trktyp
1415 && (spctab[i].len < CKDDASD_TRKHDR_SIZE
1416 || spctab[i].len > spctab[i].siz
1417 || spctab[i].len > trksz))
1418 {
1419 recovery = 1;
1420
1421 /* issue error message */
1422 cckdumsg(dev, 604, "%s[%d] l2 inconsistency: len %d, size %d\n",
1423 spaces[trktyp], spctab[i].val,
1424 spctab[i].len, spctab[i].siz);
1425
1426 /* setup recovery */
1427 rcvtab[spctab[i].val] = 1;
1428 } /* if inconsistent l2 */
1429 } /* for each space */
1430
1431 /* remove any l2 tables or tracks in error from the space table */
1432 for (i = 0; recovery && spctab[i].typ != SPCTAB_EOF; i++)
1433 if ((spctab[i].typ == SPCTAB_L2 && l2errs[spctab[i].val])
1434 || (spctab[i].typ == trktyp && rcvtab[spctab[i].val]))
1435 spctab[i].typ = SPCTAB_NONE;
1436
1437 /* overlaps are serious */
1438 if (recovery && level < 3)
1439 {
1440 level = 3;
1441 cckdumsg (dev, 600, "forcing check level %d\n", level);
1442 }
1443
1444 /* Rebuild free space if any errors */
1445 if (recovery || hdrerr
1446 || cdevhdr.size != cdevhdr2.size
1447 || cdevhdr.used != cdevhdr2.used
1448 || cdevhdr.free_number != cdevhdr2.free_number
1449 || cdevhdr.free_largest != cdevhdr2.free_largest
1450 || cdevhdr.free_total != cdevhdr2.free_total
1451 || cdevhdr.free_imbed != cdevhdr2.free_imbed
1452 )
1453 fsperr = 1;
1454
1455 /*---------------------------------------------------------------
1456 * read the free space
1457 *---------------------------------------------------------------*/
1458
1459 lopos = CCKD_L1TAB_POS + l1size;
1460 hipos = fst.st_size;
1461
1462 if (level >= 1 && !fsperr)
1463 {
1464 while (cdevhdr.free) // `while' so code can break
1465 {
1466 fsperr = 1; // be pessimistic
1467 fsp = NULL;
1468
1469 /* Read the free space */
1470 off = (off_t)cdevhdr.free;
1471 len = CCKD_FREEBLK_SIZE;
1472 if (off < lopos || off + CCKD_FREEBLK_SIZE > hipos
1473 || lseek (fd, off, SEEK_SET) < 0
1474 || (rc = read (fd, &freeblk, len)) != len)
1475 break;
1476
1477 if (memcmp (&freeblk, "FREE_BLK", 8) == 0)
1478 {
1479 /* new format free space */
1480 len = cdevhdr.free_number * CCKD_FREEBLK_SIZE;
1481 if ((fsp = malloc(len)) == NULL
1482 || (rc = read (fd, fsp, len)) != len)
1483 break;
1484
1485 for (i = 0; i < cdevhdr.free_number; i++)
1486 {
1487 if (swapend) cckd_swapend_free (&fsp[i]);
1488 spctab[s].typ = SPCTAB_FREE;
1489 spctab[s].val = -1;
1490 spctab[s].pos = fsp[i].pos;
1491 spctab[s].len =
1492 spctab[s].siz = fsp[i].len;
1493 /* Free space should be ascending */
1494 if (spctab[s].pos < lopos
1495 || spctab[s].pos + spctab[s].siz > hipos)
1496 break;
1497 lopos = spctab[s].pos + spctab[s].siz;
1498 s++;
1499 } /* for each free space */
1500 if (i >= cdevhdr.free_number)
1501 fsperr = 0;
1502 } /* new format free space */
1503 else
1504 {
1505 /* old format free space */
1506 off = (off_t)cdevhdr.free;
1507 len = CCKD_FREEBLK_SIZE;
1508 for (i = 0; i < cdevhdr.free_number; i++)
1509 {
1510 if (off < lopos || off > hipos) break;
1511 if (lseek (fd, off, SEEK_SET) < 0)
1512 goto cdsk_lseek_error;
1513 if ((rc = read (fd, &freeblk, len)) != len)
1514 goto cdsk_read_error;
1515 if (swapend) cckd_swapend_free (&freeblk);
1516 spctab[s].typ = SPCTAB_FREE;
1517 spctab[s].val = -1;
1518 spctab[s].pos = (U32)off;
1519 spctab[s].len =
1520 spctab[s].siz = freeblk.len;
1521 s++;
1522 lopos = off + freeblk.len;
1523 off = (off_t)freeblk.pos;
1524 }
1525 if (i >= cdevhdr.free_number && freeblk.pos == 0)
1526 fsperr = 0;
1527 } /* if old format free space */
1528
1529 if (fsp) free(fsp);
1530 fsp = NULL;
1531
1532 /* Check for gaps/overlaps */
1533 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
1534 for (i = 0; !fsperr && spctab[i].typ != SPCTAB_EOF; i++)
1535 if (spctab[i].pos + spctab[i].siz != spctab[i+1].pos)
1536 fsperr = 1;
1537 break;
1538 } /* while (cdevhdr.free) */
1539 } /* if (level >= 1 && !fsperr) */
1540
1541 if (fsperr)
1542 cckdumsg (dev, 610, "free space errors detected\n");
1543
1544 /*---------------------------------------------------------------
1545 * Read track headers/images
1546 *---------------------------------------------------------------*/
1547
1548 cdsk_space_check:
1549
1550 if (level >= 2)
1551 {
1552 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
1553 {
1554 if (spctab[i].typ != trktyp) continue;
1555
1556 /* read the header or image depending on the check level */
1557 off = spctab[i].pos;
1558 if ( lseek (fd, off, SEEK_SET) < 0 )
1559 goto cdsk_lseek_error;
1560 len = level < 3 ? CKDDASD_TRKHDR_SIZE : spctab[i].len;
1561 if ((rc = read (fd, buf, len)) != len)
1562 goto cdsk_read_error;
1563
1564 /* Extract header info */
1565 comp = buf[0];
1566 cyl = fetch_hw (buf + 1);
1567 head = fetch_hw (buf + 3);
1568 trk = cyl * heads + head;
1569
1570 /* Validate header info */
1571 if (compmask[comp] == 0xff
1572 || cyl >= cyls || head >= heads
1573 || trk != spctab[i].val)
1574 {
1575 cckdumsg (dev, 620, "%s[%d] hdr error offset 0x%" I64_FMT
1576 "x: %2.2x%2.2x%2.2x%2.2x%2.2x\n",
1577 spaces[trktyp], spctab[i].val, (long long)off,
1578 buf[0],buf[1],buf[2],buf[3],buf[4]);
1579
1580 /* recover this track */
1581 rcvtab[spctab[i].val] = recovery = 1;
1582 spctab[i].typ = SPCTAB_NONE;
1583
1584 /* Force level 3 checking */
1585 if (level < 3)
1586 {
1587 level = 3;
1588 cckdumsg (dev, 600, "forcing check level %d\n", level);
1589 goto cdsk_space_check;
1590 }
1591 continue;
1592 } /* if invalid header info */
1593
1594 /* Check if compression supported */
1595 if (compmask[comp])
1596 {
1597 comperrs = 1;
1598 cckdumsg ( dev, 621, "%s[%d] compressed using %s, not supported\n",
1599 spaces[trktyp], trk, comps[compmask[comp]]);
1600 continue;
1601 }
1602
1603 /* Validate the space if check level 3 */
1604 if (level > 2)
1605 {
1606 if (!cdsk_valid_trk (trk, buf, heads, len))
1607 {
1608 cckdumsg (dev, 622, "%s[%d] offset 0x%" I64_FMT
1609 "x len %d validation error\n",
1610 spaces[trktyp], trk, (long long)off, len);
1611
1612 /* recover this track */
1613 rcvtab[trk] = recovery = 1;
1614 spctab[i].typ = SPCTAB_NONE;
1615 } /* if invalid space */
1616 else
1617 rcvtab[trk] = 0;
1618 } /* if level > 2 */
1619 } /* for each space */
1620 } /* if (level >= 2) */
1621
1622 /*---------------------------------------------------------------
1623 * Recovery
1624 *---------------------------------------------------------------*/
1625
1626 cdsk_recovery:
1627
1628 if (recovery || level == 4)
1629 {
1630 U32 flen, fpos;
1631
1632 /*-----------------------------------------------------------
1633 * Phase 1 -- recover trk/blkgrp images
1634 *-----------------------------------------------------------*/
1635
1636 /*
1637 * Reset the end-of-file pos to the file size
1638 * It might have been changed if new format free space
1639 * occurred at the end of the file.
1640 */
1641 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
1642 while (spctab[s-1].typ == SPCTAB_NONE) s--;
1643 spctab[s-1].pos = fst.st_size;
1644
1645 /* count number tracks to be recovered */
1646 for (i = n = 0; i < trks; i++)
1647 if (rcvtab[i] == 1)
1648 n++;
1649
1650 /*-----------------------------------------------------------
1651 * ckd recovery
1652 *-----------------------------------------------------------*/
1653 if (ckddasd)
1654 {
1655 /* recovery loop */
1656 s = cdsk_build_free_space (spctab, s);
1657 for (f = 0; spctab[f].typ != SPCTAB_EOF && n; )
1658 {
1659 /* next free space if too small */
1660 if (spctab[f].typ != SPCTAB_FREE
1661 || spctab[f].siz <= CKDDASD_TRKHDR_SIZE+8)
1662 {
1663 for (f = f + 1; spctab[f].typ != SPCTAB_EOF; f++)
1664 if (spctab[f].typ == SPCTAB_FREE)
1665 break;
1666 continue;
1667 }
1668
1669 fpos = spctab[f].pos;
1670 flen = spctab[f].siz;
1671
1672 /* length to read */
1673 len = flen < sizeof(buf) ? flen : sizeof(buf);
1674
1675 /* read the free space */
1676 off = (off_t)fpos;
1677 if (lseek (fd, off, SEEK_SET) < 0)
1678 goto cdsk_lseek_error;
1679 if ((rc = read (fd, buf, len)) != len)
1680 goto cdsk_read_error;
1681
1682 /* Scan the space for a trkhdr */
1683 for (i = 0; i < len - (CKDDASD_TRKHDR_SIZE+8); i++)
1684 {
1685 /* Check compression byte */
1686 if (compmask[buf[i]])
1687 continue;
1688
1689 /* Fetch possible trkhdr */
1690 comp = buf[i];
1691 cyl = fetch_hw (buf + i + 1);
1692 head = fetch_hw (buf + i + 3);
1693 trk = cyl * heads + head;
1694
1695 /* Validate possible trkhdr */
1696 if (cyl >= cyls || head >= heads || rcvtab[trk] != 1)
1697 continue;
1698
1699 /* Quick validation for compress none */
1700 if (comp == CCKD_COMPRESS_NONE
1701 && (fetch_hw (buf + i + 5) != cyl // r0 cyl
1702 || fetch_hw (buf + i + 7) != head // r0 head
1703 || buf[i + 9] != 0 // r0 record
1704 || buf[i + 10] != 0 // r0 key length
1705 || fetch_hw (buf + i + 11) != 8 // r0 data length
1706 )
1707 )
1708 continue;
1709
1710 /* Quick validation for zlib */
1711 else if (comp == CCKD_COMPRESS_ZLIB
1712 && fetch_hw(buf + i + 5) % 31 != 0)
1713 continue;
1714
1715 /* Quick validation for bzip2 */
1716 else if (comp == CCKD_COMPRESS_BZIP2
1717 && (buf[i+5] != 'B' || buf[i+6] != 'Z'))
1718 continue;
1719 /*
1720 * If we are in `borrowed space' then start over
1721 * with the current position at the beginning
1722 */
1723 if (flen > (U32)len && i > len - (int)trksz)
1724 break;
1725
1726 /* Checks for comp none */
1727 if (comp == CCKD_COMPRESS_NONE)
1728 {
1729 l = len - i;
1730 if ((l = cdsk_valid_trk (trk, buf+i, heads, -l)))
1731 goto cdsk_ckd_recover;
1732 else
1733 continue;
1734 }
1735
1736 /* Check short `length' */
1737 if (flen == (U32)len && (l = len - i) <= 1024)
1738 {
1739 if (cdsk_valid_trk (trk, buf+i, heads, l))
1740 {
1741 while (cdsk_valid_trk (trk, buf+i, heads, --l));
1742 l++;
1743 goto cdsk_ckd_recover;
1744 }
1745 }
1746
1747 /* Scan for next trkhdr */
1748 for (j = i + CKDDASD_TRKHDR_SIZE+8;
1749 j <= len - (CKDDASD_TRKHDR_SIZE+8);
1750 j++)
1751 {
1752 if (j - i > (int)trksz) break;
1753
1754 if (compmask[buf[j]] != 0
1755 || fetch_hw(buf+j+1) >= cyls
1756 || fetch_hw(buf+j+3) >= heads)
1757 continue;
1758
1759 /* check uncompressed hdr */
1760 if (buf[j] == CCKD_COMPRESS_NONE
1761 && (fetch_hw (buf+j+5) != fetch_hw(buf+j+1)
1762 || fetch_hw (buf+j+7) != fetch_hw(buf+j+3)
1763 || buf[j+9] != 0 || buf[j+10] != 0
1764 || fetch_hw(buf+j+11) != 8))
1765 continue;
1766 /* check zlib compressed header */
1767 else if (buf[j] == CCKD_COMPRESS_ZLIB
1768 && fetch_hw(buf + j + 5) % 31 != 0)
1769 continue;
1770 /* check bzip2 compressed header */
1771 else if (buf[j] == CCKD_COMPRESS_BZIP2
1772 && (buf[j+5] != 'B' || buf[j+6] != 'Z'))
1773 continue;
1774
1775 /* check to possible trkhdr */
1776 l = j - i;
1777 if (cdsk_valid_trk (trk, buf+i, heads, l))
1778 {
1779 #if 0
1780 while (cdsk_valid_trk (trk, buf+i, heads, --l));
1781 l++;
1782 #endif
1783 goto cdsk_ckd_recover;
1784 }
1785
1786 } /* scan for next trkhdr */
1787
1788 /* Check `length' */
1789 if (flen == (U32)len && (l = len - i) <= (int)trksz)
1790 {
1791 if (cdsk_valid_trk (trk, buf+i, heads, l))
1792 {
1793 while (cdsk_valid_trk (trk, buf+i, heads, --l));
1794 l++;
1795 goto cdsk_ckd_recover;
1796 }
1797 }
1798
1799 /* Scan all lengths */
1800 for (l = CKDDASD_TRKHDR_SIZE+8; i + l <= len; l++)
1801 {
1802 if (l > (int)trksz)
1803 break;
1804 if (cdsk_valid_trk (trk, buf+i, heads, l))
1805 goto cdsk_ckd_recover;
1806 } /* for all lengths */
1807
1808 continue;
1809
1810 cdsk_ckd_recover:
1811
1812 cckdumsg (dev, 301, "%s[%d] recovered offset 0x%" I64_FMT "x len %d\n",
1813 spaces[trktyp], trk, (long long)off + i, l);
1814 n--;
1815 rcvtab[trk] = 2;
1816
1817 /* add recovered track to the space table */
1818 spctab[s].typ = trktyp;
1819 spctab[s].val = trk;
1820 spctab[s].pos = fpos + i;
1821 spctab[s].len =
1822 spctab[s].siz = l;
1823 s++;
1824 /*
1825 * adjust `i' knowing it will be incremented
1826 * in the `for' loop above.
1827 */
1828 i += l - 1;
1829 } /* for each byte in the free space */
1830
1831 /* Adjust the free space for what we processed */
1832 spctab[f].pos += i;
1833 spctab[f].len -= i;
1834 spctab[f].siz -= i;
1835
1836 } /* for each free space */
1837
1838 } /* if ckddasd */
1839
1840 /*-----------------------------------------------------------
1841 * fba recovery
1842 *-----------------------------------------------------------*/
1843
1844 /*
1845 * FBA blkgrps are harder to recover than CKD tracks because
1846 * there is not any information within the blkgrp itself to
1847 * validate (unlike a track, which has count fields that
1848 * terminate in an end-of-track marker).
1849 *
1850 * On the first pass we recover all compressed blkgrps since
1851 * these are readily validated (they must uncompress to a
1852 * certain size, CFBA_BLOCK_SIZE+CKDDASD_TRKHDR_SIZE). We
1853 * also recover uncompressed blkgrps if they are followed by
1854 * a valid trkhdr (and don't occur to close to the beginning
1855 * of the file).
1856 *
1857 * On the second pass we recover all uncompressed blkgrps
1858 * that weren't recovered in the first pass. The only
1859 * criteria is that the compression byte is zero and the
1860 * 4 byte blkgrp number is in range and there are at least
1861 * CFBA_BLOCK_SIZE bytes following.
1862 */
1863
1864 for (pass = 0; fbadasd && pass < 2; pass++)
1865 {
1866 lopos = CCKD_L1TAB_POS + (cdevhdr.numl1tab * 4);
1867 if (pass == 0)
1868 lopos += (cdevhdr.numl1tab * CCKD_L2TAB_SIZE);
1869
1870 /* recovery loop */
1871 s = cdsk_build_free_space (spctab, s);
1872 for (f = 0; spctab[f].typ != SPCTAB_EOF && n > 0; )
1873 {
1874 U32 flen, fpos;
1875
1876 /* next free space if too small */
1877 if (spctab[f].typ != SPCTAB_FREE
1878 || spctab[f].siz <= CKDDASD_TRKHDR_SIZE+8
1879 || (pass == 1 && spctab[f].siz < blkgrpsz))
1880 {
1881 for (f = f + 1; spctab[f].typ != SPCTAB_EOF; f++)
1882 if (spctab[f].typ == SPCTAB_FREE)
1883 break;
1884 continue;
1885 }
1886
1887 fpos = spctab[f].pos;
1888 flen = spctab[f].siz;
1889 /*
1890 * calculate length to read
1891 * if flen > len then we only read part of the space
1892 */
1893 len = flen < sizeof(buf) ? flen : sizeof(buf);
1894
1895 /* read the free space */
1896 off = (off_t)fpos;
1897 if (lseek (fd, off, SEEK_SET) < 0)
1898 goto cdsk_lseek_error;
1899 if ((rc = read (fd, buf, len)) != len)
1900 goto cdsk_read_error;
1901
1902 /* Scan the space */
1903 for (i = 0; i < len - (CKDDASD_TRKHDR_SIZE+8); i++)
1904 {
1905 /* For pass 1 the size left must be at least blkgrpsz */
1906 if (pass == 1 && len - i < (int)blkgrpsz)
1907 break;
1908
1909 /* Check compression byte */
1910 if ((pass == 0 && compmask[buf[i]])
1911 || (pass == 1 && buf[i] != CCKD_COMPRESS_NONE))
1912 continue;
1913
1914 /* Fetch possible trkhdr */
1915 comp = buf[i];
1916 blkgrp = fetch_fw (buf + i + 1);
1917
1918 /* Validate possible trkhdr */
1919 if (blkgrp < 0 || blkgrp >= blkgrps
1920 || rcvtab[blkgrp] != 1)
1921 continue;
1922
1923 /* Validation for compress none */
1924 if (comp == CCKD_COMPRESS_NONE
1925 && flen == (U32)len && len - i < (int)blkgrpsz)
1926 continue;
1927
1928 /* Quick validation for zlib */
1929 else if (comp == CCKD_COMPRESS_ZLIB
1930 && fetch_hw(buf + i + 5) % 31 != 0)
1931 continue;
1932
1933 /* Quick validation for bzip2 */
1934 else if (comp == CCKD_COMPRESS_BZIP2
1935 && (buf[i+5] != 'B' || buf[i+6] != 'Z'))
1936 continue;
1937 /*
1938 * If we are in `borrowed space' then start over
1939 * with the current position at the beginning
1940 */
1941 if (flen > (U32)len && i > len - (int)blkgrpsz)
1942 break;
1943
1944 /* Checks for comp none */
1945 if (comp == CCKD_COMPRESS_NONE)
1946 {
1947 l = blkgrpsz;
1948 if (len - i < (int)blkgrpsz || fpos + i < lopos)
1949 continue;
1950 if (len - i == (int)blkgrpsz && flen == (U32)len)
1951 goto cdsk_fba_recover;
1952 /* Pass 0 checks */
1953 if (pass == 0
1954 && (len - i - l < CKDDASD_TRKHDR_SIZE+8
1955 || compmask[buf[i+l]]
1956 || fetch_fw (buf+i+l+1) >= (unsigned int)blkgrps)
1957 )
1958 continue;
1959 goto cdsk_fba_recover;
1960 }
1961
1962 /* The tests below are for pass 0 only */
1963 if (pass == 1)
1964 continue;
1965
1966 /* Check short `length' */
1967 if (flen == (U32)len && (l = len - i) <= 1024)
1968 {
1969 if (cdsk_valid_trk (blkgrp, buf+i, heads, l))
1970 {
1971 while (cdsk_valid_trk (blkgrp, buf+i, heads, --l));
1972 l++;
1973 goto cdsk_fba_recover;
1974 }
1975 }
1976
1977 /* Scan for next trkhdr */
1978 for (j = i + CKDDASD_TRKHDR_SIZE+8;
1979 j <= len - (CKDDASD_TRKHDR_SIZE+8);
1980 j++)
1981 {
1982 if (j - i > (int)blkgrpsz) break;
1983
1984 if (compmask[buf[j]] != 0
1985 || fetch_fw(buf+j+1) >= (unsigned int)blkgrps)
1986 continue;
1987
1988 /* check zlib compressed header */
1989 if (buf[j] == CCKD_COMPRESS_ZLIB
1990 && fetch_hw(buf + j + 5) % 31 != 0)
1991 continue;
1992
1993 /* check bzip2 compressed header */
1994 else if (buf[j] == CCKD_COMPRESS_BZIP2
1995 && (buf[j+5] != 'B' || buf[j+6] != 'Z'))
1996 continue;
1997
1998 /* check to possible trkhdr */
1999 l = j - i;
2000 if (cdsk_valid_trk (blkgrp, buf+i, heads, l))
2001 {
2002 #if 0
2003 while (cdsk_valid_trk (blkgrp, buf+i, heads, --l));
2004 l++;
2005 #endif
2006 goto cdsk_fba_recover;
2007 }
2008
2009 } /* scan for next trkhdr */
2010
2011 /* Check `length' */
2012 l = len - i;
2013 if (flen == (U32)len && l <= (int)blkgrpsz)
2014 {
2015 if (cdsk_valid_trk (blkgrp, buf+i, heads, l))
2016 {
2017 while (cdsk_valid_trk (blkgrp, buf+i, heads, --l));
2018 l++;
2019 goto cdsk_fba_recover;
2020 }
2021 }
2022
2023 /* Scan all lengths */
2024 for (l = CKDDASD_TRKHDR_SIZE+8; i + l <= len; l++)
2025 {
2026 if (l > (int)blkgrpsz)
2027 break;
2028 if (cdsk_valid_trk (blkgrp, buf+i, heads, l))
2029 goto cdsk_fba_recover;
2030 } /* for all lengths */
2031
2032 continue;
2033
2034 cdsk_fba_recover:
2035
2036 cckdumsg (dev, 301, "%s[%d] recovered offset 0x%" I64_FMT "x len %d\n",
2037 spaces[trktyp], blkgrp, (long long)off + i, l);
2038 n--;
2039 rcvtab[blkgrp] = 2;
2040
2041 /* Enable recovery of comp 0 blkgrps for pass 0 */
2042 if (fpos + i < lopos)
2043 lopos = fpos + i;
2044
2045 /* add recovered block group to the space table */
2046 spctab[s].typ = trktyp;
2047 spctab[s].val = blkgrp;
2048 spctab[s].pos = fpos + i;
2049 spctab[s].len =
2050 spctab[s].siz = l;
2051 s++;
2052 /*
2053 * adjust `i' knowing it will be incremented
2054 * in the `for' loop above.
2055 */
2056 i += l - 1;
2057 } /* for each byte in the free space */
2058
2059 /* Adjust the free space for what we processed */
2060 spctab[f].pos += i;
2061 spctab[f].len -= i;
2062 spctab[f].siz -= i;
2063
2064 } /* for each free space */
2065
2066 } /* if fbadasd */
2067
2068 for (i = n = 0; i < trks; i++)
2069 if (rcvtab[i] == 2)
2070 n++;
2071 cckdumsg (dev, 300, "%d %s images recovered\n",
2072 n, spaces[trktyp]);
2073
2074 /*-----------------------------------------------------------
2075 * Phase 2 -- rebuild affected l2 tables
2076 *-----------------------------------------------------------*/
2077
2078 /*
2079 * Make sure there's at least one non-zero `rcvtab' entry
2080 * for l2 tables in `l2errs'. Space validation may have
2081 * turned off all `rcvtab' entries for an l2.
2082 */
2083 for (i = 0; i < cdevhdr.numl1tab; i++)
2084 if (l2errs[i])
2085 rcvtab[i*256] = 1;
2086
2087 /* Get storage for the l2 table array */
2088 n = cdevhdr.numl1tab;
2089 len = sizeof(void *);
2090 if ((l2 = calloc (n, len)) == NULL)
2091 goto cdsk_calloc_error;
2092
2093 /* Get storage for the rebuilt l2 tables */
2094 len = CCKD_L2TAB_SIZE;
2095 for (i = 0; i < trks; i++)
2096 {
2097 l1x = i / 256;
2098 if (rcvtab[i] != 0 && l2[l1x] == NULL)
2099 {
2100 if ((l2[l1x] = malloc (len)) == NULL)
2101 goto cdsk_malloc_error;
2102 l1[l1x] = shadow ? 0xffffffff : 0;
2103 memcpy (l2[l1x], &empty_l2, len);
2104 }
2105 }
2106
2107 /* Rebuild the l2 tables */
2108 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
2109 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
2110 {
2111 if (spctab[i].typ == SPCTAB_L2 && l2[spctab[i].val])
2112 spctab[i].typ = SPCTAB_NONE;
2113 else if (spctab[i].typ == trktyp && l2[spctab[i].val/256])
2114 {
2115 l1x = spctab[i].val / 256;
2116 l2x = spctab[i].val % 256;
2117 l2[l1x][l2x].pos = spctab[i].pos;
2118 l2[l1x][l2x].len = spctab[i].len;
2119 l2[l1x][l2x].size = spctab[i].siz;
2120 }
2121 } /* for each space */
2122 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
2123 while (spctab[s-1].typ == SPCTAB_NONE) s--;
2124
2125 /* Look for empty l2 tables */
2126 for (i = 0; i < cdevhdr.numl1tab; i++)
2127 if (l2[i] != NULL
2128 && memcmp (l2[i], &empty_l2, CCKD_L2TAB_SIZE) == 0)
2129 {
2130 free (l2[i]);
2131 l2[i] = NULL;
2132 }
2133 /*
2134 * `s-1' indexes the SPCTAB_EOF space table entry.
2135 * Set its `pos' to the maximum allowed value to ensure
2136 * there will be free space for the rebuilt l2 tables.
2137 */
2138 spctab[s-1].pos = (U32)maxsize;
2139
2140 /* Build the free space */
2141 s = cdsk_build_free_space (spctab, s);
2142
2143 /* Find space for the rebuilt l2 tables */
2144 for (i = j = 0; i < cdevhdr.numl1tab; i++)
2145 {
2146 if (l2[i] == NULL) continue;
2147
2148 /* find a free space */
2149 for ( ; spctab[j].typ != SPCTAB_EOF; j++)
2150 if (spctab[j].typ == SPCTAB_FREE
2151 && spctab[j].siz >= CCKD_L2TAB_SIZE)
2152 break;
2153
2154 /* weird error if no space */
2155 if (spctab[j].typ == SPCTAB_EOF)
2156 {
2157 cckdumsg (dev, 905, "not enough file space for recovery\n");
2158 goto cdsk_error;
2159 }
2160
2161 /* add l2 space */
2162 l1[i] = spctab[j].pos;
2163 spctab[s].typ = SPCTAB_L2;
2164 spctab[s].val = i;
2165 spctab[s].pos = spctab[j].pos;
2166 spctab[s].len =
2167 spctab[s].siz = CCKD_L2TAB_SIZE;
2168 s++;
2169
2170 /* adjust the free space */
2171 spctab[j].pos += CCKD_L2TAB_SIZE;
2172 spctab[j].len -= CCKD_L2TAB_SIZE;
2173 spctab[j].siz -= CCKD_L2TAB_SIZE;
2174 } /* for each l2 table */
2175
2176
2177 /*-----------------------------------------------------------
2178 * Phase 3 -- write l1 and l2 tables
2179 *-----------------------------------------------------------*/
2180
2181 if (ro)
2182 {
2183 cckdumsg (dev, 500, "recovery not completed, file opened read-only\n");
2184 goto cdsk_error;
2185 }
2186 if (comperrs)
2187 {
2188 cckdumsg (dev, 501, "recovery not completed, missing compression\n");
2189 goto cdsk_error;
2190 }
2191
2192 /* Write the l1 table */
2193 off = CCKD_L1TAB_POS;
2194 if (lseek (fd, off, SEEK_SET) < 0)
2195 goto cdsk_lseek_error;
2196 len = l1size;
2197 if ((rc = write (fd, l1, len)) != len)
2198 goto cdsk_write_error;
2199
2200 /* Write l2 tables */
2201 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
2202 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
2203 {
2204 l1x = spctab[i].val;
2205 if (spctab[i].typ != SPCTAB_L2 || l2[l1x] == NULL)
2206 continue;
2207 off = (off_t)l1[l1x];
2208 if (lseek (fd, off, SEEK_SET) < 0)
2209 goto cdsk_lseek_error;
2210 len = CCKD_L2TAB_SIZE;
2211 if ((rc = write (fd, l2[l1x], len)) != len)
2212 goto cdsk_write_error;
2213 free (l2[l1x]);
2214 l2[l1x] = NULL;
2215 } /* for each space */
2216
2217 /* Free recovery related storage */
2218 if (l2)
2219 {
2220 for (i = 0; i < cdevhdr.numl1tab; i++)
2221 if (l2[i])
2222 free (l2[i]);
2223 free (l2); l2 = NULL;
2224 }
2225 free (l2errs); l2errs = NULL;
2226 free (rcvtab); rcvtab = NULL;
2227
2228 /* Ensure we do free space recovery */
2229 fsperr = 1;
2230
2231 } /* if (recovery || level >= 4) */
2232
2233 /*---------------------------------------------------------------
2234 * Rebuild free space
2235 *---------------------------------------------------------------*/
2236
2237 if (fsperr && ro)
2238 cckdumsg (dev, 502, "free space not rebuilt, file opened read-only\n");
2239 else if (fsperr)
2240 {
2241 /*-----------------------------------------------------------
2242 * Phase 1 -- build the free space
2243 * make sure the last space isn't free space and
2244 * that each free space is long enough (8 bytes).
2245 *-----------------------------------------------------------*/
2246
2247 cdsk_fsperr_retry:
2248
2249 s = cdsk_build_free_space (spctab, s);
2250
2251 /*
2252 * spctab[s-1] is the SPCTAB_EOF entry.
2253 * if spctab[s-2] is SPCTAB_FREE then discard it
2254 */
2255 if (spctab[s-2].typ == SPCTAB_FREE)
2256 {
2257 spctab[s-1].typ = SPCTAB_NONE;
2258 spctab[s-2].typ = SPCTAB_EOF;
2259 spctab[s-2].val = -1;
2260 spctab[s-2].len =
2261 spctab[s-2].siz = 0;
2262 s--;
2263 }
2264 /*
2265 * Check for short free spaces.
2266 * If found, shift left until the next free space or eof.
2267 */
2268 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
2269 if (spctab[i].typ == SPCTAB_FREE
2270 && spctab[i].siz < CCKD_FREEBLK_SIZE)
2271 break;
2272 if (spctab[i].typ != SPCTAB_EOF)
2273 {
2274 /* Shift following space left */
2275 l = spctab[i++].siz;
2276 while (spctab[i].typ != SPCTAB_FREE && spctab[i].typ != SPCTAB_EOF)
2277 {
2278 /* Read the space and write shifted to the left */
2279 off = (off_t)spctab[i].pos;
2280 if (lseek (fd, off, SEEK_SET) < 0)
2281 goto cdsk_lseek_error;
2282 len = spctab[i].siz;
2283 if ((rc = read (fd, buf, len)) != len)
2284 goto cdsk_read_error;
2285 off -= l;
2286 if (lseek (fd, off, SEEK_SET) < 0)
2287 goto cdsk_lseek_error;
2288 if ((rc = write (fd, buf, len)) != len)
2289 goto cdsk_write_error;
2290 spctab[i].pos -= l;
2291
2292 /* Update the l2 or l1 table entry */
2293 if (spctab[i].typ == trktyp)
2294 {
2295 l1x = spctab[i].val/256;
2296 l2x = spctab[i].val%256;
2297 off = (off_t)l1[l1x] + l2x * CCKD_L2ENT_SIZE;
2298 if (lseek (fd, off, SEEK_SET) < 0)
2299 goto cdsk_lseek_error;
2300 len = CCKD_L2ENT_SIZE;
2301 if ((rc = read (fd, &l2ent, len)) != len)
2302 goto cdsk_read_error;
2303 l2ent.pos -= l;
2304 if (lseek (fd, off, SEEK_SET) < 0)
2305 goto cdsk_lseek_error;
2306 if ((rc = write (fd, &l2ent, len)) != len)
2307 goto cdsk_write_error;
2308 } /* trk/blkgrp relocated */
2309 else if (spctab[i].typ == SPCTAB_L2)
2310 l1[spctab[i].val] -= l;
2311 i++;
2312 } /* while not FREE space or EOF */
2313 goto cdsk_fsperr_retry;
2314 } /* if short free space found */
2315
2316 /*-----------------------------------------------------------
2317 * Phase 2 -- rebuild free space statistics
2318 *-----------------------------------------------------------*/
2319
2320 cdevhdr.vrm[0] = CCKD_VERSION;
2321 cdevhdr.vrm[1] = CCKD_RELEASE;
2322 cdevhdr.vrm[2] = CCKD_MODLVL;
2323
2324 cdevhdr.size = cdevhdr.used = cdevhdr.free =
2325 cdevhdr.free_total = cdevhdr.free_largest =
2326 cdevhdr.free_number = cdevhdr.free_imbed = 0;
2327 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
2328 if (spctab[i].typ == SPCTAB_FREE)
2329 {
2330 cdevhdr.size += spctab[i].siz;
2331 if (spctab[i].siz > cdevhdr.free_largest)
2332 cdevhdr.free_largest = spctab[i].siz;
2333 cdevhdr.free_total += spctab[i].siz;
2334 cdevhdr.free_number++;
2335 }
2336 else
2337 {
2338 cdevhdr.size += spctab[i].siz;
2339 cdevhdr.used += spctab[i].len;
2340 cdevhdr.free_total += spctab[i].siz - spctab[i].len;
2341 cdevhdr.free_imbed += spctab[i].siz - spctab[i].len;
2342 }
2343
2344 /*-----------------------------------------------------------
2345 * Phase 3 -- write the free space
2346 *-----------------------------------------------------------*/
2347 if (cdevhdr.free_number)
2348 {
2349 /* size needed for new format free space */
2350 len = (cdevhdr.free_number+1) * CCKD_FREEBLK_SIZE;
2351
2352 /* look for existing free space to fit new format free space */
2353 for (i = off = 0; !off && spctab[i].typ != SPCTAB_EOF; i++)
2354 if (spctab[i].typ == SPCTAB_FREE && len <= (int)spctab[i].siz)
2355 off = (off_t)spctab[i].pos;
2356
2357 /* if no applicable space see if we can append to the file */
2358 if (!off && maxsize - cdevhdr.size >= len)
2359 off = (off_t)cdevhdr.size;
2360
2361 /* get free space buffer */
2362 if (off && (fsp = malloc (len)) == NULL)
2363 off = 0;
2364
2365 if (off)
2366 {
2367 /* new format free space */
2368 memcpy (fsp, "FREE_BLK", 8);
2369 for (i = 0, j = 1; spctab[i].typ != SPCTAB_EOF; i++)
2370 if (spctab[i].typ == SPCTAB_FREE)
2371 {
2372 fsp[j].pos = spctab[i].pos;
2373 fsp[j++].len = spctab[i].siz;
2374 }
2375
2376 /* Write the free space */
2377 if (lseek (fd, off, SEEK_SET) < 0)
2378 goto cdsk_lseek_error;
2379 if ((rc = write (fd, fsp, len)) != len)
2380 goto cdsk_write_error;
2381 cdevhdr.free = (U32)off;
2382
2383 free (fsp);
2384 fsp = NULL;
2385 } /* new format free space */
2386 else
2387 {
2388 /* old format free space */
2389 len = CCKD_FREEBLK_SIZE;
2390 for (i = 0; spctab[i].typ != SPCTAB_FREE; i++);
2391 cdevhdr.free = spctab[i].pos;
2392 off = (off_t)spctab[i].pos;
2393 freeblk.pos = 0;
2394 freeblk.len = spctab[i].siz;
2395 for (i = i + 1; spctab[i].typ != SPCTAB_EOF; i++)
2396 if (spctab[i].typ == SPCTAB_FREE)
2397 {
2398 freeblk.pos = spctab[i].pos;
2399 if (lseek (fd, off, SEEK_SET) < 0)
2400 goto cdsk_lseek_error;
2401 if (write (fd, &freeblk, len) != len)
2402 goto cdsk_write_error;
2403 off = (off_t)spctab[i].pos;
2404 freeblk.pos = 0;
2405 freeblk.len = spctab[i].len;
2406 }
2407 if (lseek (fd, off, SEEK_SET) < 0)
2408 goto cdsk_lseek_error;
2409 if (write (fd, &freeblk, len) != len)
2410 goto cdsk_write_error;
2411 } /* old format free space */
2412 } /* if (cdevhdr.free_number) */
2413
2414 /* Write cdevhdr and l1 table */
2415 off = CCKD_DEVHDR_POS;
2416 if (lseek (fd, off, SEEK_SET) < 0)
2417 goto cdsk_lseek_error;
2418 len = CCKD_DEVHDR_SIZE;
2419 if (write (fd, &cdevhdr, len) != len)
2420 goto cdsk_write_error;
2421
2422 off = CCKD_L1TAB_POS;
2423 if (lseek (fd, off, SEEK_SET) < 0)
2424 goto cdsk_lseek_error;
2425 len = l1size;
2426 if (write (fd, l1, len) != len)
2427 goto cdsk_write_error;
2428
2429 /* Truncate the file */
2430 off = (off_t)cdevhdr.size;
2431 if (cdevhdr.free == cdevhdr.size)
2432 off += (cdevhdr.free_number+1) * CCKD_FREEBLK_SIZE;
2433 rc = ftruncate (fd, off);
2434
2435 cckdumsg (dev, 104, "free space rebuilt\n");
2436
2437 } /* if (fsperr) */
2438
2439 /*---------------------------------------------------------------
2440 * Return
2441 *---------------------------------------------------------------*/
2442
2443 cdsk_return_ok:
2444
2445 rc = recovery ? 2 : fsperr ? 1 : 0;
2446
2447 if (!ro && (cdevhdr.options & (CCKD_ORDWR|CCKD_OPENED|CCKD_SPERRS)))
2448 {
2449 /*
2450 * Leave the ORDWR bit on for now. This will prevent
2451 * old-format free space releases from doing a -1 check
2452 * on a file that has new-format free space
2453 */
2454 #if 0
2455 cdevhdr.options &= ~(CCKD_ORDWR|CCKD_OPENED|CCKD_SPERRS);
2456 #else
2457 cdevhdr.options &= ~(CCKD_OPENED|CCKD_SPERRS);
2458 #endif
2459 /* Set version.release.modlvl */
2460 cdevhdr.vrm[0] = CCKD_VERSION;
2461 cdevhdr.vrm[1] = CCKD_RELEASE;
2462 cdevhdr.vrm[2] = CCKD_MODLVL;
2463
2464 off = CCKD_DEVHDR_POS;
2465 if (lseek (fd, CCKD_DEVHDR_POS, SEEK_SET) >= 0)
2466 write (fd, &cdevhdr, CCKD_DEVHDR_SIZE);
2467 }
2468
2469 cdsk_return:
2470
2471 /* free all space */
2472 if (l1) free (l1);
2473 if (spctab) free (spctab);
2474 if (l2errs) free (l2errs);
2475 if (rcvtab) free (rcvtab);
2476 if (fsp) free (fsp);
2477 if (l2)
2478 {
2479 for (i = 0; i < cdevhdr.numl1tab; i++)
2480 if (l2[i]) free (l2[i]);
2481 free (l2);
2482 }
2483
2484 return rc;
2485
2486 /*---------------------------------------------------------------
2487 * Error exits
2488 *---------------------------------------------------------------*/
2489
2490 cdsk_fstat_error:
2491
2492 cckdumsg (dev, 701, "fstat error: %s\n", strerror(errno));
2493 goto cdsk_error;
2494
2495 cdsk_lseek_error:
2496
2497 cckdumsg (dev, 702, "lseek error offset 0x%" I64_FMT "x: %s\n",
2498 (long long)off, strerror(errno));
2499 goto cdsk_error;
2500
2501 cdsk_read_error:
2502
2503 cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n",
2504 rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete");
2505 goto cdsk_error;
2506
2507 cdsk_write_error:
2508
2509 cckdumsg (dev, 704, "write error rc=%d offset 0x%" I64_FMT "x len %d: %s\n",
2510 rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete");
2511 goto cdsk_error;
2512
2513 cdsk_malloc_error:
2514
2515 cckdumsg (dev, 705, "malloc error, size=%d: %s\n",
2516 len, strerror(errno));
2517 goto cdsk_error;
2518
2519 cdsk_calloc_error:
2520
2521 cckdumsg (dev, 706, "calloc error, size=%d: %s\n",
2522 n*len, strerror(errno));
2523 goto cdsk_error;
2524
2525 cdsk_error:
2526 rc = -1;
2527 goto cdsk_return;
2528
2529 } /* end function cckd_chkdsk */
2530
2531 /*-------------------------------------------------------------------
2532 * cckd_chkdsk() space table sort
2533 *-------------------------------------------------------------------*/
cdsk_spctab_sort(const void * a,const void * b)2534 static int cdsk_spctab_sort(const void *a, const void *b)
2535 {
2536 const SPCTAB *x = a, *y = b;
2537
2538 if (x->typ == SPCTAB_NONE) return 1;
2539 else if (y->typ == SPCTAB_NONE) return -1;
2540 else if (x->typ == SPCTAB_EOF) return 1;
2541 else if (y->typ == SPCTAB_EOF) return -1;
2542 else if (x->pos < y->pos) return -1;
2543 else return 1;
2544 } /* end function cdsk_spctab_sort */
2545
2546 /*-------------------------------------------------------------------*/
2547 /* Build free space in the space table */
2548 /*-------------------------------------------------------------------*/
cdsk_build_free_space(SPCTAB * spctab,int s)2549 static int cdsk_build_free_space(SPCTAB *spctab, int s)
2550 {
2551 int i;
2552
2553 for (i = 0; i < s; i++)
2554 if (spctab[i].typ == SPCTAB_FREE)
2555 spctab[i].typ = SPCTAB_NONE;
2556 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
2557 while (spctab[s-1].typ == SPCTAB_NONE) s--;
2558 for (i = 0; spctab[i].typ != SPCTAB_EOF; i++)
2559 if (spctab[i].pos + spctab[i].siz < spctab[i+1].pos)
2560 {
2561 spctab[s].typ = SPCTAB_FREE;
2562 spctab[s].val = -1;
2563 spctab[s].pos = spctab[i].pos + spctab[i].siz;
2564 spctab[s].len =
2565 spctab[s].siz = spctab[i+1].pos - spctab[s].pos;
2566 s++;
2567 }
2568 qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort);
2569 return s;
2570 }
2571
2572 /*-------------------------------------------------------------------*/
2573 /* Validate a track image */
2574 /* */
2575 /* If `len' is negative and compression is CCKD_COMPRESS_NONE then */
2576 /* `len' indicates a buffer size containing the track image and the */
2577 /* value returned is the actual track image length */
2578 /*-------------------------------------------------------------------*/
cdsk_valid_trk(int trk,BYTE * buf,int heads,int len)2579 static int cdsk_valid_trk (int trk, BYTE *buf, int heads, int len)
2580 {
2581 int i; /* Index */
2582 int len2; /* Positive `len' */
2583 int kl, dl; /* Key/Data lengths */
2584 BYTE *bufp; /* Buffer pointer */
2585 int bufl; /* Buffer length */
2586 #ifdef HAVE_LIBZ
2587 uLongf zlen;
2588 #endif
2589 #ifdef CCKD_BZIP2
2590 unsigned int bz2len;
2591 #endif
2592 #if defined(HAVE_LIBZ) || defined(CCKD_BZIP2)
2593 int rc; /* Return code */
2594 BYTE buf2[65536]; /* Uncompressed buffer */
2595 #endif
2596
2597 /* Negative len only allowed for comp none */
2598 len2 = len > 0 ? len : -len;
2599
2600 if (len2 < CKDDASD_TRKHDR_SIZE + 8)
2601 return 0;
2602
2603 /* Uncompress the track/block image */
2604 switch (buf[0]) {
2605
2606 case CCKD_COMPRESS_NONE:
2607 bufp = buf;
2608 bufl = len2;
2609 break;
2610
2611 #ifdef HAVE_LIBZ
2612 case CCKD_COMPRESS_ZLIB:
2613 if (len < 0) return 0;
2614 bufp = (BYTE *)buf2;
2615 memcpy (buf2, buf, CKDDASD_TRKHDR_SIZE);
2616 zlen = sizeof(buf2) - CKDDASD_TRKHDR_SIZE;
2617 rc = uncompress (buf2 + CKDDASD_TRKHDR_SIZE, &zlen,
2618 buf + CKDDASD_TRKHDR_SIZE, len - CKDDASD_TRKHDR_SIZE);
2619 if (rc != Z_OK)
2620 return 0;
2621 bufl = (int)zlen + CKDDASD_TRKHDR_SIZE;
2622 break;
2623 #endif
2624
2625 #ifdef CCKD_BZIP2
2626 case CCKD_COMPRESS_BZIP2:
2627 if (len < 0) return 0;
2628 bufp = (BYTE *)buf2;
2629 memcpy (buf2, buf, CKDDASD_TRKHDR_SIZE);
2630 bz2len = sizeof(buf2) - CKDDASD_TRKHDR_SIZE;
2631 rc = BZ2_bzBuffToBuffDecompress ( (char *)&buf2[CKDDASD_TRKHDR_SIZE], &bz2len,
2632 (char *)&buf[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE, 0, 0);
2633 if (rc != BZ_OK)
2634 return 0;
2635 bufl = (int)bz2len + CKDDASD_TRKHDR_SIZE;
2636 break;
2637 #endif
2638
2639 default:
2640 return 0;
2641
2642 } /* switch (buf[0]) */
2643
2644 /* fba check */
2645 if (heads == 65536)
2646 {
2647 if (bufl != CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE)
2648 return 0;
2649 else
2650 return len > 0 ? len : bufl;
2651 }
2652 /* Check length */
2653 if (bufl <= 5 + 8 + 8 + 8 + 8) return 0;
2654 /* Check ha */
2655 if (fetch_hw(bufp + 1) != trk / heads
2656 || fetch_hw(bufp + 3) != trk % heads)
2657 return 0;
2658 /* Check r0 */
2659 if (fetch_hw(bufp + 1) != fetch_hw(bufp + 5)
2660 || fetch_hw(bufp + 3) != fetch_hw(bufp + 7)
2661 || bufp[9] != 0 || bufp[10] != 0
2662 || fetch_hw(bufp +11) != 8)
2663 return 0;
2664 /* Check user records */
2665 for (i = 21; i < bufl - 8; i += 8 + kl + dl)
2666 {
2667 if (fetch_hw(bufp + i + 2) >= heads || bufp[i + 4] == 0)
2668 break;
2669 kl = bufp[i + 5];
2670 dl = fetch_hw(bufp + i + 6);
2671 }
2672 if (len < 0) bufl = i + 8;
2673 if (i != bufl - 8 || memcmp(bufp + i, eighthexFF, 8))
2674 return 0;
2675 return len > 0 ? len : bufl;
2676 } /* end function cdsk_valid_trk */
2677
2678 /*-------------------------------------------------------------------*/
2679 /* Message function */
2680 /*-------------------------------------------------------------------*/
cckdumsg(DEVBLK * dev,int n,char * format,...)2681 DLL_EXPORT void cckdumsg (DEVBLK *dev, int n, char *format, ...)
2682 {
2683 CCKDDASD_EXT *cckd;
2684 int sfx;
2685 int i;
2686 char *p;
2687 va_list vl;
2688 char msg[4096];
2689
2690 cckd = dev->cckd_ext;
2691 sfx = cckd ? cckd->sfn : -1;
2692
2693 i = sprintf (msg, "HHCCU%3.3d%c ",
2694 n, n < 400 ? 'I' : n < 700 ? 'W' : 'E');
2695
2696 if (sfx >= 0)
2697 i += sprintf (msg+i, "%4.4X file[%d]: ", dev->devnum, sfx);
2698 else
2699 {
2700 if ((p = strrchr(dev->filename, '/')) == NULL
2701 && (p = strrchr(dev->filename, '\\')) == NULL)
2702 p = dev->filename;
2703 else
2704 p++;
2705 i += sprintf (msg+i, "%s: ", p);
2706 }
2707
2708 va_start (vl, format);
2709 vsprintf (msg+i, format, vl);
2710 va_end (vl);
2711
2712 if (dev->batch)
2713 fprintf(stdout,"%s",msg);
2714 else
2715 logmsg("%s",msg);
2716 }
2717