1 /* $NetBSD: main.c,v 1.14 2023/08/03 08:06:11 mrg 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.14 2023/08/03 08:06:11 mrg 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;
LIST_HEAD(udf_fsck_node_hash_list,udf_fsck_node)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
printtime(time_t ftime)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
udf_print_timestamp(const char * prefix,struct timestamp * timestamp,const char * suffix)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, ×pec);
262 printf("%s", prefix);
263 printtime(timespec.tv_sec);
264 printf("%s", suffix);
265 }
266
267
268 static int
udf_compare_mtimes(struct timestamp * t1,struct timestamp * t2)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
udf_calc_node_hash(struct long_ad * icb)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 *
udf_node_lookup(struct long_ad * icb)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
udf_wipe_and_reallocate(union dscrptr * dscrptr,int vpart_num,uint32_t * l_adp)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
udf_copy_fid_verbatim(struct fileid_desc * sfid,struct fileid_desc * dfid,uint64_t dfpos,uint64_t drest)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
udf_rebuild_fid_stream(struct udf_fsck_node * node,int64_t * rest_lenp)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
udf_quick_check_fids_piece(uint8_t * piece,uint32_t piece_len,struct udf_fsck_fid_context * fid_context,uint32_t lb_num)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
udf_fids_fixup(uint8_t * piece,uint32_t piece_len,struct udf_fsck_fid_context * fid_context,uint32_t lb_num)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
udf_check_if_allocated(struct udf_fsck_node * node,int flags,uint32_t start_lb,int partnr,uint32_t piece_len)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
udf_check_overlap_pair(struct udf_fsck_node * node,int flags,uint32_t start_lb,int partnr,uint32_t piece_len)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
udf_process_ad(union dscrptr * dscrptr,int action,uint8_t ** resultp,int vpart_num,uint64_t fpos,struct short_ad * short_adp,struct long_ad * long_adp,void * process_context)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
udf_process_file(union dscrptr * dscrptr,int vpart_num,uint8_t ** resultp,int action,void * process_context)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 = udf_rw32(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
udf_readin_file(union dscrptr * dscrptr,int vpart_num,uint8_t ** resultp,struct udf_fsck_file_stats * statsp)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
udf_check_vrs9660(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
udf_find_anchor(int anum)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
udf_get_anchors(void)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
udf_retrieve_lvint(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
udf_writeout_lvint(void)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
udf_readin_partitions_free_space(void)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
udf_update_logvolname(char * logvol_id)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 *
udf_file_mtime(union dscrptr * dscr)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
udf_print_vat_details(union dscrptr * dscr)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
udf_check_for_vat(union dscrptr * dscr)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
udf_extract_vat(union dscrptr * dscr,uint8_t ** vat_contents)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 error = 0;
1877 vat_writeout = 1;
1878 goto ok;
1879 }
1880
1881 implext = (struct impl_extattr_entry *) (ea_start + offset);
1882 error = udf_impl_extattr_check(implext);
1883 if (error) {
1884 /* VAT LVExtension checksum failed */
1885 error = 0;
1886 vat_writeout = 1;
1887 goto ok;
1888 }
1889
1890 /* paranoia */
1891 if (a_l != sizeof(*implext) -2 + udf_rw32(implext->iu_l) + sizeof(lvext)) {
1892 /* VAT LVExtension size doesn't compute */
1893 error = 0;
1894 vat_writeout = 1;
1895 goto ok;
1896 }
1897
1898 /*
1899 * We have found our "VAT LVExtension attribute. BUT due to a
1900 * bug in the specification it might not be word aligned so
1901 * copy first to avoid panics on some machines (!!)
1902 */
1903 lvextpos = implext->data + udf_rw32(implext->iu_l);
1904 memcpy(&lvext, lvextpos, sizeof(lvext));
1905
1906 /* check if it was updated the last time */
1907 if (udf_rw64(lvext.unique_id_chk) == vat_unique_id) {
1908 lvinfo->num_files = lvext.num_files;
1909 lvinfo->num_directories = lvext.num_directories;
1910 udf_update_logvolname(lvext.logvol_id);
1911 } else {
1912 /* VAT LVExtension out of date */
1913 vat_writeout = 1;
1914 }
1915 } else {
1916 /* VAT 2.xy format */
1917 /* definition */
1918 vat = (struct udf_vat *) (*vat_contents);
1919 vat_offset = udf_rw16(vat->header_len);
1920 vat_entries = (vat_length - vat_offset)/4;
1921
1922 if (heuristics) {
1923 if (vat->impl_use_len == 0) {
1924 uint32_t start_val;
1925 start_val = udf_rw32(*((uint32_t *) vat->data));
1926 if (start_val == 0x694d2a00) {
1927 /* "<0>*Mic"osoft Windows */
1928 pwarn("Heuristics found corrupted MS Windows VAT\n");
1929 if (ask(0, "Repair")) {
1930 vat->impl_use_len = udf_rw16(32);
1931 vat->header_len = udf_rw16(udf_rw16(vat->header_len) + 32);
1932 vat_offset += 32;
1933 vat_writeout = 1;
1934 }
1935 }
1936 }
1937 }
1938 assert(lvinfo);
1939 lvinfo->num_files = vat->num_files;
1940 lvinfo->num_directories = vat->num_directories;
1941 lvinfo->min_udf_readver = vat->min_udf_readver;
1942 lvinfo->min_udf_writever = vat->min_udf_writever;
1943 lvinfo->max_udf_writever = vat->max_udf_writever;
1944
1945 udf_update_logvolname(vat->logvol_id);
1946 }
1947
1948 /* XXX FAULT INJECTION POINT XXX */
1949 //vat_writeout = 1;
1950
1951 ok:
1952 /* extra sanity checking */
1953 if (tag_id == TAGID_FENTRY) {
1954 /* nothing checked as yet */
1955 } else {
1956 /*
1957 * The following VAT violations are ignored but demand a clean VAT
1958 * writeout for sanity
1959 */
1960 if (!is_zero(&dscr->efe.streamdir_icb, sizeof(struct long_ad))) {
1961 /* VAT specification violation:
1962 * VAT has no cleared streamdir reference */
1963 vat_writeout = 1;
1964 }
1965 if (!is_zero(&dscr->efe.ex_attr_icb, sizeof(struct long_ad))) {
1966 /* VAT specification violation:
1967 * VAT has no cleared extended attribute reference */
1968 vat_writeout = 1;
1969 }
1970 if (dscr->efe.obj_size != dscr->efe.inf_len) {
1971 /* VAT specification violation:
1972 * VAT has invalid object size */
1973 vat_writeout = 1;
1974 }
1975 }
1976
1977 if (!vat_writeout) {
1978 context.logvol_integrity->lvint_next_unique_id = udf_rw64(vat_unique_id);
1979 context.logvol_integrity->integrity_type = udf_rw32(UDF_INTEGRITY_CLOSED);
1980 context.logvol_integrity->time = *mtime;
1981 }
1982
1983 context.unique_id = vat_unique_id;
1984 context.vat_allocated = UDF_ROUNDUP(vat_length, context.sector_size);
1985 context.vat_contents = *vat_contents;
1986 context.vat_start = vat_offset;
1987 context.vat_size = vat_offset + vat_entries * 4;
1988
1989 out:
1990 if (error) {
1991 free(*vat_contents);
1992 *vat_contents = NULL;
1993 }
1994
1995 return error;
1996 }
1997
1998
1999 #define VAT_BLK 256
2000 static int
udf_search_vat(union udf_pmap * mapping,int log_part)2001 udf_search_vat(union udf_pmap *mapping, int log_part)
2002 {
2003 union dscrptr *vat_candidate, *accepted_vat;
2004 struct part_desc *pdesc;
2005 struct mmc_trackinfo *ti, *ti_s;
2006 uint32_t part_start;
2007 uint32_t vat_loc, early_vat_loc, late_vat_loc, accepted_vat_loc;
2008 uint32_t first_possible_vat_location, last_possible_vat_location;
2009 uint8_t *vat_contents, *accepted_vat_contents;
2010 int num_tracks, tracknr, found_a_VAT, valid_loc, error;
2011
2012 /*
2013 * Start reading forward in blocks from the first possible vat
2014 * location. If not found in this block, start again a bit before
2015 * until we get a hit.
2016 */
2017
2018 /* get complete list of all our valid ranges */
2019 ti_s = calloc(mmc_discinfo.num_tracks, sizeof(struct mmc_trackinfo));
2020 for (tracknr = 1; tracknr <= mmc_discinfo.num_tracks; tracknr++) {
2021 ti = &ti_s[tracknr];
2022 ti->tracknr = tracknr;
2023 (void) udf_update_trackinfo(ti);
2024 }
2025
2026 /* derive our very first track number our base partition covers */
2027 pdesc = context.partitions[context.data_part];
2028 part_start = udf_rw32(pdesc->start_loc);
2029 for (int cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
2030 pdesc = context.partitions[cnt];
2031 if (!pdesc)
2032 continue;
2033 part_start = MIN(part_start, udf_rw32(pdesc->start_loc));
2034 }
2035 num_tracks = mmc_discinfo.num_tracks;
2036 for (tracknr = 1, ti = NULL; tracknr <= num_tracks; tracknr++) {
2037 ti = &ti_s[tracknr];
2038 if ((part_start >= ti->track_start) &&
2039 (part_start <= ti->track_start + ti->track_size))
2040 break;
2041 }
2042 context.first_ti_partition = *ti;
2043
2044 first_possible_vat_location = context.first_ti_partition.track_start;
2045 last_possible_vat_location = context.last_ti.track_start +
2046 context.last_ti.track_size -
2047 context.last_ti.free_blocks + 1;
2048
2049 /* initial guess is around 16 sectors back */
2050 late_vat_loc = last_possible_vat_location;
2051 early_vat_loc = MAX(late_vat_loc - 16, first_possible_vat_location);
2052
2053 if (!preen)
2054 printf("Full VAT range search from %d to %d\n",
2055 first_possible_vat_location,
2056 last_possible_vat_location);
2057
2058 vat_writeout = 0;
2059 accepted_vat = NULL;
2060 accepted_vat_contents = NULL;
2061 accepted_vat_loc = 0;
2062 do {
2063 vat_loc = early_vat_loc;
2064 if (!preen) {
2065 printf("\tChecking range %8d to %8d\n",
2066 early_vat_loc, late_vat_loc);
2067 fflush(stdout);
2068 }
2069 found_a_VAT = 0;
2070 while (vat_loc <= late_vat_loc) {
2071 if (print_info) {
2072 pwarn("\nchecking for VAT in sector %8d\n", vat_loc);
2073 print_info = 0;
2074 }
2075 /* check if its in readable range */
2076 valid_loc = 0;
2077 for (tracknr = 1; tracknr <= num_tracks; tracknr++) {
2078 ti = &ti_s[tracknr];
2079 if (!(ti->flags & MMC_TRACKINFO_BLANK) &&
2080 ((vat_loc >= ti->track_start) &&
2081 (vat_loc <= ti->track_start + ti->track_size))) {
2082 valid_loc = 1;
2083 break;
2084 }
2085 }
2086 if (!valid_loc) {
2087 vat_loc++;
2088 continue;
2089 }
2090
2091 error = udf_read_dscr_phys(vat_loc, &vat_candidate);
2092 if (!vat_candidate)
2093 error = ENOENT;
2094 if (!error)
2095 error = udf_check_for_vat(vat_candidate);
2096 if (error) {
2097 vat_loc++; /* walk forward */
2098 continue;
2099 }
2100
2101 if (accepted_vat) {
2102 /* check if newer vat time stamp is the same */
2103 if (udf_compare_mtimes(
2104 udf_file_mtime(vat_candidate),
2105 udf_file_mtime(accepted_vat)
2106 ) == 0) {
2107 free(vat_candidate);
2108 vat_loc++; /* walk forward */
2109 continue;
2110 }
2111 }
2112
2113 /* check if its contents are OK */
2114 error = udf_extract_vat(
2115 vat_candidate, &vat_contents);
2116 if (error) {
2117 /* unlikely */
2118 // pwarn("Unreadable or malformed VAT encountered\n");
2119 free(vat_candidate);
2120 vat_loc++;
2121 continue;
2122 }
2123 /* accept new vat */
2124 free(accepted_vat);
2125 free(accepted_vat_contents);
2126
2127 accepted_vat = vat_candidate;
2128 accepted_vat_contents = vat_contents;
2129 accepted_vat_loc = vat_loc;
2130 vat_candidate = NULL;
2131 vat_contents = NULL;
2132
2133 found_a_VAT = 1;
2134
2135 vat_loc++; /* walk forward */
2136 };
2137
2138 if (found_a_VAT && accepted_vat) {
2139 /* VAT accepted */
2140 if (!preen)
2141 udf_print_vat_details(accepted_vat);
2142 if (vat_writeout)
2143 pwarn("\tVAT accepted but marked dirty\n");
2144 if (!preen && !vat_writeout)
2145 pwarn("\tLogical volume integrity state set to CLOSED\n");
2146 if (!search_older_vat)
2147 break;
2148 if (!ask_noauto(0, "\tSearch older VAT"))
2149 break;
2150 late_vat_loc = accepted_vat_loc - 1;
2151 } else {
2152 late_vat_loc = early_vat_loc - 1;
2153 }
2154 if (early_vat_loc == first_possible_vat_location)
2155 break;
2156 early_vat_loc = first_possible_vat_location;
2157 if (late_vat_loc > VAT_BLK)
2158 early_vat_loc = MAX(early_vat_loc, late_vat_loc - VAT_BLK);
2159 } while (late_vat_loc > first_possible_vat_location);
2160
2161 if (!preen)
2162 printf("\n");
2163
2164 undo_opening_session = 0;
2165
2166 if (!accepted_vat) {
2167 if ((context.last_ti.sessionnr > 1) &&
2168 ask_noauto(0, "Undo opening of last session")) {
2169 undo_opening_session = 1;
2170 pwarn("Undoing opening of last session not implemented!\n");
2171 error = ENOENT;
2172 goto error_out;
2173 } else {
2174 pwarn("No valid VAT found!\n");
2175 error = ENOENT;
2176 goto error_out;
2177 }
2178 }
2179 if (last_possible_vat_location - accepted_vat_loc > 16) {
2180 assert(accepted_vat);
2181 pwarn("Selected VAT is not the latest or not at the end of "
2182 "track.\n");
2183 vat_writeout = 1;
2184 }
2185
2186 /* XXX FAULT INJECTION POINT XXX */
2187 //vat_writeout = 1;
2188 //udf_update_lvintd(UDF_INTEGRITY_OPEN);
2189
2190 return 0;
2191
2192 error_out:
2193 free(accepted_vat);
2194 free(accepted_vat_contents);
2195
2196 return error;
2197 }
2198
2199 /* ------------------------- sparables support ------------------------- */
2200
2201 static int
udf_read_spareables(union udf_pmap * mapping,int log_part)2202 udf_read_spareables(union udf_pmap *mapping, int log_part)
2203 {
2204 union dscrptr *dscr;
2205 struct part_map_spare *pms = &mapping->pms;
2206 uint32_t lb_num;
2207 int spar, error;
2208
2209 for (spar = 0; spar < pms->n_st; spar++) {
2210 lb_num = pms->st_loc[spar];
2211 error = udf_read_dscr_phys(lb_num, &dscr);
2212 if (error && !preen)
2213 pwarn("Error reading spareable table %d\n", spar);
2214 if (!error && dscr) {
2215 if (udf_rw16(dscr->tag.id) == TAGID_SPARING_TABLE) {
2216 free(context.sparing_table);
2217 context.sparing_table = &dscr->spt;
2218 dscr = NULL;
2219 break; /* we're done */
2220 }
2221 }
2222 free(dscr);
2223 }
2224 if (context.sparing_table == NULL)
2225 return ENOENT;
2226 return 0;
2227 }
2228
2229 /* ------------------------- metadata support ------------------------- */
2230
2231 static bool
udf_metadata_node_supported(void)2232 udf_metadata_node_supported(void)
2233 {
2234 struct extfile_entry *efe;
2235 struct short_ad *short_ad;
2236 uint32_t len;
2237 uint32_t flags;
2238 uint8_t *data_pos;
2239 int dscr_size, l_ea, l_ad, icbflags, addr_type;
2240
2241 /* we have to look into the file's allocation descriptors */
2242
2243 efe = context.meta_file;
2244 dscr_size = sizeof(struct extfile_entry) - 1;
2245 l_ea = udf_rw32(efe->l_ea);
2246 l_ad = udf_rw32(efe->l_ad);
2247
2248 icbflags = udf_rw16(efe->icbtag.flags);
2249 addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
2250 if (addr_type != UDF_ICB_SHORT_ALLOC) {
2251 warnx("specification violation: metafile not using"
2252 "short allocs");
2253 return false;
2254 }
2255
2256 data_pos = (uint8_t *) context.meta_file + dscr_size + l_ea;
2257 short_ad = (struct short_ad *) data_pos;
2258 while (l_ad > 0) {
2259 len = udf_rw32(short_ad->len);
2260 flags = UDF_EXT_FLAGS(len);
2261 if (flags == UDF_EXT_REDIRECT) {
2262 warnx("implementation limit: no support for "
2263 "extent redirections in metadata file");
2264 return false;
2265 }
2266 short_ad++;
2267 l_ad -= sizeof(struct short_ad);
2268 }
2269 /* we passed all of them */
2270 return true;
2271 }
2272
2273
2274 static int
udf_read_metadata_nodes(union udf_pmap * mapping,int log_part)2275 udf_read_metadata_nodes(union udf_pmap *mapping, int log_part)
2276 {
2277 union dscrptr *dscr1, *dscr2, *dscr3;
2278 struct part_map_meta *pmm = &mapping->pmm;
2279 uint16_t raw_phys_part, phys_part;
2280 int tagid, file_type, error;
2281
2282 /*
2283 * BUGALERT: some rogue implementations use random physical
2284 * partition numbers to break other implementations so lookup
2285 * the number.
2286 */
2287
2288 raw_phys_part = udf_rw16(pmm->part_num);
2289 phys_part = udf_find_raw_phys(raw_phys_part);
2290
2291 error = udf_read_dscr_virt(layout.meta_file, phys_part, &dscr1);
2292 if (!error) {
2293 tagid = udf_rw16(dscr1->tag.id);
2294 file_type = dscr1->efe.icbtag.file_type;
2295 if ((tagid != TAGID_EXTFENTRY) ||
2296 (file_type != UDF_ICB_FILETYPE_META_MAIN))
2297 error = ENOENT;
2298 }
2299 if (error) {
2300 pwarn("Bad primary metadata file descriptor\n");
2301 free(dscr1);
2302 dscr1 = NULL;
2303 }
2304
2305 error = udf_read_dscr_virt(layout.meta_mirror, phys_part, &dscr2);
2306 if (!error) {
2307 tagid = udf_rw16(dscr2->tag.id);
2308 file_type = dscr2->efe.icbtag.file_type;
2309 if ((tagid != TAGID_EXTFENTRY) ||
2310 (file_type != UDF_ICB_FILETYPE_META_MIRROR))
2311 error = ENOENT;
2312 }
2313 if (error) {
2314 pwarn("Bad mirror metadata file descriptor\n");
2315 free(dscr2);
2316 dscr2 = NULL;
2317 }
2318
2319 if ((dscr1 == NULL) && (dscr2 == NULL)) {
2320 pwarn("No valid metadata file descriptors found!\n");
2321 return -1;
2322 }
2323
2324 error = 0;
2325 if ((dscr1 == NULL) && dscr2) {
2326 dscr1 = malloc(context.sector_size);
2327 memcpy(dscr1, dscr2, context.sector_size);
2328 dscr1->efe.icbtag.file_type = UDF_ICB_FILETYPE_META_MAIN;
2329 if (ask(1, "Fix up bad primary metadata file descriptor")) {
2330 error = udf_write_dscr_virt(dscr1,
2331 layout.meta_file, phys_part, 1);
2332 }
2333 }
2334 if (dscr1 && (dscr2 == NULL)) {
2335 dscr2 = malloc(context.sector_size);
2336 memcpy(dscr2, dscr1, context.sector_size);
2337 dscr2->efe.icbtag.file_type = UDF_ICB_FILETYPE_META_MIRROR;
2338 if (ask(1, "Fix up bad mirror metadata file descriptor")) {
2339 error = udf_write_dscr_virt(dscr2,
2340 layout.meta_mirror, phys_part, 1);
2341 }
2342 }
2343 if (error)
2344 pwarn("Copying metadata file descriptor failed, "
2345 "trying to continue\n");
2346
2347 context.meta_file = &dscr1->efe;
2348 context.meta_mirror = &dscr2->efe;
2349
2350 dscr3 = NULL;
2351 if (layout.meta_bitmap != 0xffffffff) {
2352 error = udf_read_dscr_virt(layout.meta_bitmap, phys_part, &dscr3);
2353 if (!error) {
2354 tagid = udf_rw16(dscr3->tag.id);
2355 file_type = dscr3->efe.icbtag.file_type;
2356 if ((tagid != TAGID_EXTFENTRY) ||
2357 (file_type != UDF_ICB_FILETYPE_META_BITMAP))
2358 error = ENOENT;
2359 }
2360 if (error) {
2361 pwarn("Bad metadata bitmap file descriptor\n");
2362 free(dscr3);
2363 dscr3 = NULL;
2364 }
2365
2366 if (dscr3 == NULL) {
2367 pwarn("implementation limit: can't repair missing or "
2368 "damaged metadata bitmap descriptor\n");
2369 return -1;
2370 }
2371
2372 context.meta_bitmap = &dscr3->efe;
2373 }
2374
2375 /* TODO early check if meta_file has allocation extent redirections */
2376 if (!udf_metadata_node_supported())
2377 return EINVAL;
2378
2379 return 0;
2380 }
2381
2382 /* ------------------------- VDS readin ------------------------- */
2383
2384 /* checks if the VDS information is correct and complete */
2385 static int
udf_process_vds(void)2386 udf_process_vds(void) {
2387 union dscrptr *dscr;
2388 union udf_pmap *mapping;
2389 struct part_desc *pdesc;
2390 struct long_ad fsd_loc;
2391 uint8_t *pmap_pos;
2392 char *domain_name, *map_name;
2393 const char *check_name;
2394 int pmap_stype, pmap_size;
2395 int pmap_type, log_part, phys_part, raw_phys_part; //, maps_on;
2396 int n_pm, n_phys, n_virt, n_spar, n_meta;
2397 int len, error;
2398
2399 /* we need at least an anchor (trivial, but for safety) */
2400 if (context.anchors[0] == NULL) {
2401 pwarn("sanity check: no anchors?\n");
2402 return EINVAL;
2403 }
2404
2405 /* we need at least one primary and one logical volume descriptor */
2406 if ((context.primary_vol == NULL) || (context.logical_vol) == NULL) {
2407 pwarn("sanity check: missing primary or missing logical volume\n");
2408 return EINVAL;
2409 }
2410
2411 /* we need at least one partition descriptor */
2412 if (context.partitions[0] == NULL) {
2413 pwarn("sanity check: missing partition descriptor\n");
2414 return EINVAL;
2415 }
2416
2417 /* check logical volume sector size versus device sector size */
2418 if (udf_rw32(context.logical_vol->lb_size) != context.sector_size) {
2419 pwarn("sanity check: lb_size != sector size\n");
2420 return EINVAL;
2421 }
2422
2423 /* check domain name, should never fail */
2424 domain_name = (char *) context.logical_vol->domain_id.id;
2425 if (strncmp(domain_name, "*OSTA UDF Compliant", 20)) {
2426 pwarn("sanity check: disc not OSTA UDF Compliant, aborting\n");
2427 return EINVAL;
2428 }
2429
2430 /* retrieve logical volume integrity sequence */
2431 udf_retrieve_lvint();
2432
2433 /* check if we support this disc, ie less or equal to 0x250 */
2434 if (udf_rw16(context.logvol_info->min_udf_writever) > 0x250) {
2435 pwarn("implementation limit: minimum write version UDF 2.60 "
2436 "and on are not supported\n");
2437 return EINVAL;
2438 }
2439
2440 /*
2441 * check logvol mappings: effective virt->log partmap translation
2442 * check and recording of the mapping results. Saves expensive
2443 * strncmp() in tight places.
2444 */
2445 n_pm = udf_rw32(context.logical_vol->n_pm); /* num partmaps */
2446 pmap_pos = context.logical_vol->maps;
2447
2448 if (n_pm > UDF_PMAPS) {
2449 pwarn("implementation limit: too many logvol mappings\n");
2450 return EINVAL;
2451 }
2452
2453 /* count types and set partition numbers */
2454 context.data_part = context.metadata_part = context.fids_part = 0;
2455 n_phys = n_virt = n_spar = n_meta = 0;
2456 for (log_part = 0; log_part < n_pm; log_part++) {
2457 mapping = (union udf_pmap *) pmap_pos;
2458 pmap_stype = pmap_pos[0];
2459 pmap_size = pmap_pos[1];
2460 switch (pmap_stype) {
2461 case 1: /* physical mapping */
2462 /* volseq = udf_rw16(mapping->pm1.vol_seq_num); */
2463 raw_phys_part = udf_rw16(mapping->pm1.part_num);
2464 pmap_type = UDF_VTOP_TYPE_PHYS;
2465 n_phys++;
2466 context.data_part = log_part;
2467 context.metadata_part = log_part;
2468 context.fids_part = log_part;
2469 break;
2470 case 2: /* virtual/sparable/meta mapping */
2471 map_name = (char *) mapping->pm2.part_id.id;
2472 /* volseq = udf_rw16(mapping->pm2.vol_seq_num); */
2473 raw_phys_part = udf_rw16(mapping->pm2.part_num);
2474 pmap_type = UDF_VTOP_TYPE_UNKNOWN;
2475 len = UDF_REGID_ID_SIZE;
2476
2477 check_name = "*UDF Virtual Partition";
2478 if (strncmp(map_name, check_name, len) == 0) {
2479 pmap_type = UDF_VTOP_TYPE_VIRT;
2480 n_virt++;
2481 context.metadata_part = log_part;
2482 context.format_flags |= FORMAT_VAT;
2483 break;
2484 }
2485 check_name = "*UDF Sparable Partition";
2486 if (strncmp(map_name, check_name, len) == 0) {
2487 pmap_type = UDF_VTOP_TYPE_SPAREABLE;
2488 n_spar++;
2489 layout.spareable_blockingnr = udf_rw16(mapping->pms.packet_len);
2490
2491 context.data_part = log_part;
2492 context.metadata_part = log_part;
2493 context.fids_part = log_part;
2494 context.format_flags |= FORMAT_SPAREABLE;
2495 break;
2496 }
2497 check_name = "*UDF Metadata Partition";
2498 if (strncmp(map_name, check_name, len) == 0) {
2499 pmap_type = UDF_VTOP_TYPE_META;
2500 n_meta++;
2501 layout.meta_file = udf_rw32(mapping->pmm.meta_file_lbn);
2502 layout.meta_mirror = udf_rw32(mapping->pmm.meta_mirror_file_lbn);
2503 layout.meta_bitmap = udf_rw32(mapping->pmm.meta_bitmap_file_lbn);
2504 layout.meta_blockingnr = udf_rw32(mapping->pmm.alloc_unit_size);
2505 layout.meta_alignment = udf_rw16(mapping->pmm.alignment_unit_size);
2506 /* XXX metadata_flags in mapping->pmm.flags? XXX */
2507
2508 context.metadata_part = log_part;
2509 context.fids_part = log_part;
2510 context.format_flags |= FORMAT_META;
2511 break;
2512 }
2513 break;
2514 default:
2515 return EINVAL;
2516 }
2517
2518 /*
2519 * BUGALERT: some rogue implementations use random physical
2520 * partition numbers to break other implementations so lookup
2521 * the number.
2522 */
2523 phys_part = udf_find_raw_phys(raw_phys_part);
2524
2525 if (phys_part == UDF_PARTITIONS) {
2526 pwarn("implementation limit: too many partitions\n");
2527 return EINVAL;
2528 }
2529 if (pmap_type == UDF_VTOP_TYPE_UNKNOWN) {
2530 pwarn("implementation limit: encountered unknown "
2531 "logvol mapping `%s`!\n", map_name);
2532 return EINVAL;
2533 }
2534
2535 context.vtop [log_part] = phys_part;
2536 context.vtop_tp[log_part] = pmap_type;
2537
2538 pmap_pos += pmap_size;
2539 }
2540 /* not winning the beauty contest */
2541 context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
2542
2543 /* test some basic UDF assertions/requirements */
2544 if ((n_virt > 1) || (n_spar > 1) || (n_meta > 1)) {
2545 pwarn("Sanity check: format error, more than one "
2546 "virtual, sparable or meta mapping\n");
2547 return EINVAL;
2548 }
2549
2550 if (n_virt) {
2551 if ((n_phys == 0) || n_spar || n_meta) {
2552 pwarn("Sanity check: format error, no backing for "
2553 "virtual partition\n");
2554 return EINVAL;
2555 }
2556 }
2557 if (n_spar + n_phys == 0) {
2558 pwarn("Sanity check: can't combine a sparable and a "
2559 "physical partition\n");
2560 return EINVAL;
2561 }
2562
2563 /* print format type as derived */
2564 if (!preen) {
2565 char bits[255];
2566 snprintb(bits, sizeof(bits), FORMAT_FLAGBITS, context.format_flags);
2567 printf("Format flags %s\n\n", bits);
2568 }
2569
2570 /* read supporting tables */
2571 pmap_pos = context.logical_vol->maps;
2572 for (log_part = 0; log_part < n_pm; log_part++) {
2573 mapping = (union udf_pmap *) pmap_pos;
2574 pmap_size = pmap_pos[1];
2575 switch (context.vtop_tp[log_part]) {
2576 case UDF_VTOP_TYPE_PHYS :
2577 /* nothing */
2578 break;
2579 case UDF_VTOP_TYPE_VIRT :
2580 /* search and load VAT */
2581 error = udf_search_vat(mapping, log_part);
2582 if (error) {
2583 pwarn("Couldn't find virtual allocation table\n");
2584 return ENOENT;
2585 }
2586 break;
2587 case UDF_VTOP_TYPE_SPAREABLE :
2588 /* load one of the sparable tables */
2589 error = udf_read_spareables(mapping, log_part);
2590 if (error) {
2591 pwarn("Couldn't load sparable blocks tables\n");
2592 return ENOENT;
2593 }
2594 break;
2595 case UDF_VTOP_TYPE_META :
2596 /* load the associated file descriptors */
2597 error = udf_read_metadata_nodes(mapping, log_part);
2598 if (error) {
2599 pwarn("Couldn't read in the metadata descriptors\n");
2600 return ENOENT;
2601 }
2602
2603 /*
2604 * We have to extract the partition size from the meta
2605 * data file length
2606 */
2607 context.part_size[log_part] =
2608 udf_rw64(context.meta_file->inf_len) / context.sector_size;
2609 break;
2610 default:
2611 break;
2612 }
2613 pmap_pos += pmap_size;
2614 }
2615
2616 /*
2617 * Free/unallocated space bitmap readin delayed; the FS might be
2618 * closed already; no need to read in copious amount of data only to
2619 * not use it later.
2620 *
2621 * For now, extract partition sizes in our context
2622 */
2623 for (int cnt = 0; cnt < UDF_PARTITIONS; cnt++) {
2624 pdesc = context.partitions[cnt];
2625 if (!pdesc)
2626 continue;
2627
2628 context.part_size[cnt] = udf_rw32(pdesc->part_len);
2629 context.part_unalloc_bits[cnt] = NULL;
2630 }
2631
2632 /* read file set descriptor */
2633 fsd_loc = context.logical_vol->lv_fsd_loc;
2634 error = udf_read_dscr_virt(
2635 udf_rw32(fsd_loc.loc.lb_num),
2636 udf_rw16(fsd_loc.loc.part_num), &dscr);
2637 if (error) {
2638 pwarn("Couldn't read in file set descriptor\n");
2639 pwarn("implementation limit: can't fix this\n");
2640 return ENOENT;
2641 }
2642 if (udf_rw16(dscr->tag.id) != TAGID_FSD) {
2643 pwarn("Expected fsd at (p %d, lb %d)\n",
2644 udf_rw16(fsd_loc.loc.part_num),
2645 udf_rw32(fsd_loc.loc.lb_num));
2646 pwarn("File set descriptor not pointing to a file set!\n");
2647 return ENOENT;
2648 }
2649 context.fileset_desc = &dscr->fsd;
2650
2651 /* signal its OK for now */
2652 return 0;
2653 }
2654
2655
2656 #define UDF_UPDATE_DSCR(name, dscr) \
2657 if (name) {\
2658 free (name); \
2659 updated = 1; \
2660 } \
2661 name = calloc(1, dscr_size); \
2662 memcpy(name, dscr, dscr_size);
2663
2664 static void
udf_process_vds_descriptor(union dscrptr * dscr,int dscr_size)2665 udf_process_vds_descriptor(union dscrptr *dscr, int dscr_size) {
2666 struct pri_vol_desc *pri;
2667 struct logvol_desc *lvd;
2668 uint16_t raw_phys_part, phys_part;
2669 int updated = 0;
2670
2671 switch (udf_rw16(dscr->tag.id)) {
2672 case TAGID_PRI_VOL : /* primary partition */
2673 UDF_UPDATE_DSCR(context.primary_vol, dscr);
2674 pri = context.primary_vol;
2675
2676 context.primary_name = malloc(32);
2677 context.volset_name = malloc(128);
2678
2679 udf_to_unix_name(context.volset_name, 32, pri->volset_id, 32,
2680 &pri->desc_charset);
2681 udf_to_unix_name(context.primary_name, 128, pri->vol_id, 128,
2682 &pri->desc_charset);
2683
2684 if (!preen && !updated) {
2685 pwarn("Volume set `%s`\n", context.volset_name);
2686 pwarn("Primary volume `%s`\n", context.primary_name);
2687 }
2688 break;
2689 case TAGID_LOGVOL : /* logical volume */
2690 UDF_UPDATE_DSCR(context.logical_vol, dscr);
2691 /* could check lvd->domain_id */
2692 lvd = context.logical_vol;
2693 context.logvol_name = malloc(128);
2694
2695 udf_to_unix_name(context.logvol_name, 128, lvd->logvol_id, 128,
2696 &lvd->desc_charset);
2697
2698 if (!preen && !updated)
2699 pwarn("Logical volume `%s`\n", context.logvol_name);
2700 break;
2701 case TAGID_UNALLOC_SPACE : /* unallocated space */
2702 UDF_UPDATE_DSCR(context.unallocated, dscr);
2703 break;
2704 case TAGID_IMP_VOL : /* implementation */
2705 UDF_UPDATE_DSCR(context.implementation, dscr);
2706 break;
2707 case TAGID_PARTITION : /* partition(s) */
2708 /* not much use if its not allocated */
2709 if ((udf_rw16(dscr->pd.flags) & UDF_PART_FLAG_ALLOCATED) == 0) {
2710 pwarn("Ignoring unallocated partition\n");
2711 break;
2712 }
2713 raw_phys_part = udf_rw16(dscr->pd.part_num);
2714 phys_part = udf_find_raw_phys(raw_phys_part);
2715
2716 if (phys_part >= UDF_PARTITIONS) {
2717 pwarn("Too many physical partitions, ignoring\n");
2718 break;
2719 }
2720 UDF_UPDATE_DSCR(context.partitions[phys_part], dscr);
2721 break;
2722 case TAGID_TERM : /* terminator */
2723 break;
2724 case TAGID_VOL : /* volume space ext */
2725 pwarn("Ignoring VDS extender\n");
2726 break;
2727 default :
2728 pwarn("Unknown VDS type %d found, ignored\n",
2729 udf_rw16(dscr->tag.id));
2730 }
2731 }
2732
2733
2734 static void
udf_read_vds_extent(union dscrptr * dscr,int vds_size)2735 udf_read_vds_extent(union dscrptr *dscr, int vds_size) {
2736 uint8_t *pos;
2737 int sector_size = context.sector_size;
2738 int dscr_size;
2739
2740 pos = (uint8_t *) dscr;
2741 while (vds_size) {
2742 /* process the descriptor */
2743 dscr = (union dscrptr *) pos;
2744
2745 /* empty block terminates */
2746 if (is_zero(dscr, sector_size))
2747 return;
2748
2749 /* terminator terminates */
2750 if (udf_rw16(dscr->tag.id) == TAGID_TERM)
2751 return;
2752
2753 if (udf_check_tag(dscr))
2754 pwarn("Bad descriptor sum in vds, ignoring\n");
2755
2756 dscr_size = udf_tagsize(dscr, sector_size);
2757 if (udf_check_tag_payload(dscr, dscr_size))
2758 pwarn("Bad descriptor CRC in vds, ignoring\n");
2759
2760 udf_process_vds_descriptor(dscr, dscr_size);
2761
2762 pos += dscr_size;
2763 vds_size -= dscr_size;
2764 }
2765 }
2766
2767
2768 static int
udf_copy_VDS_area(void * destbuf,void * srcbuf)2769 udf_copy_VDS_area(void *destbuf, void *srcbuf)
2770 {
2771 pwarn("TODO implement VDS copy area, signalling success\n");
2772 return 0;
2773 }
2774
2775
2776 /* XXX why two buffers and not just read descritor by descriptor XXX */
2777 static int
udf_check_VDS_areas(void)2778 udf_check_VDS_areas(void) {
2779 union dscrptr *vds1_buf, *vds2_buf;
2780 int vds1_size, vds2_size;
2781 int error, error1, error2;
2782
2783 vds1_size = layout.vds1_size * context.sector_size;
2784 vds2_size = layout.vds2_size * context.sector_size;
2785 vds1_buf = calloc(1, vds1_size);
2786 vds2_buf = calloc(1, vds2_size);
2787 assert(vds1_buf); assert(vds2_buf);
2788
2789 error1 = udf_read_phys(vds1_buf, layout.vds1, layout.vds1_size);
2790 error2 = udf_read_phys(vds2_buf, layout.vds2, layout.vds2_size);
2791
2792 if (error1 && error2) {
2793 pwarn("Can't read both volume descriptor areas!\n");
2794 return -1;
2795 }
2796
2797 if (!error1) {
2798 /* retrieve data from VDS 1 */
2799 udf_read_vds_extent(vds1_buf, vds1_size);
2800 context.vds_buf = vds1_buf;
2801 context.vds_size = vds1_size;
2802 free(vds2_buf);
2803 vds2_buf = NULL;
2804 }
2805 if (!error2) {
2806 /* retrieve data from VDS 2 */
2807 udf_read_vds_extent(vds2_buf, vds2_size);
2808 context.vds_buf = vds2_buf;
2809 context.vds_size = vds2_size;
2810 free(vds1_buf);
2811 vds1_buf = NULL;
2812 }
2813 /* check if all is correct and complete */
2814 error = udf_process_vds();
2815 if (error)
2816 return error;
2817
2818 /* TODO check if both area's are logically the same */
2819 error = 0;
2820 if (!error1 && error2) {
2821 /* first OK, second faulty */
2822 pwarn("Backup volume descriptor missing or damaged\n");
2823 if (context.format_flags & FORMAT_SEQUENTIAL) {
2824 pwarn("Can't fixup backup volume descriptor on "
2825 "SEQUENTIAL media\n");
2826 } else if (ask(1, "Fixup backup volume descriptor")) {
2827 error = udf_copy_VDS_area(vds2_buf, vds1_buf);
2828 pwarn("\n");
2829 }
2830 }
2831 if (error1 && !error2) {
2832 /* second OK, first faulty */
2833 pwarn("Primary volume descriptor missing or damaged\n");
2834 if (context.format_flags & FORMAT_SEQUENTIAL) {
2835 pwarn("Can't fix up primary volume descriptor on "
2836 "SEQUENTIAL media\n");
2837 } else if (ask(1, "Fix up primary volume descriptor")) {
2838 error = udf_copy_VDS_area(vds1_buf, vds2_buf);
2839 }
2840 }
2841 if (error)
2842 pwarn("copying VDS areas failed!\n");
2843 if (!preen)
2844 printf("\n");
2845
2846 return error;
2847 }
2848
2849 /* --------------------------------------------------------------------- */
2850
2851 static int
udf_prepare_writing(void)2852 udf_prepare_writing(void)
2853 {
2854 union dscrptr *zero_dscr, *dscr;
2855 struct mmc_trackinfo ti;
2856 uint32_t first_lba, loc;
2857 int sector_size = context.sector_size;
2858 int error;
2859
2860 error = udf_prepare_disc();
2861 if (error) {
2862 pwarn("*** Preparing disc for writing failed!\n");
2863 return error;
2864 }
2865
2866 /* if we are not on sequential media, we're done */
2867 if ((context.format_flags & FORMAT_VAT) == 0)
2868 return 0;
2869
2870 /* if the disc is full, we drop back to read only */
2871 if (mmc_discinfo.disc_state == MMC_STATE_FULL)
2872 rdonly = 1;
2873 if (rdonly)
2874 return 0;
2875
2876 /* check if we need to open the last track */
2877 ti.tracknr = mmc_discinfo.last_track_last_session;
2878 error = udf_update_trackinfo(&ti);
2879 if (error)
2880 return error;
2881 if (!(ti.flags & MMC_TRACKINFO_BLANK) &&
2882 (ti.flags & MMC_TRACKINFO_NWA_VALID)) {
2883 /*
2884 * Not closed; translate next_writable to a position relative to our
2885 * backing partition
2886 */
2887 context.alloc_pos[context.data_part] = ti.next_writable -
2888 udf_rw32(context.partitions[context.data_part]->start_loc);
2889 wrtrack_skew = ti.next_writable % layout.blockingnr;
2890 return 0;
2891 }
2892 assert(ti.flags & MMC_TRACKINFO_NWA_VALID);
2893
2894 /* just in case */
2895 udf_suspend_writing();
2896
2897 /* 'add' a new track */
2898 udf_update_discinfo();
2899 memset(&context.last_ti, 0, sizeof(struct mmc_trackinfo));
2900 context.last_ti.tracknr = mmc_discinfo.first_track_last_session;
2901 (void) udf_update_trackinfo(&context.last_ti);
2902
2903 assert(mmc_discinfo.last_session_state == MMC_STATE_EMPTY);
2904 first_lba = context.last_ti.track_start;
2905 wrtrack_skew = context.last_ti.track_start % layout.blockingnr;
2906
2907 /*
2908 * location of iso9660 vrs is defined as first sector AFTER 32kb,
2909 * minimum `sector size' 2048
2910 */
2911 layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
2912 + first_lba;
2913
2914 /* anchor starts at specified offset in sectors */
2915 layout.anchors[0] = first_lba + 256;
2916
2917 /* ready for appending, write preamble, we are using overwrite here! */
2918 if ((zero_dscr = calloc(1, context.sector_size)) == NULL)
2919 return ENOMEM;
2920 loc = first_lba;
2921 for (; loc < first_lba + 256; loc++) {
2922 if ((error = udf_write_sector(zero_dscr, loc))) {
2923 free(zero_dscr);
2924 return error;
2925 }
2926 }
2927 free(zero_dscr);
2928
2929 /* write new ISO9660 volume recognition sequence */
2930 if ((error = udf_write_iso9660_vrs())) {
2931 pwarn("internal error: can't write iso966 VRS in new session!\n");
2932 rdonly = 1;
2933 return error;
2934 }
2935
2936 /* write out our old anchor, VDS spaces will be reused */
2937 assert(context.anchors[0]);
2938 dscr = (union dscrptr *) context.anchors[0];
2939 loc = layout.anchors[0];
2940 if ((error = udf_write_dscr_phys(dscr, loc, 1))) {
2941 pwarn("internal error: can't write anchor in new session!\n");
2942 rdonly = 1;
2943 return error;
2944 }
2945
2946 context.alloc_pos[context.data_part] = first_lba + 257 -
2947 udf_rw32(context.partitions[context.data_part]->start_loc);
2948
2949 return 0;
2950 }
2951
2952
2953 static int
udf_close_volume_vat(void)2954 udf_close_volume_vat(void)
2955 {
2956 int integrity_type;
2957
2958 /* only write out when its open */
2959 integrity_type = udf_rw32(context.logvol_integrity->integrity_type);
2960 if (integrity_type == UDF_INTEGRITY_CLOSED)
2961 return 0;
2962
2963 if (!preen)
2964 printf("\n");
2965 if (!ask(1, "Write out modifications"))
2966 return 0;
2967
2968 /* writeout our VAT contents */
2969 udf_allow_writing();
2970 return udf_writeout_VAT();
2971 }
2972
2973
2974 static int
udf_close_volume(void)2975 udf_close_volume(void)
2976 {
2977 struct part_desc *part;
2978 struct part_hdr_desc *phd;
2979 struct logvol_int_desc *lvid;
2980 struct udf_logvol_info *lvinfo;
2981 struct logvol_desc *logvol;
2982 uint32_t bitmap_len, bitmap_lb, bitmap_numlb;
2983 int i, equal, error;
2984
2985 lvid = context.logvol_integrity;
2986 logvol = context.logical_vol;
2987 lvinfo = context.logvol_info;
2988 assert(lvid);
2989 assert(logvol);
2990 assert(lvinfo);
2991
2992 /* check our highest unique id */
2993 if (context.unique_id > udf_rw64(lvid->lvint_next_unique_id)) {
2994 pwarn("Last unique id updated from %" PRIi64 " to %" PRIi64 " : FIXED\n",
2995 udf_rw64(lvid->lvint_next_unique_id),
2996 context.unique_id);
2997 open_integrity = 1;
2998 }
2999
3000 /* check file/directory counts */
3001 if (context.num_files != udf_rw32(lvinfo->num_files)) {
3002 pwarn("Number of files corrected from %d to %d : FIXED\n",
3003 udf_rw32(lvinfo->num_files),
3004 context.num_files);
3005 open_integrity = 1;
3006 }
3007 if (context.num_directories != udf_rw32(lvinfo->num_directories)) {
3008 pwarn("Number of directories corrected from %d to %d : FIXED\n",
3009 udf_rw32(lvinfo->num_directories),
3010 context.num_directories);
3011 open_integrity = 1;
3012 }
3013
3014 if (vat_writeout)
3015 open_integrity = 1;
3016
3017 if (open_integrity)
3018 udf_update_lvintd(UDF_INTEGRITY_OPEN);
3019
3020 if (context.format_flags & FORMAT_VAT)
3021 return udf_close_volume_vat();
3022
3023 /* adjust free space accounting! */
3024 for (i = 0; i < UDF_PARTITIONS; i++) {
3025 part = context.partitions[i];
3026 if (!part)
3027 continue;
3028 phd = &part->pd_part_hdr;
3029 bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
3030 bitmap_lb = udf_rw32(phd->unalloc_space_bitmap.lb_num);
3031
3032 if (bitmap_len == 0) {
3033 error = 0;
3034 continue;
3035 }
3036
3037 equal = memcmp( recorded_part_unalloc_bits[i],
3038 context.part_unalloc_bits[i],
3039 bitmap_len) == 0;
3040
3041 if (!equal || (context.part_free[i] != recorded_part_free[i])) {
3042 if (!equal)
3043 pwarn("Calculated bitmap for partition %d not equal "
3044 "to recorded one : FIXED\n", i);
3045 pwarn("Free space on partition %d corrected "
3046 "from %d to %d blocks : FIXED\n", i,
3047 recorded_part_free[i],
3048 context.part_free[i]);
3049
3050 /* write out updated free space map */
3051 pwarn("Updating unallocated bitmap for partition\n");
3052 if (!preen)
3053 printf("Writing free space map "
3054 "for partition %d\n", i);
3055 error = 0;
3056 if (context.vtop_tp[i] == UDF_VTOP_TYPE_META) {
3057 if (context.meta_bitmap) {
3058 assert(i == context.metadata_part);
3059 error = udf_process_file(
3060 (union dscrptr *) context.meta_bitmap,
3061 context.data_part,
3062 (uint8_t **) &(context.part_unalloc_bits[i]),
3063 AD_SAVE_FILE, NULL);
3064 }
3065 } else {
3066 bitmap_numlb = udf_bytes_to_sectors(bitmap_len);
3067 error = udf_write_dscr_virt(
3068 (union dscrptr *) context.part_unalloc_bits[i],
3069 bitmap_lb,
3070 i,
3071 bitmap_numlb);
3072 }
3073 if (error)
3074 pwarn("Updating unallocated bitmap failed, "
3075 "continuing\n");
3076 udf_update_lvintd(UDF_INTEGRITY_OPEN);
3077 }
3078 }
3079
3080 /* write out the logical volume integrity sequence */
3081 error = udf_writeout_lvint();
3082
3083 return error;
3084 }
3085
3086 /* --------------------------------------------------------------------- */
3087
3088 /*
3089 * Main part of file system checking.
3090 *
3091 * Walk the entire directory tree and check all link counts and rebuild the
3092 * free space map (if present) on the go.
3093 */
3094
3095 static struct udf_fsck_node *
udf_new_fsck_node(struct udf_fsck_node * parent,struct long_ad * loc,char * fname)3096 udf_new_fsck_node(struct udf_fsck_node *parent, struct long_ad *loc, char *fname)
3097 {
3098 struct udf_fsck_node *this;
3099 this = calloc(1, sizeof(struct udf_fsck_node));
3100 if (!this)
3101 return NULL;
3102
3103 this->parent = parent;
3104 this->fname = strdup(fname);
3105 this->loc = *loc;
3106 this->fsck_flags = 0;
3107
3108 this->link_count = 0;
3109 this->found_link_count = 0;
3110
3111 return this;
3112 }
3113
3114
3115 static void
udf_node_path_piece(char * pathname,struct udf_fsck_node * node)3116 udf_node_path_piece(char *pathname, struct udf_fsck_node *node)
3117 {
3118 if (node->parent) {
3119 udf_node_path_piece(pathname, node->parent);
3120 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3121 strcat(pathname, "");
3122 else
3123 strcat(pathname, "/");
3124 }
3125 strcat(pathname, node->fname);
3126 }
3127
3128
3129 static char *
udf_node_path(struct udf_fsck_node * node)3130 udf_node_path(struct udf_fsck_node *node)
3131 {
3132 static char pathname[MAXPATHLEN + 10];
3133
3134 strcpy(pathname, "`");
3135 if (node->parent)
3136 udf_node_path_piece(pathname, node);
3137 else
3138 strcat(pathname, "/");
3139 strcat(pathname, "'");
3140
3141 return pathname;
3142 }
3143
3144
3145 static void
udf_recursive_keep(struct udf_fsck_node * node)3146 udf_recursive_keep(struct udf_fsck_node *node)
3147 {
3148 while (node->parent) {
3149 node = node->parent;
3150 node->fsck_flags |= FSCK_NODE_FLAG_KEEP;
3151 }
3152 }
3153
3154
3155 static int
udf_quick_check_fids(struct udf_fsck_node * node,union dscrptr * dscr)3156 udf_quick_check_fids(struct udf_fsck_node *node, union dscrptr *dscr)
3157 {
3158 struct udf_fsck_fid_context fid_context;
3159 int error;
3160
3161 fid_context.fid_offset = 0;
3162 fid_context.data_left = node->found.inf_len;
3163 error = udf_process_file(dscr, context.fids_part,
3164 &node->directory,
3165 AD_CHECK_FIDS,
3166 &fid_context);
3167
3168 return error;
3169 }
3170
3171
3172 /* read descriptor at node's location */
3173 static int
udf_read_node_dscr(struct udf_fsck_node * node,union dscrptr ** dscrptr)3174 udf_read_node_dscr(struct udf_fsck_node *node, union dscrptr **dscrptr)
3175 {
3176 *dscrptr = NULL;
3177 return udf_read_dscr_virt(
3178 udf_rw32(node->loc.loc.lb_num),
3179 udf_rw16(node->loc.loc.part_num),
3180 dscrptr);
3181 }
3182
3183
3184 static int
udf_extract_node_info(struct udf_fsck_node * node,union dscrptr * dscr,int be_quiet)3185 udf_extract_node_info(struct udf_fsck_node *node, union dscrptr *dscr,
3186 int be_quiet)
3187 {
3188 struct icb_tag *icb = NULL;
3189 struct file_entry *fe = NULL;
3190 struct extfile_entry *efe = NULL;
3191 int ad_type, error;
3192
3193 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3194 fe = (struct file_entry *) dscr;
3195 icb = &fe->icbtag;
3196 node->declared.inf_len = udf_rw64(fe->inf_len);
3197 node->declared.obj_size = udf_rw64(fe->inf_len);
3198 node->declared.logblks_rec = udf_rw64(fe->logblks_rec);
3199 node->link_count = udf_rw16(fe->link_cnt);
3200 node->unique_id = udf_rw64(fe->unique_id);
3201
3202 /* XXX FAULT INJECTION POINT XXX */
3203 //if (fe->unique_id == 33) { return ENOENT;}
3204
3205 }
3206 if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
3207 efe = (struct extfile_entry *) dscr;
3208 icb = &efe->icbtag;
3209 node->declared.inf_len = udf_rw64(efe->inf_len);
3210 node->declared.obj_size = udf_rw64(efe->obj_size);
3211 node->declared.logblks_rec = udf_rw64(efe->logblks_rec);
3212 node->link_count = udf_rw16(efe->link_cnt);
3213 node->unique_id = udf_rw64(efe->unique_id);
3214 node->streamdir_loc = efe->streamdir_icb;
3215 if (node->streamdir_loc.len)
3216 node->fsck_flags |= FSCK_NODE_FLAG_HAS_STREAM_DIR;
3217
3218 /* XXX FAULT INJECTION POINT XXX */
3219 //if (efe->unique_id == 0x891) { return ENOENT;}
3220
3221 }
3222
3223 if (!fe && !efe) {
3224 //printf("NOT REFERENCING AN FE/EFE!\n");
3225 return ENOENT;
3226 }
3227
3228 if (node->unique_id >= context.unique_id)
3229 context.unique_id = node->unique_id+1;
3230
3231 ad_type = udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
3232 if ((ad_type != UDF_ICB_INTERN_ALLOC) &&
3233 (ad_type != UDF_ICB_SHORT_ALLOC) &&
3234 (ad_type != UDF_ICB_LONG_ALLOC)) {
3235 pwarn("%s : unknown allocation type\n",
3236 udf_node_path(node));
3237 return EINVAL;
3238 }
3239
3240 bzero(&node->found, sizeof(node->found));
3241 error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3242 AD_GATHER_STATS, (void *) &node->found);
3243
3244 switch (icb->file_type) {
3245 case UDF_ICB_FILETYPE_RANDOMACCESS :
3246 case UDF_ICB_FILETYPE_BLOCKDEVICE :
3247 case UDF_ICB_FILETYPE_CHARDEVICE :
3248 case UDF_ICB_FILETYPE_FIFO :
3249 case UDF_ICB_FILETYPE_SOCKET :
3250 case UDF_ICB_FILETYPE_SYMLINK :
3251 case UDF_ICB_FILETYPE_REALTIME :
3252 break;
3253 default:
3254 /* unknown or unsupported file type, TODO clearing? */
3255 free(dscr);
3256 pwarn("%s : specification violation, unknown file type %d\n",
3257 udf_node_path(node), icb->file_type);
3258 return ENOENT;
3259 case UDF_ICB_FILETYPE_STREAMDIR :
3260 case UDF_ICB_FILETYPE_DIRECTORY :
3261 /* read in the directory contents */
3262 error = udf_readin_file(dscr, udf_rw16(node->loc.loc.part_num),
3263 &node->directory, NULL);
3264
3265 /* XXX FAULT INJECTION POINT XXX */
3266 //if (dscr->efe.unique_id == 109) node->directory[125] = 0xff;
3267 //if (dscr->efe.unique_id == 310) memset(node->directory+1024, 0, 300);
3268
3269 if (error && !be_quiet) {
3270 pwarn("%s : directory has read errors\n",
3271 udf_node_path(node));
3272 if (ask(0, "Directory could be fixed or cleared. "
3273 "Wipe defective directory")) {
3274 return ENOENT;
3275 }
3276 udf_recursive_keep(node);
3277 node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3278 }
3279 node->fsck_flags |= FSCK_NODE_FLAG_DIRECTORY;
3280 error = udf_quick_check_fids(node, dscr);
3281 if (error) {
3282 if (!(node->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR))
3283 pwarn("%s : directory file entries need repair\n",
3284 udf_node_path(node));
3285 udf_recursive_keep(node);
3286 node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3287 }
3288 }
3289
3290 /* XXX FAULT INJECTION POINT XXX */
3291 //if (fe->unique_id == 0) node->link_count++;
3292 //if (efe->unique_id == 0) node->link_count++;
3293 //if (efe->unique_id == 772) { node->declared.inf_len += 205; node->declared.obj_size -= 0; }
3294
3295 return 0;
3296 }
3297
3298
3299 static void
udf_fixup_lengths_pass1(struct udf_fsck_node * node,union dscrptr * dscr)3300 udf_fixup_lengths_pass1(struct udf_fsck_node *node, union dscrptr *dscr)
3301 {
3302 int64_t diff;
3303
3304 /* file length check */
3305 diff = node->found.inf_len - node->declared.inf_len;
3306 if (diff) {
3307 pwarn("%s : recorded information length incorrect: "
3308 "%" PRIu64 " instead of declared %" PRIu64 "\n",
3309 udf_node_path(node),
3310 node->found.inf_len, node->declared.inf_len);
3311 node->declared.inf_len = node->found.inf_len;
3312 udf_recursive_keep(node);
3313 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3314 }
3315
3316 /* recorded logical blocks count check */
3317 diff = node->found.logblks_rec - node->declared.logblks_rec;
3318 if (diff) {
3319 pwarn("%s : logical blocks recorded incorrect: "
3320 "%" PRIu64 " instead of declared %" PRIu64 ", fixing\n",
3321 udf_node_path(node),
3322 node->found.logblks_rec, node->declared.logblks_rec);
3323 node->declared.logblks_rec = node->found.logblks_rec;
3324 udf_recursive_keep(node);
3325 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3326 }
3327
3328 /* tally object sizes for streamdirs */
3329 node->found.obj_size = node->found.inf_len;
3330 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_ENTRY) {
3331 assert(node->parent); /* streamdir itself */
3332 if (node->parent->parent)
3333 node->parent->parent->found.obj_size +=
3334 node->found.inf_len;
3335 }
3336
3337 /* check descriptor CRC length */
3338 if (udf_rw16(dscr->tag.desc_crc_len) !=
3339 udf_tagsize(dscr, 1) - sizeof(struct desc_tag)) {
3340 pwarn("%s : node file descriptor CRC length mismatch; "
3341 "%d declared, %zu\n",
3342 udf_node_path(node), udf_rw16(dscr->tag.desc_crc_len),
3343 udf_tagsize(dscr, 1) - sizeof(struct desc_tag));
3344 udf_recursive_keep(node);
3345 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3346 }
3347 }
3348
3349
3350 static void
udf_node_pass1_add_entry(struct udf_fsck_node * node,struct fileid_desc * fid,struct dirent * dirent)3351 udf_node_pass1_add_entry(struct udf_fsck_node *node,
3352 struct fileid_desc *fid, struct dirent *dirent)
3353 {
3354 struct udf_fsck_node *leaf_node;
3355 int entry;
3356
3357 /* skip deleted FID entries */
3358 if (fid->file_char & UDF_FILE_CHAR_DEL)
3359 return;
3360
3361 if (udf_rw32(fid->icb.loc.lb_num) == 0) {
3362 pwarn("%s : FileID entry `%s` has invalid location\n",
3363 udf_node_path(node), dirent->d_name);
3364 udf_recursive_keep(node);
3365 if (node->parent)
3366 node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3367 return;
3368 }
3369
3370 /* increase parent link count */
3371 if (fid->file_char & UDF_FILE_CHAR_PAR) {
3372 if (node->parent)
3373 node->parent->found_link_count++;
3374 return;
3375 }
3376
3377 /* lookup if we already know this node */
3378 leaf_node = udf_node_lookup(&fid->icb);
3379 if (leaf_node) {
3380 /* got a hard link! */
3381 leaf_node->found_link_count++;
3382 return;
3383 }
3384
3385 /* create new node */
3386 leaf_node = udf_new_fsck_node(
3387 node, &fid->icb, dirent->d_name);
3388 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3389 leaf_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_ENTRY;
3390
3391 TAILQ_INSERT_TAIL(&fs_nodes, leaf_node, next);
3392 entry = udf_calc_node_hash(&fid->icb);
3393 LIST_INSERT_HEAD(&fs_nodes_hash[entry], leaf_node, next_hash);
3394 }
3395
3396
3397 static void
udf_node_pass1_add_streamdir_entry(struct udf_fsck_node * node)3398 udf_node_pass1_add_streamdir_entry(struct udf_fsck_node *node)
3399 {
3400 struct udf_fsck_node *leaf_node;
3401 int entry;
3402
3403 /* check for recursion */
3404 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM) {
3405 /* recursive streams are not allowed by spec */
3406 pwarn("%s : specification violation, recursive stream dir\n",
3407 udf_node_path(node));
3408 udf_recursive_keep(node);
3409 node->fsck_flags |= FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3410 return;
3411 }
3412
3413 /* lookup if we already know this node */
3414 leaf_node = udf_node_lookup(&node->streamdir_loc);
3415 if (leaf_node) {
3416 pwarn("%s : specification violation, hardlinked streamdir\n",
3417 udf_node_path(leaf_node));
3418 udf_recursive_keep(node);
3419 node->fsck_flags |= FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3420 return;
3421 }
3422
3423 /* create new node */
3424 leaf_node = udf_new_fsck_node(
3425 node, &node->streamdir_loc, strdup(""));
3426 leaf_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_DIR;
3427
3428 /* streamdirs have link count 0 : ECMA 4/14.9.6 */
3429 leaf_node->found_link_count--;
3430
3431 /* insert in to lists */
3432 TAILQ_INSERT_TAIL(&fs_nodes, leaf_node, next);
3433 entry = udf_calc_node_hash(&node->streamdir_loc);
3434 LIST_INSERT_HEAD(&fs_nodes_hash[entry], leaf_node, next_hash);
3435 }
3436
3437
3438 static int
udf_process_node_pass1(struct udf_fsck_node * node,union dscrptr * dscr)3439 udf_process_node_pass1(struct udf_fsck_node *node, union dscrptr *dscr)
3440 {
3441 struct fileid_desc *fid;
3442 struct dirent dirent;
3443 struct charspec osta_charspec;
3444 int64_t fpos, new_length, rest_len;
3445 uint32_t fid_len;
3446 uint8_t *bpos;
3447 int isdir;
3448 int error;
3449
3450 isdir = node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY;
3451
3452 /* keep link count */
3453 node->found_link_count++;
3454
3455 if (isdir) {
3456 assert(node->directory);
3457 udf_rebuild_fid_stream(node, &new_length);
3458 node->found.inf_len = new_length;
3459 rest_len = new_length;
3460 }
3461
3462 udf_fixup_lengths_pass1(node, dscr);
3463
3464 /* check UniqueID */
3465 if (node->parent) {
3466 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM) {
3467
3468 /* XXX FAULT INJECTION POINT XXX */
3469 //node->unique_id = 0xdeadbeefcafe;
3470
3471 if (node->unique_id != node->parent->unique_id) {
3472 pwarn("%s : stream file/dir UniqueID mismatch "
3473 "with parent\n",
3474 udf_node_path(node));
3475 /* do the work here prematurely for our siblings */
3476 udf_recursive_keep(node);
3477 node->unique_id = node->parent->unique_id;
3478 node->fsck_flags |= FSCK_NODE_FLAG_COPY_PARENT_ID |
3479 FSCK_NODE_FLAG_DIRTY;
3480 assert(node->parent);
3481 node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3482 }
3483 } else if (node->unique_id < 16) {
3484 pwarn("%s : file has bad UniqueID\n",
3485 udf_node_path(node));
3486 udf_recursive_keep(node);
3487 node->fsck_flags |= FSCK_NODE_FLAG_NEW_UNIQUE_ID;
3488 assert(node->parent);
3489 node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3490 }
3491 } else {
3492 /* rootdir */
3493 if (node->unique_id != 0) {
3494 pwarn("%s : has bad UniqueID, has to be zero\n",
3495 udf_node_path(node));
3496 udf_recursive_keep(node);
3497 node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3498 }
3499 }
3500
3501 /* add streamdir if present */
3502 if (node->fsck_flags & FSCK_NODE_FLAG_HAS_STREAM_DIR)
3503 udf_node_pass1_add_streamdir_entry(node);
3504
3505 /* add all children */
3506 if (isdir) {
3507 node->fsck_flags |= FSCK_NODE_FLAG_PAR_NOT_FOUND;
3508 rest_len = node->found.inf_len;
3509
3510 /* walk through all our FIDs in the directory stream */
3511 bpos = node->directory;
3512 fpos = 0;
3513 while (rest_len > 0) {
3514 fid = (struct fileid_desc *) bpos;
3515 fid_len = udf_fidsize(fid);
3516
3517 /* get printable name */
3518 memset(&dirent, 0, sizeof(dirent));
3519 udf_osta_charset(&osta_charspec);
3520 udf_to_unix_name(dirent.d_name, NAME_MAX,
3521 (char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi,
3522 &osta_charspec);
3523 dirent.d_namlen = strlen(dirent.d_name);
3524
3525 /* '..' has no name, so provide one */
3526 if (fid->file_char & UDF_FILE_CHAR_PAR) {
3527 strcpy(dirent.d_name, "..");
3528 node->fsck_flags &= ~FSCK_NODE_FLAG_PAR_NOT_FOUND;
3529 }
3530
3531 udf_node_pass1_add_entry(node, fid, &dirent);
3532
3533 fpos += fid_len;
3534 bpos += fid_len;
3535 rest_len -= fid_len;
3536 }
3537 }
3538
3539 error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3540 AD_CHECK_USED, node);
3541 if (error) {
3542 pwarn("%s : internal error: checking for being allocated shouldn't fail\n",
3543 udf_node_path(node));
3544 return EINVAL;
3545 }
3546 /* file/directory is OK and referenced as its size won't change */
3547 error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3548 AD_MARK_AS_USED, NULL);
3549 if (error) {
3550 pwarn("%s : internal error: marking allocated shouldn't fail\n",
3551 udf_node_path(node));
3552 return EINVAL;
3553 }
3554 (void) fpos;
3555 return 0;
3556 }
3557
3558
3559 static void
udf_node_pass3_repairdir(struct udf_fsck_node * node,union dscrptr * dscr)3560 udf_node_pass3_repairdir(struct udf_fsck_node *node, union dscrptr *dscr)
3561 {
3562 struct fileid_desc *fid, *last_empty_fid;
3563 struct udf_fsck_node *file_node;
3564 struct udf_fsck_fid_context fid_context;
3565 struct dirent dirent;
3566 struct charspec osta_charspec;
3567 int64_t fpos, rest_len;
3568 uint32_t fid_len;
3569 uint8_t *bpos;
3570 int parent_missing;
3571 int error;
3572
3573 pwarn("%s : fixing up directory\n", udf_node_path(node));
3574 assert(node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY);
3575
3576 rest_len = node->found.inf_len;
3577
3578 udf_osta_charset(&osta_charspec);
3579 bpos = node->directory;
3580 fpos = 0;
3581 parent_missing = (node->fsck_flags & FSCK_NODE_FLAG_PAR_NOT_FOUND)? 1:0;
3582
3583 last_empty_fid = NULL;
3584 while (rest_len > 0) {
3585 fid = (struct fileid_desc *) bpos;
3586 fid_len = udf_fidsize(fid);
3587
3588 /* get printable name */
3589 memset(&dirent, 0, sizeof(dirent));
3590 udf_to_unix_name(dirent.d_name, NAME_MAX,
3591 (char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi,
3592 &osta_charspec);
3593 dirent.d_namlen = strlen(dirent.d_name);
3594
3595 /* '..' has no name, so provide one */
3596 if (fid->file_char & UDF_FILE_CHAR_PAR) {
3597 strcpy(dirent.d_name, "..");
3598 }
3599
3600 /* only look up when not deleted */
3601 file_node = NULL;
3602 if ((fid->file_char & UDF_FILE_CHAR_DEL) == 0)
3603 file_node = udf_node_lookup(&fid->icb);
3604
3605 /* if found */
3606 if (file_node) {
3607 /* delete files which couldn't be found */
3608 if (file_node && (file_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)) {
3609 fid->file_char |= UDF_FILE_CHAR_DEL;
3610 memset(&fid->icb, 0, sizeof(struct long_ad));
3611 }
3612
3613 /* fix up FID UniqueID errors */
3614 if (fid->icb.longad_uniqueid != file_node->unique_id)
3615 fid->icb.longad_uniqueid = udf_rw64(file_node->unique_id);
3616 } else {
3617 /* just mark it deleted if not found */
3618 fid->file_char |= UDF_FILE_CHAR_DEL;
3619 }
3620
3621 if (fid->file_char & UDF_FILE_CHAR_DEL) {
3622 memset(&fid->icb, 0 , sizeof(struct long_ad));
3623 if (context.dscrver == 2) {
3624 uint8_t *cpos;
3625 /* compression IDs are preserved */
3626 cpos = (fid->data + udf_rw16(fid->l_iu));
3627 if (*cpos == 254)
3628 *cpos = 8;
3629 if (*cpos == 255)
3630 *cpos = 16;
3631 }
3632 }
3633
3634 fpos += fid_len;
3635 bpos += fid_len;
3636 rest_len -= fid_len;
3637 assert(rest_len >= 0);
3638 }
3639 if (parent_missing) {
3640 /* this should be valid or we're in LALA land */
3641 assert(last_empty_fid);
3642 pwarn("%s : implementation limit, can't fix up missing parent node yet!\n",
3643 udf_node_path(node));
3644 }
3645
3646 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3647
3648 fid_context.fid_offset = 0;
3649 fid_context.data_left = node->found.inf_len;
3650 error = udf_process_file(dscr, context.fids_part,
3651 &node->directory,
3652 AD_ADJUST_FIDS | AD_SAVE_FILE,
3653 &fid_context);
3654 if (error)
3655 pwarn("Failed to write out directory!\n");
3656 (void) fpos;
3657 }
3658
3659
3660 static void
udf_node_pass3_writeout_update(struct udf_fsck_node * node,union dscrptr * dscr)3661 udf_node_pass3_writeout_update(struct udf_fsck_node *node, union dscrptr *dscr)
3662 {
3663 struct file_entry *fe = NULL;
3664 struct extfile_entry *efe = NULL;
3665 int crc_len, error;
3666
3667 vat_writeout = 1;
3668 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3669 fe = (struct file_entry *) dscr;
3670 fe->inf_len = udf_rw64(node->declared.inf_len);
3671 fe->logblks_rec = udf_rw64(node->declared.logblks_rec);
3672 fe->link_cnt = udf_rw16(node->link_count);
3673 fe->unique_id = udf_rw64(node->unique_id);
3674 }
3675 if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
3676 efe = (struct extfile_entry *) dscr;
3677 efe->inf_len = udf_rw64(node->declared.inf_len);
3678 efe->obj_size = udf_rw64(node->declared.obj_size);
3679 efe->logblks_rec = udf_rw64(node->declared.logblks_rec);
3680 efe->link_cnt = udf_rw16(node->link_count);
3681 efe->unique_id = udf_rw64(node->unique_id);
3682 /* streamdir directly cleared in dscr */
3683 }
3684
3685 /* fixup CRC length (if needed) */
3686 crc_len = udf_tagsize(dscr, 1) - sizeof(struct desc_tag);
3687 dscr->tag.desc_crc_len = udf_rw16(crc_len);
3688
3689 pwarn("%s : updating node\n", udf_node_path(node));
3690 error = udf_write_dscr_virt(dscr, udf_rw32(node->loc.loc.lb_num),
3691 udf_rw16(node->loc.loc.part_num), 1);
3692 udf_shadow_VAT_in_use(&node->loc);
3693 if (error)
3694 pwarn("%s failed\n", __func__);
3695 }
3696
3697
3698 static void
udf_create_new_space_bitmaps_and_reset_freespace(void)3699 udf_create_new_space_bitmaps_and_reset_freespace(void)
3700 {
3701 struct space_bitmap_desc *sbd, *new_sbd;
3702 struct part_desc *part;
3703 struct part_hdr_desc *phd;
3704 uint32_t bitmap_len, bitmap_lb, bitmap_numlb;
3705 uint32_t cnt;
3706 int i, p, dscr_size;
3707 int error;
3708
3709 /* copy recorded freespace info and clear counters */
3710 for (i = 0; i < UDF_PARTITIONS; i++) {
3711 recorded_part_free[i] = context.part_free[i];
3712 context.part_free[i] = context.part_size[i];
3713 }
3714
3715 /* clone existing bitmaps */
3716 for (i = 0; i < UDF_PARTITIONS; i++) {
3717 sbd = context.part_unalloc_bits[i];
3718 recorded_part_unalloc_bits[i] = sbd;
3719 if (sbd == NULL)
3720 continue;
3721 dscr_size = udf_tagsize((union dscrptr *) sbd,
3722 context.sector_size);
3723 new_sbd = calloc(1, dscr_size);
3724 memcpy(new_sbd, sbd, sizeof(struct space_bitmap_desc)-1);
3725
3726 /* fill space with 0xff to indicate free */
3727 for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
3728 new_sbd->data[cnt] = 0xff;
3729
3730 context.part_unalloc_bits[i] = new_sbd;
3731 }
3732
3733 /* allocate the space bitmaps themselves (normally one) */
3734 for (i = 0; i < UDF_PARTITIONS; i++) {
3735 part = context.partitions[i];
3736 if (!part)
3737 continue;
3738
3739 phd = &part->pd_part_hdr;
3740 bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
3741 bitmap_lb = udf_rw32(phd->unalloc_space_bitmap.lb_num);
3742 if (bitmap_len == 0)
3743 continue;
3744
3745 bitmap_numlb = udf_bytes_to_sectors(bitmap_len);
3746 sbd = context.part_unalloc_bits[i];
3747 assert(sbd);
3748
3749 udf_mark_allocated(bitmap_lb, context.vtop[i], bitmap_numlb);
3750 }
3751
3752 /* special case for metadata partition */
3753 if (context.format_flags & FORMAT_META) {
3754 i = context.metadata_part;
3755 p = context.vtop[i];
3756 assert(context.vtop_tp[i] == UDF_VTOP_TYPE_META);
3757 error = udf_process_file((union dscrptr *) context.meta_file,
3758 p, NULL, AD_MARK_AS_USED, NULL);
3759 error = udf_process_file((union dscrptr *) context.meta_mirror,
3760 p, NULL, AD_MARK_AS_USED, NULL);
3761 if (context.meta_bitmap) {
3762 error = udf_process_file(
3763 (union dscrptr *) context.meta_bitmap,
3764 p, NULL, AD_MARK_AS_USED, NULL);
3765 assert(error == 0);
3766 }
3767 }
3768
3769 /* mark fsd allocation ! */
3770 udf_mark_allocated(udf_rw32(context.fileset_desc->tag.tag_loc),
3771 context.metadata_part, 1);
3772 }
3773
3774
3775 static void
udf_shadow_VAT_in_use(struct long_ad * loc)3776 udf_shadow_VAT_in_use(struct long_ad *loc)
3777 {
3778 uint32_t i;
3779 uint8_t *vat_pos, *shadow_vat_pos;
3780
3781 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3782 return;
3783
3784 i = udf_rw32(loc->loc.lb_num);
3785 vat_pos = context.vat_contents + context.vat_start + i*4;
3786 shadow_vat_pos = shadow_vat_contents + context.vat_start + i*4;
3787 /* keeping endian */
3788 *(uint32_t *) shadow_vat_pos = *(uint32_t *) vat_pos;
3789 }
3790
3791
3792 static void
udf_create_shadow_VAT(void)3793 udf_create_shadow_VAT(void)
3794 {
3795 struct long_ad fsd_loc;
3796 uint32_t vat_entries, i;
3797 uint8_t *vat_pos;
3798
3799 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3800 return;
3801
3802 shadow_vat_contents = calloc(1, context.vat_allocated);
3803 assert(shadow_vat_contents);
3804 memcpy(shadow_vat_contents, context.vat_contents, context.vat_size);
3805
3806 vat_entries = (context.vat_size - context.vat_start)/4;
3807 for (i = 0; i < vat_entries; i++) {
3808 vat_pos = shadow_vat_contents + context.vat_start + i*4;
3809 *(uint32_t *) vat_pos = udf_rw32(0xffffffff);
3810 }
3811
3812 /*
3813 * Record our FSD in this shadow VAT since its the only one outside
3814 * the nodes.
3815 */
3816 memset(&fsd_loc, 0, sizeof(struct long_ad));
3817 fsd_loc.loc.lb_num = context.fileset_desc->tag.tag_loc;
3818 udf_shadow_VAT_in_use(&fsd_loc);
3819 }
3820
3821
3822 static void
udf_check_shadow_VAT(void)3823 udf_check_shadow_VAT(void)
3824 {
3825 uint32_t vat_entries, i;
3826 uint8_t *vat_pos, *shadow_vat_pos;
3827 int difference = 0;
3828
3829 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3830 return;
3831
3832 vat_entries = (context.vat_size - context.vat_start)/4;
3833 for (i = 0; i < vat_entries; i++) {
3834 vat_pos = context.vat_contents + context.vat_start + i*4;
3835 shadow_vat_pos = shadow_vat_contents + context.vat_start + i*4;
3836 if (*(uint32_t *) vat_pos != *(uint32_t *) shadow_vat_pos) {
3837 difference++;
3838 }
3839 }
3840 memcpy(context.vat_contents, shadow_vat_contents, context.vat_size);
3841 if (difference) {
3842 if (!preen)
3843 printf("\t\t");
3844 pwarn("%d unused VAT entries cleaned\n", difference);
3845 vat_writeout = 1;
3846 }
3847 }
3848
3849
3850 static int
udf_check_directory_tree(void)3851 udf_check_directory_tree(void)
3852 {
3853 union dscrptr *dscr;
3854 struct udf_fsck_node *root_node, *sys_stream_node;
3855 struct udf_fsck_node *cur_node, *next_node;
3856 struct long_ad root_icb, sys_stream_icb;
3857 bool dont_repair;
3858 int entry, error;
3859
3860 assert(TAILQ_EMPTY(&fs_nodes));
3861
3862 /* (re)init queues and hash lists */
3863 TAILQ_INIT(&fs_nodes);
3864 TAILQ_INIT(&fsck_overlaps);
3865 for (int i = 0; i < HASH_HASHSIZE; i++)
3866 LIST_INIT(&fs_nodes_hash[i]);
3867
3868 /* create a new empty copy of the space bitmaps */
3869 udf_create_new_space_bitmaps_and_reset_freespace();
3870 udf_create_shadow_VAT();
3871
3872 /* start from the root */
3873 root_icb = context.fileset_desc->rootdir_icb;
3874 sys_stream_icb = context.fileset_desc->streamdir_icb;
3875
3876 root_node = udf_new_fsck_node(NULL, &root_icb, strdup(""));
3877 assert(root_node);
3878 TAILQ_INSERT_TAIL(&fs_nodes, root_node, next);
3879 entry = udf_calc_node_hash(&root_node->loc);
3880 LIST_INSERT_HEAD(&fs_nodes_hash[entry], root_node, next_hash);
3881
3882 sys_stream_node = NULL;
3883 if (sys_stream_icb.len) {
3884 sys_stream_node = udf_new_fsck_node(NULL, &sys_stream_icb, strdup("#"));
3885 assert(sys_stream_node);
3886 sys_stream_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_DIR;
3887
3888 TAILQ_INSERT_TAIL(&fs_nodes, sys_stream_node, next);
3889 entry = udf_calc_node_hash(&sys_stream_node->loc);
3890 LIST_INSERT_HEAD(&fs_nodes_hash[entry], sys_stream_node, next_hash);
3891 }
3892
3893 /* pass 1 */
3894 if (!preen)
3895 printf("\tPass 1, reading in directory trees\n");
3896
3897 context.unique_id = MAX(0x10, context.unique_id);
3898 TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3899 /* read in node */
3900 error = udf_read_node_dscr(cur_node, &dscr);
3901 if (!error)
3902 error = udf_extract_node_info(cur_node, dscr, 0);
3903 if (error) {
3904 pwarn("%s : invalid reference or bad descriptor, DELETING\n",
3905 udf_node_path(cur_node));
3906 udf_recursive_keep(cur_node);
3907 cur_node->fsck_flags |= FSCK_NODE_FLAG_NOTFOUND;
3908 if (cur_node->parent) {
3909 if (cur_node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3910 cur_node->parent->fsck_flags |=
3911 FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3912 else
3913 cur_node->parent->fsck_flags |=
3914 FSCK_NODE_FLAG_REPAIRDIR;
3915 ;
3916 }
3917 free(dscr);
3918 continue;
3919 }
3920
3921 if (print_info) {
3922 pwarn("Processing %s\n", udf_node_path(cur_node));
3923 print_info = 0;
3924 }
3925
3926 /* directory found in stream directory? */
3927 if (cur_node->parent &&
3928 (cur_node->parent->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR) &&
3929 (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY))
3930 {
3931 pwarn("%s : specification violation, directory in stream directory\n",
3932 udf_node_path(cur_node));
3933 if (ask(0, "Clear directory")) {
3934 udf_recursive_keep(cur_node);
3935 cur_node->fsck_flags |= FSCK_NODE_FLAG_NOTFOUND;
3936 cur_node->parent->fsck_flags |=
3937 FSCK_NODE_FLAG_REPAIRDIR;
3938 continue;
3939 }
3940 }
3941 error = udf_process_node_pass1(cur_node, dscr);
3942 free(dscr);
3943
3944 if (error)
3945 return error;
3946 }
3947
3948 /* pass 1b, if there is overlap, find matching pairs */
3949 dont_repair = false;
3950 if (!TAILQ_EMPTY(&fsck_overlaps)) {
3951 struct udf_fsck_overlap *overlap;
3952
3953 dont_repair = true;
3954 pwarn("*** Overlaps detected! rescanning tree for matching pairs ***\n");
3955 TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3956 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
3957 continue;
3958
3959 error = udf_read_node_dscr(cur_node, &dscr);
3960 /* should not fail differently */
3961
3962 if (print_info) {
3963 pwarn("Processing %s\n", udf_node_path(cur_node));
3964 print_info = 0;
3965 }
3966
3967 error = udf_process_file(
3968 dscr,
3969 udf_rw16(cur_node->loc.loc.part_num),
3970 NULL,
3971 AD_FIND_OVERLAP_PAIR,
3972 (void *) cur_node);
3973 /* shouldn't fail */
3974
3975 free(dscr);
3976 }
3977 TAILQ_FOREACH(overlap, &fsck_overlaps, next) {
3978 pwarn("%s :overlaps with %s\n",
3979 udf_node_path(overlap->node),
3980 udf_node_path(overlap->node2));
3981 }
3982 if (!preen)
3983 printf("\n");
3984 pwarn("*** The following files/directories need to be copied/evacuated:\n");
3985 TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3986 if (cur_node->fsck_flags & FSCK_NODE_FLAG_OVERLAP) {
3987 pwarn("%s : found OVERLAP, evacuate\n",
3988 udf_node_path(cur_node));
3989 }
3990 }
3991 }
3992 if (dont_repair) {
3993 if (!preen)
3994 printf("\n");
3995 pwarn("*** Skipping further repair, only updating free space map if needed\n");
3996 pwarn("*** After deep copying and/or evacuation of these files/directories,\n");
3997 pwarn("*** remove files/directories and re-run fsck_udf\n");
3998 error = udf_prepare_writing();
3999 if (error)
4000 return error;
4001
4002 udf_update_lvintd(UDF_INTEGRITY_OPEN);
4003 return 0;
4004 }
4005
4006 /* pass 2a, checking link counts, object sizes and count files/dirs */
4007 if (!preen)
4008 printf("\n\tPass 2, checking link counts, object sizes, stats and cleaning up\n");
4009
4010 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4011 /* not sane to process files/directories that are not found */
4012 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
4013 continue;
4014
4015 /* shadow VAT */
4016 udf_shadow_VAT_in_use(&cur_node->loc);
4017
4018 /* link counts */
4019 if (cur_node->found_link_count != cur_node->link_count) {
4020 pwarn("%s : link count incorrect; "
4021 "%u instead of declared %u : FIXED\n",
4022 udf_node_path(cur_node),
4023 cur_node->found_link_count, cur_node->link_count);
4024 cur_node->link_count = cur_node->found_link_count;
4025 udf_recursive_keep(cur_node);
4026 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4027 }
4028
4029 /* object sizes */
4030 if (cur_node->declared.obj_size != cur_node->found.obj_size) {
4031 pwarn("%s : recorded object size incorrect; "
4032 "%" PRIu64 " instead of declared %" PRIu64 "\n",
4033 udf_node_path(cur_node),
4034 cur_node->found.obj_size, cur_node->declared.obj_size);
4035 cur_node->declared.obj_size = cur_node->found.obj_size;
4036 udf_recursive_keep(cur_node);
4037 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4038 }
4039
4040 /* XXX TODO XXX times */
4041 /* XXX TODO XXX extended attributes location for UDF < 1.50 */
4042
4043 /* validity of UniqueID check */
4044 if (cur_node->parent) {
4045 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NEW_UNIQUE_ID) {
4046 pwarn("%s : assigning new UniqueID\n",
4047 udf_node_path(cur_node));
4048 cur_node->unique_id = udf_rw64(context.unique_id);
4049 udf_advance_uniqueid();
4050 udf_recursive_keep(cur_node);
4051 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4052 if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY)
4053 cur_node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
4054 cur_node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
4055 }
4056 if (cur_node->fsck_flags & FSCK_NODE_FLAG_COPY_PARENT_ID) {
4057 /* work already done but make note to operator */
4058 pwarn("%s : fixing stream UniqueID to match parent\n",
4059 udf_node_path(cur_node));
4060 }
4061 } else {
4062 if (cur_node->unique_id != 0) {
4063 pwarn("%s : bad UniqueID, zeroing\n",
4064 udf_node_path(cur_node));
4065 cur_node->unique_id = 0;
4066 cur_node->fsck_flags |=
4067 FSCK_NODE_FLAG_DIRTY | FSCK_NODE_FLAG_REPAIRDIR;
4068 }
4069 }
4070
4071 /* keep nodes in a repairing dir */
4072 if (cur_node->parent)
4073 if (cur_node->parent->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR)
4074 cur_node->fsck_flags |= FSCK_NODE_FLAG_KEEP;
4075
4076 /* stream directories and files in it are not included */
4077 if (!(cur_node->fsck_flags & FSCK_NODE_FLAG_STREAM)) {
4078 /* files / directories counting */
4079 int link_count = cur_node->found_link_count;
4080
4081 /* stream directories don't count as link ECMA 4/14.9.6 */
4082 if (cur_node->fsck_flags & FSCK_NODE_FLAG_HAS_STREAM_DIR)
4083 link_count--;
4084
4085 if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY)
4086 context.num_directories++;
4087 else
4088 context.num_files += link_count;
4089 ;
4090 }
4091 }
4092
4093 /* pass 2b, cleaning */
4094 open_integrity = 0;
4095 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4096 /* can we remove the node? (to save memory) */
4097 if (FSCK_NODE_FLAG_OK(cur_node->fsck_flags)) {
4098 TAILQ_REMOVE(&fs_nodes, cur_node, next);
4099 LIST_REMOVE(cur_node, next_hash);
4100 free(cur_node->directory);
4101 bzero(cur_node, sizeof(struct udf_fsck_node));
4102 free(cur_node);
4103 } else {
4104 /* else keep erroring node */
4105 open_integrity = 1;
4106 }
4107 }
4108
4109 if (!preen)
4110 printf("\n\tPreparing disc for writing\n");
4111 error = udf_prepare_writing();
4112 if (error)
4113 return error;
4114
4115 if (open_integrity)
4116 udf_update_lvintd(UDF_INTEGRITY_OPEN);
4117
4118 /* pass 3 */
4119 if (!preen)
4120 printf("\n\tPass 3, fix errors\n");
4121
4122 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4123 /* not sane to process files/directories that are not found */
4124 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
4125 continue;
4126
4127 /* only interested in bad nodes */
4128 if (FSCK_NODE_FLAG_OK(cur_node->fsck_flags))
4129 continue;
4130
4131 error = udf_read_node_dscr(cur_node, &dscr);
4132 /* should not fail differently */
4133
4134 /* repair directories */
4135 if (cur_node->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR)
4136 udf_node_pass3_repairdir(cur_node, dscr);
4137
4138 /* remove invalid stream directories */
4139 if (cur_node->fsck_flags & FSCK_NODE_FLAG_WIPE_STREAM_DIR) {
4140 assert(udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY);
4141 bzero(&dscr->efe.streamdir_icb, sizeof(struct long_ad));
4142 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4143 }
4144
4145 if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRTY)
4146 udf_node_pass3_writeout_update(cur_node, dscr);
4147 free(dscr);
4148 }
4149 udf_check_shadow_VAT();
4150
4151 return 0;
4152 }
4153
4154
4155 static void
udf_cleanup_after_check(void)4156 udf_cleanup_after_check(void)
4157 {
4158 struct udf_fsck_node *cur_node, *next_node;
4159
4160 /* XXX yes, there are some small memory leaks here */
4161
4162 /* clean old node info from previous checks */
4163 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4164 TAILQ_REMOVE(&fs_nodes, cur_node, next);
4165 LIST_REMOVE(cur_node, next_hash);
4166 free(cur_node->directory);
4167 free(cur_node);
4168 }
4169
4170 /* free partition related info */
4171 for (int i = 0; i < UDF_PARTITIONS; i++) {
4172 free(context.partitions[i]);
4173 free(context.part_unalloc_bits[i]);
4174 free(context.part_freed_bits[i]);
4175 }
4176
4177 /* only free potentional big blobs */
4178 free(context.vat_contents);
4179 free(context.lvint_history);
4180
4181 free(shadow_vat_contents);
4182 shadow_vat_contents = NULL;
4183 }
4184
4185
4186 static int
checkfilesys(char * given_dev)4187 checkfilesys(char *given_dev)
4188 {
4189 struct mmc_trackinfo ti;
4190 int open_flags;
4191 int error;
4192
4193 udf_init_create_context();
4194 context.app_name = "*NetBSD UDF";
4195 context.app_version_main = APP_VERSION_MAIN;
4196 context.app_version_sub = APP_VERSION_SUB;
4197 context.impl_name = IMPL_NAME;
4198
4199 emul_mmc_profile = -1; /* invalid->no emulation */
4200 emul_packetsize = 1; /* reasonable default */
4201 emul_sectorsize = 512; /* minimum allowed sector size */
4202 emul_size = 0; /* empty */
4203
4204 if (!preen)
4205 pwarn("** Checking UDF file system on %s\n", given_dev);
4206
4207 /* reset sticky flags */
4208 rdonly = rdonly_flag;
4209 undo_opening_session = 0; /* trying to undo opening of last crippled session */
4210 vat_writeout = 0; /* to write out the VAT anyway */
4211
4212 /* open disc device or emulated file */
4213 open_flags = rdonly ? O_RDONLY : O_RDWR;
4214 if (udf_opendisc(given_dev, open_flags)) {
4215 udf_closedisc();
4216 warnx("can't open %s", given_dev);
4217 return FSCK_EXIT_CHECK_FAILED;
4218 }
4219
4220 if (!preen)
4221 pwarn("** Phase 1 - discovering format from disc\n\n");
4222
4223 /* check if it is an empty disc or no disc in present */
4224 ti.tracknr = mmc_discinfo.first_track;
4225 error = udf_update_trackinfo(&ti);
4226 if (error || (ti.flags & MMC_TRACKINFO_BLANK)) {
4227 /* no use erroring out */
4228 pwarn("Empty disc\n");
4229 return FSCK_EXIT_OK;
4230 }
4231
4232 context.format_flags = 0;
4233 if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL)
4234 context.format_flags |= FORMAT_SEQUENTIAL;
4235
4236 if ((context.format_flags & FORMAT_SEQUENTIAL) &&
4237 ((mmc_discinfo.disc_state == MMC_STATE_CLOSED) ||
4238 (mmc_discinfo.disc_state == MMC_STATE_FULL))) {
4239 pwarn("Disc is closed or full, can't modify disc\n");
4240 rdonly = 1;
4241 }
4242
4243 if (target_session) {
4244 context.create_new_session = 1;
4245 if (target_session < 0)
4246 target_session += mmc_discinfo.num_sessions;
4247 } else {
4248 target_session = mmc_discinfo.num_sessions;
4249 if (mmc_discinfo.last_session_state == MMC_STATE_EMPTY)
4250 target_session--;
4251 }
4252
4253 error = udf_get_anchors();
4254 if (error) {
4255 udf_closedisc();
4256 pwarn("Failed to retrieve anchors; can't check file system\n");
4257 return FSCK_EXIT_CHECK_FAILED;
4258 }
4259
4260 udf_check_vrs9660();
4261
4262 /* get both VRS areas */
4263 error = udf_check_VDS_areas();
4264 if (error) {
4265 udf_closedisc();
4266 pwarn("Failure reading volume descriptors, disc might be toast\n");
4267 return FSCK_EXIT_CHECK_FAILED;
4268 }
4269
4270 if (udf_rw32(context.logvol_integrity->integrity_type) ==
4271 UDF_INTEGRITY_CLOSED) {
4272 if (!force) {
4273 pwarn("** File system is clean; not checking\n");
4274 return FSCK_EXIT_OK;
4275 }
4276 pwarn("** File system is already clean\n");
4277 if (!preen)
4278 pwarn("\n");
4279 } else {
4280 pwarn("** File system not closed properly\n");
4281 if (!preen)
4282 printf("\n");
4283 }
4284
4285 /*
4286 * Only now read in free/unallocated space bitmap. If it reads in fine
4287 * it doesn't mean its contents is valid though. Sets partition
4288 * lengths too.
4289 */
4290 error = udf_readin_partitions_free_space();
4291 if (error) {
4292 pwarn("Error during free space bitmap reading\n");
4293 udf_update_lvintd(UDF_INTEGRITY_OPEN);
4294 }
4295
4296 if (!preen)
4297 pwarn("** Phase 2 - walking directory tree\n");
4298
4299 udf_suspend_writing();
4300 error = udf_check_directory_tree();
4301 if (error) {
4302 if ((!rdonly) && ask(0, "Write out modifications made until now"))
4303 udf_allow_writing();
4304 else
4305 pwarn("** Aborting repair, not modifying disc\n");
4306 udf_closedisc();
4307 return FSCK_EXIT_CHECK_FAILED;
4308 }
4309
4310 if (!preen)
4311 pwarn("\n** Phase 3 - closing volume if needed\n\n");
4312
4313 /* XXX FAULT INJECTION POINT XXX */
4314 //udf_update_lvintd(UDF_INTEGRITY_OPEN);
4315
4316 if (error && rdonly) {
4317 pwarn("** Aborting repair, nothing written, disc marked read-only\n");
4318 } else {
4319 error = udf_close_volume();
4320 }
4321
4322 udf_closedisc();
4323
4324 if (error)
4325 return FSCK_EXIT_CHECK_FAILED;
4326 return FSCK_EXIT_OK;
4327 }
4328
4329
4330 static void
usage(void)4331 usage(void)
4332 {
4333 (void)fprintf(stderr, "Usage: %s [-fHnpSsy] file-system ... \n",
4334 getprogname());
4335 exit(FSCK_EXIT_USAGE);
4336 }
4337
4338
4339 static void
got_siginfo(int signo)4340 got_siginfo(int signo)
4341 {
4342 print_info = 1;
4343 }
4344
4345
4346 int
main(int argc,char ** argv)4347 main(int argc, char **argv)
4348 {
4349 int ret = FSCK_EXIT_OK, erg;
4350 int ch;
4351
4352 while ((ch = getopt(argc, argv, "ps:SynfH")) != -1) {
4353 switch (ch) {
4354 case 'H':
4355 heuristics = 1;
4356 break;
4357 case 'f':
4358 force = 1;
4359 break;
4360 case 'n':
4361 rdonly_flag = alwaysno = 1;
4362 alwaysyes = preen = 0;
4363 break;
4364 case 'y':
4365 alwaysyes = 1;
4366 alwaysno = preen = 0;
4367 break;
4368 case 'p':
4369 /* small automatic repairs */
4370 preen = 1;
4371 alwaysyes = alwaysno = 0;
4372 break;
4373 case 's':
4374 /* session number or relative session */
4375 target_session = atoi(optarg);
4376 break;
4377 case 'S': /* Search for older VATs */
4378 search_older_vat = 1;
4379 break;
4380
4381 default:
4382 usage();
4383 break;
4384 }
4385 }
4386 argc -= optind;
4387 argv += optind;
4388
4389 if (!argc)
4390 usage();
4391
4392 /* TODO SIGINT and SIGQUIT catchers */
4393 #if 0
4394 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
4395 (void) signal(SIGINT, catch);
4396 if (preen)
4397 (void) signal(SIGQUIT, catch);
4398 #endif
4399
4400 signal(SIGINFO, got_siginfo);
4401
4402 while (--argc >= 0) {
4403 setcdevname(*argv, preen);
4404 erg = checkfilesys(*argv++);
4405 if (erg > ret)
4406 ret = erg;
4407 if (!preen)
4408 printf("\n");
4409 udf_cleanup_after_check();
4410 }
4411
4412 return ret;
4413 }
4414
4415
4416 /*VARARGS*/
4417 static int __printflike(2, 3)
ask(int def,const char * fmt,...)4418 ask(int def, const char *fmt, ...)
4419 {
4420 va_list ap;
4421
4422 char prompt[256];
4423 int c;
4424
4425 va_start(ap, fmt);
4426 vsnprintf(prompt, sizeof(prompt), fmt, ap);
4427 va_end(ap);
4428 if (alwaysyes || rdonly) {
4429 pwarn("%s? %s\n", prompt, rdonly ? "no" : "yes");
4430 return !rdonly;
4431 }
4432 if (preen) {
4433 pwarn("%s? %s : (default)\n", prompt, def ? "yes" : "no");
4434 return def;
4435 }
4436
4437 do {
4438 pwarn("%s? [yn] ", prompt);
4439 fflush(stdout);
4440 c = getchar();
4441 while (c != '\n' && getchar() != '\n')
4442 if (feof(stdin))
4443 return 0;
4444 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
4445 return c == 'y' || c == 'Y';
4446 }
4447
4448
4449 /*VARARGS*/
4450 static int __printflike(2, 3)
ask_noauto(int def,const char * fmt,...)4451 ask_noauto(int def, const char *fmt, ...)
4452 {
4453 va_list ap;
4454
4455 char prompt[256];
4456 int c;
4457
4458 va_start(ap, fmt);
4459 vsnprintf(prompt, sizeof(prompt), fmt, ap);
4460 va_end(ap);
4461 #if 0
4462 if (preen) {
4463 pwarn("%s? %s : (default)\n", prompt, def ? "yes" : "no");
4464 return def;
4465 }
4466 #endif
4467
4468 do {
4469 pwarn("%s? [yn] ", prompt);
4470 fflush(stdout);
4471 c = getchar();
4472 while (c != '\n' && getchar() != '\n')
4473 if (feof(stdin))
4474 return 0;
4475 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
4476 return c == 'y' || c == 'Y';
4477 }
4478