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