1 /* $NetBSD: udf.c,v 1.10 2013/08/06 13:15:30 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.10 2013/08/06 13:15:30 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, size_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 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 650 fe = &dscr->fe; 651 data = fe->data; 652 l_ea = fe->l_ea; 653 l_ad = udf_rw32(fe->l_ad); 654 icb = &fe->icbtag; 655 inf_len = udf_rw64(fe->inf_len); 656 logblks_rec = udf_rw64(fe->logblks_rec); 657 obj_size = 0; 658 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 659 efe = &dscr->efe; 660 data = efe->data; 661 l_ea = efe->l_ea; 662 l_ad = udf_rw32(efe->l_ad); 663 icb = &efe->icbtag; 664 inf_len = udf_rw64(efe->inf_len); 665 obj_size = udf_rw64(efe->obj_size); 666 logblks_rec = udf_rw64(efe->logblks_rec); 667 } else { 668 errx(1, "Bad tag passed to udf_file_append_blob"); 669 } 670 crclen = udf_rw16(dscr->tag.desc_crc_len); 671 672 pos = data + l_ea; 673 cur_alloc = udf_rw16(icb->flags); 674 size = UDF_EXT_LEN(udf_rw32(piece->len)); 675 676 /* extract last entry as a long_ad */ 677 memset(&last_piece, 0, sizeof(last_piece)); 678 last_len = 0; 679 last_lb_num = 0; 680 last_part_num = 0; 681 if (l_ad != 0) { 682 if (use_shorts) { 683 assert(cur_alloc == UDF_ICB_SHORT_ALLOC); 684 pos += l_ad - short_len; 685 last_short = (struct short_ad *) pos; 686 last_lb_num = udf_rw32(last_short->lb_num); 687 last_part_num = udf_rw16(piece->loc.part_num); 688 last_len = UDF_EXT_LEN(udf_rw32(last_short->len)); 689 last_flags = UDF_EXT_FLAGS(udf_rw32(last_short->len)); 690 } else { 691 assert(cur_alloc == UDF_ICB_LONG_ALLOC); 692 pos += l_ad - long_len; 693 last_long = (struct long_ad *) pos; 694 last_lb_num = udf_rw32(last_long->loc.lb_num); 695 last_part_num = udf_rw16(last_long->loc.part_num); 696 last_len = UDF_EXT_LEN(udf_rw32(last_long->len)); 697 last_flags = UDF_EXT_FLAGS(udf_rw32(last_long->len)); 698 } 699 } 700 701 piece_len = UDF_EXT_LEN(udf_rw32(piece->len)); 702 piece_lb_num = udf_rw32(piece->loc.lb_num); 703 piece_part_num = udf_rw16(piece->loc.part_num); 704 705 /* try merging */ 706 rest_len = max_len - last_len; 707 708 merge_len = MIN(udf_rw32(piece->len), rest_len); 709 last_end = last_lb_num + (last_len / sector_size); 710 711 if ((piece_lb_num == last_end) && (last_part_num == piece_part_num)) { 712 /* we can merge */ 713 last_len += merge_len; 714 piece_len -= merge_len; 715 716 /* write back merge result */ 717 if (use_shorts) { 718 last_short->len = udf_rw32(last_len | last_flags); 719 } else { 720 last_long->len = udf_rw32(last_len | last_flags); 721 } 722 piece_lb_num += merge_len / sector_size; 723 } 724 725 if (piece_len) { 726 /* append new entry */ 727 pos = data + l_ea + l_ad; 728 if (use_shorts) { 729 icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC); 730 memset(&new_short, 0, short_len); 731 new_short.len = udf_rw32(piece_len); 732 new_short.lb_num = udf_rw32(piece_lb_num); 733 memcpy(pos, &new_short, short_len); 734 l_ad += short_len; 735 crclen += short_len; 736 } else { 737 icb->flags = udf_rw16(UDF_ICB_LONG_ALLOC); 738 piece->len = udf_rw32(piece_len); 739 piece->loc.lb_num = udf_rw32(piece_lb_num); 740 memcpy(pos, piece, long_len); 741 l_ad += long_len; 742 crclen += long_len; 743 } 744 } 745 piece->len = udf_rw32(0); 746 747 inf_len += size; 748 obj_size += size; 749 logblks_rec += UDF_ROUNDUP(size, sector_size) / sector_size; 750 751 dscr->tag.desc_crc_len = udf_rw16(crclen); 752 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 753 fe->l_ad = udf_rw32(l_ad); 754 fe->inf_len = udf_rw64(inf_len); 755 fe->logblks_rec = udf_rw64(logblks_rec); 756 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 757 efe->l_ad = udf_rw32(l_ad); 758 efe->inf_len = udf_rw64(inf_len); 759 efe->obj_size = udf_rw64(inf_len); 760 efe->logblks_rec = udf_rw64(logblks_rec); 761 } 762 } 763 764 765 static int 766 udf_append_file_contents(union dscrptr *dscr, struct long_ad *data_icb, 767 uint8_t *fdata, size_t flen) 768 { 769 struct long_ad icb; 770 uint32_t location; 771 uint32_t phys; 772 uint16_t vpart; 773 uint8_t *bpos; 774 int cnt, sects; 775 int error; 776 777 if (udf_file_inject_blob(dscr, fdata, flen) == 0) 778 return 0; 779 780 /* has to be appended in mappings */ 781 icb = *data_icb; 782 icb.len = udf_rw32(flen); 783 while (udf_rw32(icb.len) > 0) 784 udf_append_file_mapping(dscr, &icb); 785 udf_validate_tag_and_crc_sums(dscr); 786 787 /* write out data piece */ 788 vpart = udf_rw16(data_icb->loc.part_num); 789 location = udf_rw32(data_icb->loc.lb_num); 790 sects = udf_datablocks(flen); 791 for (cnt = 0; cnt < sects; cnt++) { 792 bpos = fdata + cnt*context.sector_size; 793 phys = context.vtop_offset[vpart] + location + cnt; 794 error = udf_write_sector(bpos, phys); 795 if (error) 796 return error; 797 } 798 return 0; 799 } 800 801 802 static int 803 udf_create_new_file(struct stat *st, union dscrptr **dscr, 804 int filetype, struct long_ad *icb) 805 { 806 struct file_entry *fe; 807 struct extfile_entry *efe; 808 int error; 809 810 fe = NULL; 811 efe = NULL; 812 if (context.dscrver == 2) { 813 error = udf_create_new_fe(&fe, filetype, st); 814 if (error) 815 errx(error, "can't create fe"); 816 *dscr = (union dscrptr *) fe; 817 icb->longad_uniqueid = fe->unique_id; 818 } else { 819 error = udf_create_new_efe(&efe, filetype, st); 820 if (error) 821 errx(error, "can't create fe"); 822 *dscr = (union dscrptr *) efe; 823 icb->longad_uniqueid = efe->unique_id; 824 } 825 826 return 0; 827 } 828 829 830 static void 831 udf_estimate_walk(fsinfo_t *fsopts, 832 fsnode *root, char *dir, struct udf_stats *stats) 833 { 834 struct fileid_desc *fid; 835 struct long_ad dummy_ref; 836 fsnode *cur; 837 fsinode *fnode; 838 size_t pathlen = strlen(dir); 839 char *mydir = dir + pathlen; 840 off_t sz; 841 uint32_t nblk, ddoff; 842 uint32_t softlink_len; 843 uint8_t *softlink_buf; 844 int nentries; 845 int error; 846 847 stats->ndirs++; 848 849 /* 850 * Count number of directory entries and count directory size; needed 851 * for the reservation of enough space for the directory. Pity we 852 * don't keep the FIDs we created. If it turns out to be a issue we 853 * can cache it later. 854 */ 855 fid = (struct fileid_desc *) malloc(context.sector_size); 856 assert(fid); 857 858 ddoff = 40; /* '..' entry */ 859 for (cur = root, nentries = 0; cur != NULL; cur = cur->next) { 860 switch (cur->type & S_IFMT) { 861 default: 862 /* what kind of nodes? */ 863 break; 864 case S_IFCHR: 865 case S_IFBLK: 866 /* not supported yet */ 867 continue; 868 case S_IFDIR: 869 if (strcmp(cur->name, ".") == 0) 870 continue; 871 case S_IFLNK: 872 case S_IFREG: 873 /* create dummy FID to see how long name will become */ 874 udf_create_fid(ddoff, fid, cur->name, 0, &dummy_ref); 875 876 nentries++; 877 ddoff += udf_fidsize(fid); 878 } 879 } 880 sz = ddoff; 881 882 root->inode->st.st_size = sz; /* max now */ 883 root->inode->flags |= FI_SIZED; 884 885 nblk = udf_datablocks(sz); 886 stats->nmetadatablocks += nblk; 887 888 /* for each entry in the directory, there needs to be a (E)FE */ 889 stats->nmetadatablocks += nentries + 1; 890 891 /* recurse */ 892 for (cur = root; cur != NULL; cur = cur->next) { 893 switch (cur->type & S_IFMT) { 894 default: 895 /* what kind of nodes? */ 896 break; 897 case S_IFCHR: 898 case S_IFBLK: 899 /* not supported yet */ 900 // stats->nfiles++; 901 break; 902 case S_IFDIR: 903 if (strcmp(cur->name, ".") == 0) 904 continue; 905 /* empty dir? */ 906 if (!cur->child) 907 break; 908 mydir[0] = '/'; 909 strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); 910 udf_estimate_walk(fsopts, cur->child, dir, stats); 911 mydir[0] = '\0'; 912 break; 913 case S_IFREG: 914 fnode = cur->inode; 915 /* don't double-count hard-links */ 916 if (!(fnode->flags & FI_SIZED)) { 917 sz = fnode->st.st_size; 918 nblk = udf_datablocks(sz); 919 stats->ndatablocks += nblk; 920 /* ... */ 921 fnode->flags |= FI_SIZED; 922 } 923 stats->nfiles++; 924 break; 925 case S_IFLNK: 926 /* softlink */ 927 fnode = cur->inode; 928 /* don't double-count hard-links */ 929 if (!(fnode->flags & FI_SIZED)) { 930 error = udf_encode_symlink(&softlink_buf, 931 &softlink_len, cur->symlink); 932 if (error) { 933 printf("SOFTLINK error %d\n", error); 934 break; 935 } 936 nblk = udf_datablocks(softlink_len); 937 stats->ndatablocks += nblk; 938 fnode->flags |= FI_SIZED; 939 940 free(softlink_buf); 941 } 942 stats->nfiles++; 943 break; 944 } 945 } 946 } 947 948 949 #define UDF_MAX_CHUNK_SIZE (4*1024*1024) 950 static int 951 udf_copy_file(struct stat *st, char *path, fsnode *cur, struct fileid_desc *fid, 952 struct long_ad *icb) 953 { 954 union dscrptr *dscr; 955 struct long_ad data_icb; 956 fsinode *fnode; 957 size_t sz, chunk, rd; 958 uint8_t *data; 959 int nblk; 960 int i, f; 961 int error; 962 963 fnode = cur->inode; 964 965 f = open(path, O_RDONLY); 966 if (f < 0) { 967 warn("Can't open file %s for reading", cur->name); 968 return errno; 969 } 970 971 /* claim disc space for the (e)fe descriptor for this file */ 972 udf_metadata_alloc(1, icb); 973 udf_create_new_file(st, &dscr, UDF_ICB_FILETYPE_RANDOMACCESS, icb); 974 975 sz = fnode->st.st_size; 976 977 chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); 978 data = malloc(MAX(chunk, context.sector_size)); 979 assert(data); 980 981 printf(" "); 982 i = 0; 983 error = 0; 984 while (chunk) { 985 rd = read(f, data, chunk); 986 if (rd != chunk) { 987 warn("Short read of file %s\n", cur->name); 988 error = errno; 989 break; 990 } 991 printf("\b%c", "\\|/-"[i++ % 4]); fflush(stdout);fflush(stderr); 992 993 nblk = udf_datablocks(chunk); 994 if (nblk > 0) 995 udf_data_alloc(nblk, &data_icb); 996 udf_append_file_contents(dscr, &data_icb, data, chunk); 997 998 sz -= chunk; 999 chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); 1000 } 1001 printf("\b \n"); 1002 close(f); 1003 free(data); 1004 1005 /* write out dscr (e)fe */ 1006 udf_set_link_cnt(dscr, fnode->nlink); 1007 udf_write_dscr_virt(dscr, udf_rw32(icb->loc.lb_num), 1008 udf_rw16(icb->loc.part_num), 1); 1009 free(dscr); 1010 1011 /* remember our location for hardlinks */ 1012 cur->inode->fsuse = malloc(sizeof(struct long_ad)); 1013 memcpy(cur->inode->fsuse, icb, sizeof(struct long_ad)); 1014 1015 return error; 1016 } 1017 1018 1019 static int 1020 udf_populate_walk(fsinfo_t *fsopts, fsnode *root, char *dir, 1021 struct long_ad *parent_icb, struct long_ad *dir_icb) 1022 { 1023 union dscrptr *dir_dscr, *dscr; 1024 struct fileid_desc *fid; 1025 struct long_ad icb, data_icb, dirdata_icb; 1026 fsnode *cur; 1027 fsinode *fnode; 1028 size_t pathlen = strlen(dir); 1029 size_t dirlen; 1030 char *mydir = dir + pathlen; 1031 uint32_t nblk, ddoff; 1032 uint32_t softlink_len; 1033 uint8_t *softlink_buf; 1034 uint8_t *dirdata; 1035 int error, ret, retval; 1036 1037 /* claim disc space for the (e)fe descriptor for this dir */ 1038 udf_metadata_alloc(1, dir_icb); 1039 1040 /* create new e(fe) */ 1041 udf_create_new_file(&root->inode->st, &dir_dscr, 1042 UDF_ICB_FILETYPE_DIRECTORY, dir_icb); 1043 1044 /* claim space for the directory contents */ 1045 dirlen = root->inode->st.st_size; 1046 nblk = udf_datablocks(dirlen); 1047 if (nblk > 0) { 1048 /* claim disc space for the dir contents */ 1049 udf_data_alloc(nblk, &dirdata_icb); 1050 } 1051 1052 /* allocate memory for the directory contents */ 1053 nblk++; 1054 dirdata = malloc(nblk * context.sector_size); 1055 assert(dirdata); 1056 memset(dirdata, 0, nblk * context.sector_size); 1057 1058 /* create and append '..' */ 1059 fid = (struct fileid_desc *) dirdata; 1060 ddoff = udf_create_parentfid(fid, parent_icb); 1061 1062 /* for '..' */ 1063 udf_inc_link(dir_dscr); 1064 1065 /* recurse */ 1066 retval = 0; 1067 for (cur = root; cur != NULL; cur = cur->next) { 1068 mydir[0] = '/'; 1069 strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); 1070 1071 fid = (struct fileid_desc *) (dirdata + ddoff); 1072 switch (cur->type & S_IFMT) { 1073 default: 1074 /* what kind of nodes? */ 1075 retval = 2; 1076 break; 1077 case S_IFCHR: 1078 case S_IFBLK: 1079 /* not supported */ 1080 retval = 2; 1081 warnx("device node %s not supported", dir); 1082 break; 1083 case S_IFDIR: 1084 /* not an empty dir? */ 1085 if (strcmp(cur->name, ".") == 0) 1086 break; 1087 assert(cur->child); 1088 if (cur->child) { 1089 ret = udf_populate_walk(fsopts, cur->child, 1090 dir, dir_icb, &icb); 1091 if (ret) 1092 retval = 2; 1093 } 1094 udf_create_fid(ddoff, fid, cur->name, 1095 UDF_FILE_CHAR_DIR, &icb); 1096 udf_inc_link(dir_dscr); 1097 ddoff += udf_fidsize(fid); 1098 break; 1099 case S_IFREG: 1100 fnode = cur->inode; 1101 /* don't re-copy hard-links */ 1102 if (!(fnode->flags & FI_WRITTEN)) { 1103 printf("%s", dir); 1104 error = udf_copy_file(&fnode->st, dir, cur, 1105 fid, &icb); 1106 if (!error) { 1107 fnode->flags |= FI_WRITTEN; 1108 udf_create_fid(ddoff, fid, cur->name, 1109 0, &icb); 1110 ddoff += udf_fidsize(fid); 1111 } else { 1112 retval = 2; 1113 } 1114 } else { 1115 /* hardlink! */ 1116 printf("%s (hardlink)\n", dir); 1117 udf_create_fid(ddoff, fid, cur->name, 1118 0, (struct long_ad *) (fnode->fsuse)); 1119 ddoff += udf_fidsize(fid); 1120 } 1121 fnode->nlink--; 1122 if (fnode->nlink == 0) 1123 free(fnode->fsuse); 1124 break; 1125 case S_IFLNK: 1126 /* softlink */ 1127 fnode = cur->inode; 1128 printf("%s -> %s\n", dir, cur->symlink); 1129 error = udf_encode_symlink(&softlink_buf, 1130 &softlink_len, cur->symlink); 1131 if (error) { 1132 printf("SOFTLINK error %d\n", error); 1133 retval = 2; 1134 break; 1135 } 1136 1137 udf_metadata_alloc(1, &icb); 1138 udf_create_new_file(&fnode->st, &dscr, 1139 UDF_ICB_FILETYPE_SYMLINK, &icb); 1140 1141 nblk = udf_datablocks(softlink_len); 1142 if (nblk > 0) 1143 udf_data_alloc(nblk, &data_icb); 1144 udf_append_file_contents(dscr, &data_icb, 1145 softlink_buf, softlink_len); 1146 1147 /* write out dscr (e)fe */ 1148 udf_inc_link(dscr); 1149 udf_write_dscr_virt(dscr, udf_rw32(icb.loc.lb_num), 1150 udf_rw16(icb.loc.part_num), 1); 1151 1152 free(dscr); 1153 free(softlink_buf); 1154 1155 udf_create_fid(ddoff, fid, cur->name, 0, &icb); 1156 ddoff += udf_fidsize(fid); 1157 break; 1158 } 1159 mydir[0] = '\0'; 1160 } 1161 1162 /* writeout directory contents */ 1163 dirlen = ddoff; /* XXX might bite back */ 1164 1165 udf_prepare_fids(dir_icb, &dirdata_icb, dirdata, dirlen); 1166 udf_append_file_contents(dir_dscr, &dirdata_icb, dirdata, dirlen); 1167 1168 /* write out dir_dscr (e)fe */ 1169 udf_write_dscr_virt(dir_dscr, udf_rw32(dir_icb->loc.lb_num), 1170 udf_rw16(dir_icb->loc.part_num), 1); 1171 1172 free(dirdata); 1173 free(dir_dscr); 1174 return retval; 1175 } 1176 1177 1178 static int 1179 udf_populate(const char *dir, fsnode *root, fsinfo_t *fsopts, 1180 struct udf_stats *stats) 1181 { 1182 struct long_ad rooticb; 1183 static char path[MAXPATHLEN+1]; 1184 int error; 1185 1186 /* make sure the root gets the rootdir entry */ 1187 context.metadata_alloc_pos = layout.rootdir; 1188 context.data_alloc_pos = layout.rootdir; 1189 1190 strncpy(path, dir, sizeof(path)); 1191 error = udf_populate_walk(fsopts, root, path, &rooticb, &rooticb); 1192 1193 return error; 1194 } 1195 1196 1197 static void 1198 udf_enumerate_and_estimate(const char *dir, fsnode *root, fsinfo_t *fsopts, 1199 struct udf_stats *stats) 1200 { 1201 char path[MAXPATHLEN + 1]; 1202 off_t proposed_size; 1203 uint32_t n, nblk; 1204 1205 strncpy(path, dir, sizeof(path)); 1206 1207 /* calculate strict minimal size */ 1208 udf_estimate_walk(fsopts, root, path, stats); 1209 printf("ndirs %d\n", stats->ndirs); 1210 printf("nfiles %d\n", stats->nfiles); 1211 printf("ndata_blocks %d\n", stats->ndatablocks); 1212 printf("nmetadata_blocks %d\n", stats->nmetadatablocks); 1213 printf("\n"); 1214 1215 /* adjust for options : free file nodes */ 1216 if (fsopts->freefiles) { 1217 /* be mercifull and reserve more for the FID */ 1218 stats->nmetadatablocks += fsopts->freefiles * 1.5; 1219 } else if ((n = fsopts->freefilepc)) { 1220 stats->nmetadatablocks += (stats->nmetadatablocks*n) / (100-n); 1221 } 1222 1223 /* adjust for options : free data blocks */ 1224 if (fsopts->freeblocks) { 1225 stats->ndatablocks += fsopts->freeblocks; 1226 } else if ((n = fsopts->freeblockpc)) { 1227 stats->ndatablocks += (stats->ndatablocks * n) / (100-n); 1228 } 1229 1230 /* rough predictor of minimum disc size */ 1231 nblk = stats->ndatablocks + stats->nmetadatablocks; 1232 nblk = (double) nblk * (1.0 + 1.0/8.0); /* free space map */ 1233 nblk += 256; /* pre-volume space */ 1234 nblk += 256; /* post-volume space */ 1235 nblk += 64; /* safeguard */ 1236 1237 /* try to honour minimum size */ 1238 n = fsopts->minsize / fsopts->sectorsize; 1239 if (nblk < n) { 1240 stats->ndatablocks += (n - nblk); 1241 nblk += n - nblk; 1242 } 1243 proposed_size = (off_t) nblk * fsopts->sectorsize; 1244 /* sanity size */ 1245 if (proposed_size < 512*1024) 1246 proposed_size = 512*1024; 1247 1248 if (fsopts->size) { 1249 if (fsopts->size < proposed_size) 1250 err(EINVAL, "makefs_udf: won't fit on disc!"); 1251 } else { 1252 fsopts->size = proposed_size; 1253 } 1254 1255 fsopts->inodes = stats->nfiles + stats->ndirs; 1256 } 1257 1258 1259 void 1260 udf_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) 1261 { 1262 struct udf_stats stats; 1263 uint64_t truncate_len; 1264 char scrap[255]; 1265 int error; 1266 1267 /* determine format */ 1268 udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile); 1269 printf("req_enable %d, req_disable %d\n", req_enable, req_disable); 1270 1271 context.sector_size = fsopts->sectorsize; 1272 error = udf_derive_format(req_enable, req_disable, false); 1273 if (error) 1274 err(EINVAL, "makefs_udf: can't determine format"); 1275 1276 /* names */ 1277 error = udf_proces_names(); 1278 if (error) 1279 err(EINVAL, "makefs_udf: bad names given"); 1280 1281 /* set return value to 1 indicating error */ 1282 error = 1; 1283 1284 /* estimate the amount of space needed */ 1285 memset(&stats, 0, sizeof(stats)); 1286 udf_enumerate_and_estimate(dir, root, fsopts, &stats); 1287 1288 printf("Calculated size of `%s': %lld bytes, %ld inodes\n", 1289 image, (long long)fsopts->size, (long)fsopts->inodes); 1290 1291 /* create file image */ 1292 if ((fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1293 err(EXIT_FAILURE, "%s", image); 1294 } 1295 if (lseek(fd, fsopts->size - 1, SEEK_SET) == -1) { 1296 goto err_exit; 1297 } 1298 if (write(fd, &fd, 1) != 1) { 1299 goto err_exit; 1300 } 1301 if (lseek(fd, 0, SEEK_SET) == -1) { 1302 goto err_exit; 1303 } 1304 fsopts->fd = fd; 1305 1306 /* calculate metadata percentage */ 1307 meta_fract = fsopts->size / (stats.nmetadatablocks*fsopts->sectorsize); 1308 meta_fract = ((int) ((meta_fract + 0.005)*100.0)) / 100; 1309 1310 /* update mmc info but now with correct size */ 1311 udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile); 1312 1313 printf("Building disc compatible with UDF version %x to %x\n\n", 1314 context.min_udf, context.max_udf); 1315 (void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS, 1316 (uint64_t) format_flags); 1317 printf("UDF properties %s\n", scrap); 1318 printf("Volume set `%s'\n", context.volset_name); 1319 printf("Primary volume `%s`\n", context.primary_name); 1320 printf("Logical volume `%s`\n", context.logvol_name); 1321 if (format_flags & FORMAT_META) 1322 printf("Metadata percentage %d %%\n", 1323 (int) (100.0*stats.ndatablocks/stats.nmetadatablocks)); 1324 printf("\n"); 1325 udf_do_newfs_prefix(); 1326 1327 /* update context */ 1328 context.unique_id = 0; 1329 1330 /* XXX are the next two needed? or should be re-count them? */ 1331 context.num_files = stats.nfiles; 1332 context.num_directories = stats.ndirs; 1333 1334 error = udf_populate(dir, root, fsopts, &stats); 1335 1336 udf_do_newfs_postfix(); 1337 1338 if (format_flags & FORMAT_VAT) { 1339 truncate_len = context.vtop_offset[context.data_part] + 1340 context.data_alloc_pos; 1341 truncate_len *= context.sector_size; 1342 1343 printf("\nTruncing the disc-image to allow for VAT\n"); 1344 printf("Free space left on this volume approx. " 1345 "%"PRIu64" KiB, %"PRIu64" MiB\n", 1346 (fsopts->size - truncate_len)/1024, 1347 (fsopts->size - truncate_len)/1024/1024); 1348 ftruncate(fd, truncate_len); 1349 } 1350 1351 if (error) { 1352 error = 2; /* some files couldn't be added */ 1353 goto err_exit; 1354 } 1355 1356 close(fd); 1357 return; 1358 1359 err_exit: 1360 close(fd); 1361 if (error == 2) { 1362 errx(error, "Not all files could be added"); 1363 } else { 1364 errx(error, "creation of %s failed", image); 1365 } 1366 } 1367 1368