1 /* $NetBSD: udf.c,v 1.11 2013/08/09 11:29:44 reinoud Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2008, 2013 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 #if HAVE_NBTOOL_CONFIG_H 29 #include "nbtool_config.h" 30 #endif 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: udf.c,v 1.11 2013/08/09 11:29:44 reinoud Exp $"); 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <errno.h> 39 #include <time.h> 40 #include <assert.h> 41 #include <err.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <util.h> 48 49 #if !HAVE_NBTOOL_CONFIG_H 50 #define _EXPOSE_MMC 51 #include <sys/cdio.h> 52 #else 53 #include "udf/cdio_mmc_structs.h" 54 #endif 55 56 #include "makefs.h" 57 #include "udf_create.h" 58 #include "udf_write.h" 59 #include "newfs_udf.h" 60 61 #undef APP_NAME 62 #define APP_NAME "*NetBSD makefs" 63 64 /* 65 * Note: due to the setup of the newfs code, the current state of the program 66 * and its options are helt in a few global variables. The FS specific parts 67 * are in a global `context' structure. 68 */ 69 70 /* global variables describing disc and format requests */ 71 int fd; /* device: file descriptor */ 72 char *dev; /* device: name */ 73 struct mmc_discinfo mmc_discinfo; /* device: disc info */ 74 75 char *format_str; /* format: string representation */ 76 int format_flags; /* format: attribute flags */ 77 int media_accesstype; /* derived from current mmc cap */ 78 int check_surface; /* for rewritables */ 79 int imagefile_secsize; /* for files */ 80 81 int display_progressbar; 82 83 int wrtrack_skew; 84 float meta_fract = (float) UDF_META_PERC / 100.0; 85 86 int mmc_profile; /* emulated profile */ 87 int req_enable, req_disable; 88 89 90 /* --------------------------------------------------------------------- */ 91 92 int 93 udf_write_sector(void *sector, uint32_t location) 94 { 95 uint64_t wpos; 96 ssize_t ret; 97 98 wpos = (uint64_t) location * context.sector_size; 99 ret = pwrite(fd, sector, context.sector_size, wpos); 100 if (ret == -1) 101 return errno; 102 if (ret < (int) context.sector_size) 103 return EIO; 104 return 0; 105 } 106 107 108 /* not implemented for files */ 109 int 110 udf_surface_check(void) 111 { 112 return 0; 113 } 114 115 116 /* 117 * mmc_discinfo and mmc_trackinfo readers modified from origional in udf main 118 * code in sys/fs/udf/ 119 */ 120 121 #ifdef DEBUG 122 static void 123 udf_dump_discinfo(struct mmc_discinfo *di) 124 { 125 char bits[128]; 126 127 printf("Device/media info :\n"); 128 printf("\tMMC profile 0x%02x\n", di->mmc_profile); 129 printf("\tderived class %d\n", di->mmc_class); 130 printf("\tsector size %d\n", di->sector_size); 131 printf("\tdisc state %d\n", di->disc_state); 132 printf("\tlast ses state %d\n", di->last_session_state); 133 printf("\tbg format state %d\n", di->bg_format_state); 134 printf("\tfrst track %d\n", di->first_track); 135 printf("\tfst on last ses %d\n", di->first_track_last_session); 136 printf("\tlst on last ses %d\n", di->last_track_last_session); 137 printf("\tlink block penalty %d\n", di->link_block_penalty); 138 snprintb(bits, sizeof(bits), MMC_DFLAGS_FLAGBITS, 139 (uint64_t) di->disc_flags); 140 printf("\tdisc flags %s\n", bits); 141 printf("\tdisc id %x\n", di->disc_id); 142 printf("\tdisc barcode %"PRIx64"\n", di->disc_barcode); 143 144 printf("\tnum sessions %d\n", di->num_sessions); 145 printf("\tnum tracks %d\n", di->num_tracks); 146 147 snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cur); 148 printf("\tcapabilities cur %s\n", bits); 149 snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cap); 150 printf("\tcapabilities cap %s\n", bits); 151 printf("\n"); 152 printf("\tlast_possible_lba %d\n", di->last_possible_lba); 153 printf("\n"); 154 } 155 #else 156 #define udf_dump_discinfo(a); 157 #endif 158 159 /* --------------------------------------------------------------------- */ 160 161 static int 162 udf_emulate_discinfo(fsinfo_t *fsopts, struct mmc_discinfo *di, 163 int mmc_emuprofile) 164 { 165 off_t sectors; 166 167 memset(di, 0, sizeof(*di)); 168 169 /* file support */ 170 if ((mmc_emuprofile != 0x01) && (fsopts->sectorsize != 2048)) 171 warnx("cd/dvd/bd sectorsize is not set to default 2048"); 172 173 sectors = fsopts->size / fsopts->sectorsize; 174 175 /* commons */ 176 di->mmc_profile = mmc_emuprofile; 177 di->disc_state = MMC_STATE_CLOSED; 178 di->last_session_state = MMC_STATE_CLOSED; 179 di->bg_format_state = MMC_BGFSTATE_COMPLETED; 180 di->link_block_penalty = 0; 181 182 di->disc_flags = MMC_DFLAGS_UNRESTRICTED; 183 184 di->last_possible_lba = sectors - 1; 185 di->sector_size = fsopts->sectorsize; 186 187 di->num_sessions = 1; 188 di->num_tracks = 1; 189 190 di->first_track = 1; 191 di->first_track_last_session = di->last_track_last_session = 1; 192 193 di->mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_ZEROLINKBLK; 194 switch (mmc_emuprofile) { 195 case 0x00: /* unknown, treat as CDROM */ 196 case 0x08: /* CDROM */ 197 case 0x10: /* DVDROM */ 198 case 0x40: /* BDROM */ 199 req_enable |= FORMAT_READONLY; 200 /* FALLTROUGH */ 201 case 0x01: /* disc */ 202 /* set up a disc info profile for partitions/files */ 203 di->mmc_class = MMC_CLASS_DISC; 204 di->mmc_cur |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE; 205 break; 206 case 0x09: /* CD-R */ 207 di->mmc_class = MMC_CLASS_CD; 208 di->mmc_cur |= MMC_CAP_SEQUENTIAL; 209 di->disc_state = MMC_STATE_EMPTY; 210 break; 211 case 0x0a: /* CD-RW + CD-MRW (regretably) */ 212 di->mmc_class = MMC_CLASS_CD; 213 di->mmc_cur |= MMC_CAP_REWRITABLE; 214 break; 215 case 0x13: /* DVD-RW */ 216 di->mmc_class = MMC_CLASS_DVD; 217 di->mmc_cur |= MMC_CAP_REWRITABLE; 218 break; 219 case 0x11: /* DVD-R */ 220 case 0x14: /* DVD-RW sequential */ 221 case 0x1b: /* DVD+R */ 222 case 0x2b: /* DVD+R DL */ 223 case 0x51: /* HD DVD-R */ 224 di->mmc_class = MMC_CLASS_DVD; 225 di->mmc_cur |= MMC_CAP_SEQUENTIAL; 226 di->disc_state = MMC_STATE_EMPTY; 227 break; 228 case 0x41: /* BD-R */ 229 di->mmc_class = MMC_CLASS_BD; 230 di->mmc_cur |= MMC_CAP_SEQUENTIAL | MMC_CAP_HW_DEFECTFREE; 231 di->disc_state = MMC_STATE_EMPTY; 232 break; 233 case 0x43: /* BD-RE */ 234 di->mmc_class = MMC_CLASS_BD; 235 di->mmc_cur |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE; 236 break; 237 default: 238 err(EINVAL, "makefs_udf: unknown or unimplemented device type"); 239 return EINVAL; 240 } 241 di->mmc_cap = di->mmc_cur; 242 243 udf_dump_discinfo(di); 244 return 0; 245 } 246 247 248 int 249 udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti) 250 { 251 /* discs partition support */ 252 if (ti->tracknr != 1) 253 return EIO; 254 255 /* create fake ti */ 256 ti->sessionnr = 1; 257 258 ti->track_mode = 0; /* XXX */ 259 ti->data_mode = 0; /* XXX */ 260 ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID; 261 262 ti->track_start = 0; 263 ti->packet_size = 32; /* take sensible default */ 264 265 ti->track_size = di->last_possible_lba; 266 ti->next_writable = di->last_possible_lba; 267 ti->last_recorded = ti->next_writable; 268 ti->free_blocks = 0; 269 270 return 0; 271 } 272 273 #define OPT_STR(letter, name, desc) \ 274 { letter, name, NULL, OPT_STRBUF, 0, 0, desc } 275 276 #define OPT_NUM(letter, name, field, min, max, desc) \ 277 { letter, name, &context.field, \ 278 sizeof(context.field) == 8 ? OPT_INT64 : \ 279 (sizeof(context.field) == 4 ? OPT_INT32 : \ 280 (sizeof(context.field) == 2 ? OPT_INT16 : OPT_INT8)), \ 281 min, max, desc } 282 283 #define OPT_BOOL(letter, name, field, desc) \ 284 OPT_NUM(letter, name, field, 0, 1, desc) 285 286 void 287 udf_prep_opts(fsinfo_t *fsopts) 288 { 289 struct tm *tm; 290 time_t now; 291 292 const option_t udf_options[] = { 293 OPT_STR('T', "disctype", "disc type (cdrom,dvdrom,bdrom," 294 "dvdram,bdre,disk,cdr,dvdr,bdr,cdrw,dvdrw)"), 295 OPT_STR('L', "loglabel", "\"logical volume name\""), 296 OPT_STR('P', "discid", "\"[volset name ':']" 297 "physical volume name\""), 298 OPT_NUM('t', "tz", gmtoff, -24, 24, "timezone"), 299 OPT_STR('v', "minver", "minimum UDF version in either " 300 "``0x201'' or ``2.01'' format"), 301 #if notyet 302 OPT_STR('V', "maxver", "maximum UDF version in either " 303 "``0x201'' or ``2.01'' format"), 304 #endif 305 { .name = NULL } 306 }; 307 308 /* initialise */ 309 format_str = strdup(""); 310 req_enable = req_disable = 0; 311 format_flags = FORMAT_INVALID; 312 fsopts->sectorsize = 512; /* minimum allowed sector size */ 313 314 srandom((unsigned long) time(NULL)); 315 316 mmc_profile = 0x01; /* 'disc'/file */ 317 318 udf_init_create_context(); 319 context.app_name = "*NetBSD makefs"; 320 context.app_version_main = APP_VERSION_MAIN; 321 context.app_version_sub = APP_VERSION_SUB; 322 context.impl_name = IMPL_NAME; 323 324 /* minimum and maximum UDF versions we advise */ 325 context.min_udf = 0x102; 326 context.max_udf = 0x201; /* 0x250 and 0x260 are not ready */ 327 328 /* use user's time zone as default */ 329 (void)time(&now); 330 tm = localtime(&now); 331 context.gmtoff = tm->tm_gmtoff; 332 333 /* return info */ 334 fsopts->fs_specific = NULL; 335 fsopts->fs_options = copy_opts(udf_options); 336 } 337 338 339 void 340 udf_cleanup_opts(fsinfo_t *fsopts) 341 { 342 free(fsopts->fs_options); 343 } 344 345 346 /* ----- included from newfs_udf.c ------ */ 347 /* ----- */ 348 349 350 #define CDRSIZE ((uint64_t) 700*1024*1024) /* small approx */ 351 #define CDRWSIZE ((uint64_t) 576*1024*1024) /* small approx */ 352 #define DVDRSIZE ((uint64_t) 4488*1024*1024) /* small approx */ 353 #define DVDRAMSIZE ((uint64_t) 4330*1024*1024) /* small approx with spare */ 354 #define DVDRWSIZE ((uint64_t) 4482*1024*1024) /* small approx */ 355 #define BDRSIZE ((uint64_t) 23866*1024*1024) /* small approx */ 356 #define BDRESIZE ((uint64_t) 23098*1024*1024) /* small approx */ 357 int 358 udf_parse_opts(const char *option, fsinfo_t *fsopts) 359 { 360 option_t *udf_options = fsopts->fs_options; 361 uint64_t stdsize; 362 uint32_t set_sectorsize; 363 const char *name, *desc; 364 char buffer[1024], *buf, *colon; 365 int i; 366 367 assert(option != NULL); 368 369 if (debug & DEBUG_FS_PARSE_OPTS) 370 printf("udf_parse_opts: got `%s'\n", option); 371 372 i = set_option(udf_options, option, buffer, sizeof(buffer)); 373 if (i == -1) 374 return 0; 375 376 if (udf_options[i].name == NULL) 377 abort(); 378 379 set_sectorsize = 0; 380 stdsize = 0; 381 382 buf = buffer; 383 name = udf_options[i].name; 384 desc = udf_options[i].desc; 385 switch (udf_options[i].letter) { 386 case 'T': 387 if (strcmp(buf, "cdrom") == 0) { 388 mmc_profile = 0x00; 389 } else if (strcmp(buf, "dvdrom") == 0) { 390 mmc_profile = 0x10; 391 } else if (strcmp(buf, "bdrom") == 0) { 392 mmc_profile = 0x40; 393 } else if (strcmp(buf, "dvdram") == 0) { 394 mmc_profile = 0x12; 395 stdsize = DVDRAMSIZE; 396 } else if (strcmp(buf, "bdre") == 0) { 397 mmc_profile = 0x43; 398 stdsize = BDRESIZE; 399 } else if (strcmp(buf, "disk") == 0) { 400 mmc_profile = 0x01; 401 } else if (strcmp(buf, "cdr") == 0) { 402 mmc_profile = 0x09; 403 stdsize = CDRSIZE; 404 } else if (strcmp(buf, "dvdr") == 0) { 405 mmc_profile = 0x1b; 406 stdsize = DVDRSIZE; 407 } else if (strcmp(buf, "bdr") == 0) { 408 mmc_profile = 0x41; 409 stdsize = BDRSIZE; 410 } else if (strcmp(buf, "cdrw") == 0) { 411 mmc_profile = 0x0a; 412 stdsize = CDRWSIZE; 413 } else if (strcmp(buf, "dvdrw") == 0) { 414 mmc_profile = 0x13; 415 stdsize = DVDRWSIZE; 416 } else { 417 errx(EINVAL, "Unknown or unimplemented disc format"); 418 return 0; 419 } 420 if (mmc_profile != 0x01) 421 set_sectorsize = 2048; 422 break; 423 case 'L': 424 if (context.logvol_name) free(context.logvol_name); 425 context.logvol_name = strdup(buf); 426 break; 427 case 'P': 428 if ((colon = strstr(buf, ":"))) { 429 if (context.volset_name) 430 free(context.volset_name); 431 *colon = 0; 432 context.volset_name = strdup(buf); 433 buf = colon+1; 434 } 435 if (context.primary_name) 436 free(context.primary_name); 437 if ((strstr(buf, ":"))) { 438 errx(EINVAL, "primary name can't have ':' in its name"); 439 return 0; 440 } 441 context.primary_name = strdup(buf); 442 break; 443 case 'v': 444 context.min_udf = a_udf_version(buf, "min_udf"); 445 if (context.min_udf > 0x201) { 446 errx(EINVAL, "maximum supported version is UDF 2.01"); 447 return 0; 448 } 449 if (context.min_udf > context.max_udf) 450 context.max_udf = context.min_udf; 451 break; 452 } 453 if (set_sectorsize) 454 fsopts->sectorsize = set_sectorsize; 455 if (stdsize) 456 fsopts->size = stdsize; 457 return 1; 458 } 459 460 /* --------------------------------------------------------------------- */ 461 462 struct udf_stats { 463 uint32_t nfiles; 464 uint32_t ndirs; 465 uint32_t ndescr; 466 uint32_t nmetadatablocks; 467 uint32_t ndatablocks; 468 }; 469 470 471 /* node reference administration */ 472 static void 473 udf_inc_link(union dscrptr *dscr) 474 { 475 struct file_entry *fe; 476 struct extfile_entry *efe; 477 478 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 479 fe = &dscr->fe; 480 fe->link_cnt = udf_rw16(udf_rw16(fe->link_cnt) + 1); 481 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 482 efe = &dscr->efe; 483 efe->link_cnt = udf_rw16(udf_rw16(efe->link_cnt) + 1); 484 } else { 485 errx(1, "Bad tag passed to udf_inc_link"); 486 } 487 } 488 489 490 static void 491 udf_set_link_cnt(union dscrptr *dscr, int num) 492 { 493 struct file_entry *fe; 494 struct extfile_entry *efe; 495 496 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 497 fe = &dscr->fe; 498 fe->link_cnt = udf_rw16(num); 499 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 500 efe = &dscr->efe; 501 efe->link_cnt = udf_rw16(num); 502 } else { 503 errx(1, "Bad tag passed to udf_set_link_cnt"); 504 } 505 } 506 507 508 static uint32_t 509 udf_datablocks(off_t sz) 510 { 511 /* predictor if it can be written inside the node */ 512 if (sz < context.sector_size - UDF_EXTFENTRY_SIZE - 16) 513 return 0; 514 515 return UDF_ROUNDUP(sz, context.sector_size) / context.sector_size; 516 } 517 518 519 static void 520 udf_prepare_fids(struct long_ad *dir_icb, struct long_ad *dirdata_icb, 521 uint8_t *dirdata, uint32_t dirdata_size) 522 { 523 struct fileid_desc *fid; 524 struct long_ad *icb; 525 uint32_t fidsize, offset; 526 uint32_t location; 527 528 if (udf_datablocks(dirdata_size) == 0) { 529 /* going internal */ 530 icb = dir_icb; 531 } else { 532 /* external blocks to write to */ 533 icb = dirdata_icb; 534 } 535 536 for (offset = 0; offset < dirdata_size; offset += fidsize) { 537 /* for each FID: */ 538 fid = (struct fileid_desc *) (dirdata + offset); 539 assert(udf_rw16(fid->tag.id) == TAGID_FID); 540 541 location = udf_rw32(icb->loc.lb_num); 542 location += offset / context.sector_size; 543 544 fid->tag.tag_loc = udf_rw32(location); 545 udf_validate_tag_and_crc_sums((union dscrptr *) fid); 546 547 fidsize = udf_fidsize(fid); 548 } 549 } 550 551 static int 552 udf_file_inject_blob(union dscrptr *dscr, uint8_t *blob, off_t size) 553 { 554 struct icb_tag *icb; 555 struct file_entry *fe; 556 struct extfile_entry *efe; 557 uint64_t inf_len, obj_size; 558 uint32_t l_ea, l_ad; 559 uint32_t free_space, desc_size; 560 uint16_t crclen; 561 uint8_t *data, *pos; 562 563 fe = NULL; 564 efe = NULL; 565 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 566 fe = &dscr->fe; 567 data = fe->data; 568 l_ea = udf_rw32(fe->l_ea); 569 l_ad = udf_rw32(fe->l_ad); 570 icb = &fe->icbtag; 571 inf_len = udf_rw64(fe->inf_len); 572 obj_size = 0; 573 desc_size = sizeof(struct file_entry); 574 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 575 efe = &dscr->efe; 576 data = efe->data; 577 l_ea = udf_rw32(efe->l_ea); 578 l_ad = udf_rw32(efe->l_ad); 579 icb = &efe->icbtag; 580 inf_len = udf_rw64(efe->inf_len); 581 obj_size = udf_rw64(efe->obj_size); 582 desc_size = sizeof(struct extfile_entry); 583 } else { 584 errx(1, "Bad tag passed to udf_file_inject_blob"); 585 } 586 crclen = udf_rw16(dscr->tag.desc_crc_len); 587 588 /* calculate free space */ 589 free_space = context.sector_size - (l_ea + l_ad) - desc_size; 590 if (udf_datablocks(size)) { 591 assert(free_space < size); 592 return 1; 593 } 594 595 /* going internal */ 596 assert(l_ad == 0); 597 assert((udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) == 598 UDF_ICB_INTERN_ALLOC); 599 600 // assert(free_space >= size); 601 pos = data + l_ea + l_ad; 602 memcpy(pos, blob, size); 603 l_ad += size; 604 crclen += size; 605 606 inf_len += size; 607 obj_size += size; 608 609 if (fe) { 610 fe->l_ad = udf_rw32(l_ad); 611 fe->inf_len = udf_rw64(inf_len); 612 } else if (efe) { 613 efe->l_ad = udf_rw32(l_ad); 614 efe->inf_len = udf_rw64(inf_len); 615 efe->obj_size = udf_rw64(inf_len); 616 } 617 618 /* make sure the header sums stays correct */ 619 dscr->tag.desc_crc_len = udf_rw16(crclen); 620 udf_validate_tag_and_crc_sums(dscr); 621 622 return 0; 623 } 624 625 626 /* XXX no sparse file support */ 627 static void 628 udf_append_file_mapping(union dscrptr *dscr, struct long_ad *piece) 629 { 630 struct icb_tag *icb; 631 struct file_entry *fe; 632 struct extfile_entry *efe; 633 struct long_ad *last_long, last_piece; 634 struct short_ad *last_short, new_short; 635 uint64_t inf_len, obj_size, logblks_rec; 636 uint32_t l_ea, l_ad, size; 637 uint32_t last_lb_num, piece_lb_num; 638 uint32_t last_len, piece_len, last_flags; 639 uint32_t rest_len, merge_len, last_end; 640 uint16_t last_part_num, piece_part_num; 641 uint16_t crclen, cur_alloc; 642 uint8_t *data, *pos; 643 const int short_len = sizeof(struct short_ad); 644 const int long_len = sizeof(struct long_ad); 645 const int sector_size = context.sector_size; 646 const int use_shorts = (context.data_part == context.metadata_part); 647 uint64_t max_len = UDF_ROUNDDOWN(UDF_EXT_MAXLEN, sector_size); 648 649 fe = NULL; 650 efe = NULL; 651 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 652 fe = &dscr->fe; 653 data = fe->data; 654 l_ea = fe->l_ea; 655 l_ad = udf_rw32(fe->l_ad); 656 icb = &fe->icbtag; 657 inf_len = udf_rw64(fe->inf_len); 658 logblks_rec = udf_rw64(fe->logblks_rec); 659 obj_size = 0; 660 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 661 efe = &dscr->efe; 662 data = efe->data; 663 l_ea = efe->l_ea; 664 l_ad = udf_rw32(efe->l_ad); 665 icb = &efe->icbtag; 666 inf_len = udf_rw64(efe->inf_len); 667 obj_size = udf_rw64(efe->obj_size); 668 logblks_rec = udf_rw64(efe->logblks_rec); 669 } else { 670 errx(1, "Bad tag passed to udf_file_append_blob"); 671 } 672 crclen = udf_rw16(dscr->tag.desc_crc_len); 673 674 pos = data + l_ea; 675 cur_alloc = udf_rw16(icb->flags); 676 size = UDF_EXT_LEN(udf_rw32(piece->len)); 677 678 /* extract last entry as a long_ad */ 679 memset(&last_piece, 0, sizeof(last_piece)); 680 last_len = 0; 681 last_lb_num = 0; 682 last_part_num = 0; 683 last_flags = 0; 684 last_short = NULL; 685 last_long = NULL; 686 if (l_ad != 0) { 687 if (use_shorts) { 688 assert(cur_alloc == UDF_ICB_SHORT_ALLOC); 689 pos += l_ad - short_len; 690 last_short = (struct short_ad *) pos; 691 last_lb_num = udf_rw32(last_short->lb_num); 692 last_part_num = udf_rw16(piece->loc.part_num); 693 last_len = UDF_EXT_LEN(udf_rw32(last_short->len)); 694 last_flags = UDF_EXT_FLAGS(udf_rw32(last_short->len)); 695 } else { 696 assert(cur_alloc == UDF_ICB_LONG_ALLOC); 697 pos += l_ad - long_len; 698 last_long = (struct long_ad *) pos; 699 last_lb_num = udf_rw32(last_long->loc.lb_num); 700 last_part_num = udf_rw16(last_long->loc.part_num); 701 last_len = UDF_EXT_LEN(udf_rw32(last_long->len)); 702 last_flags = UDF_EXT_FLAGS(udf_rw32(last_long->len)); 703 } 704 } 705 706 piece_len = UDF_EXT_LEN(udf_rw32(piece->len)); 707 piece_lb_num = udf_rw32(piece->loc.lb_num); 708 piece_part_num = udf_rw16(piece->loc.part_num); 709 710 /* try merging */ 711 rest_len = max_len - last_len; 712 713 merge_len = MIN(udf_rw32(piece->len), rest_len); 714 last_end = last_lb_num + (last_len / sector_size); 715 716 if ((piece_lb_num == last_end) && (last_part_num == piece_part_num)) { 717 /* we can merge */ 718 last_len += merge_len; 719 piece_len -= merge_len; 720 721 /* write back merge result */ 722 if (use_shorts) { 723 last_short->len = udf_rw32(last_len | last_flags); 724 } else { 725 last_long->len = udf_rw32(last_len | last_flags); 726 } 727 piece_lb_num += merge_len / sector_size; 728 } 729 730 if (piece_len) { 731 /* append new entry */ 732 pos = data + l_ea + l_ad; 733 if (use_shorts) { 734 icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC); 735 memset(&new_short, 0, short_len); 736 new_short.len = udf_rw32(piece_len); 737 new_short.lb_num = udf_rw32(piece_lb_num); 738 memcpy(pos, &new_short, short_len); 739 l_ad += short_len; 740 crclen += short_len; 741 } else { 742 icb->flags = udf_rw16(UDF_ICB_LONG_ALLOC); 743 piece->len = udf_rw32(piece_len); 744 piece->loc.lb_num = udf_rw32(piece_lb_num); 745 memcpy(pos, piece, long_len); 746 l_ad += long_len; 747 crclen += long_len; 748 } 749 } 750 piece->len = udf_rw32(0); 751 752 inf_len += size; 753 obj_size += size; 754 logblks_rec += UDF_ROUNDUP(size, sector_size) / sector_size; 755 756 dscr->tag.desc_crc_len = udf_rw16(crclen); 757 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 758 fe->l_ad = udf_rw32(l_ad); 759 fe->inf_len = udf_rw64(inf_len); 760 fe->logblks_rec = udf_rw64(logblks_rec); 761 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 762 efe->l_ad = udf_rw32(l_ad); 763 efe->inf_len = udf_rw64(inf_len); 764 efe->obj_size = udf_rw64(inf_len); 765 efe->logblks_rec = udf_rw64(logblks_rec); 766 } 767 } 768 769 770 static int 771 udf_append_file_contents(union dscrptr *dscr, struct long_ad *data_icb, 772 uint8_t *fdata, off_t flen) 773 { 774 struct long_ad icb; 775 uint32_t location; 776 uint32_t phys; 777 uint16_t vpart; 778 uint8_t *bpos; 779 int cnt, sects; 780 int error; 781 782 if (udf_file_inject_blob(dscr, fdata, flen) == 0) 783 return 0; 784 785 /* has to be appended in mappings */ 786 icb = *data_icb; 787 icb.len = udf_rw32(flen); 788 while (udf_rw32(icb.len) > 0) 789 udf_append_file_mapping(dscr, &icb); 790 udf_validate_tag_and_crc_sums(dscr); 791 792 /* write out data piece */ 793 vpart = udf_rw16(data_icb->loc.part_num); 794 location = udf_rw32(data_icb->loc.lb_num); 795 sects = udf_datablocks(flen); 796 for (cnt = 0; cnt < sects; cnt++) { 797 bpos = fdata + cnt*context.sector_size; 798 phys = context.vtop_offset[vpart] + location + cnt; 799 error = udf_write_sector(bpos, phys); 800 if (error) 801 return error; 802 } 803 return 0; 804 } 805 806 807 static int 808 udf_create_new_file(struct stat *st, union dscrptr **dscr, 809 int filetype, struct long_ad *icb) 810 { 811 struct file_entry *fe; 812 struct extfile_entry *efe; 813 int error; 814 815 fe = NULL; 816 efe = NULL; 817 if (context.dscrver == 2) { 818 error = udf_create_new_fe(&fe, filetype, st); 819 if (error) 820 errx(error, "can't create fe"); 821 *dscr = (union dscrptr *) fe; 822 icb->longad_uniqueid = fe->unique_id; 823 } else { 824 error = udf_create_new_efe(&efe, filetype, st); 825 if (error) 826 errx(error, "can't create fe"); 827 *dscr = (union dscrptr *) efe; 828 icb->longad_uniqueid = efe->unique_id; 829 } 830 831 return 0; 832 } 833 834 835 static void 836 udf_estimate_walk(fsinfo_t *fsopts, 837 fsnode *root, char *dir, struct udf_stats *stats) 838 { 839 struct fileid_desc *fid; 840 struct long_ad dummy_ref; 841 fsnode *cur; 842 fsinode *fnode; 843 size_t pathlen = strlen(dir); 844 char *mydir = dir + pathlen; 845 off_t sz; 846 uint32_t nblk, ddoff; 847 uint32_t softlink_len; 848 uint8_t *softlink_buf; 849 int nentries; 850 int error; 851 852 stats->ndirs++; 853 854 /* 855 * Count number of directory entries and count directory size; needed 856 * for the reservation of enough space for the directory. Pity we 857 * don't keep the FIDs we created. If it turns out to be a issue we 858 * can cache it later. 859 */ 860 fid = (struct fileid_desc *) malloc(context.sector_size); 861 assert(fid); 862 863 ddoff = 40; /* '..' entry */ 864 for (cur = root, nentries = 0; cur != NULL; cur = cur->next) { 865 switch (cur->type & S_IFMT) { 866 default: 867 /* what kind of nodes? */ 868 break; 869 case S_IFCHR: 870 case S_IFBLK: 871 /* not supported yet */ 872 continue; 873 case S_IFDIR: 874 if (strcmp(cur->name, ".") == 0) 875 continue; 876 case S_IFLNK: 877 case S_IFREG: 878 /* create dummy FID to see how long name will become */ 879 udf_create_fid(ddoff, fid, cur->name, 0, &dummy_ref); 880 881 nentries++; 882 ddoff += udf_fidsize(fid); 883 } 884 } 885 sz = ddoff; 886 887 root->inode->st.st_size = sz; /* max now */ 888 root->inode->flags |= FI_SIZED; 889 890 nblk = udf_datablocks(sz); 891 stats->nmetadatablocks += nblk; 892 893 /* for each entry in the directory, there needs to be a (E)FE */ 894 stats->nmetadatablocks += nentries + 1; 895 896 /* recurse */ 897 for (cur = root; cur != NULL; cur = cur->next) { 898 switch (cur->type & S_IFMT) { 899 default: 900 /* what kind of nodes? */ 901 break; 902 case S_IFCHR: 903 case S_IFBLK: 904 /* not supported yet */ 905 // stats->nfiles++; 906 break; 907 case S_IFDIR: 908 if (strcmp(cur->name, ".") == 0) 909 continue; 910 /* empty dir? */ 911 if (!cur->child) 912 break; 913 mydir[0] = '/'; 914 strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); 915 udf_estimate_walk(fsopts, cur->child, dir, stats); 916 mydir[0] = '\0'; 917 break; 918 case S_IFREG: 919 fnode = cur->inode; 920 /* don't double-count hard-links */ 921 if (!(fnode->flags & FI_SIZED)) { 922 sz = fnode->st.st_size; 923 nblk = udf_datablocks(sz); 924 stats->ndatablocks += nblk; 925 /* ... */ 926 fnode->flags |= FI_SIZED; 927 } 928 stats->nfiles++; 929 break; 930 case S_IFLNK: 931 /* softlink */ 932 fnode = cur->inode; 933 /* don't double-count hard-links */ 934 if (!(fnode->flags & FI_SIZED)) { 935 error = udf_encode_symlink(&softlink_buf, 936 &softlink_len, cur->symlink); 937 if (error) { 938 printf("SOFTLINK error %d\n", error); 939 break; 940 } 941 nblk = udf_datablocks(softlink_len); 942 stats->ndatablocks += nblk; 943 fnode->flags |= FI_SIZED; 944 945 free(softlink_buf); 946 } 947 stats->nfiles++; 948 break; 949 } 950 } 951 } 952 953 954 #define UDF_MAX_CHUNK_SIZE (4*1024*1024) 955 static int 956 udf_copy_file(struct stat *st, char *path, fsnode *cur, struct fileid_desc *fid, 957 struct long_ad *icb) 958 { 959 union dscrptr *dscr; 960 struct long_ad data_icb; 961 fsinode *fnode; 962 off_t sz, chunk, rd; 963 uint8_t *data; 964 int nblk; 965 int i, f; 966 int error; 967 968 fnode = cur->inode; 969 970 f = open(path, O_RDONLY); 971 if (f < 0) { 972 warn("Can't open file %s for reading", cur->name); 973 return errno; 974 } 975 976 /* claim disc space for the (e)fe descriptor for this file */ 977 udf_metadata_alloc(1, icb); 978 udf_create_new_file(st, &dscr, UDF_ICB_FILETYPE_RANDOMACCESS, icb); 979 980 sz = fnode->st.st_size; 981 982 chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); 983 data = malloc(MAX(chunk, context.sector_size)); 984 assert(data); 985 986 printf(" "); 987 i = 0; 988 error = 0; 989 while (chunk) { 990 rd = read(f, data, chunk); 991 if (rd != chunk) { 992 warn("Short read of file %s\n", cur->name); 993 error = errno; 994 break; 995 } 996 printf("\b%c", "\\|/-"[i++ % 4]); fflush(stdout);fflush(stderr); 997 998 nblk = udf_datablocks(chunk); 999 if (nblk > 0) 1000 udf_data_alloc(nblk, &data_icb); 1001 udf_append_file_contents(dscr, &data_icb, data, chunk); 1002 1003 sz -= chunk; 1004 chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); 1005 } 1006 printf("\b \n"); 1007 close(f); 1008 free(data); 1009 1010 /* write out dscr (e)fe */ 1011 udf_set_link_cnt(dscr, fnode->nlink); 1012 udf_write_dscr_virt(dscr, udf_rw32(icb->loc.lb_num), 1013 udf_rw16(icb->loc.part_num), 1); 1014 free(dscr); 1015 1016 /* remember our location for hardlinks */ 1017 cur->inode->fsuse = malloc(sizeof(struct long_ad)); 1018 memcpy(cur->inode->fsuse, icb, sizeof(struct long_ad)); 1019 1020 return error; 1021 } 1022 1023 1024 static int 1025 udf_populate_walk(fsinfo_t *fsopts, fsnode *root, char *dir, 1026 struct long_ad *parent_icb, struct long_ad *dir_icb) 1027 { 1028 union dscrptr *dir_dscr, *dscr; 1029 struct fileid_desc *fid; 1030 struct long_ad icb, data_icb, dirdata_icb; 1031 fsnode *cur; 1032 fsinode *fnode; 1033 size_t pathlen = strlen(dir); 1034 size_t dirlen; 1035 char *mydir = dir + pathlen; 1036 uint32_t nblk, ddoff; 1037 uint32_t softlink_len; 1038 uint8_t *softlink_buf; 1039 uint8_t *dirdata; 1040 int error, ret, retval; 1041 1042 /* claim disc space for the (e)fe descriptor for this dir */ 1043 udf_metadata_alloc(1, dir_icb); 1044 1045 /* create new e(fe) */ 1046 udf_create_new_file(&root->inode->st, &dir_dscr, 1047 UDF_ICB_FILETYPE_DIRECTORY, dir_icb); 1048 1049 /* claim space for the directory contents */ 1050 dirlen = root->inode->st.st_size; 1051 nblk = udf_datablocks(dirlen); 1052 if (nblk > 0) { 1053 /* claim disc space for the dir contents */ 1054 udf_data_alloc(nblk, &dirdata_icb); 1055 } 1056 1057 /* allocate memory for the directory contents */ 1058 nblk++; 1059 dirdata = malloc(nblk * context.sector_size); 1060 assert(dirdata); 1061 memset(dirdata, 0, nblk * context.sector_size); 1062 1063 /* create and append '..' */ 1064 fid = (struct fileid_desc *) dirdata; 1065 ddoff = udf_create_parentfid(fid, parent_icb); 1066 1067 /* for '..' */ 1068 udf_inc_link(dir_dscr); 1069 1070 /* recurse */ 1071 retval = 0; 1072 for (cur = root; cur != NULL; cur = cur->next) { 1073 mydir[0] = '/'; 1074 strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); 1075 1076 fid = (struct fileid_desc *) (dirdata + ddoff); 1077 switch (cur->type & S_IFMT) { 1078 default: 1079 /* what kind of nodes? */ 1080 retval = 2; 1081 break; 1082 case S_IFCHR: 1083 case S_IFBLK: 1084 /* not supported */ 1085 retval = 2; 1086 warnx("device node %s not supported", dir); 1087 break; 1088 case S_IFDIR: 1089 /* not an empty dir? */ 1090 if (strcmp(cur->name, ".") == 0) 1091 break; 1092 assert(cur->child); 1093 if (cur->child) { 1094 ret = udf_populate_walk(fsopts, cur->child, 1095 dir, dir_icb, &icb); 1096 if (ret) 1097 retval = 2; 1098 } 1099 udf_create_fid(ddoff, fid, cur->name, 1100 UDF_FILE_CHAR_DIR, &icb); 1101 udf_inc_link(dir_dscr); 1102 ddoff += udf_fidsize(fid); 1103 break; 1104 case S_IFREG: 1105 fnode = cur->inode; 1106 /* don't re-copy hard-links */ 1107 if (!(fnode->flags & FI_WRITTEN)) { 1108 printf("%s", dir); 1109 error = udf_copy_file(&fnode->st, dir, cur, 1110 fid, &icb); 1111 if (!error) { 1112 fnode->flags |= FI_WRITTEN; 1113 udf_create_fid(ddoff, fid, cur->name, 1114 0, &icb); 1115 ddoff += udf_fidsize(fid); 1116 } else { 1117 retval = 2; 1118 } 1119 } else { 1120 /* hardlink! */ 1121 printf("%s (hardlink)\n", dir); 1122 udf_create_fid(ddoff, fid, cur->name, 1123 0, (struct long_ad *) (fnode->fsuse)); 1124 ddoff += udf_fidsize(fid); 1125 } 1126 fnode->nlink--; 1127 if (fnode->nlink == 0) 1128 free(fnode->fsuse); 1129 break; 1130 case S_IFLNK: 1131 /* softlink */ 1132 fnode = cur->inode; 1133 printf("%s -> %s\n", dir, cur->symlink); 1134 error = udf_encode_symlink(&softlink_buf, 1135 &softlink_len, cur->symlink); 1136 if (error) { 1137 printf("SOFTLINK error %d\n", error); 1138 retval = 2; 1139 break; 1140 } 1141 1142 udf_metadata_alloc(1, &icb); 1143 udf_create_new_file(&fnode->st, &dscr, 1144 UDF_ICB_FILETYPE_SYMLINK, &icb); 1145 1146 nblk = udf_datablocks(softlink_len); 1147 if (nblk > 0) 1148 udf_data_alloc(nblk, &data_icb); 1149 udf_append_file_contents(dscr, &data_icb, 1150 softlink_buf, softlink_len); 1151 1152 /* write out dscr (e)fe */ 1153 udf_inc_link(dscr); 1154 udf_write_dscr_virt(dscr, udf_rw32(icb.loc.lb_num), 1155 udf_rw16(icb.loc.part_num), 1); 1156 1157 free(dscr); 1158 free(softlink_buf); 1159 1160 udf_create_fid(ddoff, fid, cur->name, 0, &icb); 1161 ddoff += udf_fidsize(fid); 1162 break; 1163 } 1164 mydir[0] = '\0'; 1165 } 1166 1167 /* writeout directory contents */ 1168 dirlen = ddoff; /* XXX might bite back */ 1169 1170 udf_prepare_fids(dir_icb, &dirdata_icb, dirdata, dirlen); 1171 udf_append_file_contents(dir_dscr, &dirdata_icb, dirdata, dirlen); 1172 1173 /* write out dir_dscr (e)fe */ 1174 udf_write_dscr_virt(dir_dscr, udf_rw32(dir_icb->loc.lb_num), 1175 udf_rw16(dir_icb->loc.part_num), 1); 1176 1177 free(dirdata); 1178 free(dir_dscr); 1179 return retval; 1180 } 1181 1182 1183 static int 1184 udf_populate(const char *dir, fsnode *root, fsinfo_t *fsopts, 1185 struct udf_stats *stats) 1186 { 1187 struct long_ad rooticb; 1188 static char path[MAXPATHLEN+1]; 1189 int error; 1190 1191 /* make sure the root gets the rootdir entry */ 1192 context.metadata_alloc_pos = layout.rootdir; 1193 context.data_alloc_pos = layout.rootdir; 1194 1195 strncpy(path, dir, sizeof(path)); 1196 error = udf_populate_walk(fsopts, root, path, &rooticb, &rooticb); 1197 1198 return error; 1199 } 1200 1201 1202 static void 1203 udf_enumerate_and_estimate(const char *dir, fsnode *root, fsinfo_t *fsopts, 1204 struct udf_stats *stats) 1205 { 1206 char path[MAXPATHLEN + 1]; 1207 off_t proposed_size; 1208 uint32_t n, nblk; 1209 1210 strncpy(path, dir, sizeof(path)); 1211 1212 /* calculate strict minimal size */ 1213 udf_estimate_walk(fsopts, root, path, stats); 1214 printf("ndirs %d\n", stats->ndirs); 1215 printf("nfiles %d\n", stats->nfiles); 1216 printf("ndata_blocks %d\n", stats->ndatablocks); 1217 printf("nmetadata_blocks %d\n", stats->nmetadatablocks); 1218 printf("\n"); 1219 1220 /* adjust for options : free file nodes */ 1221 if (fsopts->freefiles) { 1222 /* be mercifull and reserve more for the FID */ 1223 stats->nmetadatablocks += fsopts->freefiles * 1.5; 1224 } else if ((n = fsopts->freefilepc)) { 1225 stats->nmetadatablocks += (stats->nmetadatablocks*n) / (100-n); 1226 } 1227 1228 /* adjust for options : free data blocks */ 1229 if (fsopts->freeblocks) { 1230 stats->ndatablocks += fsopts->freeblocks; 1231 } else if ((n = fsopts->freeblockpc)) { 1232 stats->ndatablocks += (stats->ndatablocks * n) / (100-n); 1233 } 1234 1235 /* rough predictor of minimum disc size */ 1236 nblk = stats->ndatablocks + stats->nmetadatablocks; 1237 nblk = (double) nblk * (1.0 + 1.0/8.0); /* free space map */ 1238 nblk += 256; /* pre-volume space */ 1239 nblk += 256; /* post-volume space */ 1240 nblk += 64; /* safeguard */ 1241 1242 /* try to honour minimum size */ 1243 n = fsopts->minsize / fsopts->sectorsize; 1244 if (nblk < n) { 1245 stats->ndatablocks += (n - nblk); 1246 nblk += n - nblk; 1247 } 1248 proposed_size = (off_t) nblk * fsopts->sectorsize; 1249 /* sanity size */ 1250 if (proposed_size < 512*1024) 1251 proposed_size = 512*1024; 1252 1253 if (fsopts->size) { 1254 if (fsopts->size < proposed_size) 1255 err(EINVAL, "makefs_udf: won't fit on disc!"); 1256 } else { 1257 fsopts->size = proposed_size; 1258 } 1259 1260 fsopts->inodes = stats->nfiles + stats->ndirs; 1261 } 1262 1263 1264 void 1265 udf_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) 1266 { 1267 struct udf_stats stats; 1268 uint64_t truncate_len; 1269 char scrap[255]; 1270 int error; 1271 1272 /* determine format */ 1273 udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile); 1274 printf("req_enable %d, req_disable %d\n", req_enable, req_disable); 1275 1276 context.sector_size = fsopts->sectorsize; 1277 error = udf_derive_format(req_enable, req_disable, false); 1278 if (error) 1279 err(EINVAL, "makefs_udf: can't determine format"); 1280 1281 /* names */ 1282 error = udf_proces_names(); 1283 if (error) 1284 err(EINVAL, "makefs_udf: bad names given"); 1285 1286 /* set return value to 1 indicating error */ 1287 error = 1; 1288 1289 /* estimate the amount of space needed */ 1290 memset(&stats, 0, sizeof(stats)); 1291 udf_enumerate_and_estimate(dir, root, fsopts, &stats); 1292 1293 printf("Calculated size of `%s': %lld bytes, %ld inodes\n", 1294 image, (long long)fsopts->size, (long)fsopts->inodes); 1295 1296 /* create file image */ 1297 if ((fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1298 err(EXIT_FAILURE, "%s", image); 1299 } 1300 if (lseek(fd, fsopts->size - 1, SEEK_SET) == -1) { 1301 goto err_exit; 1302 } 1303 if (write(fd, &fd, 1) != 1) { 1304 goto err_exit; 1305 } 1306 if (lseek(fd, 0, SEEK_SET) == -1) { 1307 goto err_exit; 1308 } 1309 fsopts->fd = fd; 1310 1311 /* calculate metadata percentage */ 1312 meta_fract = fsopts->size / (stats.nmetadatablocks*fsopts->sectorsize); 1313 meta_fract = ((int) ((meta_fract + 0.005)*100.0)) / 100; 1314 1315 /* update mmc info but now with correct size */ 1316 udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile); 1317 1318 printf("Building disc compatible with UDF version %x to %x\n\n", 1319 context.min_udf, context.max_udf); 1320 (void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS, 1321 (uint64_t) format_flags); 1322 printf("UDF properties %s\n", scrap); 1323 printf("Volume set `%s'\n", context.volset_name); 1324 printf("Primary volume `%s`\n", context.primary_name); 1325 printf("Logical volume `%s`\n", context.logvol_name); 1326 if (format_flags & FORMAT_META) 1327 printf("Metadata percentage %d %%\n", 1328 (int) (100.0*stats.ndatablocks/stats.nmetadatablocks)); 1329 printf("\n"); 1330 udf_do_newfs_prefix(); 1331 1332 /* update context */ 1333 context.unique_id = 0; 1334 1335 /* XXX are the next two needed? or should be re-count them? */ 1336 context.num_files = stats.nfiles; 1337 context.num_directories = stats.ndirs; 1338 1339 error = udf_populate(dir, root, fsopts, &stats); 1340 1341 udf_do_newfs_postfix(); 1342 1343 if (format_flags & FORMAT_VAT) { 1344 truncate_len = context.vtop_offset[context.data_part] + 1345 context.data_alloc_pos; 1346 truncate_len *= context.sector_size; 1347 1348 printf("\nTruncing the disc-image to allow for VAT\n"); 1349 printf("Free space left on this volume approx. " 1350 "%"PRIu64" KiB, %"PRIu64" MiB\n", 1351 (fsopts->size - truncate_len)/1024, 1352 (fsopts->size - truncate_len)/1024/1024); 1353 ftruncate(fd, truncate_len); 1354 } 1355 1356 if (error) { 1357 error = 2; /* some files couldn't be added */ 1358 goto err_exit; 1359 } 1360 1361 close(fd); 1362 return; 1363 1364 err_exit: 1365 close(fd); 1366 if (error == 2) { 1367 errx(error, "Not all files could be added"); 1368 } else { 1369 errx(error, "creation of %s failed", image); 1370 } 1371 } 1372 1373