1 /* $NetBSD: main.c,v 1.13 2022/04/25 15:37:14 reinoud Exp $ */
2
3 /*
4 * Copyright (c) 2022 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29
30 /*
31 * Note to reader:
32 *
33 * fsck_udf uses the common udf_core.c file with newfs and makefs. It does use
34 * some of the layout structure values but not all.
35 */
36
37
38 #include <sys/cdefs.h>
39 #ifndef lint
40 __RCSID("$NetBSD: main.c,v 1.13 2022/04/25 15:37:14 reinoud Exp $");
41 #endif /* not lint */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stddef.h>
46 #include <dirent.h>
47 #include <inttypes.h>
48 #include <stdint.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #include <util.h>
54 #include <time.h>
55 #include <tzfile.h>
56 #include <math.h>
57 #include <assert.h>
58 #include <err.h>
59
60 #if !HAVE_NBTOOL_CONFIG_H
61 #define _EXPOSE_MMC
62 #include <sys/cdio.h>
63 #else
64 #include "udf/cdio_mmc_structs.h"
65 #endif
66
67 #include <sys/ioctl.h>
68 #include <sys/stat.h>
69 #include <sys/types.h>
70 #include <sys/disklabel.h>
71 #include <sys/dkio.h>
72 #include <sys/param.h>
73 #include <sys/queue.h>
74
75 #include <fs/udf/ecma167-udf.h>
76 #include <fs/udf/udf_mount.h>
77
78 #include "fsutil.h"
79 #include "exitvalues.h"
80 #include "udf_core.h"
81
82 /* Identifying myself */
83 #define IMPL_NAME "*NetBSD fsck_udf 10.0"
84 #define APP_VERSION_MAIN 0
85 #define APP_VERSION_SUB 5
86
87 /* allocation walker actions */
88 #define AD_LOAD_FILE (1<<0)
89 #define AD_SAVE_FILE (1<<1)
90 #define AD_CHECK_FIDS (1<<2)
91 #define AD_ADJUST_FIDS (1<<3)
92 #define AD_GATHER_STATS (1<<4)
93 #define AD_CHECK_USED (1<<5)
94 #define AD_MARK_AS_USED (1<<6)
95 #define AD_FIND_OVERLAP_PAIR (1<<7)
96
97 struct udf_fsck_file_stats {
98 uint64_t inf_len;
99 uint64_t obj_size;
100 uint64_t logblks_rec;
101 };
102
103
104 struct udf_fsck_fid_context {
105 uint64_t fid_offset;
106 uint64_t data_left;
107 };
108
109
110 /* basic node administration for passes */
111 #define FSCK_NODE_FLAG_HARDLINK (1<< 0) /* hardlink, for accounting */
112 #define FSCK_NODE_FLAG_DIRECTORY (1<< 1) /* is a normal directory */
113 #define FSCK_NODE_FLAG_HAS_STREAM_DIR (1<< 2) /* has a stream directory */
114 #define FSCK_NODE_FLAG_STREAM_ENTRY (1<< 3) /* is a stream file */
115 #define FSCK_NODE_FLAG_STREAM_DIR (1<< 4) /* is a stream directory */
116 #define FSCK_NODE_FLAG_OK(f) (((f) >> 5) == 0)
117
118 #define FSCK_NODE_FLAG_KEEP (1<< 5) /* don't discard */
119 #define FSCK_NODE_FLAG_DIRTY (1<< 6) /* descriptor needs writeout */
120 #define FSCK_NODE_FLAG_REPAIRDIR (1<< 7) /* repair bad FID entries */
121 #define FSCK_NODE_FLAG_NEW_UNIQUE_ID (1<< 8) /* repair bad FID entries */
122 #define FSCK_NODE_FLAG_COPY_PARENT_ID (1<< 9) /* repair bad FID entries */
123 #define FSCK_NODE_FLAG_WIPE_STREAM_DIR (1<<10) /* wipe stream directory */
124 #define FSCK_NODE_FLAG_NOTFOUND (1<<11) /* FID pointing to garbage */
125 #define FSCK_NODE_FLAG_PAR_NOT_FOUND (1<<12) /* parent node not found! */
126 #define FSCK_NODE_FLAG_OVERLAP (1<<13) /* node has overlaps */
127
128 #define FSCK_NODE_FLAG_STREAM (FSCK_NODE_FLAG_STREAM_ENTRY | FSCK_NODE_FLAG_STREAM_DIR)
129
130
131 #define HASH_HASHBITS 5
132 #define HASH_HASHSIZE (1 << HASH_HASHBITS)
133 #define HASH_HASHMASK (HASH_HASHSIZE - 1)
134
135 /* fsck node for accounting checks */
136 struct udf_fsck_node {
137 struct udf_fsck_node *parent;
138 char *fname;
139
140 struct long_ad loc;
141 struct long_ad streamdir_loc;
142 int fsck_flags;
143
144 int link_count;
145 int found_link_count;
146 uint64_t unique_id;
147
148 struct udf_fsck_file_stats declared;
149 struct udf_fsck_file_stats found;
150
151 uint8_t *directory; /* directory contents */
152
153 LIST_ENTRY(udf_fsck_node) next_hash;
154 TAILQ_ENTRY(udf_fsck_node) next;
155 };
156 TAILQ_HEAD(udf_fsck_node_list, udf_fsck_node) fs_nodes;
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 }
2804 if (!error2) {
2805 /* retrieve data from VDS 2 */
2806 udf_read_vds_extent(vds2_buf, vds2_size);
2807 context.vds_buf = vds2_buf;
2808 context.vds_size = vds2_size;
2809 free(vds1_buf);
2810 }
2811 /* check if all is correct and complete */
2812 error = udf_process_vds();
2813 if (error)
2814 return error;
2815
2816 /* TODO check if both area's are logically the same */
2817 error = 0;
2818 if (!error1 && error2) {
2819 /* first OK, second faulty */
2820 pwarn("Backup volume descriptor missing or damaged\n");
2821 if (context.format_flags & FORMAT_SEQUENTIAL) {
2822 pwarn("Can't fixup backup volume descriptor on "
2823 "SEQUENTIAL media\n");
2824 } else if (ask(1, "Fixup backup volume descriptor")) {
2825 error = udf_copy_VDS_area(vds2_buf, vds1_buf);
2826 pwarn("\n");
2827 }
2828 }
2829 if (error1 && !error2) {
2830 /* second OK, first faulty */
2831 pwarn("Primary volume descriptor missing or damaged\n");
2832 if (context.format_flags & FORMAT_SEQUENTIAL) {
2833 pwarn("Can't fix up primary volume descriptor on "
2834 "SEQUENTIAL media\n");
2835 } else if (ask(1, "Fix up primary volume descriptor")) {
2836 error = udf_copy_VDS_area(vds1_buf, vds2_buf);
2837 }
2838 }
2839 if (error)
2840 pwarn("copying VDS areas failed!\n");
2841 if (!preen)
2842 printf("\n");
2843
2844 return error;
2845 }
2846
2847 /* --------------------------------------------------------------------- */
2848
2849 static int
udf_prepare_writing(void)2850 udf_prepare_writing(void)
2851 {
2852 union dscrptr *zero_dscr, *dscr;
2853 struct mmc_trackinfo ti;
2854 uint32_t first_lba, loc;
2855 int sector_size = context.sector_size;
2856 int error;
2857
2858 error = udf_prepare_disc();
2859 if (error) {
2860 pwarn("*** Preparing disc for writing failed!\n");
2861 return error;
2862 }
2863
2864 /* if we are not on sequential media, we're done */
2865 if ((context.format_flags & FORMAT_VAT) == 0)
2866 return 0;
2867
2868 /* if the disc is full, we drop back to read only */
2869 if (mmc_discinfo.disc_state == MMC_STATE_FULL)
2870 rdonly = 1;
2871 if (rdonly)
2872 return 0;
2873
2874 /* check if we need to open the last track */
2875 ti.tracknr = mmc_discinfo.last_track_last_session;
2876 error = udf_update_trackinfo(&ti);
2877 if (error)
2878 return error;
2879 if (!(ti.flags & MMC_TRACKINFO_BLANK) &&
2880 (ti.flags & MMC_TRACKINFO_NWA_VALID)) {
2881 /*
2882 * Not closed; translate next_writable to a position relative to our
2883 * backing partition
2884 */
2885 context.alloc_pos[context.data_part] = ti.next_writable -
2886 udf_rw32(context.partitions[context.data_part]->start_loc);
2887 wrtrack_skew = ti.next_writable % layout.blockingnr;
2888 return 0;
2889 }
2890 assert(ti.flags & MMC_TRACKINFO_NWA_VALID);
2891
2892 /* just in case */
2893 udf_suspend_writing();
2894
2895 /* 'add' a new track */
2896 udf_update_discinfo();
2897 memset(&context.last_ti, 0, sizeof(struct mmc_trackinfo));
2898 context.last_ti.tracknr = mmc_discinfo.first_track_last_session;
2899 (void) udf_update_trackinfo(&context.last_ti);
2900
2901 assert(mmc_discinfo.last_session_state == MMC_STATE_EMPTY);
2902 first_lba = context.last_ti.track_start;
2903 wrtrack_skew = context.last_ti.track_start % layout.blockingnr;
2904
2905 /*
2906 * location of iso9660 vrs is defined as first sector AFTER 32kb,
2907 * minimum `sector size' 2048
2908 */
2909 layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size)
2910 + first_lba;
2911
2912 /* anchor starts at specified offset in sectors */
2913 layout.anchors[0] = first_lba + 256;
2914
2915 /* ready for appending, write preamble, we are using overwrite here! */
2916 if ((zero_dscr = calloc(1, context.sector_size)) == NULL)
2917 return ENOMEM;
2918 loc = first_lba;
2919 for (; loc < first_lba + 256; loc++) {
2920 if ((error = udf_write_sector(zero_dscr, loc))) {
2921 free(zero_dscr);
2922 return error;
2923 }
2924 }
2925 free(zero_dscr);
2926
2927 /* write new ISO9660 volume recognition sequence */
2928 if ((error = udf_write_iso9660_vrs())) {
2929 pwarn("internal error: can't write iso966 VRS in new session!\n");
2930 rdonly = 1;
2931 return error;
2932 }
2933
2934 /* write out our old anchor, VDS spaces will be reused */
2935 assert(context.anchors[0]);
2936 dscr = (union dscrptr *) context.anchors[0];
2937 loc = layout.anchors[0];
2938 if ((error = udf_write_dscr_phys(dscr, loc, 1))) {
2939 pwarn("internal error: can't write anchor in new session!\n");
2940 rdonly = 1;
2941 return error;
2942 }
2943
2944 context.alloc_pos[context.data_part] = first_lba + 257 -
2945 udf_rw32(context.partitions[context.data_part]->start_loc);
2946
2947 return 0;
2948 }
2949
2950
2951 static int
udf_close_volume_vat(void)2952 udf_close_volume_vat(void)
2953 {
2954 int integrity_type;
2955
2956 /* only write out when its open */
2957 integrity_type = udf_rw32(context.logvol_integrity->integrity_type);
2958 if (integrity_type == UDF_INTEGRITY_CLOSED)
2959 return 0;
2960
2961 if (!preen)
2962 printf("\n");
2963 if (!ask(1, "Write out modifications"))
2964 return 0;
2965
2966 /* writeout our VAT contents */
2967 udf_allow_writing();
2968 return udf_writeout_VAT();
2969 }
2970
2971
2972 static int
udf_close_volume(void)2973 udf_close_volume(void)
2974 {
2975 struct part_desc *part;
2976 struct part_hdr_desc *phd;
2977 struct logvol_int_desc *lvid;
2978 struct udf_logvol_info *lvinfo;
2979 struct logvol_desc *logvol;
2980 uint32_t bitmap_len, bitmap_lb, bitmap_numlb;
2981 int i, equal, error;
2982
2983 lvid = context.logvol_integrity;
2984 logvol = context.logical_vol;
2985 lvinfo = context.logvol_info;
2986 assert(lvid);
2987 assert(logvol);
2988 assert(lvinfo);
2989
2990 /* check our highest unique id */
2991 if (context.unique_id > udf_rw64(lvid->lvint_next_unique_id)) {
2992 pwarn("Last unique id updated from %" PRIi64 " to %" PRIi64 " : FIXED\n",
2993 udf_rw64(lvid->lvint_next_unique_id),
2994 context.unique_id);
2995 open_integrity = 1;
2996 }
2997
2998 /* check file/directory counts */
2999 if (context.num_files != udf_rw32(lvinfo->num_files)) {
3000 pwarn("Number of files corrected from %d to %d : FIXED\n",
3001 udf_rw32(lvinfo->num_files),
3002 context.num_files);
3003 open_integrity = 1;
3004 }
3005 if (context.num_directories != udf_rw32(lvinfo->num_directories)) {
3006 pwarn("Number of directories corrected from %d to %d : FIXED\n",
3007 udf_rw32(lvinfo->num_directories),
3008 context.num_directories);
3009 open_integrity = 1;
3010 }
3011
3012 if (vat_writeout)
3013 open_integrity = 1;
3014
3015 if (open_integrity)
3016 udf_update_lvintd(UDF_INTEGRITY_OPEN);
3017
3018 if (context.format_flags & FORMAT_VAT)
3019 return udf_close_volume_vat();
3020
3021 /* adjust free space accounting! */
3022 for (i = 0; i < UDF_PARTITIONS; i++) {
3023 part = context.partitions[i];
3024 if (!part)
3025 continue;
3026 phd = &part->pd_part_hdr;
3027 bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
3028 bitmap_lb = udf_rw32(phd->unalloc_space_bitmap.lb_num);
3029
3030 if (bitmap_len == 0) {
3031 error = 0;
3032 continue;
3033 }
3034
3035 equal = memcmp( recorded_part_unalloc_bits[i],
3036 context.part_unalloc_bits[i],
3037 bitmap_len) == 0;
3038
3039 if (!equal || (context.part_free[i] != recorded_part_free[i])) {
3040 if (!equal)
3041 pwarn("Calculated bitmap for partition %d not equal "
3042 "to recorded one : FIXED\n", i);
3043 pwarn("Free space on partition %d corrected "
3044 "from %d to %d blocks : FIXED\n", i,
3045 recorded_part_free[i],
3046 context.part_free[i]);
3047
3048 /* write out updated free space map */
3049 pwarn("Updating unallocated bitmap for partition\n");
3050 if (!preen)
3051 printf("Writing free space map "
3052 "for partition %d\n", i);
3053 error = 0;
3054 if (context.vtop_tp[i] == UDF_VTOP_TYPE_META) {
3055 if (context.meta_bitmap) {
3056 assert(i == context.metadata_part);
3057 error = udf_process_file(
3058 (union dscrptr *) context.meta_bitmap,
3059 context.data_part,
3060 (uint8_t **) &(context.part_unalloc_bits[i]),
3061 AD_SAVE_FILE, NULL);
3062 }
3063 } else {
3064 bitmap_numlb = udf_bytes_to_sectors(bitmap_len);
3065 error = udf_write_dscr_virt(
3066 (union dscrptr *) context.part_unalloc_bits[i],
3067 bitmap_lb,
3068 i,
3069 bitmap_numlb);
3070 }
3071 if (error)
3072 pwarn("Updating unallocated bitmap failed, "
3073 "continuing\n");
3074 udf_update_lvintd(UDF_INTEGRITY_OPEN);
3075 }
3076 }
3077
3078 /* write out the logical volume integrity sequence */
3079 error = udf_writeout_lvint();
3080
3081 return error;
3082 }
3083
3084 /* --------------------------------------------------------------------- */
3085
3086 /*
3087 * Main part of file system checking.
3088 *
3089 * Walk the entire directory tree and check all link counts and rebuild the
3090 * free space map (if present) on the go.
3091 */
3092
3093 static struct udf_fsck_node *
udf_new_fsck_node(struct udf_fsck_node * parent,struct long_ad * loc,char * fname)3094 udf_new_fsck_node(struct udf_fsck_node *parent, struct long_ad *loc, char *fname)
3095 {
3096 struct udf_fsck_node *this;
3097 this = calloc(1, sizeof(struct udf_fsck_node));
3098 if (!this)
3099 return NULL;
3100
3101 this->parent = parent;
3102 this->fname = strdup(fname);
3103 this->loc = *loc;
3104 this->fsck_flags = 0;
3105
3106 this->link_count = 0;
3107 this->found_link_count = 0;
3108
3109 return this;
3110 }
3111
3112
3113 static void
udf_node_path_piece(char * pathname,struct udf_fsck_node * node)3114 udf_node_path_piece(char *pathname, struct udf_fsck_node *node)
3115 {
3116 if (node->parent) {
3117 udf_node_path_piece(pathname, node->parent);
3118 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3119 strcat(pathname, "");
3120 else
3121 strcat(pathname, "/");
3122 }
3123 strcat(pathname, node->fname);
3124 }
3125
3126
3127 static char *
udf_node_path(struct udf_fsck_node * node)3128 udf_node_path(struct udf_fsck_node *node)
3129 {
3130 static char pathname[MAXPATHLEN + 10];
3131
3132 strcpy(pathname, "`");
3133 if (node->parent)
3134 udf_node_path_piece(pathname, node);
3135 else
3136 strcat(pathname, "/");
3137 strcat(pathname, "'");
3138
3139 return pathname;
3140 }
3141
3142
3143 static void
udf_recursive_keep(struct udf_fsck_node * node)3144 udf_recursive_keep(struct udf_fsck_node *node)
3145 {
3146 while (node->parent) {
3147 node = node->parent;
3148 node->fsck_flags |= FSCK_NODE_FLAG_KEEP;
3149 }
3150 }
3151
3152
3153 static int
udf_quick_check_fids(struct udf_fsck_node * node,union dscrptr * dscr)3154 udf_quick_check_fids(struct udf_fsck_node *node, union dscrptr *dscr)
3155 {
3156 struct udf_fsck_fid_context fid_context;
3157 int error;
3158
3159 fid_context.fid_offset = 0;
3160 fid_context.data_left = node->found.inf_len;
3161 error = udf_process_file(dscr, context.fids_part,
3162 &node->directory,
3163 AD_CHECK_FIDS,
3164 &fid_context);
3165
3166 return error;
3167 }
3168
3169
3170 /* read descriptor at node's location */
3171 static int
udf_read_node_dscr(struct udf_fsck_node * node,union dscrptr ** dscrptr)3172 udf_read_node_dscr(struct udf_fsck_node *node, union dscrptr **dscrptr)
3173 {
3174 *dscrptr = NULL;
3175 return udf_read_dscr_virt(
3176 udf_rw32(node->loc.loc.lb_num),
3177 udf_rw16(node->loc.loc.part_num),
3178 dscrptr);
3179 }
3180
3181
3182 static int
udf_extract_node_info(struct udf_fsck_node * node,union dscrptr * dscr,int be_quiet)3183 udf_extract_node_info(struct udf_fsck_node *node, union dscrptr *dscr,
3184 int be_quiet)
3185 {
3186 struct icb_tag *icb = NULL;
3187 struct file_entry *fe = NULL;
3188 struct extfile_entry *efe = NULL;
3189 int ad_type, error;
3190
3191 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3192 fe = (struct file_entry *) dscr;
3193 icb = &fe->icbtag;
3194 node->declared.inf_len = udf_rw64(fe->inf_len);
3195 node->declared.obj_size = udf_rw64(fe->inf_len);
3196 node->declared.logblks_rec = udf_rw64(fe->logblks_rec);
3197 node->link_count = udf_rw16(fe->link_cnt);
3198 node->unique_id = udf_rw64(fe->unique_id);
3199
3200 /* XXX FAULT INJECTION POINT XXX */
3201 //if (fe->unique_id == 33) { return ENOENT;}
3202
3203 }
3204 if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
3205 efe = (struct extfile_entry *) dscr;
3206 icb = &efe->icbtag;
3207 node->declared.inf_len = udf_rw64(efe->inf_len);
3208 node->declared.obj_size = udf_rw64(efe->obj_size);
3209 node->declared.logblks_rec = udf_rw64(efe->logblks_rec);
3210 node->link_count = udf_rw16(efe->link_cnt);
3211 node->unique_id = udf_rw64(efe->unique_id);
3212 node->streamdir_loc = efe->streamdir_icb;
3213 if (node->streamdir_loc.len)
3214 node->fsck_flags |= FSCK_NODE_FLAG_HAS_STREAM_DIR;
3215
3216 /* XXX FAULT INJECTION POINT XXX */
3217 //if (efe->unique_id == 0x891) { return ENOENT;}
3218
3219 }
3220
3221 if (!fe && !efe) {
3222 //printf("NOT REFERENCING AN FE/EFE!\n");
3223 return ENOENT;
3224 }
3225
3226 if (node->unique_id >= context.unique_id)
3227 context.unique_id = node->unique_id+1;
3228
3229 ad_type = udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
3230 if ((ad_type != UDF_ICB_INTERN_ALLOC) &&
3231 (ad_type != UDF_ICB_SHORT_ALLOC) &&
3232 (ad_type != UDF_ICB_LONG_ALLOC)) {
3233 pwarn("%s : unknown allocation type\n",
3234 udf_node_path(node));
3235 return EINVAL;
3236 }
3237
3238 bzero(&node->found, sizeof(node->found));
3239 error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3240 AD_GATHER_STATS, (void *) &node->found);
3241
3242 switch (icb->file_type) {
3243 case UDF_ICB_FILETYPE_RANDOMACCESS :
3244 case UDF_ICB_FILETYPE_BLOCKDEVICE :
3245 case UDF_ICB_FILETYPE_CHARDEVICE :
3246 case UDF_ICB_FILETYPE_FIFO :
3247 case UDF_ICB_FILETYPE_SOCKET :
3248 case UDF_ICB_FILETYPE_SYMLINK :
3249 case UDF_ICB_FILETYPE_REALTIME :
3250 break;
3251 default:
3252 /* unknown or unsupported file type, TODO clearing? */
3253 free(dscr);
3254 pwarn("%s : specification violation, unknown file type %d\n",
3255 udf_node_path(node), icb->file_type);
3256 return ENOENT;
3257 case UDF_ICB_FILETYPE_STREAMDIR :
3258 case UDF_ICB_FILETYPE_DIRECTORY :
3259 /* read in the directory contents */
3260 error = udf_readin_file(dscr, udf_rw16(node->loc.loc.part_num),
3261 &node->directory, NULL);
3262
3263 /* XXX FAULT INJECTION POINT XXX */
3264 //if (dscr->efe.unique_id == 109) node->directory[125] = 0xff;
3265 //if (dscr->efe.unique_id == 310) memset(node->directory+1024, 0, 300);
3266
3267 if (error && !be_quiet) {
3268 pwarn("%s : directory has read errors\n",
3269 udf_node_path(node));
3270 if (ask(0, "Directory could be fixed or cleared. "
3271 "Wipe defective directory")) {
3272 return ENOENT;
3273 }
3274 udf_recursive_keep(node);
3275 node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3276 }
3277 node->fsck_flags |= FSCK_NODE_FLAG_DIRECTORY;
3278 error = udf_quick_check_fids(node, dscr);
3279 if (error) {
3280 if (!(node->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR))
3281 pwarn("%s : directory file entries need repair\n",
3282 udf_node_path(node));
3283 udf_recursive_keep(node);
3284 node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3285 }
3286 }
3287
3288 /* XXX FAULT INJECTION POINT XXX */
3289 //if (fe->unique_id == 0) node->link_count++;
3290 //if (efe->unique_id == 0) node->link_count++;
3291 //if (efe->unique_id == 772) { node->declared.inf_len += 205; node->declared.obj_size -= 0; }
3292
3293 return 0;
3294 }
3295
3296
3297 static void
udf_fixup_lengths_pass1(struct udf_fsck_node * node,union dscrptr * dscr)3298 udf_fixup_lengths_pass1(struct udf_fsck_node *node, union dscrptr *dscr)
3299 {
3300 int64_t diff;
3301
3302 /* file length check */
3303 diff = node->found.inf_len - node->declared.inf_len;
3304 if (diff) {
3305 pwarn("%s : recorded information length incorrect: "
3306 "%" PRIu64 " instead of declared %" PRIu64 "\n",
3307 udf_node_path(node),
3308 node->found.inf_len, node->declared.inf_len);
3309 node->declared.inf_len = node->found.inf_len;
3310 udf_recursive_keep(node);
3311 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3312 }
3313
3314 /* recorded logical blocks count check */
3315 diff = node->found.logblks_rec - node->declared.logblks_rec;
3316 if (diff) {
3317 pwarn("%s : logical blocks recorded incorrect: "
3318 "%" PRIu64 " instead of declared %" PRIu64 ", fixing\n",
3319 udf_node_path(node),
3320 node->found.logblks_rec, node->declared.logblks_rec);
3321 node->declared.logblks_rec = node->found.logblks_rec;
3322 udf_recursive_keep(node);
3323 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3324 }
3325
3326 /* tally object sizes for streamdirs */
3327 node->found.obj_size = node->found.inf_len;
3328 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_ENTRY) {
3329 assert(node->parent); /* streamdir itself */
3330 if (node->parent->parent)
3331 node->parent->parent->found.obj_size +=
3332 node->found.inf_len;
3333 }
3334
3335 /* check descriptor CRC length */
3336 if (udf_rw16(dscr->tag.desc_crc_len) !=
3337 udf_tagsize(dscr, 1) - sizeof(struct desc_tag)) {
3338 pwarn("%s : node file descriptor CRC length mismatch; "
3339 "%d declared, %zu\n",
3340 udf_node_path(node), udf_rw16(dscr->tag.desc_crc_len),
3341 udf_tagsize(dscr, 1) - sizeof(struct desc_tag));
3342 udf_recursive_keep(node);
3343 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3344 }
3345 }
3346
3347
3348 static void
udf_node_pass1_add_entry(struct udf_fsck_node * node,struct fileid_desc * fid,struct dirent * dirent)3349 udf_node_pass1_add_entry(struct udf_fsck_node *node,
3350 struct fileid_desc *fid, struct dirent *dirent)
3351 {
3352 struct udf_fsck_node *leaf_node;
3353 int entry;
3354
3355 /* skip deleted FID entries */
3356 if (fid->file_char & UDF_FILE_CHAR_DEL)
3357 return;
3358
3359 if (udf_rw32(fid->icb.loc.lb_num) == 0) {
3360 pwarn("%s : FileID entry `%s` has invalid location\n",
3361 udf_node_path(node), dirent->d_name);
3362 udf_recursive_keep(node);
3363 if (node->parent)
3364 node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3365 return;
3366 }
3367
3368 /* increase parent link count */
3369 if (fid->file_char & UDF_FILE_CHAR_PAR) {
3370 if (node->parent)
3371 node->parent->found_link_count++;
3372 return;
3373 }
3374
3375 /* lookup if we already know this node */
3376 leaf_node = udf_node_lookup(&fid->icb);
3377 if (leaf_node) {
3378 /* got a hard link! */
3379 leaf_node->found_link_count++;
3380 return;
3381 }
3382
3383 /* create new node */
3384 leaf_node = udf_new_fsck_node(
3385 node, &fid->icb, dirent->d_name);
3386 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3387 leaf_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_ENTRY;
3388
3389 TAILQ_INSERT_TAIL(&fs_nodes, leaf_node, next);
3390 entry = udf_calc_node_hash(&fid->icb);
3391 LIST_INSERT_HEAD(&fs_nodes_hash[entry], leaf_node, next_hash);
3392 }
3393
3394
3395 static void
udf_node_pass1_add_streamdir_entry(struct udf_fsck_node * node)3396 udf_node_pass1_add_streamdir_entry(struct udf_fsck_node *node)
3397 {
3398 struct udf_fsck_node *leaf_node;
3399 int entry;
3400
3401 /* check for recursion */
3402 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM) {
3403 /* recursive streams are not allowed by spec */
3404 pwarn("%s : specification violation, recursive stream dir\n",
3405 udf_node_path(node));
3406 udf_recursive_keep(node);
3407 node->fsck_flags |= FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3408 return;
3409 }
3410
3411 /* lookup if we already know this node */
3412 leaf_node = udf_node_lookup(&node->streamdir_loc);
3413 if (leaf_node) {
3414 pwarn("%s : specification violation, hardlinked streamdir\n",
3415 udf_node_path(leaf_node));
3416 udf_recursive_keep(node);
3417 node->fsck_flags |= FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3418 return;
3419 }
3420
3421 /* create new node */
3422 leaf_node = udf_new_fsck_node(
3423 node, &node->streamdir_loc, strdup(""));
3424 leaf_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_DIR;
3425
3426 /* streamdirs have link count 0 : ECMA 4/14.9.6 */
3427 leaf_node->found_link_count--;
3428
3429 /* insert in to lists */
3430 TAILQ_INSERT_TAIL(&fs_nodes, leaf_node, next);
3431 entry = udf_calc_node_hash(&node->streamdir_loc);
3432 LIST_INSERT_HEAD(&fs_nodes_hash[entry], leaf_node, next_hash);
3433 }
3434
3435
3436 static int
udf_process_node_pass1(struct udf_fsck_node * node,union dscrptr * dscr)3437 udf_process_node_pass1(struct udf_fsck_node *node, union dscrptr *dscr)
3438 {
3439 struct fileid_desc *fid;
3440 struct dirent dirent;
3441 struct charspec osta_charspec;
3442 int64_t fpos, new_length, rest_len;
3443 uint32_t fid_len;
3444 uint8_t *bpos;
3445 int isdir;
3446 int error;
3447
3448 isdir = node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY;
3449
3450 /* keep link count */
3451 node->found_link_count++;
3452
3453 if (isdir) {
3454 assert(node->directory);
3455 udf_rebuild_fid_stream(node, &new_length);
3456 node->found.inf_len = new_length;
3457 rest_len = new_length;
3458 }
3459
3460 udf_fixup_lengths_pass1(node, dscr);
3461
3462 /* check UniqueID */
3463 if (node->parent) {
3464 if (node->fsck_flags & FSCK_NODE_FLAG_STREAM) {
3465
3466 /* XXX FAULT INJECTION POINT XXX */
3467 //node->unique_id = 0xdeadbeefcafe;
3468
3469 if (node->unique_id != node->parent->unique_id) {
3470 pwarn("%s : stream file/dir UniqueID mismatch "
3471 "with parent\n",
3472 udf_node_path(node));
3473 /* do the work here prematurely for our siblings */
3474 udf_recursive_keep(node);
3475 node->unique_id = node->parent->unique_id;
3476 node->fsck_flags |= FSCK_NODE_FLAG_COPY_PARENT_ID |
3477 FSCK_NODE_FLAG_DIRTY;
3478 assert(node->parent);
3479 node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3480 }
3481 } else if (node->unique_id < 16) {
3482 pwarn("%s : file has bad UniqueID\n",
3483 udf_node_path(node));
3484 udf_recursive_keep(node);
3485 node->fsck_flags |= FSCK_NODE_FLAG_NEW_UNIQUE_ID;
3486 assert(node->parent);
3487 node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3488 }
3489 } else {
3490 /* rootdir */
3491 if (node->unique_id != 0) {
3492 pwarn("%s : has bad UniqueID, has to be zero\n",
3493 udf_node_path(node));
3494 udf_recursive_keep(node);
3495 node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
3496 }
3497 }
3498
3499 /* add streamdir if present */
3500 if (node->fsck_flags & FSCK_NODE_FLAG_HAS_STREAM_DIR)
3501 udf_node_pass1_add_streamdir_entry(node);
3502
3503 /* add all children */
3504 if (isdir) {
3505 node->fsck_flags |= FSCK_NODE_FLAG_PAR_NOT_FOUND;
3506 rest_len = node->found.inf_len;
3507
3508 /* walk through all our FIDs in the directory stream */
3509 bpos = node->directory;
3510 fpos = 0;
3511 while (rest_len > 0) {
3512 fid = (struct fileid_desc *) bpos;
3513 fid_len = udf_fidsize(fid);
3514
3515 /* get printable name */
3516 memset(&dirent, 0, sizeof(dirent));
3517 udf_osta_charset(&osta_charspec);
3518 udf_to_unix_name(dirent.d_name, NAME_MAX,
3519 (char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi,
3520 &osta_charspec);
3521 dirent.d_namlen = strlen(dirent.d_name);
3522
3523 /* '..' has no name, so provide one */
3524 if (fid->file_char & UDF_FILE_CHAR_PAR) {
3525 strcpy(dirent.d_name, "..");
3526 node->fsck_flags &= ~FSCK_NODE_FLAG_PAR_NOT_FOUND;
3527 }
3528
3529 udf_node_pass1_add_entry(node, fid, &dirent);
3530
3531 fpos += fid_len;
3532 bpos += fid_len;
3533 rest_len -= fid_len;
3534 }
3535 }
3536
3537 error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3538 AD_CHECK_USED, node);
3539 if (error) {
3540 pwarn("%s : internal error: checking for being allocated shouldn't fail\n",
3541 udf_node_path(node));
3542 return EINVAL;
3543 }
3544 /* file/directory is OK and referenced as its size won't change */
3545 error = udf_process_file(dscr, udf_rw16(node->loc.loc.part_num), NULL,
3546 AD_MARK_AS_USED, NULL);
3547 if (error) {
3548 pwarn("%s : internal error: marking allocated shouldn't fail\n",
3549 udf_node_path(node));
3550 return EINVAL;
3551 }
3552 (void) fpos;
3553 return 0;
3554 }
3555
3556
3557 static void
udf_node_pass3_repairdir(struct udf_fsck_node * node,union dscrptr * dscr)3558 udf_node_pass3_repairdir(struct udf_fsck_node *node, union dscrptr *dscr)
3559 {
3560 struct fileid_desc *fid, *last_empty_fid;
3561 struct udf_fsck_node *file_node;
3562 struct udf_fsck_fid_context fid_context;
3563 struct dirent dirent;
3564 struct charspec osta_charspec;
3565 int64_t fpos, rest_len;
3566 uint32_t fid_len;
3567 uint8_t *bpos;
3568 int parent_missing;
3569 int error;
3570
3571 pwarn("%s : fixing up directory\n", udf_node_path(node));
3572 assert(node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY);
3573
3574 rest_len = node->found.inf_len;
3575
3576 udf_osta_charset(&osta_charspec);
3577 bpos = node->directory;
3578 fpos = 0;
3579 parent_missing = (node->fsck_flags & FSCK_NODE_FLAG_PAR_NOT_FOUND)? 1:0;
3580
3581 last_empty_fid = NULL;
3582 while (rest_len > 0) {
3583 fid = (struct fileid_desc *) bpos;
3584 fid_len = udf_fidsize(fid);
3585
3586 /* get printable name */
3587 memset(&dirent, 0, sizeof(dirent));
3588 udf_to_unix_name(dirent.d_name, NAME_MAX,
3589 (char *) fid->data + udf_rw16(fid->l_iu), fid->l_fi,
3590 &osta_charspec);
3591 dirent.d_namlen = strlen(dirent.d_name);
3592
3593 /* '..' has no name, so provide one */
3594 if (fid->file_char & UDF_FILE_CHAR_PAR) {
3595 strcpy(dirent.d_name, "..");
3596 }
3597
3598 /* only look up when not deleted */
3599 file_node = NULL;
3600 if ((fid->file_char & UDF_FILE_CHAR_DEL) == 0)
3601 file_node = udf_node_lookup(&fid->icb);
3602
3603 /* if found */
3604 if (file_node) {
3605 /* delete files which couldn't be found */
3606 if (file_node && (file_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)) {
3607 fid->file_char |= UDF_FILE_CHAR_DEL;
3608 memset(&fid->icb, 0, sizeof(struct long_ad));
3609 }
3610
3611 /* fix up FID UniqueID errors */
3612 if (fid->icb.longad_uniqueid != file_node->unique_id)
3613 fid->icb.longad_uniqueid = udf_rw64(file_node->unique_id);
3614 } else {
3615 /* just mark it deleted if not found */
3616 fid->file_char |= UDF_FILE_CHAR_DEL;
3617 }
3618
3619 if (fid->file_char & UDF_FILE_CHAR_DEL) {
3620 memset(&fid->icb, 0 , sizeof(struct long_ad));
3621 if (context.dscrver == 2) {
3622 uint8_t *cpos;
3623 /* compression IDs are preserved */
3624 cpos = (fid->data + udf_rw16(fid->l_iu));
3625 if (*cpos == 254)
3626 *cpos = 8;
3627 if (*cpos == 255)
3628 *cpos = 16;
3629 }
3630 }
3631
3632 fpos += fid_len;
3633 bpos += fid_len;
3634 rest_len -= fid_len;
3635 assert(rest_len >= 0);
3636 }
3637 if (parent_missing) {
3638 /* this should be valid or we're in LALA land */
3639 assert(last_empty_fid);
3640 pwarn("%s : implementation limit, can't fix up missing parent node yet!\n",
3641 udf_node_path(node));
3642 }
3643
3644 node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
3645
3646 fid_context.fid_offset = 0;
3647 fid_context.data_left = node->found.inf_len;
3648 error = udf_process_file(dscr, context.fids_part,
3649 &node->directory,
3650 AD_ADJUST_FIDS | AD_SAVE_FILE,
3651 &fid_context);
3652 if (error)
3653 pwarn("Failed to write out directory!\n");
3654 (void) fpos;
3655 }
3656
3657
3658 static void
udf_node_pass3_writeout_update(struct udf_fsck_node * node,union dscrptr * dscr)3659 udf_node_pass3_writeout_update(struct udf_fsck_node *node, union dscrptr *dscr)
3660 {
3661 struct file_entry *fe = NULL;
3662 struct extfile_entry *efe = NULL;
3663 int crc_len, error;
3664
3665 vat_writeout = 1;
3666 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
3667 fe = (struct file_entry *) dscr;
3668 fe->inf_len = udf_rw64(node->declared.inf_len);
3669 fe->logblks_rec = udf_rw64(node->declared.logblks_rec);
3670 fe->link_cnt = udf_rw16(node->link_count);
3671 fe->unique_id = udf_rw64(node->unique_id);
3672 }
3673 if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
3674 efe = (struct extfile_entry *) dscr;
3675 efe->inf_len = udf_rw64(node->declared.inf_len);
3676 efe->obj_size = udf_rw64(node->declared.obj_size);
3677 efe->logblks_rec = udf_rw64(node->declared.logblks_rec);
3678 efe->link_cnt = udf_rw16(node->link_count);
3679 efe->unique_id = udf_rw64(node->unique_id);
3680 /* streamdir directly cleared in dscr */
3681 }
3682
3683 /* fixup CRC length (if needed) */
3684 crc_len = udf_tagsize(dscr, 1) - sizeof(struct desc_tag);
3685 dscr->tag.desc_crc_len = udf_rw16(crc_len);
3686
3687 pwarn("%s : updating node\n", udf_node_path(node));
3688 error = udf_write_dscr_virt(dscr, udf_rw32(node->loc.loc.lb_num),
3689 udf_rw16(node->loc.loc.part_num), 1);
3690 udf_shadow_VAT_in_use(&node->loc);
3691 if (error)
3692 pwarn("%s failed\n", __func__);
3693 }
3694
3695
3696 static void
udf_create_new_space_bitmaps_and_reset_freespace(void)3697 udf_create_new_space_bitmaps_and_reset_freespace(void)
3698 {
3699 struct space_bitmap_desc *sbd, *new_sbd;
3700 struct part_desc *part;
3701 struct part_hdr_desc *phd;
3702 uint32_t bitmap_len, bitmap_lb, bitmap_numlb;
3703 uint32_t cnt;
3704 int i, p, dscr_size;
3705 int error;
3706
3707 /* copy recorded freespace info and clear counters */
3708 for (i = 0; i < UDF_PARTITIONS; i++) {
3709 recorded_part_free[i] = context.part_free[i];
3710 context.part_free[i] = context.part_size[i];
3711 }
3712
3713 /* clone existing bitmaps */
3714 for (i = 0; i < UDF_PARTITIONS; i++) {
3715 sbd = context.part_unalloc_bits[i];
3716 recorded_part_unalloc_bits[i] = sbd;
3717 if (sbd == NULL)
3718 continue;
3719 dscr_size = udf_tagsize((union dscrptr *) sbd,
3720 context.sector_size);
3721 new_sbd = calloc(1, dscr_size);
3722 memcpy(new_sbd, sbd, sizeof(struct space_bitmap_desc)-1);
3723
3724 /* fill space with 0xff to indicate free */
3725 for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++)
3726 new_sbd->data[cnt] = 0xff;
3727
3728 context.part_unalloc_bits[i] = new_sbd;
3729 }
3730
3731 /* allocate the space bitmaps themselves (normally one) */
3732 for (i = 0; i < UDF_PARTITIONS; i++) {
3733 part = context.partitions[i];
3734 if (!part)
3735 continue;
3736
3737 phd = &part->pd_part_hdr;
3738 bitmap_len = udf_rw32(phd->unalloc_space_bitmap.len);
3739 bitmap_lb = udf_rw32(phd->unalloc_space_bitmap.lb_num);
3740 if (bitmap_len == 0)
3741 continue;
3742
3743 bitmap_numlb = udf_bytes_to_sectors(bitmap_len);
3744 sbd = context.part_unalloc_bits[i];
3745 assert(sbd);
3746
3747 udf_mark_allocated(bitmap_lb, context.vtop[i], bitmap_numlb);
3748 }
3749
3750 /* special case for metadata partition */
3751 if (context.format_flags & FORMAT_META) {
3752 i = context.metadata_part;
3753 p = context.vtop[i];
3754 assert(context.vtop_tp[i] == UDF_VTOP_TYPE_META);
3755 error = udf_process_file((union dscrptr *) context.meta_file,
3756 p, NULL, AD_MARK_AS_USED, NULL);
3757 error = udf_process_file((union dscrptr *) context.meta_mirror,
3758 p, NULL, AD_MARK_AS_USED, NULL);
3759 if (context.meta_bitmap) {
3760 error = udf_process_file(
3761 (union dscrptr *) context.meta_bitmap,
3762 p, NULL, AD_MARK_AS_USED, NULL);
3763 assert(error == 0);
3764 }
3765 }
3766
3767 /* mark fsd allocation ! */
3768 udf_mark_allocated(udf_rw32(context.fileset_desc->tag.tag_loc),
3769 context.metadata_part, 1);
3770 }
3771
3772
3773 static void
udf_shadow_VAT_in_use(struct long_ad * loc)3774 udf_shadow_VAT_in_use(struct long_ad *loc)
3775 {
3776 uint32_t i;
3777 uint8_t *vat_pos, *shadow_vat_pos;
3778
3779 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3780 return;
3781
3782 i = udf_rw32(loc->loc.lb_num);
3783 vat_pos = context.vat_contents + context.vat_start + i*4;
3784 shadow_vat_pos = shadow_vat_contents + context.vat_start + i*4;
3785 /* keeping endian */
3786 *(uint32_t *) shadow_vat_pos = *(uint32_t *) vat_pos;
3787 }
3788
3789
3790 static void
udf_create_shadow_VAT(void)3791 udf_create_shadow_VAT(void)
3792 {
3793 struct long_ad fsd_loc;
3794 uint32_t vat_entries, i;
3795 uint8_t *vat_pos;
3796
3797 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3798 return;
3799
3800 shadow_vat_contents = calloc(1, context.vat_allocated);
3801 assert(shadow_vat_contents);
3802 memcpy(shadow_vat_contents, context.vat_contents, context.vat_size);
3803
3804 vat_entries = (context.vat_size - context.vat_start)/4;
3805 for (i = 0; i < vat_entries; i++) {
3806 vat_pos = shadow_vat_contents + context.vat_start + i*4;
3807 *(uint32_t *) vat_pos = udf_rw32(0xffffffff);
3808 }
3809
3810 /*
3811 * Record our FSD in this shadow VAT since its the only one outside
3812 * the nodes.
3813 */
3814 memset(&fsd_loc, 0, sizeof(struct long_ad));
3815 fsd_loc.loc.lb_num = context.fileset_desc->tag.tag_loc;
3816 udf_shadow_VAT_in_use(&fsd_loc);
3817 }
3818
3819
3820 static void
udf_check_shadow_VAT(void)3821 udf_check_shadow_VAT(void)
3822 {
3823 uint32_t vat_entries, i;
3824 uint8_t *vat_pos, *shadow_vat_pos;
3825 int difference = 0;
3826
3827 if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
3828 return;
3829
3830 vat_entries = (context.vat_size - context.vat_start)/4;
3831 for (i = 0; i < vat_entries; i++) {
3832 vat_pos = context.vat_contents + context.vat_start + i*4;
3833 shadow_vat_pos = shadow_vat_contents + context.vat_start + i*4;
3834 if (*(uint32_t *) vat_pos != *(uint32_t *) shadow_vat_pos) {
3835 difference++;
3836 }
3837 }
3838 memcpy(context.vat_contents, shadow_vat_contents, context.vat_size);
3839 if (difference) {
3840 if (!preen)
3841 printf("\t\t");
3842 pwarn("%d unused VAT entries cleaned\n", difference);
3843 vat_writeout = 1;
3844 }
3845 }
3846
3847
3848 static int
udf_check_directory_tree(void)3849 udf_check_directory_tree(void)
3850 {
3851 union dscrptr *dscr;
3852 struct udf_fsck_node *root_node, *sys_stream_node;
3853 struct udf_fsck_node *cur_node, *next_node;
3854 struct long_ad root_icb, sys_stream_icb;
3855 bool dont_repair;
3856 int entry, error;
3857
3858 assert(TAILQ_EMPTY(&fs_nodes));
3859
3860 /* (re)init queues and hash lists */
3861 TAILQ_INIT(&fs_nodes);
3862 TAILQ_INIT(&fsck_overlaps);
3863 for (int i = 0; i < HASH_HASHSIZE; i++)
3864 LIST_INIT(&fs_nodes_hash[i]);
3865
3866 /* create a new empty copy of the space bitmaps */
3867 udf_create_new_space_bitmaps_and_reset_freespace();
3868 udf_create_shadow_VAT();
3869
3870 /* start from the root */
3871 root_icb = context.fileset_desc->rootdir_icb;
3872 sys_stream_icb = context.fileset_desc->streamdir_icb;
3873
3874 root_node = udf_new_fsck_node(NULL, &root_icb, strdup(""));
3875 assert(root_node);
3876 TAILQ_INSERT_TAIL(&fs_nodes, root_node, next);
3877 entry = udf_calc_node_hash(&root_node->loc);
3878 LIST_INSERT_HEAD(&fs_nodes_hash[entry], root_node, next_hash);
3879
3880 sys_stream_node = NULL;
3881 if (sys_stream_icb.len) {
3882 sys_stream_node = udf_new_fsck_node(NULL, &sys_stream_icb, strdup("#"));
3883 assert(sys_stream_node);
3884 sys_stream_node->fsck_flags |= FSCK_NODE_FLAG_STREAM_DIR;
3885
3886 TAILQ_INSERT_TAIL(&fs_nodes, sys_stream_node, next);
3887 entry = udf_calc_node_hash(&sys_stream_node->loc);
3888 LIST_INSERT_HEAD(&fs_nodes_hash[entry], sys_stream_node, next_hash);
3889 }
3890
3891 /* pass 1 */
3892 if (!preen)
3893 printf("\tPass 1, reading in directory trees\n");
3894
3895 context.unique_id = MAX(0x10, context.unique_id);
3896 TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3897 /* read in node */
3898 error = udf_read_node_dscr(cur_node, &dscr);
3899 if (!error)
3900 error = udf_extract_node_info(cur_node, dscr, 0);
3901 if (error) {
3902 pwarn("%s : invalid reference or bad descriptor, DELETING\n",
3903 udf_node_path(cur_node));
3904 udf_recursive_keep(cur_node);
3905 cur_node->fsck_flags |= FSCK_NODE_FLAG_NOTFOUND;
3906 if (cur_node->parent) {
3907 if (cur_node->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR)
3908 cur_node->parent->fsck_flags |=
3909 FSCK_NODE_FLAG_WIPE_STREAM_DIR;
3910 else
3911 cur_node->parent->fsck_flags |=
3912 FSCK_NODE_FLAG_REPAIRDIR;
3913 ;
3914 }
3915 free(dscr);
3916 continue;
3917 }
3918
3919 if (print_info) {
3920 pwarn("Processing %s\n", udf_node_path(cur_node));
3921 print_info = 0;
3922 }
3923
3924 /* directory found in stream directory? */
3925 if (cur_node->parent &&
3926 (cur_node->parent->fsck_flags & FSCK_NODE_FLAG_STREAM_DIR) &&
3927 (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY))
3928 {
3929 pwarn("%s : specification violation, directory in stream directory\n",
3930 udf_node_path(cur_node));
3931 if (ask(0, "Clear directory")) {
3932 udf_recursive_keep(cur_node);
3933 cur_node->fsck_flags |= FSCK_NODE_FLAG_NOTFOUND;
3934 cur_node->parent->fsck_flags |=
3935 FSCK_NODE_FLAG_REPAIRDIR;
3936 continue;
3937 }
3938 }
3939 error = udf_process_node_pass1(cur_node, dscr);
3940 free(dscr);
3941
3942 if (error)
3943 return error;
3944 }
3945
3946 /* pass 1b, if there is overlap, find matching pairs */
3947 dont_repair = false;
3948 if (!TAILQ_EMPTY(&fsck_overlaps)) {
3949 struct udf_fsck_overlap *overlap;
3950
3951 dont_repair = true;
3952 pwarn("*** Overlaps detected! rescanning tree for matching pairs ***\n");
3953 TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3954 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
3955 continue;
3956
3957 error = udf_read_node_dscr(cur_node, &dscr);
3958 /* should not fail differently */
3959
3960 if (print_info) {
3961 pwarn("Processing %s\n", udf_node_path(cur_node));
3962 print_info = 0;
3963 }
3964
3965 error = udf_process_file(
3966 dscr,
3967 udf_rw16(cur_node->loc.loc.part_num),
3968 NULL,
3969 AD_FIND_OVERLAP_PAIR,
3970 (void *) cur_node);
3971 /* shouldn't fail */
3972
3973 free(dscr);
3974 }
3975 TAILQ_FOREACH(overlap, &fsck_overlaps, next) {
3976 pwarn("%s :overlaps with %s\n",
3977 udf_node_path(overlap->node),
3978 udf_node_path(overlap->node2));
3979 }
3980 if (!preen)
3981 printf("\n");
3982 pwarn("*** The following files/directories need to be copied/evacuated:\n");
3983 TAILQ_FOREACH(cur_node, &fs_nodes, next) {
3984 if (cur_node->fsck_flags & FSCK_NODE_FLAG_OVERLAP) {
3985 pwarn("%s : found OVERLAP, evacuate\n",
3986 udf_node_path(cur_node));
3987 }
3988 }
3989 }
3990 if (dont_repair) {
3991 if (!preen)
3992 printf("\n");
3993 pwarn("*** Skipping further repair, only updating free space map if needed\n");
3994 pwarn("*** After deep copying and/or evacuation of these files/directories,\n");
3995 pwarn("*** remove files/directories and re-run fsck_udf\n");
3996 error = udf_prepare_writing();
3997 if (error)
3998 return error;
3999
4000 udf_update_lvintd(UDF_INTEGRITY_OPEN);
4001 return 0;
4002 }
4003
4004 /* pass 2a, checking link counts, object sizes and count files/dirs */
4005 if (!preen)
4006 printf("\n\tPass 2, checking link counts, object sizes, stats and cleaning up\n");
4007
4008 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4009 /* not sane to process files/directories that are not found */
4010 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
4011 continue;
4012
4013 /* shadow VAT */
4014 udf_shadow_VAT_in_use(&cur_node->loc);
4015
4016 /* link counts */
4017 if (cur_node->found_link_count != cur_node->link_count) {
4018 pwarn("%s : link count incorrect; "
4019 "%u instead of declared %u : FIXED\n",
4020 udf_node_path(cur_node),
4021 cur_node->found_link_count, cur_node->link_count);
4022 cur_node->link_count = cur_node->found_link_count;
4023 udf_recursive_keep(cur_node);
4024 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4025 }
4026
4027 /* object sizes */
4028 if (cur_node->declared.obj_size != cur_node->found.obj_size) {
4029 pwarn("%s : recorded object size incorrect; "
4030 "%" PRIu64 " instead of declared %" PRIu64 "\n",
4031 udf_node_path(cur_node),
4032 cur_node->found.obj_size, cur_node->declared.obj_size);
4033 cur_node->declared.obj_size = cur_node->found.obj_size;
4034 udf_recursive_keep(cur_node);
4035 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4036 }
4037
4038 /* XXX TODO XXX times */
4039 /* XXX TODO XXX extended attributes location for UDF < 1.50 */
4040
4041 /* validity of UniqueID check */
4042 if (cur_node->parent) {
4043 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NEW_UNIQUE_ID) {
4044 pwarn("%s : assigning new UniqueID\n",
4045 udf_node_path(cur_node));
4046 cur_node->unique_id = udf_rw64(context.unique_id);
4047 udf_advance_uniqueid();
4048 udf_recursive_keep(cur_node);
4049 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4050 if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY)
4051 cur_node->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
4052 cur_node->parent->fsck_flags |= FSCK_NODE_FLAG_REPAIRDIR;
4053 }
4054 if (cur_node->fsck_flags & FSCK_NODE_FLAG_COPY_PARENT_ID) {
4055 /* work already done but make note to operator */
4056 pwarn("%s : fixing stream UniqueID to match parent\n",
4057 udf_node_path(cur_node));
4058 }
4059 } else {
4060 if (cur_node->unique_id != 0) {
4061 pwarn("%s : bad UniqueID, zeroing\n",
4062 udf_node_path(cur_node));
4063 cur_node->unique_id = 0;
4064 cur_node->fsck_flags |=
4065 FSCK_NODE_FLAG_DIRTY | FSCK_NODE_FLAG_REPAIRDIR;
4066 }
4067 }
4068
4069 /* keep nodes in a repairing dir */
4070 if (cur_node->parent)
4071 if (cur_node->parent->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR)
4072 cur_node->fsck_flags |= FSCK_NODE_FLAG_KEEP;
4073
4074 /* stream directories and files in it are not included */
4075 if (!(cur_node->fsck_flags & FSCK_NODE_FLAG_STREAM)) {
4076 /* files / directories counting */
4077 int link_count = cur_node->found_link_count;
4078
4079 /* stream directories don't count as link ECMA 4/14.9.6 */
4080 if (cur_node->fsck_flags & FSCK_NODE_FLAG_HAS_STREAM_DIR)
4081 link_count--;
4082
4083 if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRECTORY)
4084 context.num_directories++;
4085 else
4086 context.num_files += link_count;
4087 ;
4088 }
4089 }
4090
4091 /* pass 2b, cleaning */
4092 open_integrity = 0;
4093 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4094 /* can we remove the node? (to save memory) */
4095 if (FSCK_NODE_FLAG_OK(cur_node->fsck_flags)) {
4096 TAILQ_REMOVE(&fs_nodes, cur_node, next);
4097 LIST_REMOVE(cur_node, next_hash);
4098 free(cur_node->directory);
4099 bzero(cur_node, sizeof(struct udf_fsck_node));
4100 free(cur_node);
4101 } else {
4102 /* else keep erroring node */
4103 open_integrity = 1;
4104 }
4105 }
4106
4107 if (!preen)
4108 printf("\n\tPreparing disc for writing\n");
4109 error = udf_prepare_writing();
4110 if (error)
4111 return error;
4112
4113 if (open_integrity)
4114 udf_update_lvintd(UDF_INTEGRITY_OPEN);
4115
4116 /* pass 3 */
4117 if (!preen)
4118 printf("\n\tPass 3, fix errors\n");
4119
4120 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4121 /* not sane to process files/directories that are not found */
4122 if (cur_node->fsck_flags & FSCK_NODE_FLAG_NOTFOUND)
4123 continue;
4124
4125 /* only interested in bad nodes */
4126 if (FSCK_NODE_FLAG_OK(cur_node->fsck_flags))
4127 continue;
4128
4129 error = udf_read_node_dscr(cur_node, &dscr);
4130 /* should not fail differently */
4131
4132 /* repair directories */
4133 if (cur_node->fsck_flags & FSCK_NODE_FLAG_REPAIRDIR)
4134 udf_node_pass3_repairdir(cur_node, dscr);
4135
4136 /* remove invalid stream directories */
4137 if (cur_node->fsck_flags & FSCK_NODE_FLAG_WIPE_STREAM_DIR) {
4138 assert(udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY);
4139 bzero(&dscr->efe.streamdir_icb, sizeof(struct long_ad));
4140 cur_node->fsck_flags |= FSCK_NODE_FLAG_DIRTY;
4141 }
4142
4143 if (cur_node->fsck_flags & FSCK_NODE_FLAG_DIRTY)
4144 udf_node_pass3_writeout_update(cur_node, dscr);
4145 free(dscr);
4146 }
4147 udf_check_shadow_VAT();
4148
4149 return 0;
4150 }
4151
4152
4153 static void
udf_cleanup_after_check(void)4154 udf_cleanup_after_check(void)
4155 {
4156 struct udf_fsck_node *cur_node, *next_node;
4157
4158 /* XXX yes, there are some small memory leaks here */
4159
4160 /* clean old node info from previous checks */
4161 TAILQ_FOREACH_SAFE(cur_node, &fs_nodes, next, next_node) {
4162 TAILQ_REMOVE(&fs_nodes, cur_node, next);
4163 LIST_REMOVE(cur_node, next_hash);
4164 free(cur_node->directory);
4165 free(cur_node);
4166 }
4167
4168 /* free partition related info */
4169 for (int i = 0; i < UDF_PARTITIONS; i++) {
4170 free(context.partitions[i]);
4171 free(context.part_unalloc_bits[i]);
4172 free(context.part_freed_bits[i]);
4173 }
4174
4175 /* only free potentional big blobs */
4176 free(context.vat_contents);
4177 free(context.lvint_history);
4178
4179 free(shadow_vat_contents);
4180 shadow_vat_contents = NULL;
4181 }
4182
4183
4184 static int
checkfilesys(char * given_dev)4185 checkfilesys(char *given_dev)
4186 {
4187 struct mmc_trackinfo ti;
4188 int open_flags;
4189 int error;
4190
4191 udf_init_create_context();
4192 context.app_name = "*NetBSD UDF";
4193 context.app_version_main = APP_VERSION_MAIN;
4194 context.app_version_sub = APP_VERSION_SUB;
4195 context.impl_name = IMPL_NAME;
4196
4197 emul_mmc_profile = -1; /* invalid->no emulation */
4198 emul_packetsize = 1; /* reasonable default */
4199 emul_sectorsize = 512; /* minimum allowed sector size */
4200 emul_size = 0; /* empty */
4201
4202 if (!preen)
4203 pwarn("** Checking UDF file system on %s\n", given_dev);
4204
4205 /* reset sticky flags */
4206 rdonly = rdonly_flag;
4207 undo_opening_session = 0; /* trying to undo opening of last crippled session */
4208 vat_writeout = 0; /* to write out the VAT anyway */
4209
4210 /* open disc device or emulated file */
4211 open_flags = rdonly ? O_RDONLY : O_RDWR;
4212 if (udf_opendisc(given_dev, open_flags)) {
4213 udf_closedisc();
4214 warnx("can't open %s", given_dev);
4215 return FSCK_EXIT_CHECK_FAILED;
4216 }
4217
4218 if (!preen)
4219 pwarn("** Phase 1 - discovering format from disc\n\n");
4220
4221 /* check if it is an empty disc or no disc in present */
4222 ti.tracknr = mmc_discinfo.first_track;
4223 error = udf_update_trackinfo(&ti);
4224 if (error || (ti.flags & MMC_TRACKINFO_BLANK)) {
4225 /* no use erroring out */
4226 pwarn("Empty disc\n");
4227 return FSCK_EXIT_OK;
4228 }
4229
4230 context.format_flags = 0;
4231 if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL)
4232 context.format_flags |= FORMAT_SEQUENTIAL;
4233
4234 if ((context.format_flags & FORMAT_SEQUENTIAL) &&
4235 ((mmc_discinfo.disc_state == MMC_STATE_CLOSED) ||
4236 (mmc_discinfo.disc_state == MMC_STATE_FULL))) {
4237 pwarn("Disc is closed or full, can't modify disc\n");
4238 rdonly = 1;
4239 }
4240
4241 if (target_session) {
4242 context.create_new_session = 1;
4243 if (target_session < 0)
4244 target_session += mmc_discinfo.num_sessions;
4245 } else {
4246 target_session = mmc_discinfo.num_sessions;
4247 if (mmc_discinfo.last_session_state == MMC_STATE_EMPTY)
4248 target_session--;
4249 }
4250
4251 error = udf_get_anchors();
4252 if (error) {
4253 udf_closedisc();
4254 pwarn("Failed to retrieve anchors; can't check file system\n");
4255 return FSCK_EXIT_CHECK_FAILED;
4256 }
4257
4258 udf_check_vrs9660();
4259
4260 /* get both VRS areas */
4261 error = udf_check_VDS_areas();
4262 if (error) {
4263 udf_closedisc();
4264 pwarn("Failure reading volume descriptors, disc might be toast\n");
4265 return FSCK_EXIT_CHECK_FAILED;
4266 }
4267
4268 if (udf_rw32(context.logvol_integrity->integrity_type) ==
4269 UDF_INTEGRITY_CLOSED) {
4270 if (!force) {
4271 pwarn("** File system is clean; not checking\n");
4272 return FSCK_EXIT_OK;
4273 }
4274 pwarn("** File system is already clean\n");
4275 if (!preen)
4276 pwarn("\n");
4277 } else {
4278 pwarn("** File system not closed properly\n");
4279 if (!preen)
4280 printf("\n");
4281 }
4282
4283 /*
4284 * Only now read in free/unallocated space bitmap. If it reads in fine
4285 * it doesn't mean its contents is valid though. Sets partition
4286 * lengths too.
4287 */
4288 error = udf_readin_partitions_free_space();
4289 if (error) {
4290 pwarn("Error during free space bitmap reading\n");
4291 udf_update_lvintd(UDF_INTEGRITY_OPEN);
4292 }
4293
4294 if (!preen)
4295 pwarn("** Phase 2 - walking directory tree\n");
4296
4297 udf_suspend_writing();
4298 error = udf_check_directory_tree();
4299 if (error) {
4300 if ((!rdonly) && ask(0, "Write out modifications made until now"))
4301 udf_allow_writing();
4302 else
4303 pwarn("** Aborting repair, not modifying disc\n");
4304 udf_closedisc();
4305 return FSCK_EXIT_CHECK_FAILED;
4306 }
4307
4308 if (!preen)
4309 pwarn("\n** Phase 3 - closing volume if needed\n\n");
4310
4311 /* XXX FAULT INJECTION POINT XXX */
4312 //udf_update_lvintd(UDF_INTEGRITY_OPEN);
4313
4314 if (error && rdonly) {
4315 pwarn("** Aborting repair, nothing written, disc marked read-only\n");
4316 } else {
4317 error = udf_close_volume();
4318 }
4319
4320 udf_closedisc();
4321
4322 if (error)
4323 return FSCK_EXIT_CHECK_FAILED;
4324 return FSCK_EXIT_OK;
4325 }
4326
4327
4328 static void
usage(void)4329 usage(void)
4330 {
4331 (void)fprintf(stderr, "Usage: %s [-fHnpSsy] file-system ... \n",
4332 getprogname());
4333 exit(FSCK_EXIT_USAGE);
4334 }
4335
4336
4337 static void
got_siginfo(int signo)4338 got_siginfo(int signo)
4339 {
4340 print_info = 1;
4341 }
4342
4343
4344 int
main(int argc,char ** argv)4345 main(int argc, char **argv)
4346 {
4347 int ret = FSCK_EXIT_OK, erg;
4348 int ch;
4349
4350 while ((ch = getopt(argc, argv, "ps:SynfH")) != -1) {
4351 switch (ch) {
4352 case 'H':
4353 heuristics = 1;
4354 break;
4355 case 'f':
4356 force = 1;
4357 break;
4358 case 'n':
4359 rdonly_flag = alwaysno = 1;
4360 alwaysyes = preen = 0;
4361 break;
4362 case 'y':
4363 alwaysyes = 1;
4364 alwaysno = preen = 0;
4365 break;
4366 case 'p':
4367 /* small automatic repairs */
4368 preen = 1;
4369 alwaysyes = alwaysno = 0;
4370 break;
4371 case 's':
4372 /* session number or relative session */
4373 target_session = atoi(optarg);
4374 break;
4375 case 'S': /* Search for older VATs */
4376 search_older_vat = 1;
4377 break;
4378
4379 default:
4380 usage();
4381 break;
4382 }
4383 }
4384 argc -= optind;
4385 argv += optind;
4386
4387 if (!argc)
4388 usage();
4389
4390 /* TODO SIGINT and SIGQUIT catchers */
4391 #if 0
4392 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
4393 (void) signal(SIGINT, catch);
4394 if (preen)
4395 (void) signal(SIGQUIT, catch);
4396 #endif
4397
4398 signal(SIGINFO, got_siginfo);
4399
4400 while (--argc >= 0) {
4401 setcdevname(*argv, preen);
4402 erg = checkfilesys(*argv++);
4403 if (erg > ret)
4404 ret = erg;
4405 if (!preen)
4406 printf("\n");
4407 udf_cleanup_after_check();
4408 }
4409
4410 return ret;
4411 }
4412
4413
4414 /*VARARGS*/
4415 static int __printflike(2, 3)
ask(int def,const char * fmt,...)4416 ask(int def, const char *fmt, ...)
4417 {
4418 va_list ap;
4419
4420 char prompt[256];
4421 int c;
4422
4423 va_start(ap, fmt);
4424 vsnprintf(prompt, sizeof(prompt), fmt, ap);
4425 va_end(ap);
4426 if (alwaysyes || rdonly) {
4427 pwarn("%s? %s\n", prompt, rdonly ? "no" : "yes");
4428 return !rdonly;
4429 }
4430 if (preen) {
4431 pwarn("%s? %s : (default)\n", prompt, def ? "yes" : "no");
4432 return def;
4433 }
4434
4435 do {
4436 pwarn("%s? [yn] ", prompt);
4437 fflush(stdout);
4438 c = getchar();
4439 while (c != '\n' && getchar() != '\n')
4440 if (feof(stdin))
4441 return 0;
4442 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
4443 return c == 'y' || c == 'Y';
4444 }
4445
4446
4447 /*VARARGS*/
4448 static int __printflike(2, 3)
ask_noauto(int def,const char * fmt,...)4449 ask_noauto(int def, const char *fmt, ...)
4450 {
4451 va_list ap;
4452
4453 char prompt[256];
4454 int c;
4455
4456 va_start(ap, fmt);
4457 vsnprintf(prompt, sizeof(prompt), fmt, ap);
4458 va_end(ap);
4459 #if 0
4460 if (preen) {
4461 pwarn("%s? %s : (default)\n", prompt, def ? "yes" : "no");
4462 return def;
4463 }
4464 #endif
4465
4466 do {
4467 pwarn("%s? [yn] ", prompt);
4468 fflush(stdout);
4469 c = getchar();
4470 while (c != '\n' && getchar() != '\n')
4471 if (feof(stdin))
4472 return 0;
4473 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
4474 return c == 'y' || c == 'Y';
4475 }
4476