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