xref: /netbsd/sbin/fsck_udf/main.c (revision 1a0a9b38)
1 /*	$NetBSD: main.c,v 1.8 2022/04/22 20:56:46 reinoud Exp $	*/
2 
3 /*
4  * Copyright (c) 2022 Reinoud Zandijk
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 
30 /*
31  * Note to reader:
32  *
33  * fsck_udf uses the common udf_core.c file with newfs and makefs. It does use
34  * some of the layout structure values but not all.
35  */
36 
37 
38 #include <sys/cdefs.h>
39 #ifndef lint
40 __RCSID("$NetBSD: main.c,v 1.8 2022/04/22 20:56:46 reinoud Exp $");
41 #endif /* not lint */
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stddef.h>
46 #include <dirent.h>
47 #include <inttypes.h>
48 #include <stdint.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <util.h>
54 #include <time.h>
55 #include <tzfile.h>
56 #include <math.h>
57 #include <assert.h>
58 #include <err.h>
59 
60 #if !HAVE_NBTOOL_CONFIG_H
61 #define _EXPOSE_MMC
62 #include <sys/cdio.h>
63 #else
64 #include "udf/cdio_mmc_structs.h"
65 #endif
66 
67 #include <sys/ioctl.h>
68 #include <sys/stat.h>
69 #include <sys/types.h>
70 #include <sys/disklabel.h>
71 #include <sys/dkio.h>
72 #include <sys/param.h>
73 #include <sys/queue.h>
74 
75 #include <fs/udf/ecma167-udf.h>
76 #include <fs/udf/udf_mount.h>
77 
78 #include "fsutil.h"
79 #include "exitvalues.h"
80 #include "udf_core.h"
81 
82 /* Identifying myself */
83 #define IMPL_NAME		"*NetBSD fsck_udf 10.0"
84 #define APP_VERSION_MAIN	0
85 #define APP_VERSION_SUB		5
86 
87 /* allocation walker actions */
88 #define AD_LOAD_FILE		(1<<0)
89 #define AD_SAVE_FILE		(1<<1)
90 #define AD_CHECK_FIDS		(1<<2)
91 #define AD_ADJUST_FIDS		(1<<3)
92 #define AD_GATHER_STATS		(1<<4)
93 #define AD_CHECK_USED		(1<<5)
94 #define AD_MARK_AS_USED		(1<<6)
95 #define AD_FIND_OVERLAP_PAIR	(1<<7)
96 
97 struct udf_fsck_file_stats {
98 	uint64_t inf_len;
99 	uint64_t obj_size;
100 	uint64_t logblks_rec;
101 };
102 
103 
104 struct udf_fsck_fid_context {
105 	uint64_t fid_offset;
106 	uint64_t data_left;
107 };
108 
109 
110 /* basic node administration for passes */
111 #define FSCK_NODE_FLAG_HARDLINK		(1<< 0)	/* hardlink, for accounting */
112 #define FSCK_NODE_FLAG_DIRECTORY	(1<< 1)	/* is a normal directory */
113 #define FSCK_NODE_FLAG_HAS_STREAM_DIR	(1<< 2)	/* has a stream directory */
114 #define FSCK_NODE_FLAG_STREAM_ENTRY	(1<< 3)	/* is a stream file */
115 #define FSCK_NODE_FLAG_STREAM_DIR	(1<< 4)	/* is a stream directory */
116 #define FSCK_NODE_FLAG_OK(f)		(((f) >> 5) == 0)
117 
118 #define FSCK_NODE_FLAG_KEEP		(1<< 5)	/* don't discard */
119 #define FSCK_NODE_FLAG_DIRTY		(1<< 6)	/* descriptor needs writeout */
120 #define FSCK_NODE_FLAG_REPAIRDIR	(1<< 7)	/* repair bad FID entries */
121 #define FSCK_NODE_FLAG_NEW_UNIQUE_ID	(1<< 8)	/* repair bad FID entries */
122 #define FSCK_NODE_FLAG_COPY_PARENT_ID	(1<< 9)	/* repair bad FID entries */
123 #define FSCK_NODE_FLAG_WIPE_STREAM_DIR	(1<<10)	/* wipe stream directory */
124 #define FSCK_NODE_FLAG_NOTFOUND		(1<<11)	/* FID pointing to garbage */
125 #define FSCK_NODE_FLAG_PAR_NOT_FOUND	(1<<12)	/* parent node not found! */
126 #define FSCK_NODE_FLAG_OVERLAP		(1<<13) /* node has overlaps */
127 
128 #define FSCK_NODE_FLAG_STREAM (FSCK_NODE_FLAG_STREAM_ENTRY | FSCK_NODE_FLAG_STREAM_DIR)
129 
130 
131 #define	HASH_HASHBITS	5
132 #define	HASH_HASHSIZE	(1 << HASH_HASHBITS)
133 #define	HASH_HASHMASK	(HASH_HASHSIZE - 1)
134 
135 /* fsck node for accounting checks */
136 struct udf_fsck_node {
137 	struct udf_fsck_node *parent;
138 	char *fname;
139 
140 	struct long_ad	loc;
141 	struct long_ad	streamdir_loc;
142 	int		fsck_flags;
143 
144 	int		link_count;
145 	int		found_link_count;
146 	uint64_t	unique_id;
147 
148 	struct udf_fsck_file_stats declared;
149 	struct udf_fsck_file_stats found;
150 
151 	uint8_t		*directory;		/* directory contents */
152 
153 	LIST_ENTRY(udf_fsck_node) next_hash;
154 	TAILQ_ENTRY(udf_fsck_node) next;
155 };
156 TAILQ_HEAD(udf_fsck_node_list, udf_fsck_node) fs_nodes;
157 LIST_HEAD(udf_fsck_node_hash_list, udf_fsck_node) fs_nodes_hash[HASH_HASHSIZE];
158 
159 
160 /* fsck used space bitmap conflict list */
161 #define FSCK_OVERLAP_MAIN_NODE	(1<<0)
162 #define FSCK_OVERLAP_EXTALLOC	(1<<1)
163 #define FSCK_OVERLAP_EXTENT	(1<<2)
164 
165 struct udf_fsck_overlap {
166 	struct udf_fsck_node *node;
167 	struct udf_fsck_node *node2;
168 
169 	struct long_ad	loc;
170 	struct long_ad	loc2;
171 
172 	int		flags;
173 	int		flags2;
174 
175 	TAILQ_ENTRY(udf_fsck_overlap) next;
176 };
177 TAILQ_HEAD(udf_fsck_overlap_list, udf_fsck_overlap) fsck_overlaps;
178 
179 
180 /* backup of old read in free space bitmaps */
181 struct space_bitmap_desc *recorded_part_unalloc_bits[UDF_PARTITIONS];
182 uint32_t recorded_part_free[UDF_PARTITIONS];
183 
184 /* shadow VAT build */
185 uint8_t *shadow_vat_contents;
186 
187 
188 /* options */
189 int alwaysno = 0;		/* assume "no" for all questions */
190 int alwaysyes = 0;		/* assume "yes" for all questions */
191 int search_older_vat = 0;	/* search for older VATs */
192 int force = 0;			/* do check even if its marked clean */
193 int preen = 0;			/* set when preening, doing automatic small repairs */
194 int rdonly = 0;			/* open device/image read-only */
195 int rdonly_flag = 0;		/* as passed on command line */
196 int heuristics = 0;		/* use heuristics to fix esoteric corruptions */
197 int target_session = 0;		/* offset to last session to check */
198 
199 
200 /* actions to undertake */
201 int undo_opening_session = 0;	/* trying to undo opening of last crippled session */
202 int open_integrity = 0;		/* should be open the integrity ie close later */
203 int vat_writeout = 0;		/* write out the VAT anyway */
204 
205 
206 /* SIGINFO */
207 static sig_atomic_t print_info = 0;		/* request for information on progress */
208 
209 
210 /* prototypes */
211 static void usage(void) __dead;
212 static int checkfilesys(char *given_dev);
213 static int ask(int def, const char *fmt, ...);
214 static int ask_noauto(int def, const char *fmt, ...);
215 
216 static void udf_recursive_keep(struct udf_fsck_node *node);
217 static char *udf_node_path(struct udf_fsck_node *node);
218 static void udf_shadow_VAT_in_use(struct long_ad *loc);
219 static int udf_quick_check_fids(struct udf_fsck_node *node, union dscrptr *dscr);
220 
221 
222 /* --------------------------------------------------------------------- */
223 
224 /* from bin/ls */
225 static void
226 printtime(time_t ftime)
227 {
228 	struct timespec clock;
229         const char *longstring;
230 	time_t now;
231         int i;
232 
233 	clock_gettime(CLOCK_REALTIME, &clock);
234 	now = clock.tv_sec;
235 
236         if ((longstring = ctime(&ftime)) == NULL) {
237                            /* 012345678901234567890123 */
238                 longstring = "????????????????????????";
239         }
240         for (i = 4; i < 11; ++i)
241                 (void)putchar(longstring[i]);
242 
243 #define SIXMONTHS       ((DAYSPERNYEAR / 2) * SECSPERDAY)
244         if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now)
245                 for (i = 11; i < 16; ++i)
246                         (void)putchar(longstring[i]);
247         else {
248                 (void)putchar(' ');
249                 for (i = 20; i < 24; ++i)
250                         (void)putchar(longstring[i]);
251         }
252         (void)putchar(' ');
253 }
254 
255 
256 static void
257 udf_print_timestamp(const char *prefix, struct timestamp *timestamp, const char *suffix)
258 {
259 	struct timespec timespec;
260 
261 	udf_timestamp_to_timespec(timestamp, &timespec);
262 	printf("%s", prefix);
263 	printtime(timespec.tv_sec);
264 	printf("%s", suffix);
265 }
266 
267 
268 static int
269 udf_compare_mtimes(struct timestamp *t1, struct timestamp *t2)
270 {
271 	struct timespec t1_tsp, t2_tsp;
272 
273 	udf_timestamp_to_timespec(t1, &t1_tsp);
274 	udf_timestamp_to_timespec(t2, &t2_tsp);
275 
276 	if (t1_tsp.tv_sec  < t2_tsp.tv_sec)
277 		return -1;
278 	if (t1_tsp.tv_sec  > t2_tsp.tv_sec)
279 		return  1;
280 	if (t1_tsp.tv_nsec < t2_tsp.tv_nsec)
281 		return -1;
282 	if (t1_tsp.tv_nsec > t2_tsp.tv_nsec)
283 		return  1;
284 	return 0;
285 }
286 
287 /* --------------------------------------------------------------------- */
288 
289 static int
290 udf_calc_node_hash(struct long_ad *icb)
291 {
292 	uint32_t lb_num = udf_rw32(icb->loc.lb_num);
293 	uint16_t vpart  = udf_rw16(icb->loc.part_num);
294 
295 	return ((uint64_t) (vpart + lb_num * 257)) & HASH_HASHMASK;
296 }
297 
298 
299 static struct udf_fsck_node *
300 udf_node_lookup(struct long_ad *icb)
301 {
302 	struct udf_fsck_node *pos;
303 	int entry = udf_calc_node_hash(icb);
304 
305 	pos = LIST_FIRST(&fs_nodes_hash[entry]);
306 	while (pos) {
307 		if (pos->loc.loc.part_num == icb->loc.part_num)
308 			if (pos->loc.loc.lb_num == icb->loc.lb_num)
309 				return pos;
310 		pos = LIST_NEXT(pos, next_hash);
311 	}
312 	return NULL;
313 }
314 
315 /* --------------------------------------------------------------------- */
316 
317 /* Note: only for VAT media since we don't allocate in bitmap */
318 static void
319 udf_wipe_and_reallocate(union dscrptr *dscrptr, int vpart_num, uint32_t *l_adp)
320 {
321 	struct file_entry    *fe  = &dscrptr->fe;
322 	struct extfile_entry *efe = &dscrptr->efe;
323 	struct desc_tag      *tag = &dscrptr->tag;
324 	struct icb_tag       *icb;
325 	struct long_ad        allocated;
326 	struct long_ad       *long_adp  = NULL;
327 	struct short_ad      *short_adp = NULL;
328 	uint64_t inf_len;
329 	uint32_t l_ea, l_ad;
330 	uint8_t *bpos;
331 	int bpos_start, ad_type, id;
332 
333 	assert(context.format_flags & FORMAT_VAT);
334 
335 	id = udf_rw16(tag->id);
336 	assert(id == TAGID_FENTRY || id == TAGID_EXTFENTRY);
337 	if (id == TAGID_FENTRY) {
338 		icb         = &fe->icbtag;
339 		inf_len     = udf_rw64(fe->inf_len);
340 		l_ea        = udf_rw32(fe->l_ea);
341 		bpos        = (uint8_t *) fe->data + l_ea;
342 		bpos_start  = offsetof(struct file_entry, data) + l_ea;
343 	} else {
344 		icb         = &efe->icbtag;
345 		inf_len     = udf_rw64(efe->inf_len);
346 		l_ea        = udf_rw32(efe->l_ea);
347 		bpos        = (uint8_t *) efe->data + l_ea;
348 		bpos_start  = offsetof(struct extfile_entry, data) + l_ea;
349 	}
350 	/* inf_len should be correct for one slot */
351 	assert(inf_len < UDF_EXT_MAXLEN);
352 
353 	ad_type = udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
354 	if (ad_type == UDF_ICB_INTERN_ALLOC) {
355 		/* no action needed */
356 		return;
357 	}
358 
359 	assert(vpart_num == context.data_part);
360 	udf_data_alloc(udf_bytes_to_sectors(inf_len), &allocated);
361 	memset(bpos, 0, context.sector_size - bpos_start);
362 	/* create one short_ad or one long_ad */
363 	if (ad_type == UDF_ICB_SHORT_ALLOC) {
364 		short_adp = (struct short_ad *) bpos;
365 		short_adp->len    = udf_rw32(inf_len);
366 		short_adp->lb_num = allocated.loc.lb_num;
367 		l_ad = sizeof(struct short_ad);
368 	} else {
369 		long_adp  = (struct long_ad  *) bpos;
370 		memcpy(long_adp, &allocated, sizeof(struct long_ad));
371 		long_adp->len = udf_rw32(inf_len);
372 		l_ad = sizeof(struct long_ad);
373 	}
374 	if (id == TAGID_FENTRY)
375 		fe->l_ad = udf_rw32(l_ad);
376 	else
377 		efe->l_ad = udf_rw32(l_ad);
378 	;
379 	*l_adp = l_ad;
380 }
381 
382 
383 static void
384 udf_copy_fid_verbatim(struct fileid_desc *sfid, struct fileid_desc *dfid,
385 		uint64_t dfpos, uint64_t drest)
386 {
387 	uint64_t endfid;
388 	uint32_t minlen, lb_rest, fidsize;
389 
390 	if (udf_rw16(sfid->l_iu) == 0) {
391 		memcpy(dfid, sfid, udf_fidsize(sfid));
392 		return;
393 	}
394 
395 	/* see if we can reduce its size */
396 	minlen = udf_fidsize(sfid) - udf_rw16(sfid->l_iu);
397 
398 	/*
399 	 * OK, tricky part: we need to pad so the next descriptor header won't
400 	 * cross the sector boundary
401 	 */
402 	endfid = dfpos + minlen;
403 	lb_rest = context.sector_size - (endfid % context.sector_size);
404 
405 	memcpy(dfid, sfid, UDF_FID_SIZE);
406 	if (lb_rest < sizeof(struct desc_tag)) {
407 		/* add at least 32 */
408 		dfid->l_iu = udf_rw16(32);
409 		udf_set_regid((struct regid *) dfid->data, context.impl_name);
410 		udf_add_impl_regid((struct regid *) dfid->data);
411 
412 	}
413 	memcpy( dfid->data + udf_rw16(dfid->l_iu),
414 		sfid->data + udf_rw16(sfid->l_iu),
415 		minlen - UDF_FID_SIZE);
416 
417 	fidsize = udf_fidsize(dfid);
418 	dfid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
419 }
420 
421 
422 static int
423 udf_rebuild_fid_stream(struct udf_fsck_node *node, int64_t *rest_lenp)
424 {
425 	struct fileid_desc *sfid, *dfid;
426 	uint64_t inf_len;
427 	uint64_t sfpos, dfpos;
428 	int64_t srest, drest;
429 //	uint32_t sfid_len, dfid_len;
430 	uint8_t *directory, *rebuild_dir;
431 //	int namelen;
432 	int error, streaming, was_streaming, warned, error_in_stream;
433 
434 	directory = node->directory;
435 	inf_len   = node->found.inf_len;
436 
437 	rebuild_dir = calloc(1, inf_len);
438 	assert(rebuild_dir);
439 
440 	sfpos  = 0;
441 	srest  = inf_len;
442 
443 	dfpos  = 0;
444 	drest  = inf_len;
445 
446 	error_in_stream = 0;
447 	streaming = 1;
448 	was_streaming = 1;
449 	warned = 0;
450 	while (srest > 0) {
451 		if (was_streaming & !streaming) {
452 			if (!warned) {
453 				pwarn("%s : BROKEN directory\n",
454 					udf_node_path(node));
455 				udf_recursive_keep(node);
456 				node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
457 			}
458 			warned = 1;
459 			pwarn("%s : <directory resync>\n",
460 					udf_node_path(node));
461 		}
462 		was_streaming = streaming;
463 
464 		assert(drest >= UDF_FID_SIZE);
465 		sfid = (struct fileid_desc *) (directory + sfpos);
466 		dfid = (struct fileid_desc *) (rebuild_dir + dfpos);
467 
468 		/* check if we can read/salvage the next source fid */
469 		if (udf_rw16(sfid->tag.id) != TAGID_FID) {
470 			streaming = 0;
471 			sfpos += 4;
472 			srest -= 4;
473 			error_in_stream = 1;
474 			continue;
475 		}
476 		error = udf_check_tag(sfid);
477 		if (error) {
478 			/* unlikely to be recoverable */
479 			streaming = 0;
480 			sfpos += 4;
481 			srest -= 4;
482 			error_in_stream = 1;
483 			continue;
484 		}
485 		error = udf_check_tag_payload(
486 			(union dscrptr *) sfid,
487 			context.sector_size);
488 		if (!error) {
489 			streaming = 1;
490 			/* all OK, just copy verbatim, shrinking if possible */
491 			udf_copy_fid_verbatim(sfid, dfid, dfpos, drest);
492 
493 			sfpos += udf_fidsize(sfid);
494 			srest -= udf_fidsize(sfid);
495 
496 			dfpos += udf_fidsize(dfid);
497 			drest -= udf_fidsize(dfid);
498 
499 			assert(udf_fidsize(sfid) == udf_fidsize(dfid));
500 			continue;
501 		}
502 
503 		/*
504 		 * The hard part, we need to try to recover of what is
505 		 * deductible of the bad source fid. The tag itself is OK, but
506 		 * that doesn't say much; its contents can still be off.
507 		 */
508 
509 		/* TODO NOT IMPLEMENTED YET, skip this entry the blunt way */
510 		streaming = 0;
511 		sfpos += 4;
512 		srest -= 4;
513 		error_in_stream = 1;
514 	}
515 
516 	/* if we could shrink/fix the node, mark it for repair */
517 	if (error_in_stream) {
518 		udf_recursive_keep(node);
519 		node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
520 	}
521 
522 	if (sfpos != dfpos)
523 		printf("%s: could save %" PRIi64 " bytes in directory\n", udf_node_path(node), sfpos - dfpos);
524 
525 	memset(directory, 0, inf_len);
526 	memcpy(directory, rebuild_dir, dfpos);
527 
528 	free(rebuild_dir);
529 
530 	*rest_lenp = dfpos;
531 	return error_in_stream;
532 }
533 
534 
535 static int
536 udf_quick_check_fids_piece(uint8_t *piece, uint32_t piece_len,
537 		struct udf_fsck_fid_context *fid_context,
538 		uint32_t lb_num)
539 {
540 	int error;
541 	struct fileid_desc *fid;
542 	uint32_t location;
543 	uint32_t offset, fidsize;
544 
545 	offset = fid_context->fid_offset % context.sector_size;
546 	while (fid_context->data_left && (offset < piece_len)) {
547 		fid = (struct fileid_desc *) (piece + offset);
548 		if (udf_rw16(fid->tag.id) == TAGID_FID) {
549 			error = udf_check_tag_payload(
550 					(union dscrptr *) fid,
551 					context.sector_size);
552 			if (error)
553 				return error;
554 		} else {
555 			return EINVAL;
556 		}
557 		assert(udf_rw16(fid->tag.id) == TAGID_FID);
558 
559 		location = lb_num + offset / context.sector_size;
560 
561 		if (udf_rw32(fid->tag.tag_loc) != location)
562 			return EINVAL;
563 
564 		if (context.dscrver == 2) {
565 			/* compression IDs should be preserved in UDF < 2.00 */
566 			if (*(fid->data + udf_rw16(fid->l_iu)) > 16)
567 				return EINVAL;
568 		}
569 
570 		fidsize      = udf_fidsize(fid);
571 		offset      += fidsize;
572 		fid_context->fid_offset += fidsize;
573 		fid_context->data_left  -= fidsize;
574 	}
575 
576 	return 0;
577 }
578 
579 
580 static void
581 udf_fids_fixup(uint8_t *piece, uint32_t piece_len,
582 		struct udf_fsck_fid_context *fid_context,
583 		uint32_t lb_num)
584 {
585 	struct fileid_desc *fid;
586 	uint32_t location;
587 	uint32_t offset, fidsize;
588 
589 	offset = fid_context->fid_offset % context.sector_size;
590 	while (fid_context->data_left && (offset < piece_len)) {
591 
592 		fid = (struct fileid_desc *) (piece + offset);
593 		assert(udf_rw16(fid->tag.id) == TAGID_FID);
594 
595 		location = lb_num + offset / context.sector_size;
596 		fid->tag.tag_loc = udf_rw32(location);
597 
598 		udf_validate_tag_and_crc_sums((union dscrptr *) fid);
599 
600 		fidsize      = udf_fidsize(fid);
601 		offset      += fidsize;
602 		fid_context->fid_offset += fidsize;
603 		fid_context->data_left  -= fidsize;
604 	}
605 }
606 
607 
608 /* NOTE returns non 0 for overlap, not an error code */
609 static int
610 udf_check_if_allocated(struct udf_fsck_node *node, int flags,
611 		uint32_t start_lb, int partnr, uint32_t piece_len)
612 {
613 	union dscrptr *dscr;
614 	struct udf_fsck_overlap *new_overlap;
615 	uint8_t *bpos;
616 	uint32_t cnt, bit;
617 	uint32_t blocks = udf_bytes_to_sectors(piece_len);
618 	int overlap = 0;
619 
620 	/* account for space used on underlying partition */
621 #ifdef DEBUG
622 	printf("check allocated : node %p, flags %d, partnr %d, start_lb %d for %d blocks\n",
623 		node, flags, partnr, start_lb, blocks);
624 #endif
625 
626 	switch (context.vtop_tp[partnr]) {
627 	case UDF_VTOP_TYPE_VIRT:
628 		/* nothing */
629 		break;
630 	case UDF_VTOP_TYPE_PHYS:
631 	case UDF_VTOP_TYPE_SPAREABLE:
632 	case UDF_VTOP_TYPE_META:
633 		if (context.part_unalloc_bits[context.vtop[partnr]] == NULL)
634 			break;
635 #ifdef DEBUG
636 		printf("checking allocation of %d+%d for being used\n", start_lb, blocks);
637 #endif
638 		dscr = (union dscrptr *) (context.part_unalloc_bits[partnr]);
639 		for (cnt = start_lb; cnt < start_lb + blocks; cnt++) {
640 			 bpos  = &dscr->sbd.data[cnt / 8];
641 			 bit   = cnt % 8;
642 			 /* only account for bits marked free */
643 			 if ((*bpos & (1 << bit)) == 0)
644 				 overlap++;
645 		}
646 		if (overlap == 0)
647 			break;
648 
649 		/* overlap */
650 //		pwarn("%s allocation OVERLAP found, type %d\n",
651 //				udf_node_path(node), flags);
652 		udf_recursive_keep(node);
653 		node->fsck_flags |= FSCK_NODE_FLAG_OVERLAP;
654 
655 		new_overlap = calloc(1, sizeof(struct udf_fsck_overlap));
656 		assert(new_overlap);
657 
658 		new_overlap->node              = node;
659 		new_overlap->node2             = NULL;
660 		new_overlap->flags             = flags;
661 		new_overlap->flags2            = 0;
662 		new_overlap->loc.len           = udf_rw32(piece_len);
663 		new_overlap->loc.loc.lb_num    = udf_rw32(start_lb);
664 		new_overlap->loc.loc.part_num  = udf_rw16(partnr);
665 
666 		TAILQ_INSERT_TAIL(&fsck_overlaps, new_overlap, next);
667 
668 		return overlap;
669 		break;
670 	default:
671 		errx(1, "internal error: bad mapping type %d in %s",
672 			context.vtop_tp[partnr], __func__);
673 	}
674 	/* no overlap */
675 	return 0;
676 }
677 
678 
679 /* NOTE returns non 0 for overlap, not an error code */
680 static void
681 udf_check_overlap_pair(struct udf_fsck_node *node, int flags,
682 		uint32_t start_lb, int partnr, uint32_t piece_len)
683 {
684 	struct udf_fsck_overlap *overlap;
685 	uint32_t ostart_lb, opiece_len, oblocks;
686 	uint32_t blocks = udf_bytes_to_sectors(piece_len);
687 	int opartnr;
688 
689 	/* account for space used on underlying partition */
690 #ifdef DEBUG
691 	printf("check overlap pair : node %p, flags %d, partnr %d, start_lb %d for %d blocks\n",
692 		node, flags, partnr, start_lb, blocks);
693 #endif
694 
695 	switch (context.vtop_tp[partnr]) {
696 	case UDF_VTOP_TYPE_VIRT:
697 		/* nothing */
698 		break;
699 	case UDF_VTOP_TYPE_PHYS:
700 	case UDF_VTOP_TYPE_SPAREABLE:
701 	case UDF_VTOP_TYPE_META:
702 		if (context.part_unalloc_bits[context.vtop[partnr]] == NULL)
703 			break;
704 #ifdef DEBUG
705 		printf("checking overlap of %d+%d for being used\n", start_lb, blocks);
706 #endif
707 		/* check all current overlaps with the piece we have here */
708 		TAILQ_FOREACH(overlap, &fsck_overlaps, next) {
709 			opiece_len = udf_rw32(overlap->loc.len);
710 			ostart_lb  = udf_rw32(overlap->loc.loc.lb_num);
711 			opartnr    = udf_rw16(overlap->loc.loc.part_num);
712 			oblocks    = udf_bytes_to_sectors(opiece_len);
713 
714 			if (partnr != opartnr)
715 				continue;
716 			/* piece before overlap? */
717 			if (start_lb + blocks < ostart_lb)
718 				continue;
719 			/* piece after overlap? */
720 			if (start_lb > ostart_lb + oblocks)
721 				continue;
722 
723 			/* overlap, mark conflict */
724 			overlap->node2             = node;
725 			overlap->flags2            = flags;
726 			overlap->loc2.len          = udf_rw32(piece_len);
727 			overlap->loc2.loc.lb_num   = udf_rw32(start_lb);
728 			overlap->loc2.loc.part_num = udf_rw16(partnr);
729 
730 			udf_recursive_keep(node);
731 			node->fsck_flags |= FSCK_NODE_FLAG_OVERLAP;
732 		}
733 		return;
734 	default:
735 		errx(1, "internal error: bad mapping type %d in %s",
736 			context.vtop_tp[partnr], __func__);
737 	}
738 	/* no overlap */
739 	return;
740 }
741 
742 
743 
744 static int
745 udf_process_ad(union dscrptr *dscrptr, int action, uint8_t **resultp,
746 	int vpart_num, uint64_t fpos,
747 	struct short_ad *short_adp, struct long_ad *long_adp, void *process_context)
748 {
749 	struct file_entry    *fe  = &dscrptr->fe;
750 	struct extfile_entry *efe = &dscrptr->efe;
751 	struct desc_tag      *tag = &dscrptr->tag;
752 	struct icb_tag  *icb;
753 	struct udf_fsck_file_stats *stats;
754 	uint64_t inf_len;
755 	uint32_t l_ea, piece_len, piece_alloc_len, piece_sectors, lb_num, flags;
756 	uint32_t dscr_lb_num;
757 	uint32_t i;
758 	uint8_t *bpos, *piece;
759 	int id, ad_type;
760 	int error, piece_error, return_error;
761 
762 	assert(dscrptr);
763 	stats = (struct udf_fsck_file_stats *) process_context;
764 
765 	id = udf_rw16(tag->id);
766 	assert(id == TAGID_FENTRY || id == TAGID_EXTFENTRY);
767 	if (id == TAGID_FENTRY) {
768 		icb         = &fe->icbtag;
769 		dscr_lb_num = udf_rw32(fe->tag.tag_loc);
770 		inf_len     = udf_rw64(fe->inf_len);
771 		l_ea        = udf_rw32(fe->l_ea);
772 		bpos        = (uint8_t *) fe->data + l_ea;
773 	} else {
774 		icb         = &efe->icbtag;
775 		dscr_lb_num = udf_rw32(efe->tag.tag_loc);
776 		inf_len     = udf_rw64(efe->inf_len);
777 		l_ea        = udf_rw32(efe->l_ea);
778 		bpos        = (uint8_t *) efe->data + l_ea;
779 	}
780 
781 	lb_num = 0;
782 	piece_len = 0;
783 
784 	ad_type = udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
785 	if (ad_type == UDF_ICB_INTERN_ALLOC) {
786 		piece_len = inf_len;
787 	}
788 	if (short_adp) {
789 		piece_len = udf_rw32(short_adp->len);
790 		lb_num    = udf_rw32(short_adp->lb_num);
791 	}
792 	if (long_adp) {
793 		piece_len = udf_rw32(long_adp->len);
794 		lb_num    = udf_rw32(long_adp->loc.lb_num);
795 		vpart_num = udf_rw16(long_adp->loc.part_num);
796 	}
797 	flags = UDF_EXT_FLAGS(piece_len);
798 	piece_len = UDF_EXT_LEN(piece_len);
799 	piece_alloc_len = UDF_ROUNDUP(piece_len, context.sector_size);
800 	piece_sectors   = piece_alloc_len / context.sector_size;
801 
802 	return_error = 0;
803 	if (action & AD_GATHER_STATS) {
804 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
805 			stats->inf_len     = piece_len;
806 			stats->obj_size    = piece_len;
807 			stats->logblks_rec = 0;
808 		}  else if (flags == UDF_EXT_ALLOCATED) {
809 			stats->inf_len     += piece_len;
810 			stats->obj_size    += piece_len;
811 			stats->logblks_rec += piece_sectors;
812 		} else if (flags == UDF_EXT_FREED) {
813 			stats->inf_len     += piece_len;
814 			stats->obj_size    += piece_len;
815 			stats->logblks_rec += piece_sectors;
816 		} else if (flags == UDF_EXT_FREE) {
817 			stats->inf_len     += piece_len;
818 			stats->obj_size    += piece_len;
819 		}
820 	}
821 	if (action & AD_LOAD_FILE) {
822 		uint32_t alloc_len;
823 
824 		piece = calloc(1, piece_alloc_len);
825 		if (piece == NULL)
826 			return errno;
827 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
828 			memcpy(piece, bpos, piece_len);
829 		} else if (flags == 0) {
830 			/* not empty */
831 			/* read sector by sector reading as much as possible */
832 			for (i = 0; i < piece_sectors; i++) {
833 				piece_error = udf_read_virt(
834 					piece + i * context.sector_size,
835 					lb_num + i, vpart_num, 1);
836 				if (piece_error)
837 					return_error = piece_error;
838 			}
839 		}
840 
841 		alloc_len = UDF_ROUNDUP(fpos + piece_len, context.sector_size);
842 		error = reallocarr(resultp, 1, alloc_len);
843 		if (error) {
844 			/* fatal */
845 			free(piece);
846 			free(*resultp);
847 			return errno;
848 		}
849 
850 		memcpy(*resultp + fpos, piece, piece_alloc_len);
851 		free(piece);
852 	}
853 	if (action & AD_ADJUST_FIDS) {
854 		piece = *resultp + fpos;
855 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
856 			udf_fids_fixup(piece, piece_len, process_context,
857 				dscr_lb_num);
858 		} else if (flags == 0) {
859 			udf_fids_fixup(piece, piece_len, process_context,
860 				lb_num);
861 		}
862 	}
863 	if (action & AD_CHECK_FIDS) {
864 		piece = *resultp + fpos;
865 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
866 			error = udf_quick_check_fids_piece(piece, piece_len,
867 				process_context, dscr_lb_num);
868 		} else if (flags == 0) {
869 			error = udf_quick_check_fids_piece(piece, piece_len,
870 				process_context, lb_num);
871 		}
872 		if (error)
873 			return error;
874 	}
875 	if (action & AD_SAVE_FILE) {
876 		/*
877 		 * Note: only used for directory contents.
878 		 */
879 		piece = *resultp + fpos;
880 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
881 			memcpy(bpos, piece, piece_len);
882 			/* nothing */
883 		} else if (flags == 0) {
884 			/* not empty */
885 			error = udf_write_virt(
886 				piece, lb_num, vpart_num,
887 				piece_sectors);
888 			if (error) {
889 				pwarn("Got error writing piece\n");
890 				return error;
891 			}
892 		} else {
893 			/* allocated but not written piece, skip */
894 		}
895 	}
896 	if (action & AD_CHECK_USED) {
897 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
898 			/* nothing */
899 		} else if (flags != UDF_EXT_FREE) {
900 			struct udf_fsck_node *node = process_context;
901 			(void) udf_check_if_allocated(
902 				node,
903 				FSCK_OVERLAP_EXTENT,
904 				lb_num, vpart_num,
905 				piece_len);
906 		}
907 	}
908 	if (action & AD_FIND_OVERLAP_PAIR) {
909 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
910 			/* nothing */
911 		} else if (flags != UDF_EXT_FREE) {
912 			struct udf_fsck_node *node = process_context;
913 			udf_check_overlap_pair(
914 				node,
915 				FSCK_OVERLAP_EXTENT,
916 				lb_num, vpart_num,
917 				piece_len);
918 		}
919 	}
920 	if (action & AD_MARK_AS_USED) {
921 		if (ad_type == UDF_ICB_INTERN_ALLOC) {
922 			/* nothing */
923 		} else if (flags != UDF_EXT_FREE) {
924 			udf_mark_allocated(lb_num, vpart_num,
925 				udf_bytes_to_sectors(piece_len));
926 		}
927 	}
928 
929 	return return_error;
930 }
931 
932 
933 static int
934 udf_process_file(union dscrptr *dscrptr, int vpart_num, uint8_t **resultp,
935 	int action, void *process_context)
936 {
937 	struct file_entry    *fe  = &dscrptr->fe;
938 	struct extfile_entry *efe = &dscrptr->efe;
939 	struct desc_tag      *tag = &dscrptr->tag;
940 	struct alloc_ext_entry *ext;
941 	struct icb_tag  *icb;
942 	struct long_ad  *long_adp  = NULL;
943 	struct short_ad *short_adp = NULL;
944 	union  dscrptr *extdscr = NULL;
945 	uint64_t fpos;
946 	uint32_t l_ad, l_ea, piece_len, lb_num, flags;
947 	uint8_t *bpos;
948 	int id, extid, ad_type, ad_len;
949 	int error;
950 
951 	id = udf_rw16(tag->id);
952 	assert(id == TAGID_FENTRY || id == TAGID_EXTFENTRY);
953 
954 	if (action & AD_CHECK_USED) {
955 		struct udf_fsck_node *node = process_context;
956 		(void) udf_check_if_allocated(
957 			node,
958 			FSCK_OVERLAP_MAIN_NODE,
959 			udf_rw32(node->loc.loc.lb_num),
960 			udf_rw16(node->loc.loc.part_num),
961 			context.sector_size);
962 		/* return error code? */
963 	}
964 
965 	if (action & AD_FIND_OVERLAP_PAIR) {
966 		struct udf_fsck_node *node = process_context;
967 		udf_check_overlap_pair(
968 			node,
969 			FSCK_OVERLAP_MAIN_NODE,
970 			udf_rw32(node->loc.loc.lb_num),
971 			udf_rw16(node->loc.loc.part_num),
972 			context.sector_size);
973 		/* return error code? */
974 	}
975 
976 	if (action & AD_MARK_AS_USED)
977 		udf_mark_allocated(udf_rw32(tag->tag_loc), vpart_num, 1);
978 
979 	if (id == TAGID_FENTRY) {
980 		icb         = &fe->icbtag;
981 		l_ad   = udf_rw32(fe->l_ad);
982 		l_ea   = udf_rw32(fe->l_ea);
983 		bpos = (uint8_t *) fe->data + l_ea;
984 	} else {
985 		icb         = &efe->icbtag;
986 		l_ad   = udf_rw32(efe->l_ad);
987 		l_ea   = udf_rw32(efe->l_ea);
988 		bpos = (uint8_t *) efe->data + l_ea;
989 	}
990 
991 	ad_type = udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
992 	if (ad_type == UDF_ICB_INTERN_ALLOC) {
993 		error = udf_process_ad(dscrptr, action, resultp, -1, 0,
994 				NULL, NULL, process_context);
995 		return error;
996 	}
997 	if ((ad_type != UDF_ICB_SHORT_ALLOC) &&
998 			(ad_type != UDF_ICB_LONG_ALLOC))
999 		return EINVAL;
1000 
1001 	if (ad_type == UDF_ICB_SHORT_ALLOC)
1002 		short_adp = (struct short_ad *) bpos;
1003 	else
1004 		long_adp  = (struct long_ad  *) bpos;
1005 	;
1006 
1007 	if (action & AD_SAVE_FILE) {
1008 		/*
1009 		 * Special case for writeout file/directory on recordable
1010 		 * media. We write in one go so wipe and (re)allocate the
1011 		 * entire space.
1012 		 */
1013 		if (context.format_flags & FORMAT_VAT)
1014 			udf_wipe_and_reallocate(dscrptr, vpart_num, &l_ad);
1015 	}
1016 
1017 	fpos = 0;
1018 	bpos = NULL;
1019 	error = 0;
1020 	while (l_ad) {
1021 		if (ad_type == UDF_ICB_SHORT_ALLOC) {
1022 			piece_len = udf_rw32(short_adp->len);
1023 			lb_num    = udf_rw32(short_adp->lb_num);
1024 			ad_len = sizeof(struct short_ad);
1025 		} else /* UDF_ICB_LONG_ALLOC  */ {
1026 			piece_len = udf_rw32(long_adp->len);
1027 			lb_num    = udf_rw32(long_adp->loc.lb_num);
1028 			vpart_num = udf_rw16(long_adp->loc.part_num);
1029 			ad_len = sizeof(struct long_ad);
1030 		}
1031 		flags = UDF_EXT_FLAGS(piece_len);
1032 		piece_len = UDF_EXT_LEN(piece_len);
1033 
1034 		switch (flags) {
1035 		default :
1036 			error = udf_process_ad(dscrptr, action, resultp,
1037 					vpart_num, fpos, short_adp, long_adp,
1038 					process_context);
1039 			break;
1040 		case UDF_EXT_REDIRECT  :
1041 			if (piece_len != context.sector_size) {
1042 				/* should this be an error? */
1043 				pwarn("Got extension redirect with wrong size %d\n",
1044 					piece_len);
1045 				error = EINVAL;
1046 				break;
1047 			}
1048 			free(extdscr);
1049 			error = udf_read_dscr_virt(lb_num, vpart_num, &extdscr);
1050 			if (error)
1051 				break;
1052 			/* empty block is terminator */
1053 			if (extdscr == NULL)
1054 				return 0;
1055 			ext = &extdscr->aee;
1056 			extid = udf_rw16(ext->tag.id);
1057 			if (extid != TAGID_ALLOCEXTENT) {
1058 				pwarn("Corruption in allocated extents chain\n");
1059 				/* corruption! */
1060 				free(extdscr);
1061 				errno = EINVAL;
1062 				break;
1063 			}
1064 
1065 			if (action & AD_CHECK_USED) {
1066 				(void) udf_check_if_allocated(
1067 					(struct udf_fsck_node *) process_context,
1068 					FSCK_OVERLAP_EXTALLOC,
1069 					lb_num,
1070 					vpart_num,
1071 					context.sector_size);
1072 				/* returning error code ? */
1073 			}
1074 
1075 			if (action & AD_FIND_OVERLAP_PAIR) {
1076 				struct udf_fsck_node *node = process_context;
1077 				udf_check_overlap_pair(
1078 					node,
1079 					FSCK_OVERLAP_EXTALLOC,
1080 					lb_num,
1081 					vpart_num,
1082 					context.sector_size);
1083 				/* return error code? */
1084 			}
1085 
1086 			if (action & AD_MARK_AS_USED)
1087 				udf_mark_allocated(
1088 					lb_num, vpart_num,
1089 					1);
1090 			/* TODO check for prev_entry? */
1091 			l_ad = ext->l_ad;
1092 			bpos = ext->data;
1093 			if (ad_type == UDF_ICB_SHORT_ALLOC)
1094 				short_adp = (struct short_ad *) bpos;
1095 			else
1096 				long_adp  = (struct long_ad  *) bpos;
1097 			;
1098 			continue;
1099 		}
1100 		if (error)
1101 			break;
1102 
1103 		if (long_adp)  long_adp++;
1104 		if (short_adp) short_adp++;
1105 		fpos += piece_len;
1106 		bpos += piece_len;
1107 		l_ad -= ad_len;
1108 	}
1109 
1110 	return error;
1111 }
1112 
1113 
1114 static int
1115 udf_readin_file(union dscrptr *dscrptr, int vpart_num, uint8_t **resultp,
1116 		struct udf_fsck_file_stats *statsp)
1117 {
1118 	struct udf_fsck_file_stats stats;
1119 	int error;
1120 
1121 	bzero(&stats, sizeof(stats));
1122 	*resultp = NULL;
1123 	error = udf_process_file(dscrptr, vpart_num, resultp,
1124 			AD_LOAD_FILE | AD_GATHER_STATS, (void *) &stats);
1125 	if (statsp)
1126 		*statsp = stats;
1127 	return error;
1128 }
1129 
1130 /* --------------------------------------------------------------------- */
1131 
1132 #define MAX_BSIZE		(0x10000)
1133 #define UDF_ISO_VRS_SIZE	(32*2048) /* 32 ISO `sectors' */
1134 
1135 static void
1136 udf_check_vrs9660(void)
1137 {
1138 	struct vrs_desc *vrs;
1139 	uint8_t buffer[MAX_BSIZE];
1140 	uint64_t rpos;
1141 	uint8_t *pos;
1142 	int max_sectors, sector, factor;
1143 	int ret, ok;
1144 
1145 	if (context.format_flags & FORMAT_TRACK512)
1146 		return;
1147 
1148 	/*
1149 	 * location of iso9660 VRS is defined as first sector AFTER 32kb,
1150 	 * minimum `sector size' 2048
1151 	 */
1152 	layout.iso9660_vrs = ((32*1024 + context.sector_size - 1) /
1153 			context.sector_size);
1154 	max_sectors = UDF_ISO_VRS_SIZE / 2048;
1155 	factor = (2048 + context.sector_size -1) / context.sector_size;
1156 
1157 	ok = 1;
1158 	rpos = (uint64_t) layout.iso9660_vrs * context.sector_size;
1159 	ret = pread(dev_fd, buffer, UDF_ISO_VRS_SIZE, rpos);
1160 	if (ret == -1) {
1161 		pwarn("Error reading in ISO9660 VRS\n");
1162 		ok = 0;
1163 	}
1164 	if (ok && ((uint32_t) ret != UDF_ISO_VRS_SIZE)) {
1165 		pwarn("Short read in ISO9660 VRS\n");
1166 		ok = 0;
1167 	}
1168 
1169 	if (ok) {
1170 		ok = 0;
1171 		for (sector = 0; sector < max_sectors; sector++) {
1172 			pos = buffer + sector * factor * context.sector_size;
1173 			vrs = (struct vrs_desc *) pos;
1174 			if (strncmp((const char *) vrs->identifier, VRS_BEA01, 5) == 0)
1175 				ok  = 1;
1176 			if (strncmp((const char *) vrs->identifier, VRS_NSR02, 5) == 0)
1177 				ok |= 2;
1178 			if (strncmp((const char *) vrs->identifier, VRS_NSR03, 5) == 0)
1179 				ok |= 2;
1180 			if (strncmp((const char *) vrs->identifier, VRS_TEA01, 5) == 0) {
1181 				ok |= 4;
1182 				break;
1183 			}
1184 		}
1185 		if (ok != 7)
1186 			ok = 0;
1187 	}
1188 	if (!ok) {
1189 		pwarn("Error in ISO 9660 volume recognition sequence\n");
1190 		if (context.format_flags & FORMAT_SEQUENTIAL) {
1191 			pwarn("ISO 9660 volume recognition sequence can't be repaired "
1192 			       "on SEQUENTIAL media\n");
1193 		} else if (ask(0, "fix ISO 9660 volume recognition sequence")) {
1194 			if (!rdonly)
1195 				udf_write_iso9660_vrs();
1196 		}
1197 	}
1198 }
1199 
1200 
1201 /*
1202  * Read in disc and try to find basic properties like sector size, expected
1203  * UDF versions etc.
1204  */
1205 
1206 static int
1207 udf_find_anchor(int anum)
1208 {
1209 	uint8_t buffer[MAX_BSIZE];
1210 	struct anchor_vdp *avdp = (struct anchor_vdp *) buffer;
1211 	uint64_t rpos;
1212 	uint32_t location;
1213 	int sz_guess, ret;
1214 	int error;
1215 
1216 	location = layout.anchors[anum];
1217 
1218 	/*
1219 	 * Search ADVP by reading bigger and bigger sectors NOTE we can't use
1220 	 * udf_read_phys yet since the sector size is not known yet
1221 	 */
1222 	sz_guess = mmc_discinfo.sector_size;	/* assume media is bigger */
1223 	for (; sz_guess <= MAX_BSIZE; sz_guess += 512) {
1224 		rpos = (uint64_t) location * sz_guess;
1225 		ret = pread(dev_fd, buffer, sz_guess, rpos);
1226 		if (ret == -1) {
1227 			if (errno == ENODEV)
1228 				return errno;
1229 		} else if (ret != sz_guess) {
1230 			/* most likely EOF, ignore */
1231 		} else {
1232 			error = udf_check_tag_and_location(buffer, location);
1233 			if (!error) {
1234 				if (udf_rw16(avdp->tag.id) != TAGID_ANCHOR)
1235 					continue;
1236 				error = udf_check_tag_payload(buffer, sz_guess);
1237 				if (!error)
1238 					break;
1239 			}
1240 		}
1241 	}
1242 	if (sz_guess > MAX_BSIZE)
1243 		return -1;
1244 
1245 	/* special case for disc images */
1246 	if (mmc_discinfo.sector_size != (unsigned int) sz_guess) {
1247 		emul_sectorsize = sz_guess;
1248 		udf_update_discinfo();
1249 	}
1250 	context.sector_size = sz_guess;
1251 	context.dscrver = udf_rw16(avdp->tag.descriptor_ver);
1252 
1253 	context.anchors[anum] = calloc(1, context.sector_size);
1254 	memcpy(context.anchors[anum], avdp, context.sector_size);
1255 
1256 	context.min_udf = 0x102;
1257 	context.max_udf = 0x150;
1258 	if (context.dscrver > 2) {
1259 		context.min_udf = 0x200;
1260 		context.max_udf = 0x260;
1261 	}
1262 	return 0;
1263 }
1264 
1265 
1266 static int
1267 udf_get_anchors(void)
1268 {
1269 	struct mmc_trackinfo ti;
1270 	struct anchor_vdp *avdp;
1271 	int need_fixup, error;
1272 
1273 	memset(&layout, 0, sizeof(layout));
1274 	memset(&ti, 0, sizeof(ti));
1275 
1276 	/* search start */
1277 	for (int i = 1; i <= mmc_discinfo.num_tracks; i++) {
1278 		ti.tracknr = i;
1279 		error = udf_update_trackinfo(&ti);
1280 		assert(!error);
1281 		if (ti.sessionnr == target_session)
1282 			break;
1283 	}
1284 	/* support for track 512 */
1285 	if (ti.flags & MMC_TRACKINFO_BLANK)
1286 		context.format_flags |= FORMAT_TRACK512;
1287 
1288 	assert(!error);
1289 	context.first_ti = ti;
1290 
1291 	/* search end */
1292 	for (int i = mmc_discinfo.num_tracks; i > 0; i--) {
1293 		ti.tracknr = i;
1294 		error = udf_update_trackinfo(&ti);
1295 		assert(!error);
1296 		if (ti.sessionnr == target_session)
1297 			break;
1298 	}
1299 	context.last_ti = ti;
1300 
1301 	layout.first_lba  = context.first_ti.track_start;
1302 	layout.last_lba   = mmc_discinfo.last_possible_lba;
1303 	layout.blockingnr = udf_get_blockingnr(&ti);
1304 
1305 	layout.anchors[0] = layout.first_lba + 256;
1306 	if (context.format_flags & FORMAT_TRACK512)
1307 		layout.anchors[0] = layout.first_lba + 512;
1308 	layout.anchors[1] = layout.last_lba - 256;
1309 	layout.anchors[2] = layout.last_lba;
1310 
1311 	need_fixup = 0;
1312 	error = udf_find_anchor(0);
1313 	if (error == ENODEV) {
1314 		pwarn("Drive empty?\n");
1315 		return errno;
1316 	}
1317 	if (error) {
1318 		need_fixup = 1;
1319 		if (!preen)
1320 			pwarn("Anchor ADVP0 can't be found! Searching others\n");
1321 		error = udf_find_anchor(2);
1322 		if (error) {
1323 			if (!preen)
1324 				pwarn("Anchor ADVP2 can't be found! Searching ADVP1\n");
1325 			/* this may be fidly, but search */
1326 			error = udf_find_anchor(1);
1327 			if (error) {
1328 				if (!preen)
1329 					pwarn("No valid anchors found!\n");
1330 				/* TODO scan media for VDS? */
1331 				return -1;
1332 			}
1333 		}
1334 	}
1335 
1336 	if (need_fixup) {
1337 		if (context.format_flags & FORMAT_SEQUENTIAL) {
1338 			pwarn("Missing primary anchor can't be resolved on "
1339 			      "SEQUENTIAL media\n");
1340 		} else if (ask(1, "Fixup missing anchors")) {
1341 			pwarn("TODO fixup missing anchors\n");
1342 			need_fixup = 0;
1343 		}
1344 		if (need_fixup)
1345 			return -1;
1346 	}
1347 	if (!preen)
1348 		printf("Filesystem sectorsize is %d bytes.\n\n",
1349 			context.sector_size);
1350 
1351 	/* update our last track info since our idea of sector size might have changed */
1352 	(void) udf_update_trackinfo(&context.last_ti);
1353 
1354 	/* sector size is now known */
1355 	wrtrack_skew = context.last_ti.next_writable % layout.blockingnr;
1356 
1357 	avdp = context.anchors[0];
1358 	/* extract info from current anchor */
1359 	layout.vds1      = udf_rw32(avdp->main_vds_ex.loc);
1360 	layout.vds1_size = udf_rw32(avdp->main_vds_ex.len) / context.sector_size;
1361 	layout.vds2      = udf_rw32(avdp->reserve_vds_ex.loc);
1362 	layout.vds2_size = udf_rw32(avdp->reserve_vds_ex.len) / context.sector_size;
1363 
1364 	return 0;
1365 }
1366 
1367 
1368 #define UDF_LVINT_HIST_CHUNK 32
1369 static void
1370 udf_retrieve_lvint(void) {
1371 	union dscrptr *dscr;
1372 	struct logvol_int_desc *lvint;
1373 	struct udf_lvintq *trace;
1374 	uint32_t lbnum, len, *pos;
1375 	uint8_t *wpos;
1376 	int num_partmappings;
1377 	int error, cnt, trace_len;
1378 	int sector_size = context.sector_size;
1379 
1380 	len     = udf_rw32(context.logical_vol->integrity_seq_loc.len);
1381 	lbnum   = udf_rw32(context.logical_vol->integrity_seq_loc.loc);
1382 	layout.lvis = lbnum;
1383 	layout.lvis_size = len / sector_size;
1384 
1385 	udf_create_lvintd(UDF_INTEGRITY_OPEN);
1386 
1387 	/* clean trace and history */
1388 	memset(context.lvint_trace, 0,
1389 	    UDF_LVDINT_SEGMENTS * sizeof(struct udf_lvintq));
1390 	context.lvint_history_wpos = 0;
1391 	context.lvint_history_len = UDF_LVINT_HIST_CHUNK;
1392 	context.lvint_history = calloc(UDF_LVINT_HIST_CHUNK, sector_size);
1393 
1394 	/* record the length on this segment */
1395 	context.lvint_history_ondisc_len = (len / sector_size);
1396 
1397 	trace_len    = 0;
1398 	trace        = context.lvint_trace;
1399 	trace->start = lbnum;
1400 	trace->end   = lbnum + len/sector_size;
1401 	trace->pos   = 0;
1402 	trace->wpos  = 0;
1403 
1404 	dscr  = NULL;
1405 	error = 0;
1406 	while (len) {
1407 		trace->pos  = lbnum - trace->start;
1408 		trace->wpos = trace->pos + 1;
1409 
1410 		free(dscr);
1411 		error = udf_read_dscr_phys(lbnum, &dscr);
1412 		/* bad descriptors mean corruption, terminate */
1413 		if (error)
1414 			break;
1415 
1416 		/* empty terminates */
1417 		if (dscr == NULL) {
1418 			trace->wpos = trace->pos;
1419 			break;
1420 		}
1421 
1422 		/* we got a valid descriptor */
1423 		if (udf_rw16(dscr->tag.id) == TAGID_TERM) {
1424 			trace->wpos = trace->pos;
1425 			break;
1426 		}
1427 		/* only logical volume integrity descriptors are valid */
1428 		if (udf_rw16(dscr->tag.id) != TAGID_LOGVOL_INTEGRITY) {
1429 			error = ENOENT;
1430 			break;
1431 		}
1432 		lvint = &dscr->lvid;
1433 
1434 		/* see if our history is long enough, with one spare */
1435 		if (context.lvint_history_wpos+2 >= context.lvint_history_len) {
1436 			int new_len = context.lvint_history_len +
1437 				UDF_LVINT_HIST_CHUNK;
1438 			if (reallocarr(&context.lvint_history,
1439 					new_len, sector_size))
1440 				err(FSCK_EXIT_CHECK_FAILED, "can't expand logvol history");
1441 			context.lvint_history_len = new_len;
1442 		}
1443 
1444 		/* are we linking to a new piece? */
1445 		if (lvint->next_extent.len) {
1446 			len   = udf_rw32(lvint->next_extent.len);
1447 			lbnum = udf_rw32(lvint->next_extent.loc);
1448 
1449 			if (trace_len >= UDF_LVDINT_SEGMENTS-1) {
1450 				/* IEK! segment link full... */
1451 				pwarn("implementation limit: logical volume "
1452 					"integrity segment list full\n");
1453 				error = ENOMEM;
1454 				break;
1455 			}
1456 			trace++;
1457 			trace_len++;
1458 
1459 			trace->start = lbnum;
1460 			trace->end   = lbnum + len/sector_size;
1461 			trace->pos   = 0;
1462 			trace->wpos  = 0;
1463 
1464 			context.lvint_history_ondisc_len += (len / sector_size);
1465 		}
1466 
1467 		/* record this found lvint; it is one sector long */
1468 		wpos = context.lvint_history +
1469 			context.lvint_history_wpos * sector_size;
1470 		memcpy(wpos, dscr, sector_size);
1471 		memcpy(context.logvol_integrity, dscr, sector_size);
1472 		context.lvint_history_wpos++;
1473 
1474 		/* proceed sequential */
1475 		lbnum += 1;
1476 		len   -= sector_size;
1477 	}
1478 
1479 	/* clean up the mess, esp. when there is an error */
1480 	free(dscr);
1481 
1482 	if (error) {
1483 		if (!preen)
1484 			printf("Error in logical volume integrity sequence\n");
1485 		printf("Marking logical volume integrity OPEN\n");
1486 		udf_update_lvintd(UDF_INTEGRITY_OPEN);
1487 	}
1488 
1489 	if (udf_rw16(context.logvol_info->min_udf_readver) > context.min_udf)
1490 		context.min_udf   = udf_rw16(context.logvol_info->min_udf_readver);
1491 	if (udf_rw16(context.logvol_info->min_udf_writever) > context.min_udf)
1492 		context.min_udf   = udf_rw16(context.logvol_info->min_udf_writever);
1493 	if (udf_rw16(context.logvol_info->max_udf_writever) < context.max_udf)
1494 		context.max_udf   = udf_rw16(context.logvol_info->max_udf_writever);
1495 
1496 	context.unique_id = udf_rw64(context.logvol_integrity->lvint_next_unique_id);
1497 
1498 	/* fill in current size/free values */
1499 	pos = &context.logvol_integrity->tables[0];
1500 	num_partmappings = udf_rw32(context.logical_vol->n_pm);
1501 	for (cnt = 0; cnt < num_partmappings; cnt++) {
1502 		context.part_free[cnt] = udf_rw32(*pos);
1503 		pos++;
1504 	}
1505 	/* leave the partition sizes alone; no idea why they are stated here */
1506 	/* TODO sanity check the free space and partition sizes? */
1507 
1508 /* XXX FAULT INJECTION POINT XXX */
1509 //udf_update_lvintd(UDF_INTEGRITY_OPEN);
1510 
1511 	if (!preen) {
1512 		int ver;
1513 
1514 		printf("\n");
1515 		ver = udf_rw16(context.logvol_info->min_udf_readver);
1516 		printf("Minimum read  version v%x.%02x\n", ver/0x100, ver&0xff);
1517 		ver = udf_rw16(context.logvol_info->min_udf_writever);
1518 		printf("Minimum write version v%x.%02x\n", ver/0x100, ver&0xff);
1519 		ver = udf_rw16(context.logvol_info->max_udf_writever);
1520 		printf("Maximum write version v%x.%02x\n", ver/0x100, ver&0xff);
1521 
1522 		printf("\nLast logical volume integrity state is %s.\n",
1523 			udf_rw32(context.logvol_integrity->integrity_type) ?
1524 			"CLOSED" : "OPEN");
1525 	}
1526 }
1527 
1528 
1529 static int
1530 udf_writeout_lvint(void)
1531 {
1532 	union dscrptr *terminator;
1533 	struct udf_lvintq *intq, *nintq;
1534 	struct logvol_int_desc *lvint;
1535 	uint32_t location;
1536 	int wpos, num_avail;
1537 	int sector_size = context.sector_size;
1538 	int integrity_type, error;
1539 	int next_present, end_slot, last_segment;
1540 
1541 	/* only write out when its open */
1542 	integrity_type = udf_rw32(context.logvol_integrity->integrity_type);
1543 	if (integrity_type == UDF_INTEGRITY_CLOSED)
1544 		return 0;
1545 
1546 	if (!preen)
1547 		printf("\n");
1548 	if (!ask(1, "Write out modifications"))
1549 		return 0;
1550 
1551 	udf_allow_writing();
1552 
1553 	/* close logical volume */
1554 	udf_update_lvintd(UDF_INTEGRITY_CLOSED);
1555 
1556 	/* do we need to lose some history? */
1557 	if ((context.lvint_history_ondisc_len - context.lvint_history_wpos) < 2) {
1558 		uint8_t *src, *dst;
1559 		uint32_t size;
1560 
1561 		dst = context.lvint_history;
1562 		src = dst + sector_size;
1563 		size = (context.lvint_history_wpos-2) * sector_size;
1564 		memmove(dst, src, size);
1565 		context.lvint_history_wpos -= 2;
1566 	}
1567 
1568 	/* write out complete trace just in case */
1569 	wpos = 0;
1570 	location = 0;
1571 	for (int i = 0; i < UDF_LVDINT_SEGMENTS; i++) {
1572 		intq = &context.lvint_trace[i];
1573 		nintq = &context.lvint_trace[i+1];
1574 
1575 		/* end of line? */
1576 		if (intq->start == intq->end)
1577 			break;
1578 		num_avail = intq->end - intq->start;
1579 		location  = intq->start;
1580 		for (int sector = 0; sector < num_avail; sector++) {
1581 			lvint = (struct logvol_int_desc *)
1582 				(context.lvint_history + wpos * sector_size);
1583 			memset(&lvint->next_extent, 0, sizeof(struct extent_ad));
1584 			next_present = (wpos != context.lvint_history_wpos);
1585 			end_slot     = (sector == num_avail -1);
1586 			last_segment = (i == UDF_LVDINT_SEGMENTS-1);
1587 			if (end_slot && next_present && !last_segment) {
1588 				/* link to next segment */
1589 				lvint->next_extent.len = udf_rw32(
1590 					sector_size * (nintq->end - nintq->start));
1591 				lvint->next_extent.loc = udf_rw32(nintq->start);
1592 			}
1593 			error = udf_write_dscr_phys((union dscrptr *) lvint, location, 1);
1594 			assert(!error);
1595 			wpos++;
1596 			location++;
1597 			if (wpos == context.lvint_history_wpos)
1598 				break;
1599 		}
1600 	}
1601 
1602 	/* at write pos, write out our integrity */
1603 	assert(location);
1604 	lvint = context.logvol_integrity;
1605 	error = udf_write_dscr_phys((union dscrptr *) lvint, location, 1);
1606 	assert(!error);
1607 	wpos++;
1608 	location++;
1609 
1610 	/* write out terminator */
1611 	terminator = calloc(1, context.sector_size);
1612 	assert(terminator);
1613 	udf_create_terminator(terminator, 0);
1614 
1615 	/* same or increasing serial number: ECMA 3/7.2.5, 4/7.2.5, UDF 2.3.1.1. */
1616 	terminator->tag.serial_num = lvint->tag.serial_num;
1617 
1618 	error = udf_write_dscr_phys(terminator, location, 1);
1619 	free(terminator);
1620 	assert(!error);
1621 	wpos++;
1622 	location++;
1623 
1624 	return 0;
1625 }
1626 
1627 
1628 static int
1629 udf_readin_partitions_free_space(void)
1630 {
1631 	union dscrptr *dscr;
1632 	struct part_desc *part;
1633 	struct part_hdr_desc *phd;
1634 	uint32_t bitmap_len, bitmap_lb;
1635 	int cnt, tagid, error;
1636 
1637 	/* XXX freed space bitmap ignored XXX */
1638 	error = 0;
1639 	for (cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
1640 		part = context.partitions[cnt];
1641 		if (!part)
1642 			continue;
1643 
1644 		phd = &part->pd_part_hdr;
1645 		bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
1646 		bitmap_lb  = udf_rw32(phd->unalloc_space_bitmap.lb_num);
1647 
1648 		if (bitmap_len == 0) {
1649 			error = 0;
1650 			continue;
1651 		}
1652 
1653 		if (!preen)
1654 			printf("Reading in free space map for partition %d\n", cnt);
1655 		error = udf_read_dscr_virt(bitmap_lb, cnt, &dscr);
1656 		if (error)
1657 			break;
1658 		if (!dscr) {
1659 			error = ENOENT;
1660 			break;
1661 		}
1662 		tagid = udf_rw16(dscr->tag.id);
1663 		if (tagid != TAGID_SPACE_BITMAP) {
1664 			pwarn("Unallocated space bitmap expected but got "
1665 			      "tag %d\n", tagid);
1666 			free(dscr);
1667 			error = ENOENT;
1668 			break;
1669 		}
1670 		if (udf_tagsize(dscr, context.sector_size) > bitmap_len) {
1671 			pwarn("Warning, size of read in bitmap %d is "
1672 			      "not equal to expected size %d\n",
1673 			      udf_tagsize(dscr, context.sector_size),
1674 			      bitmap_len);
1675 		}
1676 		context.part_unalloc_bits[cnt] = &dscr->sbd;
1677 	}
1678 
1679 	/* special case for metadata partitions */
1680 	for (cnt = 0; cnt < UDF_PMAPS; cnt++) {
1681 		if (context.vtop_tp[cnt] != UDF_VTOP_TYPE_META)
1682 			continue;
1683 		/* only if present */
1684 		if (layout.meta_bitmap == 0xffffffff)
1685 			continue;
1686 		if (!preen)
1687 			printf("Reading in free space map for partition %d\n", cnt);
1688 		error = udf_readin_file(
1689 				(union dscrptr *) context.meta_bitmap,
1690 				context.vtop[cnt],
1691 				(uint8_t **) &context.part_unalloc_bits[cnt],
1692 				NULL);
1693 		if (error) {
1694 			free(context.part_unalloc_bits[cnt]);
1695 			context.part_unalloc_bits[cnt] = NULL;
1696 			pwarn("implementation limit: metadata bitmap file read error, "
1697 			      "can't fix this up yet\n");
1698 			return error;
1699 		}
1700 	}
1701 	if (!preen)
1702 		printf("\n");
1703 
1704 	return error;
1705 }
1706 
1707 
1708 /* ------------------------- VAT support ------------------------- */
1709 
1710 /*
1711  * Update logical volume name in all structures that keep a record of it. We
1712  * use memmove since each of them might be specified as a source.
1713  *
1714  * Note that it doesn't update the VAT structure!
1715  */
1716 
1717 static void
1718 udf_update_logvolname(char *logvol_id)
1719 {
1720 	struct logvol_desc     *lvd = NULL;
1721 	struct fileset_desc    *fsd = NULL;
1722 	struct udf_lv_info     *lvi = NULL;
1723 
1724 	lvd = context.logical_vol;
1725 	fsd = context.fileset_desc;
1726 	if (context.implementation)
1727 		lvi = &context.implementation->_impl_use.lv_info;
1728 
1729 	/* logvol's id might be specified as original so use memmove here */
1730 	memmove(lvd->logvol_id, logvol_id, 128);
1731 	if (fsd)
1732 		memmove(fsd->logvol_id, logvol_id, 128);
1733 	if (lvi)
1734 		memmove(lvi->logvol_id, logvol_id, 128);
1735 }
1736 
1737 
1738 static struct timestamp *
1739 udf_file_mtime(union dscrptr *dscr)
1740 {
1741 	int tag_id = udf_rw16(dscr->tag.id);
1742 
1743 	assert((tag_id == TAGID_FENTRY) || (tag_id == TAGID_EXTFENTRY));
1744 	if (tag_id == TAGID_FENTRY)
1745 		return &dscr->fe.mtime;
1746 	else
1747 		return &dscr->efe.mtime;
1748 	;
1749 }
1750 
1751 
1752 static void
1753 udf_print_vat_details(union dscrptr *dscr)
1754 {
1755 	printf("\n");
1756 	udf_print_timestamp("\tFound VAT timestamped at ",
1757 		udf_file_mtime(dscr), "\n");
1758 }
1759 
1760 
1761 static int
1762 udf_check_for_vat(union dscrptr *dscr)
1763 {
1764 	struct icb_tag   *icbtag;
1765 	uint32_t  vat_length;
1766 	int tag_id, filetype;
1767 
1768 	tag_id = udf_rw16(dscr->tag.id);
1769 
1770 	if ((tag_id != TAGID_FENTRY) && (tag_id != TAGID_EXTFENTRY))
1771 		return ENOENT;
1772 
1773 	if (tag_id == TAGID_FENTRY) {
1774 		vat_length = udf_rw64(dscr->fe.inf_len);
1775 		icbtag    = &dscr->fe.icbtag;
1776 	} else {
1777 		vat_length = udf_rw64(dscr->efe.inf_len);
1778 		icbtag = &dscr->efe.icbtag;
1779 	}
1780 	filetype = icbtag->file_type;
1781 	if ((filetype != 0) && (filetype != UDF_ICB_FILETYPE_VAT))
1782 		return ENOENT;
1783 
1784 	/* TODO sanity check vat length */
1785 	(void)vat_length;
1786 
1787 	return 0;
1788 }
1789 
1790 
1791 static int
1792 udf_extract_vat(union dscrptr *dscr, uint8_t **vat_contents)
1793 {
1794 	struct udf_fsck_file_stats	 stats;
1795 	struct icb_tag			*icbtag;
1796 	struct timestamp		*mtime;
1797 	struct udf_vat			*vat;
1798 	struct udf_oldvat_tail		*oldvat_tl;
1799 	struct udf_logvol_info		*lvinfo;
1800 	struct impl_extattr_entry	*implext;
1801 	struct vatlvext_extattr_entry	 lvext;
1802 	const char *extstr = "*UDF VAT LVExtension";
1803 	uint64_t vat_unique_id;
1804 	uint64_t vat_length;
1805 	uint32_t vat_entries, vat_offset;
1806 	uint32_t offset, a_l;
1807 	uint8_t *ea_start, *lvextpos;
1808 	char *regid_name;
1809 	int tag_id, filetype;
1810 	int error;
1811 
1812 	*vat_contents = NULL;
1813 	lvinfo = context.logvol_info;
1814 
1815 	/* read in VAT contents */
1816 	error = udf_readin_file(dscr, context.data_part, vat_contents, &stats);
1817 	if (error) {
1818 		error = ENOENT;
1819 		goto out;
1820 	}
1821 
1822 	/* tag_id already checked */
1823 	tag_id = udf_rw16(dscr->tag.id);
1824 	if (tag_id == TAGID_FENTRY) {
1825 		vat_length    = udf_rw64(dscr->fe.inf_len);
1826 		icbtag        = &dscr->fe.icbtag;
1827 		mtime         = &dscr->fe.mtime;
1828 		vat_unique_id = udf_rw64(dscr->fe.unique_id);
1829 		ea_start      = dscr->fe.data;
1830 	} else {
1831 		vat_length    = udf_rw64(dscr->efe.inf_len);
1832 		icbtag        = &dscr->efe.icbtag;
1833 		mtime         = &dscr->efe.mtime;
1834 		vat_unique_id = udf_rw64(dscr->efe.unique_id);
1835 		ea_start      = dscr->efe.data;	/* for completion */
1836 	}
1837 
1838 	if (vat_length > stats.inf_len) {
1839 		error = ENOENT;
1840 		goto out;
1841 	}
1842 
1843 	/* file type already checked */
1844 	filetype = icbtag->file_type;
1845 
1846 	/* extract info from our VAT data */
1847 	if (filetype == 0) {
1848 		/* VAT 1.50 format */
1849 		/* definition */
1850 		vat_offset = 0;
1851 		vat_entries = (vat_length-36)/4;
1852 		oldvat_tl = (struct udf_oldvat_tail *)
1853 			(*vat_contents + vat_entries * 4);
1854 		regid_name = (char *) oldvat_tl->id.id;
1855 		error = strncmp(regid_name, "*UDF Virtual Alloc Tbl", 22);
1856 		if (error) {
1857 			pwarn("Possible VAT 1.50 detected without tail\n");
1858 			if (ask_noauto(0, "Accept anyway")) {
1859 				vat_entries = vat_length/4;
1860 				vat_writeout = 1;
1861 				error = 0;
1862 				goto ok;
1863 			}
1864 			pwarn("VAT format 1.50 rejected\n");
1865 			error = ENOENT;
1866 			goto out;
1867 		}
1868 
1869 		/*
1870 		 * The following VAT extensions are optional and ignored but
1871 		 * demand a clean VAT write out for sanity.
1872 		 */
1873 		error = udf_extattr_search_intern(dscr, 2048, extstr, &offset, &a_l);
1874 		if (error) {
1875 			/* VAT LVExtension extended attribute missing */
1876 			vat_writeout = 1;
1877 			goto ok;
1878 		}
1879 
1880 		implext = (struct impl_extattr_entry *) (ea_start + offset);
1881 		error = udf_impl_extattr_check(implext);
1882 		if (error) {
1883 			/* VAT LVExtension checksum failed */
1884 			vat_writeout = 1;
1885 			goto ok;
1886 		}
1887 
1888 		/* paranoia */
1889 		if (a_l != sizeof(*implext) -2 + udf_rw32(implext->iu_l) + sizeof(lvext)) {
1890 			/* VAT LVExtension size doesn't compute */
1891 			vat_writeout = 1;
1892 			goto ok;
1893 		}
1894 
1895 		/*
1896 		 * We have found our "VAT LVExtension attribute. BUT due to a
1897 		 * bug in the specification it might not be word aligned so
1898 		 * copy first to avoid panics on some machines (!!)
1899 		 */
1900 		lvextpos = implext->data + udf_rw32(implext->iu_l);
1901 		memcpy(&lvext, lvextpos, sizeof(lvext));
1902 
1903 		/* check if it was updated the last time */
1904 		if (udf_rw64(lvext.unique_id_chk) == vat_unique_id) {
1905 			lvinfo->num_files       = lvext.num_files;
1906 			lvinfo->num_directories = lvext.num_directories;
1907 			udf_update_logvolname(lvext.logvol_id);
1908 		} else {
1909 			/* VAT LVExtension out of date */
1910 			vat_writeout = 1;
1911 		}
1912 	} else {
1913 		/* VAT 2.xy format */
1914 		/* definition */
1915 		vat = (struct udf_vat *) (*vat_contents);
1916 		vat_offset  = udf_rw16(vat->header_len);
1917 		vat_entries = (vat_length - vat_offset)/4;
1918 
1919 		if (heuristics) {
1920 			if (vat->impl_use_len == 0) {
1921 				uint32_t start_val;
1922 				start_val = udf_rw32(*((uint32_t *) vat->data));
1923 				if (start_val == 0x694d2a00) {
1924 					/* "<0>*Mic"osoft Windows */
1925 					pwarn("Heuristics found corrupted MS Windows VAT\n");
1926 					if (ask(0, "Repair")) {
1927 						vat->impl_use_len = udf_rw16(32);
1928 						vat->header_len = udf_rw16(udf_rw16(vat->header_len) + 32);
1929 						vat_offset += 32;
1930 						vat_writeout = 1;
1931 					}
1932 				}
1933 			}
1934 		}
1935 		assert(lvinfo);
1936 		lvinfo->num_files        = vat->num_files;
1937 		lvinfo->num_directories  = vat->num_directories;
1938 		lvinfo->min_udf_readver  = vat->min_udf_readver;
1939 		lvinfo->min_udf_writever = vat->min_udf_writever;
1940 		lvinfo->max_udf_writever = vat->max_udf_writever;
1941 
1942 		udf_update_logvolname(vat->logvol_id);
1943 	}
1944 
1945 /* XXX FAULT INJECTION POINT XXX */
1946 //vat_writeout = 1;
1947 
1948 ok:
1949 	/* extra sanity checking */
1950 	if (tag_id == TAGID_FENTRY) {
1951 		/* nothing checked as yet */
1952 	} else {
1953 		/*
1954 		 * The following VAT violations are ignored but demand a clean VAT
1955 		 * writeout for sanity
1956 		 */
1957 		if (!is_zero(&dscr->efe.streamdir_icb, sizeof(struct long_ad))) {
1958 			/* VAT specification violation:
1959 			 * 	VAT has no cleared streamdir reference */
1960 			vat_writeout = 1;
1961 		}
1962 		if (!is_zero(&dscr->efe.ex_attr_icb, sizeof(struct long_ad))) {
1963 			/* VAT specification violation:
1964 			 * 	VAT has no cleared extended attribute reference */
1965 			vat_writeout = 1;
1966 		}
1967 		if (dscr->efe.obj_size != dscr->efe.inf_len) {
1968 			/* VAT specification violation:
1969 			 * 	VAT has invalid object size */
1970 			vat_writeout = 1;
1971 		}
1972 	}
1973 
1974 	if (!vat_writeout) {
1975 		context.logvol_integrity->lvint_next_unique_id = udf_rw64(vat_unique_id);
1976 		context.logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_CLOSED);
1977 		context.logvol_integrity->time           = *mtime;
1978 	}
1979 
1980 	context.unique_id     = vat_unique_id;
1981 	context.vat_allocated = UDF_ROUNDUP(vat_length, context.sector_size);
1982 	context.vat_contents  = *vat_contents;
1983 	context.vat_start     = vat_offset;
1984 	context.vat_size      = vat_offset + vat_entries * 4;
1985 
1986 out:
1987 	if (error) {
1988 		free(*vat_contents);
1989 		*vat_contents = NULL;
1990 	}
1991 
1992 	return error;
1993 }
1994 
1995 
1996 #define VAT_BLK 256
1997 static int
1998 udf_search_vat(union udf_pmap *mapping, int log_part)
1999 {
2000 	union dscrptr *vat_candidate, *accepted_vat;
2001 	struct part_desc *pdesc;
2002 	struct mmc_trackinfo *ti, *ti_s;
2003 	uint32_t part_start;
2004 	uint32_t vat_loc, early_vat_loc, late_vat_loc, accepted_vat_loc;
2005 	uint32_t first_possible_vat_location, last_possible_vat_location;
2006 	uint8_t *vat_contents, *accepted_vat_contents;
2007 	int num_tracks, tracknr, found_a_VAT, valid_loc, error;
2008 
2009 	/*
2010 	 * Start reading forward in blocks from the first possible vat
2011 	 * location. If not found in this block, start again a bit before
2012 	 * until we get a hit.
2013 	 */
2014 
2015 	/* get complete list of all our valid ranges */
2016 	ti_s = calloc(mmc_discinfo.num_tracks, sizeof(struct mmc_trackinfo));
2017 	for (tracknr = 1; tracknr <= mmc_discinfo.num_tracks; tracknr++) {
2018 		ti = &ti_s[tracknr];
2019 		ti->tracknr = tracknr;
2020 		(void) udf_update_trackinfo(ti);
2021 	}
2022 
2023 	/* derive our very first track number our base partition covers */
2024 	pdesc = context.partitions[context.data_part];
2025 	part_start = udf_rw32(pdesc->start_loc);
2026 	for (int cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
2027 		pdesc = context.partitions[cnt];
2028 		if (!pdesc)
2029 			continue;
2030 		part_start = MIN(part_start, udf_rw32(pdesc->start_loc));
2031 	}
2032 	num_tracks = mmc_discinfo.num_tracks;
2033 	for (tracknr = 1, ti = NULL; tracknr <= num_tracks; tracknr++) {
2034 		ti = &ti_s[tracknr];
2035 		if ((part_start >= ti->track_start) &&
2036 				(part_start <= ti->track_start + ti->track_size))
2037 			break;
2038 	}
2039 	context.first_ti_partition = *ti;
2040 
2041 	first_possible_vat_location = context.first_ti_partition.track_start;
2042 	last_possible_vat_location  = context.last_ti.track_start +
2043 			context.last_ti.track_size -
2044 			context.last_ti.free_blocks + 1;
2045 
2046 	/* initial guess is around 16 sectors back */
2047 	late_vat_loc = last_possible_vat_location;
2048 	early_vat_loc = MAX(late_vat_loc - 16, first_possible_vat_location);
2049 
2050 	if (!preen)
2051 		printf("Full VAT range search from %d to %d\n",
2052 			first_possible_vat_location,
2053 			last_possible_vat_location);
2054 
2055 	vat_writeout = 0;
2056 	accepted_vat = NULL;
2057 	accepted_vat_contents = NULL;
2058 	accepted_vat_loc = 0;
2059 	do {
2060 		vat_loc = early_vat_loc;
2061 		if (!preen) {
2062 			printf("\tChecking range %8d to %8d\n",
2063 					early_vat_loc, late_vat_loc);
2064 			fflush(stdout);
2065 		}
2066 		found_a_VAT = 0;
2067 		while (vat_loc <= late_vat_loc) {
2068 			if (print_info) {
2069 				pwarn("\nchecking for VAT in sector %8d\n", vat_loc);
2070 				print_info = 0;
2071 			}
2072 			/* check if its in readable range */
2073 			valid_loc = 0;
2074 			for (tracknr = 1; tracknr <= num_tracks; tracknr++) {
2075 				ti = &ti_s[tracknr];
2076 				if (!(ti->flags & MMC_TRACKINFO_BLANK) &&
2077 					((vat_loc >= ti->track_start) &&
2078 					    (vat_loc <= ti->track_start + ti->track_size))) {
2079 					valid_loc = 1;
2080 					break;
2081 				}
2082 			}
2083 			if (!valid_loc) {
2084 				vat_loc++;
2085 				continue;
2086 			}
2087 
2088 			error = udf_read_dscr_phys(vat_loc, &vat_candidate);
2089 			if (!vat_candidate)
2090 				error = ENOENT;
2091 			if (!error)
2092 				error = udf_check_for_vat(vat_candidate);
2093 			if (error) {
2094 				vat_loc++;	/* walk forward */
2095 				continue;
2096 			}
2097 
2098 			if (accepted_vat) {
2099 				/* check if newer vat time stamp is the same */
2100 				if (udf_compare_mtimes(
2101 						udf_file_mtime(vat_candidate),
2102 						udf_file_mtime(accepted_vat)
2103 						) == 0) {
2104 					free(vat_candidate);
2105 					vat_loc++;	/* walk forward */
2106 					continue;
2107 				}
2108 			}
2109 
2110 			/* check if its contents are OK */
2111 			error = udf_extract_vat(
2112 					vat_candidate, &vat_contents);
2113 			if (error) {
2114 				/* unlikely */
2115 				// pwarn("Unreadable or malformed VAT encountered\n");
2116 				free(vat_candidate);
2117 				vat_loc++;
2118 				continue;
2119 			}
2120 			/* accept new vat */
2121 			free(accepted_vat);
2122 			free(accepted_vat_contents);
2123 
2124 			accepted_vat = vat_candidate;
2125 			accepted_vat_contents = vat_contents;
2126 			accepted_vat_loc = vat_loc;
2127 			vat_candidate = NULL;
2128 			vat_contents  = NULL;
2129 
2130 			found_a_VAT = 1;
2131 
2132 			vat_loc++;	/* walk forward */
2133 		};
2134 
2135 		if (found_a_VAT && accepted_vat) {
2136 			/* VAT accepted */
2137 			if (!preen)
2138 				udf_print_vat_details(accepted_vat);
2139 			if (vat_writeout)
2140 				pwarn("\tVAT accepted but marked dirty\n");
2141 			if (!preen && !vat_writeout)
2142 				pwarn("\tLogical volume integrity state set to CLOSED\n");
2143 			if (!search_older_vat)
2144 				break;
2145 			if (!ask_noauto(0, "\tSearch older VAT"))
2146 				break;
2147 			late_vat_loc  = accepted_vat_loc - 1;
2148 		} else {
2149 			late_vat_loc = early_vat_loc - 1;
2150 		}
2151 		early_vat_loc = first_possible_vat_location;
2152 		if (late_vat_loc > VAT_BLK)
2153 			early_vat_loc = MAX(early_vat_loc, late_vat_loc - VAT_BLK);
2154 	} while (late_vat_loc > first_possible_vat_location);
2155 
2156 	if (!preen)
2157 		printf("\n");
2158 
2159 	undo_opening_session = 0;
2160 
2161 	if (!accepted_vat) {
2162 		if ((context.last_ti.sessionnr > 1) &&
2163 				ask_noauto(0, "Undo opening of last session")) {
2164 			undo_opening_session = 1;
2165 			pwarn("Undoing opening of last session not implemented!\n");
2166 			error = ENOENT;
2167 			goto error_out;
2168 		} else {
2169 			pwarn("No valid VAT found!\n");
2170 			error = ENOENT;
2171 			goto error_out;
2172 		}
2173 	}
2174 	if (last_possible_vat_location - accepted_vat_loc > 16) {
2175 		assert(accepted_vat);
2176 		pwarn("Selected VAT is not the latest or not at the end of "
2177 			"track.\n");
2178 			vat_writeout = 1;
2179 	}
2180 
2181 /* XXX FAULT INJECTION POINT XXX */
2182 //vat_writeout = 1;
2183 //udf_update_lvintd(UDF_INTEGRITY_OPEN);
2184 
2185 	return 0;
2186 
2187 error_out:
2188 	free(accepted_vat);
2189 	free(accepted_vat_contents);
2190 
2191 	return error;
2192 }
2193 
2194 /* ------------------------- sparables support ------------------------- */
2195 
2196 static int
2197 udf_read_spareables(union udf_pmap *mapping, int log_part)
2198 {
2199 	union dscrptr *dscr;
2200 	struct part_map_spare *pms = &mapping->pms;
2201 	uint32_t lb_num;
2202 	int spar, error;
2203 
2204 	for (spar = 0; spar < pms->n_st; spar++) {
2205 		lb_num = pms->st_loc[spar];
2206 		error = udf_read_dscr_phys(lb_num, &dscr);
2207 		if (error && !preen)
2208 			pwarn("Error reading spareable table %d\n", spar);
2209 		if (!error && dscr) {
2210 			if (udf_rw16(dscr->tag.id) == TAGID_SPARING_TABLE) {
2211 				free(context.sparing_table);
2212 				context.sparing_table = &dscr->spt;
2213 				dscr = NULL;
2214 				break;	/* we're done */
2215 			}
2216 		}
2217 		free(dscr);
2218 	}
2219 	if (context.sparing_table == NULL)
2220 		return ENOENT;
2221 	return 0;
2222 }
2223 
2224 /* ------------------------- metadata support ------------------------- */
2225 
2226 static bool
2227 udf_metadata_node_supported(void)
2228 {
2229 	struct extfile_entry   *efe;
2230 	struct short_ad        *short_ad;
2231 	uint32_t len;
2232 	uint32_t flags;
2233 	uint8_t *data_pos;
2234 	int dscr_size, l_ea, l_ad, icbflags, addr_type;
2235 
2236 	/* we have to look into the file's allocation descriptors */
2237 
2238 	efe = context.meta_file;
2239 	dscr_size = sizeof(struct extfile_entry) - 1;
2240 	l_ea = udf_rw32(efe->l_ea);
2241 	l_ad = udf_rw32(efe->l_ad);
2242 
2243 	icbflags = udf_rw16(efe->icbtag.flags);
2244 	addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
2245 	if (addr_type != UDF_ICB_SHORT_ALLOC) {
2246 		warnx("specification violation: metafile not using"
2247 			"short allocs");
2248 		return false;
2249 	}
2250 
2251 	data_pos = (uint8_t *) context.meta_file + dscr_size + l_ea;
2252 	short_ad = (struct short_ad *) data_pos;
2253 	while (l_ad > 0) {
2254 		len      = udf_rw32(short_ad->len);
2255 		flags    = UDF_EXT_FLAGS(len);
2256 		if (flags == UDF_EXT_REDIRECT) {
2257 			warnx("implementation limit: no support for "
2258 			      "extent redirections in metadata file");
2259 			return false;
2260 		}
2261 		short_ad++;
2262 		l_ad -= sizeof(struct short_ad);
2263 	}
2264 	/* we passed all of them */
2265 	return true;
2266 }
2267 
2268 
2269 static int
2270 udf_read_metadata_nodes(union udf_pmap *mapping, int log_part)
2271 {
2272 	union dscrptr *dscr1, *dscr2, *dscr3;
2273 	struct part_map_meta *pmm = &mapping->pmm;
2274 	uint16_t raw_phys_part, phys_part;
2275 	int tagid, file_type, error;
2276 
2277 	/*
2278 	 * BUGALERT: some rogue implementations use random physical
2279 	 * partition numbers to break other implementations so lookup
2280 	 * the number.
2281 	 */
2282 
2283 	raw_phys_part = udf_rw16(pmm->part_num);
2284 	phys_part = udf_find_raw_phys(raw_phys_part);
2285 
2286 	error = udf_read_dscr_virt(layout.meta_file, phys_part, &dscr1);
2287 	if (!error) {
2288 		tagid = udf_rw16(dscr1->tag.id);
2289 		file_type = dscr1->efe.icbtag.file_type;
2290 		if ((tagid != TAGID_EXTFENTRY) ||
2291 				(file_type != UDF_ICB_FILETYPE_META_MAIN))
2292 			error = ENOENT;
2293 	}
2294 	if (error) {
2295 		pwarn("Bad primary metadata file descriptor\n");
2296 		free(dscr1);
2297 		dscr1 = NULL;
2298 	}
2299 
2300 	error = udf_read_dscr_virt(layout.meta_mirror, phys_part, &dscr2);
2301 	if (!error) {
2302 		tagid = udf_rw16(dscr2->tag.id);
2303 		file_type = dscr2->efe.icbtag.file_type;
2304 		if ((tagid != TAGID_EXTFENTRY) ||
2305 				(file_type != UDF_ICB_FILETYPE_META_MIRROR))
2306 			error = ENOENT;
2307 	}
2308 	if (error) {
2309 		pwarn("Bad mirror metadata file descriptor\n");
2310 		free(dscr2);
2311 		dscr2 = NULL;
2312 	}
2313 
2314 	if ((dscr1 == NULL) && (dscr2 == NULL)) {
2315 		pwarn("No valid metadata file descriptors found!\n");
2316 		return -1;
2317 	}
2318 
2319 	error = 0;
2320 	if ((dscr1 == NULL) && dscr2) {
2321 		dscr1 = malloc(context.sector_size);
2322 		memcpy(dscr1, dscr2, context.sector_size);
2323 		dscr1->efe.icbtag.file_type = UDF_ICB_FILETYPE_META_MAIN;
2324 		if (ask(1, "Fix up bad primary metadata file descriptor")) {
2325 			error = udf_write_dscr_virt(dscr1,
2326 					layout.meta_file, phys_part, 1);
2327 		}
2328 	}
2329 	if (dscr1 && (dscr2 == NULL)) {
2330 		dscr2 = malloc(context.sector_size);
2331 		memcpy(dscr2, dscr1, context.sector_size);
2332 		dscr2->efe.icbtag.file_type = UDF_ICB_FILETYPE_META_MIRROR;
2333 		if (ask(1, "Fix up bad mirror metadata file descriptor")) {
2334 			error = udf_write_dscr_virt(dscr2,
2335 					layout.meta_mirror, phys_part, 1);
2336 		}
2337 	}
2338 	if (error)
2339 		pwarn("Copying metadata file descriptor failed, "
2340 		      "trying to continue\n");
2341 
2342 	context.meta_file   = &dscr1->efe;
2343 	context.meta_mirror = &dscr2->efe;
2344 
2345 	dscr3 = NULL;
2346 	if (layout.meta_bitmap != 0xffffffff) {
2347 		error = udf_read_dscr_virt(layout.meta_bitmap, phys_part, &dscr3);
2348 		if (!error) {
2349 			tagid = udf_rw16(dscr3->tag.id);
2350 			file_type = dscr3->efe.icbtag.file_type;
2351 			if ((tagid != TAGID_EXTFENTRY) ||
2352 					(file_type != UDF_ICB_FILETYPE_META_BITMAP))
2353 				error = ENOENT;
2354 		}
2355 		if (error) {
2356 			pwarn("Bad metadata bitmap file descriptor\n");
2357 			free(dscr3);
2358 			dscr3 = NULL;
2359 		}
2360 
2361 		if (dscr3 == NULL) {
2362 			pwarn("implementation limit: can't repair missing or "
2363 			      "damaged metadata bitmap descriptor\n");
2364 			return -1;
2365 		}
2366 
2367 		context.meta_bitmap = &dscr3->efe;
2368 	}
2369 
2370 	/* TODO early check if meta_file has allocation extent redirections */
2371 	if (!udf_metadata_node_supported())
2372 		return EINVAL;
2373 
2374 	return 0;
2375 }
2376 
2377 /* ------------------------- VDS readin ------------------------- */
2378 
2379 /* checks if the VDS information is correct and complete */
2380 static int
2381 udf_process_vds(void) {
2382 	union dscrptr *dscr;
2383 	union udf_pmap *mapping;
2384 	struct part_desc *pdesc;
2385 	struct long_ad fsd_loc;
2386 	uint8_t *pmap_pos;
2387 	char *domain_name, *map_name;
2388 	const char *check_name;
2389 	int pmap_stype, pmap_size;
2390 	int pmap_type, log_part, phys_part, raw_phys_part; //, maps_on;
2391 	int n_pm, n_phys, n_virt, n_spar, n_meta;
2392 	int len, error;
2393 
2394 	/* we need at least an anchor (trivial, but for safety) */
2395 	if (context.anchors[0] == NULL) {
2396 		pwarn("sanity check: no anchors?\n");
2397 		return EINVAL;
2398 	}
2399 
2400 	/* we need at least one primary and one logical volume descriptor */
2401 	if ((context.primary_vol == NULL) || (context.logical_vol) == NULL) {
2402 		pwarn("sanity check: missing primary or missing logical volume\n");
2403 		return EINVAL;
2404 	}
2405 
2406 	/* we need at least one partition descriptor */
2407 	if (context.partitions[0] == NULL) {
2408 		pwarn("sanity check: missing partition descriptor\n");
2409 		return EINVAL;
2410 	}
2411 
2412 	/* check logical volume sector size versus device sector size */
2413 	if (udf_rw32(context.logical_vol->lb_size) != context.sector_size) {
2414 		pwarn("sanity check: lb_size != sector size\n");
2415 		return EINVAL;
2416 	}
2417 
2418 	/* check domain name, should never fail */
2419 	domain_name = (char *) context.logical_vol->domain_id.id;
2420 	if (strncmp(domain_name, "*OSTA UDF Compliant", 20)) {
2421 		pwarn("sanity check: disc not OSTA UDF Compliant, aborting\n");
2422 		return EINVAL;
2423 	}
2424 
2425 	/* retrieve logical volume integrity sequence */
2426 	udf_retrieve_lvint();
2427 
2428 	/* check if we support this disc, ie less or equal to 0x250 */
2429 	if (udf_rw16(context.logvol_info->min_udf_writever) > 0x250) {
2430 		pwarn("implementation limit: minimum write version UDF 2.60 "
2431 		      "and on are not supported\n");
2432 		return EINVAL;
2433 	}
2434 
2435 	/*
2436 	 * check logvol mappings: effective virt->log partmap translation
2437 	 * check and recording of the mapping results. Saves expensive
2438 	 * strncmp() in tight places.
2439 	 */
2440 	n_pm = udf_rw32(context.logical_vol->n_pm);   /* num partmaps         */
2441 	pmap_pos =  context.logical_vol->maps;
2442 
2443 	if (n_pm > UDF_PMAPS) {
2444 		pwarn("implementation limit: too many logvol mappings\n");
2445 		return EINVAL;
2446 	}
2447 
2448 	/* count types and set partition numbers */
2449 	context.data_part = context.metadata_part = context.fids_part = 0;
2450 	n_phys = n_virt = n_spar = n_meta = 0;
2451 	for (log_part = 0; log_part < n_pm; log_part++) {
2452 		mapping = (union udf_pmap *) pmap_pos;
2453 		pmap_stype = pmap_pos[0];
2454 		pmap_size  = pmap_pos[1];
2455 		switch (pmap_stype) {
2456 		case 1:	/* physical mapping */
2457 			/* volseq    = udf_rw16(mapping->pm1.vol_seq_num); */
2458 			raw_phys_part = udf_rw16(mapping->pm1.part_num);
2459 			pmap_type = UDF_VTOP_TYPE_PHYS;
2460 			n_phys++;
2461 			context.data_part     = log_part;
2462 			context.metadata_part = log_part;
2463 			context.fids_part     = log_part;
2464 			break;
2465 		case 2: /* virtual/sparable/meta mapping */
2466 			map_name  = (char *) mapping->pm2.part_id.id;
2467 			/* volseq  = udf_rw16(mapping->pm2.vol_seq_num); */
2468 			raw_phys_part = udf_rw16(mapping->pm2.part_num);
2469 			pmap_type = UDF_VTOP_TYPE_UNKNOWN;
2470 			len = UDF_REGID_ID_SIZE;
2471 
2472 			check_name = "*UDF Virtual Partition";
2473 			if (strncmp(map_name, check_name, len) == 0) {
2474 				pmap_type = UDF_VTOP_TYPE_VIRT;
2475 				n_virt++;
2476 				context.metadata_part = log_part;
2477 				context.format_flags |= FORMAT_VAT;
2478 				break;
2479 			}
2480 			check_name = "*UDF Sparable Partition";
2481 			if (strncmp(map_name, check_name, len) == 0) {
2482 				pmap_type = UDF_VTOP_TYPE_SPAREABLE;
2483 				n_spar++;
2484 				layout.spareable_blockingnr = udf_rw16(mapping->pms.packet_len);
2485 
2486 				context.data_part     = log_part;
2487 				context.metadata_part = log_part;
2488 				context.fids_part     = log_part;
2489 				context.format_flags |= FORMAT_SPAREABLE;
2490 				break;
2491 			}
2492 			check_name = "*UDF Metadata Partition";
2493 			if (strncmp(map_name, check_name, len) == 0) {
2494 				pmap_type = UDF_VTOP_TYPE_META;
2495 				n_meta++;
2496 				layout.meta_file	= udf_rw32(mapping->pmm.meta_file_lbn);
2497 				layout.meta_mirror	= udf_rw32(mapping->pmm.meta_mirror_file_lbn);
2498 				layout.meta_bitmap	= udf_rw32(mapping->pmm.meta_bitmap_file_lbn);
2499 				layout.meta_blockingnr	= udf_rw32(mapping->pmm.alloc_unit_size);
2500 				layout.meta_alignment	= udf_rw16(mapping->pmm.alignment_unit_size);
2501 				/* XXX metadata_flags in mapping->pmm.flags? XXX */
2502 
2503 				context.metadata_part = log_part;
2504 				context.fids_part     = log_part;
2505 				context.format_flags |= FORMAT_META;
2506 				break;
2507 			}
2508 			break;
2509 		default:
2510 			return EINVAL;
2511 		}
2512 
2513 		/*
2514 		 * BUGALERT: some rogue implementations use random physical
2515 		 * partition numbers to break other implementations so lookup
2516 		 * the number.
2517 		 */
2518 		phys_part = udf_find_raw_phys(raw_phys_part);
2519 
2520 		if (phys_part == UDF_PARTITIONS) {
2521 			pwarn("implementation limit: too many partitions\n");
2522 			return EINVAL;
2523 		}
2524 		if (pmap_type == UDF_VTOP_TYPE_UNKNOWN) {
2525 			pwarn("implementation limit: encountered unknown "
2526 				"logvol mapping `%s`!\n", map_name);
2527 			return EINVAL;
2528 		}
2529 
2530 		context.vtop   [log_part] = phys_part;
2531 		context.vtop_tp[log_part] = pmap_type;
2532 
2533 		pmap_pos += pmap_size;
2534 	}
2535 	/* not winning the beauty contest */
2536 	context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
2537 
2538 	/* test some basic UDF assertions/requirements */
2539 	if ((n_virt > 1) || (n_spar > 1) || (n_meta > 1)) {
2540 		pwarn("Sanity check: format error, more than one "
2541 		      "virtual, sparable or meta mapping\n");
2542 		return EINVAL;
2543 	}
2544 
2545 	if (n_virt) {
2546 		if ((n_phys == 0) || n_spar || n_meta) {
2547 			pwarn("Sanity check: format error, no backing for "
2548 			      "virtual partition\n");
2549 			return EINVAL;
2550 		}
2551 	}
2552 	if (n_spar + n_phys == 0) {
2553 		pwarn("Sanity check: can't combine a sparable and a "
2554 		      "physical partition\n");
2555 		return EINVAL;
2556 	}
2557 
2558 	/* print format type as derived */
2559 	if (!preen) {
2560 		char bits[255];
2561 		snprintb(bits, sizeof(bits), FORMAT_FLAGBITS, context.format_flags);
2562 		printf("Format flags %s\n\n", bits);
2563 	}
2564 
2565 	/* read supporting tables */
2566 	pmap_pos =  context.logical_vol->maps;
2567 	for (log_part = 0; log_part < n_pm; log_part++) {
2568 		mapping = (union udf_pmap *) pmap_pos;
2569 		pmap_size  = pmap_pos[1];
2570 		switch (context.vtop_tp[log_part]) {
2571 		case UDF_VTOP_TYPE_PHYS :
2572 			/* nothing */
2573 			break;
2574 		case UDF_VTOP_TYPE_VIRT :
2575 			/* search and load VAT */
2576 			error = udf_search_vat(mapping, log_part);
2577 			if (error) {
2578 				pwarn("Couldn't find virtual allocation table\n");
2579 				return ENOENT;
2580 			}
2581 			break;
2582 		case UDF_VTOP_TYPE_SPAREABLE :
2583 			/* load one of the sparable tables */
2584 			error = udf_read_spareables(mapping, log_part);
2585 			if (error) {
2586 				pwarn("Couldn't load sparable blocks tables\n");
2587 				return ENOENT;
2588 			}
2589 			break;
2590 		case UDF_VTOP_TYPE_META :
2591 			/* load the associated file descriptors */
2592 			error = udf_read_metadata_nodes(mapping, log_part);
2593 			if (error) {
2594 				pwarn("Couldn't read in the metadata descriptors\n");
2595 				return ENOENT;
2596 			}
2597 
2598 			/*
2599 			 * We have to extract the partition size from the meta
2600 			 * data file length
2601 			 */
2602 			context.part_size[log_part] =
2603 				udf_rw64(context.meta_file->inf_len) / context.sector_size;
2604 			break;
2605 		default:
2606 			break;
2607 		}
2608 		pmap_pos += pmap_size;
2609 	}
2610 
2611 	/*
2612 	 * Free/unallocated space bitmap readin delayed; the FS might be
2613 	 * closed already; no need to read in copious amount of data only to
2614 	 * not use it later.
2615 	 *
2616 	 * For now, extract partition sizes in our context
2617 	 */
2618 	for (int cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
2619 		pdesc = context.partitions[cnt];
2620 		if (!pdesc)
2621 			continue;
2622 
2623 		context.part_size[cnt] = udf_rw32(pdesc->part_len);
2624 		context.part_unalloc_bits[cnt] = NULL;
2625 	}
2626 
2627 	/* read file set descriptor */
2628 	fsd_loc = context.logical_vol->lv_fsd_loc;
2629 	error = udf_read_dscr_virt(
2630 			udf_rw32(fsd_loc.loc.lb_num),
2631 			udf_rw16(fsd_loc.loc.part_num), &dscr);
2632 	if (error) {
2633 		pwarn("Couldn't read in file set descriptor\n");
2634 		pwarn("implementation limit: can't fix this\n");
2635 		return ENOENT;
2636 	}
2637 	if (udf_rw16(dscr->tag.id) != TAGID_FSD) {
2638 		pwarn("Expected fsd at (p %d, lb %d)\n",
2639 				udf_rw16(fsd_loc.loc.part_num),
2640 				udf_rw32(fsd_loc.loc.lb_num));
2641 		pwarn("File set descriptor not pointing to a file set!\n");
2642 		return ENOENT;
2643 	}
2644 	context.fileset_desc = &dscr->fsd;
2645 
2646 	/* signal its OK for now */
2647 	return 0;
2648 }
2649 
2650 
2651 #define UDF_UPDATE_DSCR(name, dscr) \
2652 	if (name) {\
2653 		free (name); \
2654 		updated = 1; \
2655 	} \
2656 	name = calloc(1, dscr_size); \
2657 	memcpy(name, dscr, dscr_size);
2658 
2659 static void
2660 udf_process_vds_descriptor(union dscrptr *dscr, int dscr_size) {
2661 	struct pri_vol_desc *pri;
2662 	struct logvol_desc *lvd;
2663 	uint16_t raw_phys_part, phys_part;
2664 	int updated = 0;
2665 
2666 	switch (udf_rw16(dscr->tag.id)) {
2667 	case TAGID_PRI_VOL :		/* primary partition */
2668 		UDF_UPDATE_DSCR(context.primary_vol, dscr);
2669 		pri = context.primary_vol;
2670 
2671 		context.primary_name = malloc(32);
2672 		context.volset_name  = malloc(128);
2673 
2674 		udf_to_unix_name(context.volset_name, 32, pri->volset_id, 32,
2675 			&pri->desc_charset);
2676 		udf_to_unix_name(context.primary_name, 128, pri->vol_id, 128,
2677 			&pri->desc_charset);
2678 
2679 		if (!preen && !updated) {
2680 			pwarn("Volume set       `%s`\n", context.volset_name);
2681 			pwarn("Primary volume   `%s`\n", context.primary_name);
2682 		}
2683 		break;
2684 	case TAGID_LOGVOL :		/* logical volume    */
2685 		UDF_UPDATE_DSCR(context.logical_vol, dscr);
2686 		/* could check lvd->domain_id */
2687 		lvd = context.logical_vol;
2688 		context.logvol_name = malloc(128);
2689 
2690 		udf_to_unix_name(context.logvol_name, 128, lvd->logvol_id, 128,
2691 			&lvd->desc_charset);
2692 
2693 		if (!preen && !updated)
2694 			pwarn("Logical volume   `%s`\n", context.logvol_name);
2695 		break;
2696 	case TAGID_UNALLOC_SPACE :	/* unallocated space */
2697 		UDF_UPDATE_DSCR(context.unallocated, dscr);
2698 		break;
2699 	case TAGID_IMP_VOL :		/* implementation    */
2700 		UDF_UPDATE_DSCR(context.implementation, dscr);
2701 		break;
2702 	case TAGID_PARTITION :		/* partition(s)	     */
2703 		/* not much use if its not allocated */
2704 		if ((udf_rw16(dscr->pd.flags) & UDF_PART_FLAG_ALLOCATED) == 0) {
2705 			pwarn("Ignoring unallocated partition\n");
2706 			break;
2707 		}
2708 		raw_phys_part = udf_rw16(dscr->pd.part_num);
2709 		phys_part = udf_find_raw_phys(raw_phys_part);
2710 
2711 		if (phys_part >= UDF_PARTITIONS) {
2712 			pwarn("Too many physical partitions, ignoring\n");
2713 			break;
2714 		}
2715 		UDF_UPDATE_DSCR(context.partitions[phys_part], dscr);
2716 		break;
2717 	case TAGID_TERM :		/* terminator        */
2718 		break;
2719 	case TAGID_VOL :		/* volume space ext  */
2720 		pwarn("Ignoring VDS extender\n");
2721 		break;
2722 	default :
2723 		pwarn("Unknown VDS type %d found, ignored\n",
2724 			udf_rw16(dscr->tag.id));
2725 	}
2726 }
2727 
2728 
2729 static void
2730 udf_read_vds_extent(union dscrptr *dscr, int vds_size) {
2731 	uint8_t *pos;
2732 	int sector_size = context.sector_size;
2733 	int dscr_size;
2734 
2735 	pos = (uint8_t *) dscr;
2736 	while (vds_size) {
2737 		/* process the descriptor */
2738 		dscr = (union dscrptr *) pos;
2739 
2740 		/* empty block terminates */
2741 		if (is_zero(dscr, sector_size))
2742 			return;
2743 
2744 		/* terminator terminates */
2745 		if (udf_rw16(dscr->tag.id) == TAGID_TERM)
2746 			return;
2747 
2748 		if (udf_check_tag(dscr))
2749 			pwarn("Bad descriptor sum in vds, ignoring\n");
2750 
2751 		dscr_size = udf_tagsize(dscr, sector_size);
2752 		if (udf_check_tag_payload(dscr, dscr_size))
2753 			pwarn("Bad descriptor CRC in vds, ignoring\n");
2754 
2755 		udf_process_vds_descriptor(dscr, dscr_size);
2756 
2757 		pos      += dscr_size;
2758 		vds_size -= dscr_size;
2759 	}
2760 }
2761 
2762 
2763 static int
2764 udf_copy_VDS_area(void *destbuf, void *srcbuf)
2765 {
2766 	pwarn("TODO implement VDS copy area, signalling success\n");
2767 	return 0;
2768 }
2769 
2770 
2771 /* XXX why two buffers and not just read descritor by descriptor XXX */
2772 static int
2773 udf_check_VDS_areas(void) {
2774 	union dscrptr *vds1_buf, *vds2_buf;
2775 	int vds1_size, vds2_size;
2776 	int error, error1, error2;
2777 
2778 	vds1_size = layout.vds1_size * context.sector_size;
2779 	vds2_size = layout.vds2_size * context.sector_size;
2780 	vds1_buf = calloc(1, vds1_size);
2781 	vds2_buf = calloc(1, vds2_size);
2782 	assert(vds1_buf); assert(vds2_buf);
2783 
2784 	error1 = udf_read_phys(vds1_buf, layout.vds1, layout.vds1_size);
2785 	error2 = udf_read_phys(vds2_buf, layout.vds2, layout.vds2_size);
2786 
2787 	if (error1 && error2) {
2788 		pwarn("Can't read both volume descriptor areas!\n");
2789 		return -1;
2790 	}
2791 
2792 	if (!error1) {
2793 		/* retrieve data from VDS 1 */
2794 		udf_read_vds_extent(vds1_buf, vds1_size);
2795 		context.vds_buf  = vds1_buf;
2796 		context.vds_size = vds1_size;
2797 		free(vds2_buf);
2798 	}
2799 	if (!error2) {
2800 		/* retrieve data from VDS 2 */
2801 		udf_read_vds_extent(vds2_buf, vds2_size);
2802 		context.vds_buf  = vds2_buf;
2803 		context.vds_size = vds2_size;
2804 		free(vds1_buf);
2805 	}
2806 	/* check if all is correct and complete */
2807 	error = udf_process_vds();
2808 	if (error)
2809 		return error;
2810 
2811 	/* TODO check if both area's are logically the same */
2812 	error = 0;
2813 	if (!error1 && error2) {
2814 		/* first OK, second faulty */
2815 		pwarn("Backup volume descriptor missing or damaged\n");
2816 		if (context.format_flags & FORMAT_SEQUENTIAL) {
2817 			pwarn("Can't fixup backup volume descriptor on "
2818 			      "SEQUENTIAL media\n");
2819 		} else if (ask(1, "Fixup backup volume descriptor")) {
2820 			error = udf_copy_VDS_area(vds2_buf, vds1_buf);
2821 			pwarn("\n");
2822 		}
2823 	}
2824 	if (error1 && !error2) {
2825 		/* second OK, first faulty */
2826 		pwarn("Primary volume descriptor missing or damaged\n");
2827 		if (context.format_flags & FORMAT_SEQUENTIAL) {
2828 			pwarn("Can't fix up primary volume descriptor on "
2829 			      "SEQUENTIAL media\n");
2830 		} else if (ask(1, "Fix up primary volume descriptor")) {
2831 			error = udf_copy_VDS_area(vds1_buf, vds2_buf);
2832 		}
2833 	}
2834 	if (error)
2835 		pwarn("copying VDS areas failed!\n");
2836 	if (!preen)
2837 		printf("\n");
2838 
2839 	return error;
2840 }
2841 
2842 /* --------------------------------------------------------------------- */
2843 
2844 static int
2845 udf_prepare_writing(void)
2846 {
2847 	union dscrptr *zero_dscr, *dscr;
2848 	struct mmc_trackinfo ti;
2849 	uint32_t first_lba, loc;
2850 	int sector_size = context.sector_size;
2851 	int error;
2852 
2853 	error = udf_prepare_disc();
2854 	if (error) {
2855 		pwarn("*** Preparing disc for writing failed!\n");
2856 		return error;
2857 	}
2858 
2859 	/* if we are not on sequential media, we're done */
2860 	if ((mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) == 0)
2861 		return 0;
2862 	assert(context.format_flags & FORMAT_VAT);
2863 
2864 	/* if the disc is full, we drop back to read only */
2865 	if (mmc_discinfo.disc_state == MMC_STATE_FULL)
2866 		rdonly = 1;
2867 	if (rdonly)
2868 		return 0;
2869 
2870 	/* check if we need to open the last track */
2871 	ti.tracknr = mmc_discinfo.last_track_last_session;
2872 	error = udf_update_trackinfo(&ti);
2873 	if (error)
2874 		return error;
2875 	if (!(ti.flags & MMC_TRACKINFO_BLANK) &&
2876 	     (ti.flags & MMC_TRACKINFO_NWA_VALID)) {
2877 		/*
2878 		 * Not closed; translate next_writable to a position relative to our
2879 		 * backing partition
2880 		 */
2881 		context.alloc_pos[context.data_part] = ti.next_writable -
2882 			udf_rw32(context.partitions[context.data_part]->start_loc);
2883 		wrtrack_skew = ti.next_writable % layout.blockingnr;
2884 		return 0;
2885 	}
2886 	assert(ti.flags & MMC_TRACKINFO_NWA_VALID);
2887 
2888 	/* just in case */
2889 	udf_suspend_writing();
2890 
2891 	/* 'add' a new track */
2892 	udf_update_discinfo();
2893 	memset(&context.last_ti, 0, sizeof(struct mmc_trackinfo));
2894 	context.last_ti.tracknr = mmc_discinfo.first_track_last_session;
2895 	(void) udf_update_trackinfo(&context.last_ti);
2896 
2897 	assert(mmc_discinfo.last_session_state == MMC_STATE_EMPTY);
2898 	first_lba = context.last_ti.track_start;
2899 	wrtrack_skew = context.last_ti.track_start % layout.blockingnr;
2900 
2901 	/*
2902 	 * location of iso9660 vrs is defined as first sector AFTER 32kb,
2903 	 * minimum `sector size' 2048
2904 	 */
2905 	layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
2906 		+ first_lba;
2907 
2908 	/* anchor starts at specified offset in sectors */
2909 	layout.anchors[0] = first_lba + 256;
2910 
2911 	/* ready for appending, write preamble, we are using overwrite here! */
2912 	if ((zero_dscr = calloc(1, context.sector_size)) == NULL)
2913 		return ENOMEM;
2914 	loc = first_lba;
2915 	for (; loc < first_lba + 256; loc++) {
2916 		if ((error = udf_write_sector(zero_dscr, loc))) {
2917 			free(zero_dscr);
2918 			return error;
2919 		}
2920 	}
2921 	free(zero_dscr);
2922 
2923 	/* write new ISO9660 volume recognition sequence */
2924 	if ((error = udf_write_iso9660_vrs())) {
2925 		pwarn("internal error: can't write iso966 VRS in new session!\n");
2926 		rdonly = 1;
2927 		return error;
2928 	}
2929 
2930 	/* write out our old anchor, VDS spaces will be reused */
2931 	assert(context.anchors[0]);
2932 	dscr = (union dscrptr *) context.anchors[0];
2933 	loc  = layout.anchors[0];
2934 	if ((error = udf_write_dscr_phys(dscr, loc, 1))) {
2935 		pwarn("internal error: can't write anchor in new session!\n");
2936 		rdonly = 1;
2937 		return error;
2938 	}
2939 
2940 	context.alloc_pos[context.data_part] = first_lba + 257 -
2941 		udf_rw32(context.partitions[context.data_part]->start_loc);
2942 
2943 	return 0;
2944 }
2945 
2946 
2947 static int
2948 udf_close_volume_vat(void)
2949 {
2950 	int integrity_type;
2951 
2952 	/* only write out when its open */
2953 	integrity_type = udf_rw32(context.logvol_integrity->integrity_type);
2954 	if (integrity_type == UDF_INTEGRITY_CLOSED)
2955 		return 0;
2956 
2957 	if (!preen)
2958 		printf("\n");
2959 	if (!ask(1, "Write out modifications"))
2960 		return 0;
2961 
2962 	/* writeout our VAT contents */
2963 	udf_allow_writing();
2964 	return udf_writeout_VAT();
2965 }
2966 
2967 
2968 static int
2969 udf_close_volume(void)
2970 {
2971 	struct part_desc       *part;
2972 	struct part_hdr_desc   *phd;
2973 	struct logvol_int_desc *lvid;
2974 	struct udf_logvol_info *lvinfo;
2975 	struct logvol_desc     *logvol;
2976 	uint32_t bitmap_len, bitmap_lb, bitmap_numlb;
2977 	int i, equal, error;
2978 
2979 	lvid = context.logvol_integrity;
2980 	logvol = context.logical_vol;
2981 	lvinfo = context.logvol_info;
2982 	assert(lvid);
2983 	assert(logvol);
2984 	assert(lvinfo);
2985 
2986 	/* check our highest unique id */
2987 	if (context.unique_id > udf_rw64(lvid->lvint_next_unique_id)) {
2988 		pwarn("Last unique id updated from %" PRIi64 " to %" PRIi64 " : FIXED\n",
2989 				udf_rw64(lvid->lvint_next_unique_id),
2990 				context.unique_id);
2991 		open_integrity = 1;
2992 	}
2993 
2994 	/* check file/directory counts */
2995 	if (context.num_files != udf_rw32(lvinfo->num_files)) {
2996 		pwarn("Number of files corrected from %d to %d : FIXED\n",
2997 				udf_rw32(lvinfo->num_files),
2998 				context.num_files);
2999 		open_integrity = 1;
3000 	}
3001 	if (context.num_directories != udf_rw32(lvinfo->num_directories)) {
3002 		pwarn("Number of directories corrected from %d to %d : FIXED\n",
3003 				udf_rw32(lvinfo->num_directories),
3004 				context.num_directories);
3005 		open_integrity = 1;
3006 	}
3007 
3008 	if (vat_writeout)
3009 		open_integrity = 1;
3010 
3011 	if (open_integrity)
3012 		udf_update_lvintd(UDF_INTEGRITY_OPEN);
3013 
3014 	if (context.format_flags & FORMAT_VAT)
3015 		return udf_close_volume_vat();
3016 
3017 	/* adjust free space accounting! */
3018 	for (i = 0; i < UDF_PARTITIONS; i++) {
3019 		part = context.partitions[i];
3020 		if (!part)
3021 			continue;
3022 		phd = &part->pd_part_hdr;
3023 		bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
3024 		bitmap_lb  = udf_rw32(phd->unalloc_space_bitmap.lb_num);
3025 
3026 		if (bitmap_len == 0) {
3027 			error = 0;
3028 			continue;
3029 		}
3030 
3031 		equal = memcmp( recorded_part_unalloc_bits[i],
3032 				context.part_unalloc_bits[i],
3033 				bitmap_len) == 0;
3034 
3035 		if (!equal || (context.part_free[i] != recorded_part_free[i])) {
3036 			if (!equal)
3037 				pwarn("Calculated bitmap for partition %d not equal "
3038 				      "to recorded one : FIXED\n", i);
3039 			pwarn("Free space on partition %d corrected "
3040 			      "from %d to %d blocks : FIXED\n", i,
3041 			      recorded_part_free[i],
3042 			      context.part_free[i]);
3043 
3044 			/* write out updated free space map */
3045 			pwarn("Updating unallocated bitmap for partition\n");
3046 			if (!preen)
3047 				printf("Writing free space map "
3048 				       "for partition %d\n", i);
3049 			error = 0;
3050 			if (context.vtop_tp[i] == UDF_VTOP_TYPE_META) {
3051 				if (context.meta_bitmap) {
3052 					assert(i == context.metadata_part);
3053 					error = udf_process_file(
3054 						(union dscrptr *) context.meta_bitmap,
3055 						context.data_part,
3056 						(uint8_t **) &(context.part_unalloc_bits[i]),
3057 						AD_SAVE_FILE, NULL);
3058 				}
3059 			} else {
3060 				bitmap_numlb = udf_bytes_to_sectors(bitmap_len);
3061 				error = udf_write_dscr_virt(
3062 					(union dscrptr *) context.part_unalloc_bits[i],
3063 					bitmap_lb,
3064 					i,
3065 					bitmap_numlb);
3066 			}
3067 			if (error)
3068 				pwarn("Updating unallocated bitmap failed, "
3069 				      "continuing\n");
3070 			udf_update_lvintd(UDF_INTEGRITY_OPEN);
3071 		}
3072 	}
3073 
3074 	/* write out the logical volume integrity sequence */
3075 	error = udf_writeout_lvint();
3076 
3077 	return error;
3078 }
3079 
3080 /* --------------------------------------------------------------------- */
3081 
3082 /*
3083  * Main part of file system checking.
3084  *
3085  * Walk the entire directory tree and check all link counts and rebuild the
3086  * free space map (if present) on the go.
3087  */
3088 
3089 static struct udf_fsck_node *
3090 udf_new_fsck_node(struct udf_fsck_node *parent, struct long_ad *loc, char *fname)
3091 {
3092 	struct udf_fsck_node *this;
3093 	this = calloc(1, sizeof(struct udf_fsck_node));
3094 	if (!this)
3095 		return NULL;
3096 
3097 	this->parent = parent;
3098 	this->fname = strdup(fname);
3099 	this->loc = *loc;
3100 	this->fsck_flags = 0;
3101 
3102 	this->link_count = 0;
3103 	this->found_link_count = 0;
3104 
3105 	return this;
3106 }
3107 
3108 
3109 static void
3110 udf_node_path_piece(char *pathname, struct udf_fsck_node *node)
3111 {
3112 	if (node->parent) {
3113 		udf_node_path_piece(pathname, node->parent);
3114 		if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3115 			strcat(pathname, "");
3116 		else
3117 			strcat(pathname, "/");
3118 	}
3119 	strcat(pathname, node->fname);
3120 }
3121 
3122 
3123 static char *
3124 udf_node_path(struct udf_fsck_node *node)
3125 {
3126 	static char pathname[MAXPATHLEN + 10];
3127 
3128 	strcpy(pathname, "`");
3129 	if (node->parent)
3130 		udf_node_path_piece(pathname, node);
3131 	else
3132 		strcat(pathname, "/");
3133 	strcat(pathname, "'");
3134 
3135 	return pathname;
3136 }
3137 
3138 
3139 static void
3140 udf_recursive_keep(struct udf_fsck_node *node)
3141 {
3142 	while (node->parent) {
3143 		node = node->parent;
3144 		node->fsck_flags |= FSCK_NODE_FLAG_KEEP;
3145 	}
3146 }
3147 
3148 
3149 static int
3150 udf_quick_check_fids(struct udf_fsck_node *node, union dscrptr *dscr)
3151 {
3152 	struct udf_fsck_fid_context fid_context;
3153 	int error;
3154 
3155 	fid_context.fid_offset = 0;
3156 	fid_context.data_left = node->found.inf_len;
3157 	error = udf_process_file(dscr, context.fids_part,
3158 			&node->directory,
3159 			AD_CHECK_FIDS,
3160 			&fid_context);
3161 
3162 	return error;
3163 }
3164 
3165 
3166 /* read descriptor at node's location */
3167 static int
3168 udf_read_node_dscr(struct udf_fsck_node *node, union dscrptr **dscrptr)
3169 {
3170 	*dscrptr = NULL;
3171 	return udf_read_dscr_virt(
3172 			udf_rw32(node->loc.loc.lb_num),
3173 			udf_rw16(node->loc.loc.part_num),
3174 			dscrptr);
3175 }
3176 
3177 
3178 static int
3179 udf_extract_node_info(struct udf_fsck_node *node, union dscrptr *dscr,
3180 		int be_quiet)
3181 {
3182 	struct icb_tag       *icb = NULL;
3183 	struct file_entry    *fe  = NULL;
3184 	struct extfile_entry *efe = NULL;
3185 	int ad_type, error;
3186 
3187 	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3188 		fe = (struct file_entry *) dscr;
3189 		icb = &fe->icbtag;
3190 		node->declared.inf_len     = udf_rw64(fe->inf_len);
3191 		node->declared.obj_size    = udf_rw64(fe->inf_len);
3192 		node->declared.logblks_rec = udf_rw64(fe->logblks_rec);
3193 		node->link_count           = udf_rw16(fe->link_cnt);
3194 		node->unique_id            = udf_rw64(fe->unique_id);
3195 
3196 /* XXX FAULT INJECTION POINT XXX */
3197 //if (fe->unique_id == 33) { return ENOENT;}
3198 
3199 	}
3200 	if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
3201 		efe = (struct extfile_entry *) dscr;
3202 		icb = &efe->icbtag;
3203 		node->declared.inf_len     = udf_rw64(efe->inf_len);
3204 		node->declared.obj_size    = udf_rw64(efe->obj_size);
3205 		node->declared.logblks_rec = udf_rw64(efe->logblks_rec);
3206 		node->link_count           = udf_rw16(efe->link_cnt);
3207 		node->unique_id            = udf_rw64(efe->unique_id);
3208 		node->streamdir_loc = efe->streamdir_icb;
3209 		if (node->streamdir_loc.len)
3210 			node->fsck_flags |= FSCK_NODE_FLAG_HAS_STREAM_DIR;
3211 
3212 /* XXX FAULT INJECTION POINT XXX */
3213 //if (efe->unique_id == 0x891) { return ENOENT;}
3214 
3215 	}
3216 
3217 	if (!fe && !efe) {
3218 //printf("NOT REFERENCING AN FE/EFE!\n");
3219 		return ENOENT;
3220 	}
3221 
3222 	if (node->unique_id >= context.unique_id)
3223 		context.unique_id = node->unique_id+1;
3224 
3225 	ad_type = udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
3226 	if ((ad_type != UDF_ICB_INTERN_ALLOC) &&
3227 			(ad_type != UDF_ICB_SHORT_ALLOC) &&
3228 			(ad_type != UDF_ICB_LONG_ALLOC)) {
3229 		pwarn("%s : unknown allocation type\n",
3230 				udf_node_path(node));
3231 		return EINVAL;
3232 	}
3233 
3234 	bzero(&node->found, sizeof(node->found));
3235 	error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3236 			AD_GATHER_STATS, (void *) &node->found);
3237 
3238 	switch (icb->file_type) {
3239 	case UDF_ICB_FILETYPE_RANDOMACCESS :
3240 	case UDF_ICB_FILETYPE_BLOCKDEVICE :
3241 	case UDF_ICB_FILETYPE_CHARDEVICE :
3242 	case UDF_ICB_FILETYPE_FIFO :
3243 	case UDF_ICB_FILETYPE_SOCKET :
3244 	case UDF_ICB_FILETYPE_SYMLINK :
3245 	case UDF_ICB_FILETYPE_REALTIME :
3246 		break;
3247 	default:
3248 		/* unknown or unsupported file type, TODO clearing? */
3249 		free(dscr);
3250 		pwarn("%s : specification violation, unknown file type %d\n",
3251 			udf_node_path(node), icb->file_type);
3252 		return ENOENT;
3253 	case UDF_ICB_FILETYPE_STREAMDIR :
3254 	case UDF_ICB_FILETYPE_DIRECTORY :
3255 		/* read in the directory contents */
3256 		error = udf_readin_file(dscr, udf_rw16(node->loc.loc.part_num),
3257 				&node->directory, NULL);
3258 
3259 /* XXX FAULT INJECTION POINT XXX */
3260 //if (dscr->efe.unique_id == 109) node->directory[125] = 0xff;
3261 //if (dscr->efe.unique_id == 310) memset(node->directory+1024, 0, 300);
3262 
3263 		if (error && !be_quiet) {
3264 			pwarn("%s : directory has read errors\n",
3265 				udf_node_path(node));
3266 			if (ask(0, "Directory could be fixed or cleared. "
3267 				   "Wipe defective directory")) {
3268 				return ENOENT;
3269 			}
3270 			udf_recursive_keep(node);
3271 			node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3272 		}
3273 		node->fsck_flags |= FSCK_NODE_FLAG_DIRECTORY;
3274 		error = udf_quick_check_fids(node, dscr);
3275 		if (error) {
3276 			if (!(node->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR))
3277 				pwarn("%s : directory file entries need repair\n",
3278 					udf_node_path(node));
3279 			udf_recursive_keep(node);
3280 			node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3281 		}
3282 	}
3283 
3284 /* XXX FAULT INJECTION POINT XXX */
3285 //if (fe->unique_id == 0) node->link_count++;
3286 //if (efe->unique_id == 0) node->link_count++;
3287 //if (efe->unique_id == 772) { node->declared.inf_len += 205; node->declared.obj_size -= 0; }
3288 
3289 	return 0;
3290 }
3291 
3292 
3293 static void
3294 udf_fixup_lengths_pass1(struct udf_fsck_node *node, union dscrptr *dscr)
3295 {
3296 	int64_t diff;
3297 
3298 	/* file length check */
3299 	diff = node->found.inf_len - node->declared.inf_len;
3300 	if (diff) {
3301 		pwarn("%s : recorded information length incorrect: "
3302 			"%" PRIu64 " instead of declared %" PRIu64 "\n",
3303 			udf_node_path(node),
3304 			node->found.inf_len, node->declared.inf_len);
3305 			node->declared.inf_len = node->found.inf_len;
3306 		udf_recursive_keep(node);
3307 		node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3308 	}
3309 
3310 	/* recorded logical blocks count check */
3311 	diff = node->found.logblks_rec - node->declared.logblks_rec;
3312 	if (diff) {
3313 		pwarn("%s : logical blocks recorded incorrect: "
3314 		      "%" PRIu64 " instead of declared %" PRIu64 ", fixing\n",
3315 			udf_node_path(node),
3316 			node->found.logblks_rec, node->declared.logblks_rec);
3317 		node->declared.logblks_rec = node->found.logblks_rec;
3318 		udf_recursive_keep(node);
3319 		node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3320 	}
3321 
3322 	/* tally object sizes for streamdirs */
3323 	node->found.obj_size = node->found.inf_len;
3324 	if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_ENTRY) {
3325 		assert(node->parent);		/* streamdir itself */
3326 		if (node->parent->parent)
3327 			node->parent->parent->found.obj_size +=
3328 				node->found.inf_len;
3329 	}
3330 
3331 	/* check descriptor CRC length */
3332 	if (udf_rw16(dscr->tag.desc_crc_len) !=
3333 			udf_tagsize(dscr, 1) - sizeof(struct desc_tag)) {
3334 		pwarn("%s : node file descriptor CRC length mismatch; "
3335 			"%d declared, %zu\n",
3336 			udf_node_path(node), udf_rw16(dscr->tag.desc_crc_len),
3337 			udf_tagsize(dscr, 1) - sizeof(struct desc_tag));
3338 		udf_recursive_keep(node);
3339 		node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3340 	}
3341 }
3342 
3343 
3344 static void
3345 udf_node_pass1_add_entry(struct udf_fsck_node *node,
3346 		struct fileid_desc *fid, struct dirent *dirent)
3347 {
3348 	struct udf_fsck_node *leaf_node;
3349 	int entry;
3350 
3351 	/* skip deleted FID entries */
3352 	if (fid->file_char & UDF_FILE_CHAR_DEL)
3353 		return;
3354 
3355 	if (udf_rw32(fid->icb.loc.lb_num) == 0) {
3356 		pwarn("%s : FileID entry `%s` has invalid location\n",
3357 				udf_node_path(node), dirent->d_name);
3358 		udf_recursive_keep(node);
3359 		if (node->parent)
3360 			node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3361 		return;
3362 	}
3363 
3364 	/* increase parent link count */
3365 	if (fid->file_char & UDF_FILE_CHAR_PAR) {
3366 		if (node->parent)
3367 			node->parent->found_link_count++;
3368 		return;
3369 	}
3370 
3371 	/* lookup if we already know this node */
3372 	leaf_node = udf_node_lookup(&fid->icb);
3373 	if (leaf_node) {
3374 		/* got a hard link! */
3375 		leaf_node->found_link_count++;
3376 		return;
3377 	}
3378 
3379 	/* create new node */
3380 	leaf_node = udf_new_fsck_node(
3381 			node, &fid->icb, dirent->d_name);
3382 	if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3383 		leaf_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_ENTRY;
3384 
3385 	TAILQ_INSERT_TAIL(&fs_nodes, leaf_node, next);
3386 	entry = udf_calc_node_hash(&fid->icb);
3387 	LIST_INSERT_HEAD(&fs_nodes_hash[entry], leaf_node, next_hash);
3388 }
3389 
3390 
3391 static void
3392 udf_node_pass1_add_streamdir_entry(struct udf_fsck_node *node)
3393 {
3394 	struct udf_fsck_node *leaf_node;
3395 	int entry;
3396 
3397 	/* check for recursion */
3398 	if (node->fsck_flags & FSCK_NODE_FLAG_STREAM) {
3399 		/* recursive streams are not allowed by spec */
3400 		pwarn("%s : specification violation, recursive stream dir\n",
3401 			udf_node_path(node));
3402 		udf_recursive_keep(node);
3403 		node->fsck_flags |= FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3404 		return;
3405 	}
3406 
3407 	/* lookup if we already know this node */
3408 	leaf_node = udf_node_lookup(&node->streamdir_loc);
3409 	if (leaf_node) {
3410 		pwarn("%s : specification violation, hardlinked streamdir\n",
3411 			udf_node_path(leaf_node));
3412 		udf_recursive_keep(node);
3413 		node->fsck_flags |= FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3414 		return;
3415 	}
3416 
3417 	/* create new node */
3418 	leaf_node = udf_new_fsck_node(
3419 			node, &node->streamdir_loc, strdup(""));
3420 	leaf_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_DIR;
3421 
3422 	/* streamdirs have link count 0 : ECMA 4/14.9.6 */
3423 	leaf_node->found_link_count--;
3424 
3425 	/* insert in to lists */
3426 	TAILQ_INSERT_TAIL(&fs_nodes, leaf_node, next);
3427 	entry = udf_calc_node_hash(&node->streamdir_loc);
3428 	LIST_INSERT_HEAD(&fs_nodes_hash[entry], leaf_node, next_hash);
3429 }
3430 
3431 
3432 static int
3433 udf_process_node_pass1(struct udf_fsck_node *node, union dscrptr *dscr)
3434 {
3435 	struct fileid_desc *fid;
3436 	struct dirent dirent;
3437 	struct charspec osta_charspec;
3438 	int64_t fpos, new_length, rest_len;
3439 	uint32_t fid_len;
3440 	uint8_t *bpos;
3441 	int isdir;
3442 	int error;
3443 
3444 	isdir = node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY;
3445 
3446 	/* keep link count */
3447 	node->found_link_count++;
3448 
3449 	if (isdir) {
3450 		assert(node->directory);
3451 		udf_rebuild_fid_stream(node, &new_length);
3452 		node->found.inf_len = new_length;
3453 		rest_len = new_length;
3454 	}
3455 
3456 	udf_fixup_lengths_pass1(node, dscr);
3457 
3458 	/* check UniqueID */
3459 	if (node->parent) {
3460 		if (node->fsck_flags & FSCK_NODE_FLAG_STREAM) {
3461 
3462 /* XXX FAULT INJECTION POINT XXX */
3463 //node->unique_id = 0xdeadbeefcafe;
3464 
3465 			if (node->unique_id != node->parent->unique_id) {
3466 				pwarn("%s : stream file/dir UniqueID mismatch "
3467 				      "with parent\n",
3468 						udf_node_path(node));
3469 				/* do the work here prematurely for our siblings */
3470 				udf_recursive_keep(node);
3471 				node->unique_id = node->parent->unique_id;
3472 				node->fsck_flags |= FSCK_NODE_FLAG_COPY_PARENT_ID |
3473 					FSCK_NODE_FLAG_DIRTY;
3474 				assert(node->parent);
3475 				node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3476 			}
3477 		} else if (node->unique_id < 16) {
3478 			pwarn("%s : file has bad UniqueID\n",
3479 					udf_node_path(node));
3480 			udf_recursive_keep(node);
3481 			node->fsck_flags |= FSCK_NODE_FLAG_NEW_UNIQUE_ID;
3482 			assert(node->parent);
3483 			node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3484 		}
3485 	} else {
3486 		/* rootdir */
3487 		if (node->unique_id != 0) {
3488 			pwarn("%s : has bad UniqueID, has to be zero\n",
3489 					udf_node_path(node));
3490 			udf_recursive_keep(node);
3491 			node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3492 		}
3493 	}
3494 
3495 	/* add streamdir if present */
3496 	if (node->fsck_flags & FSCK_NODE_FLAG_HAS_STREAM_DIR)
3497 		udf_node_pass1_add_streamdir_entry(node);
3498 
3499 	/* add all children */
3500 	if (isdir) {
3501 		node->fsck_flags |= FSCK_NODE_FLAG_PAR_NOT_FOUND;
3502 		rest_len = node->found.inf_len;
3503 
3504 		/* walk through all our FIDs in the directory stream */
3505 		bpos = node->directory;
3506 		fpos = 0;
3507 		while (rest_len > 0) {
3508 			fid = (struct fileid_desc *) bpos;
3509 			fid_len = udf_fidsize(fid);
3510 
3511 			/* get printable name */
3512 			memset(&dirent, 0, sizeof(dirent));
3513 			udf_osta_charset(&osta_charspec);
3514 			udf_to_unix_name(dirent.d_name, NAME_MAX,
3515 				(char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi,
3516 				&osta_charspec);
3517 			dirent.d_namlen = strlen(dirent.d_name);
3518 
3519 			/* '..' has no name, so provide one */
3520 			if (fid->file_char & UDF_FILE_CHAR_PAR) {
3521 				strcpy(dirent.d_name, "..");
3522 				node->fsck_flags &= ~FSCK_NODE_FLAG_PAR_NOT_FOUND;
3523 			}
3524 
3525 			udf_node_pass1_add_entry(node, fid, &dirent);
3526 
3527 			fpos += fid_len;
3528 			bpos += fid_len;
3529 			rest_len -= fid_len;
3530 		}
3531 	}
3532 
3533 	error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3534 			AD_CHECK_USED, node);
3535 	if (error) {
3536 		pwarn("%s : internal error: checking for being allocated shouldn't fail\n",
3537 			udf_node_path(node));
3538 		return EINVAL;
3539 	}
3540 	/* file/directory is OK and referenced as its size won't change */
3541 	error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3542 			AD_MARK_AS_USED, NULL);
3543 	if (error) {
3544 		pwarn("%s : internal error: marking allocated shouldn't fail\n",
3545 			udf_node_path(node));
3546 		return EINVAL;
3547 	}
3548 	(void) fpos;
3549 	return 0;
3550 }
3551 
3552 
3553 static void
3554 udf_node_pass3_repairdir(struct udf_fsck_node *node, union dscrptr *dscr)
3555 {
3556 	struct fileid_desc *fid, *last_empty_fid;
3557 	struct udf_fsck_node *file_node;
3558 	struct udf_fsck_fid_context fid_context;
3559 	struct dirent dirent;
3560 	struct charspec osta_charspec;
3561 	int64_t fpos, rest_len;
3562 	uint32_t fid_len;
3563 	uint8_t *bpos;
3564 	int parent_missing;
3565 	int error;
3566 
3567 	pwarn("%s : fixing up directory\n", udf_node_path(node));
3568 	assert(node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY);
3569 
3570 	rest_len = node->found.inf_len;
3571 
3572 	udf_osta_charset(&osta_charspec);
3573 	bpos = node->directory;
3574 	fpos = 0;
3575 	parent_missing = (node->fsck_flags & FSCK_NODE_FLAG_PAR_NOT_FOUND)? 1:0;
3576 
3577 	last_empty_fid = NULL;
3578 	while (rest_len > 0) {
3579 		fid = (struct fileid_desc *) bpos;
3580 		fid_len = udf_fidsize(fid);
3581 
3582 		/* get printable name */
3583 		memset(&dirent, 0, sizeof(dirent));
3584 		udf_to_unix_name(dirent.d_name, NAME_MAX,
3585 			(char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi,
3586 			&osta_charspec);
3587 		dirent.d_namlen = strlen(dirent.d_name);
3588 
3589 		/* '..' has no name, so provide one */
3590 		if (fid->file_char & UDF_FILE_CHAR_PAR) {
3591 			strcpy(dirent.d_name, "..");
3592 		}
3593 
3594 		/* only look up when not deleted */
3595 		file_node = NULL;
3596 		if ((fid->file_char & UDF_FILE_CHAR_DEL) == 0)
3597 			file_node = udf_node_lookup(&fid->icb);
3598 
3599 		/* if found */
3600 		if (file_node) {
3601 			/* delete files which couldn't be found */
3602 			if (file_node && (file_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)) {
3603 				fid->file_char |= UDF_FILE_CHAR_DEL;
3604 				memset(&fid->icb, 0, sizeof(struct long_ad));
3605 			}
3606 
3607 			/* fix up FID UniqueID errors */
3608 			if (fid->icb.longad_uniqueid != file_node->unique_id)
3609 				fid->icb.longad_uniqueid = udf_rw64(file_node->unique_id);
3610 		} else {
3611 			/* just mark it deleted if not found */
3612 			fid->file_char |= UDF_FILE_CHAR_DEL;
3613 		}
3614 
3615 		if (fid->file_char & UDF_FILE_CHAR_DEL) {
3616 			memset(&fid->icb, 0 , sizeof(struct long_ad));
3617 			if (context.dscrver == 2) {
3618 				uint8_t *cpos;
3619 				/* compression IDs are preserved */
3620 				cpos = (fid->data + udf_rw16(fid->l_iu));
3621 				if (*cpos == 254)
3622 					*cpos = 8;
3623 				if (*cpos == 255)
3624 					*cpos = 16;
3625 			}
3626 		}
3627 
3628 		fpos += fid_len;
3629 		bpos += fid_len;
3630 		rest_len -= fid_len;
3631 		assert(rest_len >= 0);
3632 	}
3633 	if (parent_missing) {
3634 		/* this should be valid or we're in LALA land */
3635 		assert(last_empty_fid);
3636 		pwarn("%s : implementation limit, can't fix up missing parent node yet!\n",
3637 			udf_node_path(node));
3638 	}
3639 
3640 	node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3641 
3642 	fid_context.fid_offset = 0;
3643 	fid_context.data_left = node->found.inf_len;
3644 	error = udf_process_file(dscr, context.fids_part,
3645 			&node->directory,
3646 			AD_ADJUST_FIDS | AD_SAVE_FILE,
3647 			&fid_context);
3648 	if (error)
3649 		pwarn("Failed to write out directory!\n");
3650 	(void) fpos;
3651 }
3652 
3653 
3654 static void
3655 udf_node_pass3_writeout_update(struct udf_fsck_node *node, union dscrptr *dscr)
3656 {
3657 	struct file_entry    *fe  = NULL;
3658 	struct extfile_entry *efe = NULL;
3659 	int error;
3660 
3661 	vat_writeout = 1;
3662 	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3663 		fe = (struct file_entry *) dscr;
3664 		fe->inf_len      = udf_rw64(node->declared.inf_len);
3665 		fe->logblks_rec  = udf_rw64(node->declared.logblks_rec);
3666 		fe->link_cnt     = udf_rw16(node->link_count);
3667 		fe->unique_id    = udf_rw64(node->unique_id);
3668 	}
3669 	if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
3670 		efe = (struct extfile_entry *) dscr;
3671 		efe->inf_len     = udf_rw64(node->declared.inf_len);
3672 		efe->obj_size    = udf_rw64(node->declared.obj_size);
3673 		efe->logblks_rec = udf_rw64(node->declared.logblks_rec);
3674 		efe->link_cnt    = udf_rw16(node->link_count);
3675 		efe->unique_id   = udf_rw64(node->unique_id);
3676 		/* streamdir directly cleared in dscr */
3677 	}
3678 
3679 	/* fixup CRC length (if needed) */
3680 	dscr->tag.desc_crc_len = udf_tagsize(dscr, 1) - sizeof(struct desc_tag);
3681 
3682 	pwarn("%s : updating node\n", udf_node_path(node));
3683 	error = udf_write_dscr_virt(dscr, udf_rw32(node->loc.loc.lb_num),
3684 			udf_rw16(node->loc.loc.part_num), 1);
3685 	udf_shadow_VAT_in_use(&node->loc);
3686 	if (error)
3687 		pwarn("%s failed\n", __func__);
3688 }
3689 
3690 
3691 static void
3692 udf_create_new_space_bitmaps_and_reset_freespace(void)
3693 {
3694 	struct space_bitmap_desc *sbd, *new_sbd;
3695 	struct part_desc *part;
3696 	struct part_hdr_desc *phd;
3697 	uint32_t bitmap_len, bitmap_lb, bitmap_numlb;
3698 	uint32_t cnt;
3699 	int i, p, dscr_size;
3700 	int error;
3701 
3702 	/* copy recorded freespace info and clear counters */
3703 	for (i = 0; i < UDF_PARTITIONS; i++) {
3704 		recorded_part_free[i] = context.part_free[i];
3705 		context.part_free[i]  = context.part_size[i];
3706 	}
3707 
3708 	/* clone existing bitmaps */
3709 	for (i = 0; i < UDF_PARTITIONS; i++) {
3710 		sbd = context.part_unalloc_bits[i];
3711 		recorded_part_unalloc_bits[i] = sbd;
3712 		if (sbd == NULL)
3713 			continue;
3714 		dscr_size = udf_tagsize((union dscrptr *) sbd,
3715 				context.sector_size);
3716 		new_sbd = calloc(1, dscr_size);
3717 		memcpy(new_sbd, sbd, sizeof(struct space_bitmap_desc)-1);
3718 
3719 		/* fill space with 0xff to indicate free */
3720 		for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
3721 			new_sbd->data[cnt] = 0xff;
3722 
3723 		context.part_unalloc_bits[i] = new_sbd;
3724 	}
3725 
3726 	/* allocate the space bitmaps themselves (normally one) */
3727 	for (i = 0; i < UDF_PARTITIONS; i++) {
3728 		part = context.partitions[i];
3729 		if (!part)
3730 			continue;
3731 
3732 		phd = &part->pd_part_hdr;
3733 		bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
3734 		bitmap_lb  = udf_rw32(phd->unalloc_space_bitmap.lb_num);
3735 		if (bitmap_len == 0)
3736 			continue;
3737 
3738 		bitmap_numlb = udf_bytes_to_sectors(bitmap_len);
3739 		sbd = context.part_unalloc_bits[i];
3740 		assert(sbd);
3741 
3742 		udf_mark_allocated(bitmap_lb, context.vtop[i], bitmap_numlb);
3743 	}
3744 
3745 	/* special case for metadata partition */
3746 	if (context.format_flags & FORMAT_META) {
3747 		i = context.metadata_part;
3748 		p = context.vtop[i];
3749 		assert(context.vtop_tp[i] == UDF_VTOP_TYPE_META);
3750 		error = udf_process_file((union dscrptr *) context.meta_file,
3751 			p, NULL, AD_MARK_AS_USED, NULL);
3752 		error = udf_process_file((union dscrptr *) context.meta_mirror,
3753 			p, NULL, AD_MARK_AS_USED, NULL);
3754 		if (context.meta_bitmap) {
3755 			error = udf_process_file(
3756 				(union dscrptr *) context.meta_bitmap,
3757 				p, NULL, AD_MARK_AS_USED, NULL);
3758 			assert(error == 0);
3759 		}
3760 	}
3761 
3762 	/* mark fsd allocation ! */
3763 	udf_mark_allocated(udf_rw32(context.fileset_desc->tag.tag_loc),
3764 		context.metadata_part, 1);
3765 }
3766 
3767 
3768 static void
3769 udf_shadow_VAT_in_use(struct long_ad *loc)
3770 {
3771 	uint32_t i;
3772 	uint8_t *vat_pos, *shadow_vat_pos;
3773 
3774 	if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3775 		return;
3776 
3777 	i = udf_rw32(loc->loc.lb_num);
3778 	vat_pos = context.vat_contents + context.vat_start + i*4;
3779 	shadow_vat_pos = shadow_vat_contents + context.vat_start + i*4;
3780 	/* keeping endian */
3781 	*(uint32_t *) shadow_vat_pos = *(uint32_t *) vat_pos;
3782 }
3783 
3784 
3785 static void
3786 udf_create_shadow_VAT(void)
3787 {
3788 	struct long_ad fsd_loc;
3789 	uint32_t  vat_entries, i;
3790 	uint8_t *vat_pos;
3791 
3792 	if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3793 		return;
3794 
3795 	shadow_vat_contents = calloc(1, context.vat_allocated);
3796 	assert(shadow_vat_contents);
3797 	memcpy(shadow_vat_contents, context.vat_contents, context.vat_size);
3798 
3799 	vat_entries = (context.vat_size - context.vat_start)/4;
3800 	for (i = 0; i < vat_entries; i++) {
3801 		vat_pos = shadow_vat_contents + context.vat_start + i*4;
3802 		*(uint32_t *) vat_pos = udf_rw32(0xffffffff);
3803 	}
3804 
3805 	/*
3806 	 * Record our FSD in this shadow VAT since its the only one outside
3807 	 * the nodes.
3808 	 */
3809 	memset(&fsd_loc, 0, sizeof(struct long_ad));
3810 	fsd_loc.loc.lb_num = context.fileset_desc->tag.tag_loc;
3811 	udf_shadow_VAT_in_use(&fsd_loc);
3812 }
3813 
3814 
3815 static void
3816 udf_check_shadow_VAT(void)
3817 {
3818 	uint32_t vat_entries, i;
3819 	uint8_t *vat_pos, *shadow_vat_pos;
3820 	int difference = 0;
3821 
3822 	if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3823 		return;
3824 
3825 	vat_entries = (context.vat_size - context.vat_start)/4;
3826 	for (i = 0; i < vat_entries; i++) {
3827 		vat_pos = context.vat_contents + context.vat_start + i*4;
3828 		shadow_vat_pos = shadow_vat_contents + context.vat_start + i*4;
3829 		if (*(uint32_t *) vat_pos != *(uint32_t *) shadow_vat_pos) {
3830 			difference++;
3831 		}
3832 	}
3833 	memcpy(context.vat_contents, shadow_vat_contents, context.vat_size);
3834 	if (difference) {
3835 		if (!preen)
3836 			printf("\t\t");
3837 		pwarn("%d unused VAT entries cleaned\n", difference);
3838 		vat_writeout = 1;
3839 	}
3840 }
3841 
3842 
3843 static int
3844 udf_check_directory_tree(void)
3845 {
3846 	union dscrptr *dscr;
3847 	struct udf_fsck_node *root_node, *sys_stream_node;
3848 	struct udf_fsck_node *cur_node, *next_node;
3849 	struct long_ad root_icb, sys_stream_icb;
3850 	bool dont_repair;
3851 	int entry, error;
3852 
3853 	assert(TAILQ_EMPTY(&fs_nodes));
3854 
3855 	/* (re)init queues and hash lists */
3856 	TAILQ_INIT(&fs_nodes);
3857 	TAILQ_INIT(&fsck_overlaps);
3858 	for (int i = 0; i < HASH_HASHSIZE; i++)
3859 		LIST_INIT(&fs_nodes_hash[i]);
3860 
3861 	/* create a new empty copy of the space bitmaps */
3862 	udf_create_new_space_bitmaps_and_reset_freespace();
3863 	udf_create_shadow_VAT();
3864 
3865 	/* start from the root */
3866 	root_icb       = context.fileset_desc->rootdir_icb;
3867 	sys_stream_icb = context.fileset_desc->streamdir_icb;
3868 
3869 	root_node = udf_new_fsck_node(NULL, &root_icb, strdup(""));
3870 	assert(root_node);
3871 	TAILQ_INSERT_TAIL(&fs_nodes, root_node, next);
3872 	entry = udf_calc_node_hash(&root_node->loc);
3873 	LIST_INSERT_HEAD(&fs_nodes_hash[entry], root_node, next_hash);
3874 
3875 	sys_stream_node = NULL;
3876 	if (sys_stream_icb.len) {
3877 		sys_stream_node = udf_new_fsck_node(NULL, &sys_stream_icb, strdup("#"));
3878 		assert(sys_stream_node);
3879 		sys_stream_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_DIR;
3880 
3881 		TAILQ_INSERT_TAIL(&fs_nodes, sys_stream_node, next);
3882 		entry = udf_calc_node_hash(&sys_stream_node->loc);
3883 		LIST_INSERT_HEAD(&fs_nodes_hash[entry], sys_stream_node, next_hash);
3884 	}
3885 
3886 	/* pass 1 */
3887 	if (!preen)
3888 		printf("\tPass 1, reading in directory trees\n");
3889 
3890 	context.unique_id = MAX(0x10, context.unique_id);
3891 	TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3892 		/* read in node */
3893 		error = udf_read_node_dscr(cur_node, &dscr);
3894 		if (!error)
3895 			error = udf_extract_node_info(cur_node, dscr, 0);
3896 		if (error) {
3897 			pwarn("%s : invalid reference or bad descriptor, DELETING\n",
3898 				udf_node_path(cur_node));
3899 			udf_recursive_keep(cur_node);
3900 			cur_node->fsck_flags |= FSCK_NODE_FLAG_NOTFOUND;
3901 			if (cur_node->parent) {
3902 				if (cur_node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3903 					cur_node->parent->fsck_flags |=
3904 						FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3905 				else
3906 					cur_node->parent->fsck_flags |=
3907 						FSCK_NODE_FLAG_REPAIRDIR;
3908 				;
3909 			}
3910 			free(dscr);
3911 			continue;
3912 		}
3913 
3914 		if (print_info) {
3915 			pwarn("Processing %s\n", udf_node_path(cur_node));
3916 			print_info = 0;
3917 		}
3918 
3919 		/* directory found in stream directory? */
3920 		if (cur_node->parent &&
3921 			(cur_node->parent->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR) &&
3922 			(cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY))
3923 		{
3924 			pwarn("%s : specification violation, directory in stream directory\n",
3925 				udf_node_path(cur_node));
3926 			if (ask(0, "Clear directory")) {
3927 				udf_recursive_keep(cur_node);
3928 				cur_node->fsck_flags |= FSCK_NODE_FLAG_NOTFOUND;
3929 				cur_node->parent->fsck_flags |=
3930 					FSCK_NODE_FLAG_REPAIRDIR;
3931 				continue;
3932 			}
3933 		}
3934 		error = udf_process_node_pass1(cur_node, dscr);
3935 		free(dscr);
3936 
3937 		if (error)
3938 			return error;
3939 	}
3940 
3941 	/* pass 1b, if there is overlap, find matching pairs */
3942 	dont_repair = false;
3943 	if (!TAILQ_EMPTY(&fsck_overlaps)) {
3944 		struct udf_fsck_overlap *overlap;
3945 
3946 		dont_repair = true;
3947 		pwarn("*** Overlaps detected! rescanning tree for matching pairs ***\n");
3948 		TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3949 			if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
3950 				continue;
3951 
3952 			error = udf_read_node_dscr(cur_node, &dscr);
3953 			/* should not fail differently */
3954 
3955 			if (print_info) {
3956 				pwarn("Processing %s\n", udf_node_path(cur_node));
3957 				print_info = 0;
3958 			}
3959 
3960 			error = udf_process_file(
3961 					dscr,
3962 					udf_rw16(cur_node->loc.loc.part_num),
3963 					NULL,
3964 					AD_FIND_OVERLAP_PAIR,
3965 					(void *) cur_node);
3966 			/* shouldn't fail */
3967 
3968 			free(dscr);
3969 		}
3970 		TAILQ_FOREACH(overlap, &fsck_overlaps, next) {
3971 			pwarn("%s :overlaps with %s\n",
3972 				udf_node_path(overlap->node),
3973 				udf_node_path(overlap->node2));
3974 		}
3975 		if (!preen)
3976 			printf("\n");
3977 		pwarn("*** The following files/directories need to be copied/evacuated:\n");
3978 		TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3979 			if (cur_node->fsck_flags & FSCK_NODE_FLAG_OVERLAP) {
3980 				pwarn("%s : found OVERLAP, evacuate\n",
3981 					udf_node_path(cur_node));
3982 			}
3983 		}
3984 	}
3985 	if (dont_repair) {
3986 		if (!preen)
3987 			printf("\n");
3988 		pwarn("*** Skipping further repair, only updating free space map if needed\n");
3989 		pwarn("*** After deep copying and/or evacuation of these files/directories,\n");
3990 		pwarn("*** remove files/directories and re-run fsck_udf\n");
3991 		error = udf_prepare_writing();
3992 		if (error)
3993 			return error;
3994 
3995 		udf_update_lvintd(UDF_INTEGRITY_OPEN);
3996 		return 0;
3997 	}
3998 
3999 	/* pass 2a, checking link counts, object sizes and count files/dirs */
4000 	if (!preen)
4001 		printf("\n\tPass 2, checking link counts, object sizes, stats and cleaning up\n");
4002 
4003 	TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4004 		/* not sane to process files/directories that are not found */
4005 		if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
4006 			continue;
4007 
4008 		/* shadow VAT */
4009 		udf_shadow_VAT_in_use(&cur_node->loc);
4010 
4011 		/* link counts */
4012 		if (cur_node->found_link_count != cur_node->link_count) {
4013 			pwarn("%s : link count incorrect; "
4014 			      "%u instead of declared %u : FIXED\n",
4015 				udf_node_path(cur_node),
4016 				cur_node->found_link_count, cur_node->link_count);
4017 			cur_node->link_count = cur_node->found_link_count;
4018 			udf_recursive_keep(cur_node);
4019 			cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4020 		}
4021 
4022 		/* object sizes */
4023 		if (cur_node->declared.obj_size != cur_node->found.obj_size) {
4024 			pwarn("%s : recorded object size incorrect; "
4025 			      "%" PRIu64 " instead of declared %" PRIu64 "\n",
4026 				udf_node_path(cur_node),
4027 				cur_node->found.obj_size, cur_node->declared.obj_size);
4028 			cur_node->declared.obj_size = cur_node->found.obj_size;
4029 			udf_recursive_keep(cur_node);
4030 			cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4031 		}
4032 
4033 		/* XXX TODO XXX times */
4034 		/* XXX TODO XXX extended attributes location for UDF < 1.50 */
4035 
4036 		/* validity of UniqueID check */
4037 		if (cur_node->parent) {
4038 			if (cur_node->fsck_flags & FSCK_NODE_FLAG_NEW_UNIQUE_ID) {
4039 				pwarn("%s : assigning new UniqueID\n",
4040 					udf_node_path(cur_node));
4041 				cur_node->unique_id = udf_rw64(context.unique_id);
4042 				udf_advance_uniqueid();
4043 				udf_recursive_keep(cur_node);
4044 				cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4045 				if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY)
4046 					cur_node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
4047 				cur_node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
4048 			}
4049 			if (cur_node->fsck_flags & FSCK_NODE_FLAG_COPY_PARENT_ID) {
4050 				/* work already done but make note to operator */
4051 				pwarn("%s : fixing stream UniqueID to match parent\n",
4052 					udf_node_path(cur_node));
4053 			}
4054 		} else {
4055 			if (cur_node->unique_id != 0) {
4056 				pwarn("%s : bad UniqueID, zeroing\n",
4057 						udf_node_path(cur_node));
4058 				cur_node->unique_id = 0;
4059 				cur_node->fsck_flags |=
4060 					FSCK_NODE_FLAG_DIRTY | FSCK_NODE_FLAG_REPAIRDIR;
4061 			}
4062 		}
4063 
4064 		/* keep nodes in a repairing dir */
4065 		if (cur_node->parent)
4066 			if (cur_node->parent->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR)
4067 				cur_node->fsck_flags |= FSCK_NODE_FLAG_KEEP;
4068 
4069 		/* stream directories and files in it are not included */
4070 		if (!(cur_node->fsck_flags & FSCK_NODE_FLAG_STREAM)) {
4071 			/* files / directories counting */
4072 			int link_count = cur_node->found_link_count;
4073 
4074 			/* stream directories don't count as link ECMA 4/14.9.6 */
4075 			if (cur_node->fsck_flags & FSCK_NODE_FLAG_HAS_STREAM_DIR)
4076 				link_count--;
4077 
4078 			if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY)
4079 				context.num_directories++;
4080 			else
4081 				context.num_files += link_count;
4082 			;
4083 		}
4084 	}
4085 
4086 	/* pass 2b, cleaning */
4087 	open_integrity = 0;
4088 	TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4089 		/* can we remove the node? (to save memory) */
4090 		if (FSCK_NODE_FLAG_OK(cur_node->fsck_flags)) {
4091 			TAILQ_REMOVE(&fs_nodes, cur_node, next);
4092 			LIST_REMOVE(cur_node, next_hash);
4093 			free(cur_node->directory);
4094 			bzero(cur_node, sizeof(struct udf_fsck_node));
4095 			free(cur_node);
4096 		} else {
4097 			/* else keep erroring node */
4098 			open_integrity = 1;
4099 		}
4100 	}
4101 
4102 	if (!preen)
4103 		printf("\n\tPreparing disc for writing\n");
4104 	error = udf_prepare_writing();
4105 	if (error)
4106 		return error;
4107 
4108 	if (open_integrity)
4109 		udf_update_lvintd(UDF_INTEGRITY_OPEN);
4110 
4111 	/* pass 3 */
4112 	if (!preen)
4113 		printf("\n\tPass 3, fix errors\n");
4114 
4115 	TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4116 		/* not sane to process files/directories that are not found */
4117 		if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
4118 			continue;
4119 
4120 		/* only interested in bad nodes */
4121 		if (FSCK_NODE_FLAG_OK(cur_node->fsck_flags))
4122 			continue;
4123 
4124 		error = udf_read_node_dscr(cur_node, &dscr);
4125 		/* should not fail differently */
4126 
4127 		/* repair directories */
4128 		if (cur_node->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR)
4129 			udf_node_pass3_repairdir(cur_node, dscr);
4130 
4131 		/* remove invalid stream directories */
4132 		if (cur_node->fsck_flags & FSCK_NODE_FLAG_WIPE_STREAM_DIR) {
4133 			assert(udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY);
4134 			bzero(&dscr->efe.streamdir_icb, sizeof(struct long_ad));
4135 			cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4136 		}
4137 
4138 		if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRTY)
4139 			udf_node_pass3_writeout_update(cur_node, dscr);
4140 		free(dscr);
4141 	}
4142 	udf_check_shadow_VAT();
4143 
4144 	return 0;
4145 }
4146 
4147 
4148 static void
4149 udf_cleanup_after_check(void)
4150 {
4151 	struct udf_fsck_node *cur_node, *next_node;
4152 
4153 	/* XXX yes, there are some small memory leaks here */
4154 
4155 	/* clean old node info from previous checks */
4156 	TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4157 		TAILQ_REMOVE(&fs_nodes, cur_node, next);
4158 		LIST_REMOVE(cur_node, next_hash);
4159 		free(cur_node->directory);
4160 		free(cur_node);
4161 	}
4162 
4163 	/* free partition related info */
4164 	for (int i = 0; i < UDF_PARTITIONS; i++) {
4165 		free(context.partitions[i]);
4166 		free(context.part_unalloc_bits[i]);
4167 		free(context.part_freed_bits[i]);
4168 	}
4169 
4170 	/* only free potentional big blobs */
4171 	free(context.vat_contents);
4172 	free(context.lvint_history);
4173 
4174 	free(shadow_vat_contents);
4175 	shadow_vat_contents = NULL;
4176 }
4177 
4178 
4179 static int
4180 checkfilesys(char *given_dev)
4181 {
4182 	struct mmc_trackinfo ti;
4183 	int open_flags;
4184 	int error;
4185 
4186 	udf_init_create_context();
4187 	context.app_name         = "*NetBSD UDF";
4188 	context.app_version_main = APP_VERSION_MAIN;
4189 	context.app_version_sub  = APP_VERSION_SUB;
4190 	context.impl_name        = IMPL_NAME;
4191 
4192 	emul_mmc_profile  =  -1;	/* invalid->no emulation	*/
4193 	emul_packetsize   =   1;	/* reasonable default		*/
4194 	emul_sectorsize   = 512;	/* minimum allowed sector size	*/
4195 	emul_size	  =   0;	/* empty			*/
4196 
4197 	if (!preen)
4198 		pwarn("** Checking UDF file system on %s\n", given_dev);
4199 
4200 	/* reset sticky flags */
4201 	rdonly = rdonly_flag;
4202 	undo_opening_session = 0;	/* trying to undo opening of last crippled session */
4203 	vat_writeout = 0;		/* to write out the VAT anyway */
4204 
4205 	/* open disc device or emulated file */
4206 	open_flags = rdonly ? O_RDONLY : O_RDWR;
4207 	if (udf_opendisc(given_dev, open_flags)) {
4208 		udf_closedisc();
4209 		warnx("can't open %s", given_dev);
4210 		return FSCK_EXIT_CHECK_FAILED;
4211 	}
4212 
4213 	if (!preen)
4214 		pwarn("** Phase 1 - discovering format from disc\n\n");
4215 
4216 	/* check if it is an empty disc or no disc in present */
4217 	ti.tracknr = mmc_discinfo.first_track;
4218 	error = udf_update_trackinfo(&ti);
4219 	if (error || (ti.flags & MMC_TRACKINFO_BLANK)) {
4220 		/* no use erroring out */
4221 		pwarn("Empty disc\n");
4222 		return FSCK_EXIT_OK;
4223 	}
4224 
4225 	context.format_flags = 0;
4226 	if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL)
4227 		context.format_flags |= FORMAT_SEQUENTIAL;
4228 
4229 	if ((context.format_flags & FORMAT_SEQUENTIAL) &&
4230 		    ((mmc_discinfo.disc_state == MMC_STATE_CLOSED) ||
4231 		     (mmc_discinfo.disc_state == MMC_STATE_FULL))) {
4232 		pwarn("Disc is closed or full, can't modify disc\n");
4233 		rdonly = 1;
4234 	}
4235 
4236 	if (target_session) {
4237 		context.create_new_session = 1;
4238 		if (target_session < 0)
4239 			target_session += mmc_discinfo.num_sessions;
4240 	} else {
4241 		target_session = mmc_discinfo.num_sessions;
4242 		if (mmc_discinfo.last_session_state == MMC_STATE_EMPTY)
4243 			target_session--;
4244 	}
4245 
4246 	error = udf_get_anchors();
4247 	if (error) {
4248 		udf_closedisc();
4249 		pwarn("Failed to retrieve anchors; can't check file system\n");
4250 		return FSCK_EXIT_CHECK_FAILED;
4251 	}
4252 
4253 	udf_check_vrs9660();
4254 
4255 	/* get both VRS areas */
4256 	error = udf_check_VDS_areas();
4257 	if (error) {
4258 		udf_closedisc();
4259 		pwarn("Failure reading volume descriptors, disc might be toast\n");
4260 		return FSCK_EXIT_CHECK_FAILED;
4261 	}
4262 
4263 	if (udf_rw32(context.logvol_integrity->integrity_type) ==
4264 		UDF_INTEGRITY_CLOSED) {
4265 		if (!force) {
4266 			pwarn("** File system is clean; not checking\n");
4267 			return FSCK_EXIT_OK;
4268 		}
4269 		pwarn("** File system is already clean\n");
4270 		if (!preen)
4271 			pwarn("\n");
4272 	} else {
4273 		pwarn("** File system not closed properly\n");
4274 		if (!preen)
4275 			printf("\n");
4276 	}
4277 
4278 	/*
4279 	 * Only now read in free/unallocated space bitmap. If it reads in fine
4280 	 * it doesn't mean its contents is valid though. Sets partition
4281 	 * lengths too.
4282 	 */
4283 	error = udf_readin_partitions_free_space();
4284 	if (error) {
4285 		pwarn("Error during free space bitmap reading\n");
4286 		udf_update_lvintd(UDF_INTEGRITY_OPEN);
4287 	}
4288 
4289 	if (!preen)
4290 		pwarn("** Phase 2 - walking directory tree\n");
4291 
4292 	udf_suspend_writing();
4293 	error = udf_check_directory_tree();
4294 	if (error) {
4295 		if ((!rdonly) && ask(0, "Write out modifications made until now"))
4296 			udf_allow_writing();
4297 		else
4298 			pwarn("** Aborting repair, not modifying disc\n");
4299 		udf_closedisc();
4300 		return FSCK_EXIT_CHECK_FAILED;
4301 	}
4302 
4303 	if (!preen)
4304 		pwarn("\n** Phase 3 - closing volume if needed\n\n");
4305 
4306 /* XXX FAULT INJECTION POINT XXX */
4307 //udf_update_lvintd(UDF_INTEGRITY_OPEN);
4308 
4309 	if (error && rdonly) {
4310 		pwarn("** Aborting repair, nothing written, disc marked read-only\n");
4311 	} else {
4312 		error = udf_close_volume();
4313 	}
4314 
4315 	udf_closedisc();
4316 
4317 	if (error)
4318 		return FSCK_EXIT_CHECK_FAILED;
4319 	return FSCK_EXIT_OK;
4320 }
4321 
4322 
4323 static void
4324 usage(void)
4325 {
4326     	(void)fprintf(stderr, "Usage: %s [-fHnpSsy] file-system ... \n",
4327 	    getprogname());
4328 	exit(FSCK_EXIT_USAGE);
4329 }
4330 
4331 
4332 static void
4333 got_siginfo(int signo)
4334 {
4335 	print_info = 1;
4336 }
4337 
4338 
4339 int
4340 main(int argc, char **argv)
4341 {
4342 	int ret = FSCK_EXIT_OK, erg;
4343 	int ch;
4344 
4345 	while ((ch = getopt(argc, argv, "ps:SynfH")) != -1) {
4346 		switch (ch) {
4347 		case 'H':
4348 			heuristics = 1;
4349 			break;
4350 		case 'f':
4351 			force = 1;
4352 			break;
4353 		case 'n':
4354 			rdonly_flag = alwaysno = 1;
4355 			alwaysyes = preen = 0;
4356 			break;
4357 		case 'y':
4358 			alwaysyes = 1;
4359 			alwaysno = preen = 0;
4360 			break;
4361 		case 'p':
4362 			/* small automatic repairs */
4363 			preen = 1;
4364 			alwaysyes = alwaysno = 0;
4365 			break;
4366 		case 's':
4367 			/* session number or relative session */
4368 			target_session = atoi(optarg);
4369 			break;
4370 		case 'S':		/* Search for older VATs */
4371 			search_older_vat = 1;
4372 			break;
4373 
4374 		default:
4375 			usage();
4376 			break;
4377 		}
4378 	}
4379 	argc -= optind;
4380 	argv += optind;
4381 
4382 	if (!argc)
4383 		usage();
4384 
4385 	/* TODO SIGINT and SIGQUIT catchers */
4386 #if 0
4387 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
4388 		(void) signal(SIGINT, catch);
4389 	if (preen)
4390 		(void) signal(SIGQUIT, catch);
4391 #endif
4392 
4393 	signal(SIGINFO, got_siginfo);
4394 
4395 	while (--argc >= 0) {
4396 		setcdevname(*argv, preen);
4397 		erg = checkfilesys(*argv++);
4398 		if (erg > ret)
4399 			ret = erg;
4400 		if (!preen)
4401 			printf("\n");
4402 		udf_cleanup_after_check();
4403 	}
4404 
4405 	return ret;
4406 }
4407 
4408 
4409 /*VARARGS*/
4410 static int __printflike(2, 3)
4411 ask(int def, const char *fmt, ...)
4412 {
4413 	va_list ap;
4414 
4415 	char prompt[256];
4416 	int c;
4417 
4418 	va_start(ap, fmt);
4419 	vsnprintf(prompt, sizeof(prompt), fmt, ap);
4420 	va_end(ap);
4421 	if (alwaysyes || rdonly) {
4422 		pwarn("%s? %s\n", prompt, rdonly ? "no" : "yes");
4423 		return !rdonly;
4424 	}
4425 	if (preen) {
4426 		pwarn("%s? %s : (default)\n", prompt, def ? "yes" : "no");
4427 		return def;
4428 	}
4429 
4430 	do {
4431 		pwarn("%s? [yn] ", prompt);
4432 		fflush(stdout);
4433 		c = getchar();
4434 		while (c != '\n' && getchar() != '\n')
4435 			if (feof(stdin))
4436 				return 0;
4437 	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
4438 	return c == 'y' || c == 'Y';
4439 }
4440 
4441 
4442 /*VARARGS*/
4443 static int __printflike(2, 3)
4444 ask_noauto(int def, const char *fmt, ...)
4445 {
4446 	va_list ap;
4447 
4448 	char prompt[256];
4449 	int c;
4450 
4451 	va_start(ap, fmt);
4452 	vsnprintf(prompt, sizeof(prompt), fmt, ap);
4453 	va_end(ap);
4454 #if 0
4455 	if (preen) {
4456 		pwarn("%s? %s : (default)\n", prompt, def ? "yes" : "no");
4457 		return def;
4458 	}
4459 #endif
4460 
4461 	do {
4462 		pwarn("%s? [yn] ", prompt);
4463 		fflush(stdout);
4464 		c = getchar();
4465 		while (c != '\n' && getchar() != '\n')
4466 			if (feof(stdin))
4467 				return 0;
4468 	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
4469 	return c == 'y' || c == 'Y';
4470 }
4471