1 /* $NetBSD: udf.c,v 1.7 2013/08/06 09:32:23 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.7 2013/08/06 09:32:23 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 < 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, &diskStructure->field, \ 276 sizeof(diskStructure->field) == 8 ? OPT_INT64 : \ 277 (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \ 278 (sizeof(diskStructure->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,dvdram,bdre,disk,cdr,dvdr,bdr,cdrw,dvdrw)"), 292 // { 'P', "progress", &display_progressbar, OPT_INT32, false, true, 293 // "display progress bar" }, 294 { .name = NULL } 295 }; 296 297 /* initialise */ 298 format_str = strdup(""); 299 req_enable = req_disable = 0; 300 format_flags = FORMAT_INVALID; 301 fsopts->sectorsize = 512; /* minimum allowed sector size */ 302 303 srandom((unsigned long) time(NULL)); 304 305 mmc_profile = 0x01; /* 'disc'/file */ 306 307 udf_init_create_context(); 308 context.app_name = APP_NAME; 309 context.impl_name = IMPL_NAME; 310 context.app_version_main = APP_VERSION_MAIN; 311 context.app_version_sub = APP_VERSION_SUB; 312 313 /* minimum and maximum UDF versions we advise */ 314 context.min_udf = 0x102; 315 context.max_udf = 0x201; 316 317 /* use user's time zone as default */ 318 (void)time(&now); 319 tm = localtime(&now); 320 context.gmtoff = tm->tm_gmtoff; 321 322 /* return info */ 323 fsopts->fs_specific = NULL; 324 fsopts->fs_options = copy_opts(udf_options); 325 } 326 327 328 void 329 udf_cleanup_opts(fsinfo_t *fsopts) 330 { 331 free(fsopts->fs_options); 332 } 333 334 335 #define CDRSIZE ((uint64_t) 700*1024*1024) /* small approx */ 336 #define CDRWSIZE ((uint64_t) 576*1024*1024) /* small approx */ 337 #define DVDRSIZE ((uint64_t) 4488*1024*1024) /* small approx */ 338 #define DVDRAMSIZE ((uint64_t) 4330*1024*1024) /* small approx with spare */ 339 #define DVDRWSIZE ((uint64_t) 4482*1024*1024) /* small approx */ 340 #define BDRSIZE ((uint64_t) 23866*1024*1024) /* small approx */ 341 #define BDRESIZE ((uint64_t) 23098*1024*1024) /* small approx */ 342 343 int 344 udf_parse_opts(const char *option, fsinfo_t *fsopts) 345 { 346 option_t *udf_options = fsopts->fs_options; 347 uint64_t stdsize; 348 uint32_t set_sectorsize; 349 const char *name, *desc; 350 char buf[1024]; 351 int i; 352 353 assert(option != NULL); 354 355 if (debug & DEBUG_FS_PARSE_OPTS) 356 printf("udf_parse_opts: got `%s'\n", option); 357 358 i = set_option(udf_options, option, buf, sizeof(buf)); 359 if (i == -1) 360 return 0; 361 362 if (udf_options[i].name == NULL) 363 abort(); 364 365 set_sectorsize = 0; 366 stdsize = 0; 367 368 name = udf_options[i].name; 369 desc = udf_options[i].desc; 370 switch (udf_options[i].letter) { 371 case 'T': 372 if (strcmp(buf, "cdrom") == 0) { 373 mmc_profile = 0x00; 374 } else if (strcmp(buf, "dvdrom") == 0) { 375 mmc_profile = 0x10; 376 } else if (strcmp(buf, "bdrom") == 0) { 377 mmc_profile = 0x40; 378 } else if (strcmp(buf, "dvdram") == 0) { 379 mmc_profile = 0x12; 380 stdsize = DVDRAMSIZE; 381 } else if (strcmp(buf, "bdre") == 0) { 382 mmc_profile = 0x43; 383 stdsize = BDRESIZE; 384 } else if (strcmp(buf, "disk") == 0) { 385 mmc_profile = 0x01; 386 } else if (strcmp(buf, "cdr") == 0) { 387 mmc_profile = 0x09; 388 stdsize = CDRSIZE; 389 } else if (strcmp(buf, "dvdr") == 0) { 390 mmc_profile = 0x1b; 391 stdsize = DVDRSIZE; 392 } else if (strcmp(buf, "bdr") == 0) { 393 mmc_profile = 0x41; 394 stdsize = BDRSIZE; 395 } else if (strcmp(buf, "cdrw") == 0) { 396 mmc_profile = 0x0a; 397 stdsize = CDRWSIZE; 398 } else if (strcmp(buf, "dvdrw") == 0) { 399 mmc_profile = 0x13; 400 stdsize = DVDRWSIZE; 401 } else { 402 errx(EINVAL, "Unknown or unimplemented disc format"); 403 return 0; 404 } 405 if (mmc_profile != 0x01) 406 set_sectorsize = 2048; 407 } 408 if (set_sectorsize) 409 fsopts->sectorsize = set_sectorsize; 410 if (stdsize) 411 fsopts->size = stdsize; 412 return 1; 413 } 414 415 /* --------------------------------------------------------------------- */ 416 417 struct udf_stats { 418 uint32_t nfiles; 419 uint32_t ndirs; 420 uint32_t ndescr; 421 uint32_t nmetadatablocks; 422 uint32_t ndatablocks; 423 }; 424 425 426 /* node reference administration */ 427 static void 428 udf_inc_link(union dscrptr *dscr) 429 { 430 struct file_entry *fe; 431 struct extfile_entry *efe; 432 433 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 434 fe = &dscr->fe; 435 fe->link_cnt = udf_rw16(udf_rw16(fe->link_cnt) + 1); 436 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 437 efe = &dscr->efe; 438 efe->link_cnt = udf_rw16(udf_rw16(efe->link_cnt) + 1); 439 } else { 440 errx(1, "Bad tag passed to udf_inc_link"); 441 } 442 } 443 444 445 static void 446 udf_set_link_cnt(union dscrptr *dscr, int num) 447 { 448 struct file_entry *fe; 449 struct extfile_entry *efe; 450 451 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 452 fe = &dscr->fe; 453 fe->link_cnt = udf_rw16(num); 454 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 455 efe = &dscr->efe; 456 efe->link_cnt = udf_rw16(num); 457 } else { 458 errx(1, "Bad tag passed to udf_set_link_cnt"); 459 } 460 } 461 462 463 static uint32_t 464 udf_datablocks(off_t sz) 465 { 466 /* predictor if it can be written inside the node */ 467 if (sz < context.sector_size - UDF_EXTFENTRY_SIZE - 16) 468 return 0; 469 470 return UDF_ROUNDUP(sz, context.sector_size) / context.sector_size; 471 } 472 473 474 static void 475 udf_prepare_fids(struct long_ad *dir_icb, struct long_ad *dirdata_icb, 476 uint8_t *dirdata, uint32_t dirdata_size) 477 { 478 struct fileid_desc *fid; 479 struct long_ad *icb; 480 uint32_t fidsize, offset; 481 uint32_t location; 482 483 if (udf_datablocks(dirdata_size) == 0) { 484 /* going internal */ 485 icb = dir_icb; 486 } else { 487 /* external blocks to write to */ 488 icb = dirdata_icb; 489 } 490 491 for (offset = 0; offset < dirdata_size; offset += fidsize) { 492 /* for each FID: */ 493 fid = (struct fileid_desc *) (dirdata + offset); 494 assert(udf_rw16(fid->tag.id) == TAGID_FID); 495 496 location = udf_rw32(icb->loc.lb_num); 497 location += offset / context.sector_size; 498 499 fid->tag.tag_loc = udf_rw32(location); 500 udf_validate_tag_and_crc_sums((union dscrptr *) fid); 501 502 fidsize = udf_fidsize(fid); 503 } 504 } 505 506 static int 507 udf_file_inject_blob(union dscrptr *dscr, uint8_t *blob, size_t size) 508 { 509 struct icb_tag *icb; 510 struct file_entry *fe; 511 struct extfile_entry *efe; 512 uint64_t inf_len, obj_size; 513 uint32_t l_ea, l_ad; 514 uint32_t free_space, desc_size; 515 uint16_t crclen; 516 uint8_t *data, *pos; 517 518 fe = NULL; 519 efe = NULL; 520 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 521 fe = &dscr->fe; 522 data = fe->data; 523 l_ea = udf_rw32(fe->l_ea); 524 l_ad = udf_rw32(fe->l_ad); 525 icb = &fe->icbtag; 526 inf_len = udf_rw64(fe->inf_len); 527 obj_size = 0; 528 desc_size = sizeof(struct file_entry); 529 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 530 efe = &dscr->efe; 531 data = efe->data; 532 l_ea = udf_rw32(efe->l_ea); 533 l_ad = udf_rw32(efe->l_ad); 534 icb = &efe->icbtag; 535 inf_len = udf_rw64(efe->inf_len); 536 obj_size = udf_rw64(efe->obj_size); 537 desc_size = sizeof(struct extfile_entry); 538 } else { 539 errx(1, "Bad tag passed to udf_file_inject_blob"); 540 } 541 crclen = udf_rw16(dscr->tag.desc_crc_len); 542 543 /* calculate free space */ 544 free_space = context.sector_size - (l_ea + l_ad) - desc_size; 545 if (udf_datablocks(size)) { 546 assert(free_space < size); 547 return 1; 548 } 549 550 /* going internal */ 551 assert(l_ad == 0); 552 assert((udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) == 553 UDF_ICB_INTERN_ALLOC); 554 555 // assert(free_space >= size); 556 pos = data + l_ea + l_ad; 557 memcpy(pos, blob, size); 558 l_ad += size; 559 crclen += size; 560 561 inf_len += size; 562 obj_size += size; 563 564 if (fe) { 565 fe->l_ad = udf_rw32(l_ad); 566 fe->inf_len = udf_rw64(inf_len); 567 } else if (efe) { 568 efe->l_ad = udf_rw32(l_ad); 569 efe->inf_len = udf_rw64(inf_len); 570 efe->obj_size = udf_rw64(inf_len); 571 } 572 573 /* make sure the header sums stays correct */ 574 dscr->tag.desc_crc_len = udf_rw16(crclen); 575 udf_validate_tag_and_crc_sums(dscr); 576 577 return 0; 578 } 579 580 581 /* XXX no sparse file support */ 582 static void 583 udf_append_file_mapping(union dscrptr *dscr, struct long_ad *piece) 584 { 585 struct icb_tag *icb; 586 struct file_entry *fe; 587 struct extfile_entry *efe; 588 struct long_ad *last_long, last_piece; 589 struct short_ad *last_short, new_short; 590 uint64_t inf_len, obj_size, logblks_rec; 591 uint32_t l_ea, l_ad, size; 592 uint32_t last_lb_num, piece_lb_num; 593 uint32_t last_len, piece_len, last_flags; 594 uint32_t rest_len, merge_len, last_end; 595 uint16_t last_part_num, piece_part_num; 596 uint16_t crclen, cur_alloc; 597 uint8_t *data, *pos; 598 const int short_len = sizeof(struct short_ad); 599 const int long_len = sizeof(struct long_ad); 600 const int sector_size = context.sector_size; 601 const int use_shorts = (context.data_part == context.metadata_part); 602 uint64_t max_len = UDF_ROUNDDOWN(UDF_EXT_MAXLEN, sector_size); 603 604 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 605 fe = &dscr->fe; 606 data = fe->data; 607 l_ea = fe->l_ea; 608 l_ad = udf_rw32(fe->l_ad); 609 icb = &fe->icbtag; 610 inf_len = udf_rw64(fe->inf_len); 611 logblks_rec = udf_rw64(fe->logblks_rec); 612 obj_size = 0; 613 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 614 efe = &dscr->efe; 615 data = efe->data; 616 l_ea = efe->l_ea; 617 l_ad = udf_rw32(efe->l_ad); 618 icb = &efe->icbtag; 619 inf_len = udf_rw64(efe->inf_len); 620 obj_size = udf_rw64(efe->obj_size); 621 logblks_rec = udf_rw64(efe->logblks_rec); 622 } else { 623 errx(1, "Bad tag passed to udf_file_append_blob"); 624 } 625 crclen = udf_rw16(dscr->tag.desc_crc_len); 626 627 pos = data + l_ea; 628 cur_alloc = udf_rw16(icb->flags); 629 size = UDF_EXT_LEN(udf_rw32(piece->len)); 630 631 /* extract last entry as a long_ad */ 632 memset(&last_piece, 0, sizeof(last_piece)); 633 last_len = 0; 634 last_lb_num = 0; 635 last_part_num = 0; 636 if (l_ad != 0) { 637 if (use_shorts) { 638 assert(cur_alloc == UDF_ICB_SHORT_ALLOC); 639 pos += l_ad - short_len; 640 last_short = (struct short_ad *) pos; 641 last_lb_num = udf_rw32(last_short->lb_num); 642 last_part_num = udf_rw16(piece->loc.part_num); 643 last_len = UDF_EXT_LEN(udf_rw32(last_short->len)); 644 last_flags = UDF_EXT_FLAGS(udf_rw32(last_short->len)); 645 } else { 646 assert(cur_alloc == UDF_ICB_LONG_ALLOC); 647 pos += l_ad - long_len; 648 last_long = (struct long_ad *) pos; 649 last_lb_num = udf_rw32(last_long->loc.lb_num); 650 last_part_num = udf_rw16(last_long->loc.part_num); 651 last_len = UDF_EXT_LEN(udf_rw32(last_long->len)); 652 last_flags = UDF_EXT_FLAGS(udf_rw32(last_long->len)); 653 } 654 } 655 656 piece_len = UDF_EXT_LEN(udf_rw32(piece->len)); 657 piece_lb_num = udf_rw32(piece->loc.lb_num); 658 piece_part_num = udf_rw16(piece->loc.part_num); 659 660 /* try merging */ 661 rest_len = max_len - last_len; 662 663 merge_len = MIN(udf_rw32(piece->len), rest_len); 664 last_end = last_lb_num + (last_len / sector_size); 665 666 if ((piece_lb_num == last_end) && (last_part_num == piece_part_num)) { 667 /* we can merge */ 668 last_len += merge_len; 669 piece_len -= merge_len; 670 671 /* write back merge result */ 672 if (use_shorts) { 673 last_short->len = udf_rw32(last_len | last_flags); 674 } else { 675 last_long->len = udf_rw32(last_len | last_flags); 676 } 677 piece_lb_num += merge_len / sector_size; 678 } 679 680 if (piece_len) { 681 /* append new entry */ 682 pos = data + l_ea + l_ad; 683 if (use_shorts) { 684 icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC); 685 memset(&new_short, 0, short_len); 686 new_short.len = udf_rw32(piece_len); 687 new_short.lb_num = udf_rw32(piece_lb_num); 688 memcpy(pos, &new_short, short_len); 689 l_ad += short_len; 690 crclen += short_len; 691 } else { 692 icb->flags = udf_rw16(UDF_ICB_LONG_ALLOC); 693 piece->len = udf_rw32(piece_len); 694 piece->loc.lb_num = udf_rw32(piece_lb_num); 695 memcpy(pos, piece, long_len); 696 l_ad += long_len; 697 crclen += long_len; 698 } 699 } 700 piece->len = udf_rw32(0); 701 702 inf_len += size; 703 obj_size += size; 704 logblks_rec += UDF_ROUNDUP(size, sector_size) / sector_size; 705 706 dscr->tag.desc_crc_len = udf_rw16(crclen); 707 if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { 708 fe->l_ad = udf_rw32(l_ad); 709 fe->inf_len = udf_rw64(inf_len); 710 fe->logblks_rec = udf_rw64(logblks_rec); 711 } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { 712 efe->l_ad = udf_rw32(l_ad); 713 efe->inf_len = udf_rw64(inf_len); 714 efe->obj_size = udf_rw64(inf_len); 715 efe->logblks_rec = udf_rw64(logblks_rec); 716 } 717 } 718 719 720 static int 721 udf_append_file_contents(union dscrptr *dscr, struct long_ad *data_icb, 722 uint8_t *fdata, size_t flen) 723 { 724 struct long_ad icb; 725 uint32_t location; 726 uint32_t phys; 727 uint16_t vpart; 728 uint8_t *bpos; 729 int cnt, sects; 730 int error; 731 732 if (udf_file_inject_blob(dscr, fdata, flen) == 0) 733 return 0; 734 735 /* has to be appended in mappings */ 736 icb = *data_icb; 737 icb.len = udf_rw32(flen); 738 while (udf_rw32(icb.len) > 0) 739 udf_append_file_mapping(dscr, &icb); 740 udf_validate_tag_and_crc_sums(dscr); 741 742 /* write out data piece */ 743 vpart = udf_rw16(data_icb->loc.part_num); 744 location = udf_rw32(data_icb->loc.lb_num); 745 sects = udf_datablocks(flen); 746 for (cnt = 0; cnt < sects; cnt++) { 747 bpos = fdata + cnt*context.sector_size; 748 phys = context.vtop_offset[vpart] + location + cnt; 749 error = udf_write_sector(bpos, phys); 750 if (error) 751 return error; 752 } 753 return 0; 754 } 755 756 757 static int 758 udf_create_new_file(struct stat *st, union dscrptr **dscr, 759 int filetype, struct long_ad *icb) 760 { 761 struct file_entry *fe; 762 struct extfile_entry *efe; 763 int error; 764 765 fe = NULL; 766 efe = NULL; 767 if (context.dscrver == 2) { 768 error = udf_create_new_fe(&fe, filetype, st); 769 if (error) 770 errx(error, "can't create fe"); 771 *dscr = (union dscrptr *) fe; 772 icb->longad_uniqueid = fe->unique_id; 773 } else { 774 error = udf_create_new_efe(&efe, filetype, st); 775 if (error) 776 errx(error, "can't create fe"); 777 *dscr = (union dscrptr *) efe; 778 icb->longad_uniqueid = efe->unique_id; 779 } 780 781 return 0; 782 } 783 784 785 static void 786 udf_estimate_walk(fsinfo_t *fsopts, 787 fsnode *root, char *dir, struct udf_stats *stats) 788 { 789 struct fileid_desc *fid; 790 struct long_ad dummy_ref; 791 fsnode *cur; 792 fsinode *fnode; 793 size_t pathlen = strlen(dir); 794 char *mydir = dir + pathlen; 795 off_t sz; 796 uint32_t nblk, ddoff; 797 uint32_t softlink_len; 798 uint8_t *softlink_buf; 799 int nentries; 800 int error; 801 802 stats->ndirs++; 803 804 /* 805 * Count number of directory entries and count directory size; needed 806 * for the reservation of enough space for the directory. Pity we 807 * don't keep the FIDs we created. If it turns out to be a issue we 808 * can cache it later. 809 */ 810 fid = (struct fileid_desc *) malloc(context.sector_size); 811 assert(fid); 812 813 ddoff = 40; /* '..' entry */ 814 for (cur = root, nentries = 0; cur != NULL; cur = cur->next) { 815 switch (cur->type & S_IFMT) { 816 default: 817 /* what kind of nodes? */ 818 break; 819 case S_IFCHR: 820 case S_IFBLK: 821 /* not supported yet */ 822 continue; 823 case S_IFDIR: 824 if (strcmp(cur->name, ".") == 0) 825 continue; 826 case S_IFLNK: 827 case S_IFREG: 828 /* create dummy FID to see how long name will become */ 829 udf_create_fid(ddoff, fid, cur->name, 0, &dummy_ref); 830 831 nentries++; 832 ddoff += udf_fidsize(fid); 833 } 834 } 835 sz = ddoff; 836 837 root->inode->st.st_size = sz; /* max now */ 838 root->inode->flags |= FI_SIZED; 839 840 nblk = udf_datablocks(sz); 841 stats->nmetadatablocks += nblk; 842 843 /* for each entry in the directory, there needs to be a (E)FE */ 844 stats->nmetadatablocks += nentries + 1; 845 846 /* recurse */ 847 for (cur = root; cur != NULL; cur = cur->next) { 848 switch (cur->type & S_IFMT) { 849 default: 850 /* what kind of nodes? */ 851 break; 852 case S_IFCHR: 853 case S_IFBLK: 854 /* not supported yet */ 855 // stats->nfiles++; 856 break; 857 case S_IFDIR: 858 if (strcmp(cur->name, ".") == 0) 859 continue; 860 /* empty dir? */ 861 if (!cur->child) 862 break; 863 mydir[0] = '/'; 864 strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); 865 udf_estimate_walk(fsopts, cur->child, dir, stats); 866 mydir[0] = '\0'; 867 break; 868 case S_IFREG: 869 fnode = cur->inode; 870 /* don't double-count hard-links */ 871 if (!(fnode->flags & FI_SIZED)) { 872 sz = fnode->st.st_size; 873 nblk = udf_datablocks(sz); 874 stats->ndatablocks += nblk; 875 /* ... */ 876 fnode->flags |= FI_SIZED; 877 } 878 stats->nfiles++; 879 break; 880 case S_IFLNK: 881 /* softlink */ 882 fnode = cur->inode; 883 /* don't double-count hard-links */ 884 if (!(fnode->flags & FI_SIZED)) { 885 error = udf_encode_symlink(&softlink_buf, 886 &softlink_len, cur->symlink); 887 if (error) { 888 printf("SOFTLINK error %d\n", error); 889 break; 890 } 891 nblk = udf_datablocks(softlink_len); 892 stats->ndatablocks += nblk; 893 fnode->flags |= FI_SIZED; 894 895 free(softlink_buf); 896 } 897 stats->nfiles++; 898 break; 899 } 900 } 901 } 902 903 904 #define UDF_MAX_CHUNK_SIZE (4*1024*1024) 905 static int 906 udf_copy_file(struct stat *st, char *path, fsnode *cur, struct fileid_desc *fid, 907 struct long_ad *icb) 908 { 909 union dscrptr *dscr; 910 struct long_ad data_icb; 911 fsinode *fnode; 912 size_t sz, chunk, rd; 913 uint8_t *data; 914 int nblk; 915 int i, f; 916 int error; 917 918 fnode = cur->inode; 919 920 f = open(path, O_RDONLY); 921 if (f < 0) { 922 warn("Can't open file %s for reading", cur->name); 923 return errno; 924 } 925 926 /* claim disc space for the (e)fe descriptor for this file */ 927 udf_metadata_alloc(1, icb); 928 udf_create_new_file(st, &dscr, UDF_ICB_FILETYPE_RANDOMACCESS, icb); 929 930 sz = fnode->st.st_size; 931 932 chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); 933 data = malloc(MAX(chunk, context.sector_size)); 934 assert(data); 935 936 printf(" "); 937 i = 0; 938 error = 0; 939 while (chunk) { 940 rd = read(f, data, chunk); 941 if (rd != chunk) { 942 warn("Short read of file %s\n", cur->name); 943 error = errno; 944 break; 945 } 946 printf("\b%c", "\\|/-"[i++ % 4]); fflush(stdout);fflush(stderr); 947 948 nblk = udf_datablocks(chunk); 949 if (nblk > 0) 950 udf_data_alloc(nblk, &data_icb); 951 udf_append_file_contents(dscr, &data_icb, data, chunk); 952 953 sz -= chunk; 954 chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); 955 } 956 printf("\b \n"); 957 close(f); 958 free(data); 959 960 /* write out dscr (e)fe */ 961 udf_set_link_cnt(dscr, fnode->nlink); 962 udf_write_dscr_virt(dscr, udf_rw32(icb->loc.lb_num), 963 udf_rw16(icb->loc.part_num), 1); 964 free(dscr); 965 966 /* remember our location for hardlinks */ 967 cur->inode->fsuse = malloc(sizeof(struct long_ad)); 968 memcpy(cur->inode->fsuse, icb, sizeof(struct long_ad)); 969 970 return error; 971 } 972 973 974 static int 975 udf_populate_walk(fsinfo_t *fsopts, fsnode *root, char *dir, 976 struct long_ad *parent_icb, struct long_ad *dir_icb) 977 { 978 union dscrptr *dir_dscr, *dscr; 979 struct fileid_desc *fid; 980 struct long_ad icb, data_icb, dirdata_icb; 981 fsnode *cur; 982 fsinode *fnode; 983 size_t pathlen = strlen(dir); 984 size_t dirlen; 985 char *mydir = dir + pathlen; 986 uint32_t nblk, ddoff; 987 uint32_t softlink_len; 988 uint8_t *softlink_buf; 989 uint8_t *dirdata; 990 int error, ret, retval; 991 992 /* claim disc space for the (e)fe descriptor for this dir */ 993 udf_metadata_alloc(1, dir_icb); 994 995 /* create new e(fe) */ 996 udf_create_new_file(&root->inode->st, &dir_dscr, 997 UDF_ICB_FILETYPE_DIRECTORY, dir_icb); 998 999 /* claim space for the directory contents */ 1000 dirlen = root->inode->st.st_size; 1001 nblk = udf_datablocks(dirlen); 1002 if (nblk > 0) { 1003 /* claim disc space for the dir contents */ 1004 udf_data_alloc(nblk, &dirdata_icb); 1005 } 1006 1007 /* allocate memory for the directory contents */ 1008 nblk++; 1009 dirdata = malloc(nblk * context.sector_size); 1010 assert(dirdata); 1011 memset(dirdata, 0, nblk * context.sector_size); 1012 1013 /* create and append '..' */ 1014 fid = (struct fileid_desc *) dirdata; 1015 ddoff = udf_create_parentfid(fid, parent_icb); 1016 1017 /* for '..' */ 1018 udf_inc_link(dir_dscr); 1019 1020 /* recurse */ 1021 retval = 0; 1022 for (cur = root; cur != NULL; cur = cur->next) { 1023 mydir[0] = '/'; 1024 strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); 1025 1026 fid = (struct fileid_desc *) (dirdata + ddoff); 1027 switch (cur->type & S_IFMT) { 1028 default: 1029 /* what kind of nodes? */ 1030 retval = 2; 1031 break; 1032 case S_IFCHR: 1033 case S_IFBLK: 1034 /* not supported */ 1035 retval = 2; 1036 warnx("device node %s not supported", dir); 1037 break; 1038 case S_IFDIR: 1039 /* not an empty dir? */ 1040 if (strcmp(cur->name, ".") == 0) 1041 break; 1042 assert(cur->child); 1043 if (cur->child) { 1044 ret = udf_populate_walk(fsopts, cur->child, 1045 dir, dir_icb, &icb); 1046 if (ret) 1047 retval = 2; 1048 } 1049 udf_create_fid(ddoff, fid, cur->name, 1050 UDF_FILE_CHAR_DIR, &icb); 1051 udf_inc_link(dir_dscr); 1052 ddoff += udf_fidsize(fid); 1053 break; 1054 case S_IFREG: 1055 fnode = cur->inode; 1056 /* don't re-copy hard-links */ 1057 if (!(fnode->flags & FI_WRITTEN)) { 1058 printf("%s", dir); 1059 error = udf_copy_file(&fnode->st, dir, cur, 1060 fid, &icb); 1061 if (!error) { 1062 fnode->flags |= FI_WRITTEN; 1063 udf_create_fid(ddoff, fid, cur->name, 1064 0, &icb); 1065 ddoff += udf_fidsize(fid); 1066 } else { 1067 retval = 2; 1068 } 1069 } else { 1070 /* hardlink! */ 1071 printf("%s (hardlink)\n", dir); 1072 udf_create_fid(ddoff, fid, cur->name, 1073 0, (struct long_ad *) (fnode->fsuse)); 1074 ddoff += udf_fidsize(fid); 1075 } 1076 fnode->nlink--; 1077 if (fnode->nlink == 0) 1078 free(fnode->fsuse); 1079 break; 1080 case S_IFLNK: 1081 /* softlink */ 1082 fnode = cur->inode; 1083 printf("%s -> %s\n", dir, cur->symlink); 1084 error = udf_encode_symlink(&softlink_buf, 1085 &softlink_len, cur->symlink); 1086 if (error) { 1087 printf("SOFTLINK error %d\n", error); 1088 retval = 2; 1089 break; 1090 } 1091 1092 udf_metadata_alloc(1, &icb); 1093 udf_create_new_file(&fnode->st, &dscr, 1094 UDF_ICB_FILETYPE_SYMLINK, &icb); 1095 1096 nblk = udf_datablocks(softlink_len); 1097 if (nblk > 0) 1098 udf_data_alloc(nblk, &data_icb); 1099 udf_append_file_contents(dscr, &data_icb, 1100 softlink_buf, softlink_len); 1101 1102 /* write out dscr (e)fe */ 1103 udf_inc_link(dscr); 1104 udf_write_dscr_virt(dscr, udf_rw32(icb.loc.lb_num), 1105 udf_rw16(icb.loc.part_num), 1); 1106 1107 free(dscr); 1108 free(softlink_buf); 1109 1110 udf_create_fid(ddoff, fid, cur->name, 0, &icb); 1111 ddoff += udf_fidsize(fid); 1112 break; 1113 } 1114 mydir[0] = '\0'; 1115 } 1116 1117 /* writeout directory contents */ 1118 dirlen = ddoff; /* XXX might bite back */ 1119 1120 udf_prepare_fids(dir_icb, &dirdata_icb, dirdata, dirlen); 1121 udf_append_file_contents(dir_dscr, &dirdata_icb, dirdata, dirlen); 1122 1123 /* write out dir_dscr (e)fe */ 1124 udf_write_dscr_virt(dir_dscr, udf_rw32(dir_icb->loc.lb_num), 1125 udf_rw16(dir_icb->loc.part_num), 1); 1126 1127 free(dirdata); 1128 free(dir_dscr); 1129 return retval; 1130 } 1131 1132 1133 static int 1134 udf_populate(const char *dir, fsnode *root, fsinfo_t *fsopts, 1135 struct udf_stats *stats) 1136 { 1137 struct long_ad rooticb; 1138 static char path[MAXPATHLEN+1]; 1139 int error; 1140 1141 /* make sure the root gets the rootdir entry */ 1142 context.metadata_alloc_pos = layout.rootdir; 1143 context.data_alloc_pos = layout.rootdir; 1144 1145 strncpy(path, dir, sizeof(path)); 1146 error = udf_populate_walk(fsopts, root, path, &rooticb, &rooticb); 1147 1148 return error; 1149 } 1150 1151 1152 static void 1153 udf_enumerate_and_estimate(const char *dir, fsnode *root, fsinfo_t *fsopts, 1154 struct udf_stats *stats) 1155 { 1156 char path[MAXPATHLEN + 1]; 1157 off_t proposed_size; 1158 uint32_t n, nblk; 1159 1160 strncpy(path, dir, sizeof(path)); 1161 1162 /* calculate strict minimal size */ 1163 udf_estimate_walk(fsopts, root, path, stats); 1164 printf("ndirs %d\n", stats->ndirs); 1165 printf("nfiles %d\n", stats->nfiles); 1166 printf("ndata_blocks %d\n", stats->ndatablocks); 1167 printf("nmetadata_blocks %d\n", stats->nmetadatablocks); 1168 printf("\n"); 1169 1170 /* adjust for options : free file nodes */ 1171 if (fsopts->freefiles) { 1172 /* be mercifull and reserve more for the FID */ 1173 stats->nmetadatablocks += fsopts->freefiles * 1.5; 1174 } else if ((n = fsopts->freefilepc)) { 1175 stats->nmetadatablocks += (stats->nmetadatablocks*n) / (100-n); 1176 } 1177 1178 /* adjust for options : free data blocks */ 1179 if (fsopts->freeblocks) { 1180 stats->ndatablocks += fsopts->freeblocks; 1181 } else if ((n = fsopts->freeblockpc)) { 1182 stats->ndatablocks += (stats->ndatablocks * n) / (100-n); 1183 } 1184 1185 /* rough predictor of minimum disc size */ 1186 nblk = stats->ndatablocks + stats->nmetadatablocks; 1187 nblk = (double) nblk * (1.0 + 1.0/8.0); /* free space map */ 1188 nblk += 256; /* pre-volume space */ 1189 nblk += 256; /* post-volume space */ 1190 nblk += 64; /* safeguard */ 1191 1192 /* try to honour minimum size */ 1193 n = fsopts->minsize / fsopts->sectorsize; 1194 if (nblk < n) { 1195 stats->ndatablocks += (n - nblk); 1196 nblk += n - nblk; 1197 } 1198 proposed_size = (off_t) nblk * fsopts->sectorsize; 1199 /* sanity size */ 1200 if (proposed_size < 512*1024) 1201 proposed_size = 512*1024; 1202 1203 if (fsopts->size) { 1204 if (fsopts->size < proposed_size) 1205 err(EINVAL, "makefs_udf: won't fit on disc!"); 1206 } else { 1207 fsopts->size = proposed_size; 1208 } 1209 1210 fsopts->inodes = stats->nfiles + stats->ndirs; 1211 } 1212 1213 1214 void 1215 udf_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) 1216 { 1217 struct udf_stats stats; 1218 uint64_t truncate_len; 1219 int error; 1220 1221 /* determine format */ 1222 udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile); 1223 printf("req_enable %d, req_disable %d\n", req_enable, req_disable); 1224 1225 context.sector_size = fsopts->sectorsize; 1226 error = udf_derive_format(req_enable, req_disable, false); 1227 if (error) 1228 err(EINVAL, "makefs_udf: can't determine format"); 1229 1230 /* names */ 1231 error = udf_proces_names(); 1232 if (error) 1233 err(EINVAL, "makefs_udf: bad names given"); 1234 1235 /* set return value to 1 indicating error */ 1236 error = 1; 1237 1238 /* estimate the amount of space needed */ 1239 memset(&stats, 0, sizeof(stats)); 1240 udf_enumerate_and_estimate(dir, root, fsopts, &stats); 1241 1242 printf("Calculated size of `%s': %lld bytes, %ld inodes\n", 1243 image, (long long)fsopts->size, (long)fsopts->inodes); 1244 1245 /* create file image */ 1246 if ((fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1247 err(EXIT_FAILURE, "%s", image); 1248 } 1249 if (lseek(fd, fsopts->size - 1, SEEK_SET) == -1) { 1250 goto err_exit; 1251 } 1252 if (write(fd, &fd, 1) != 1) { 1253 goto err_exit; 1254 } 1255 if (lseek(fd, 0, SEEK_SET) == -1) { 1256 goto err_exit; 1257 } 1258 fsopts->fd = fd; 1259 1260 /* calculate metadata percentage */ 1261 meta_fract = fsopts->size / (stats.nmetadatablocks*fsopts->sectorsize); 1262 meta_fract = ((int) ((meta_fract + 0.005)*100.0)) / 100; 1263 1264 /* update mmc info but now with correct size */ 1265 udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile); 1266 1267 udf_do_newfs_prefix(); 1268 1269 /* update context */ 1270 context.unique_id = 0; 1271 1272 /* XXX are the next two needed? or should be re-count them? */ 1273 context.num_files = stats.nfiles; 1274 context.num_directories = stats.ndirs; 1275 1276 error = udf_populate(dir, root, fsopts, &stats); 1277 1278 udf_do_newfs_postfix(); 1279 1280 if (format_flags & FORMAT_VAT) { 1281 truncate_len = context.vtop_offset[context.data_part] + 1282 context.data_alloc_pos; 1283 truncate_len *= context.sector_size; 1284 1285 printf("\nTruncing the disc-image to allow for VAT\n"); 1286 printf("Free space left on this volume approx. " 1287 "%"PRIu64" KiB, %"PRIu64" MiB\n", 1288 (fsopts->size - truncate_len)/1024, 1289 (fsopts->size - truncate_len)/1024/1024); 1290 ftruncate(fd, truncate_len); 1291 } 1292 1293 if (error) { 1294 error = 2; /* some files couldn't be added */ 1295 goto err_exit; 1296 } 1297 1298 close(fd); 1299 return; 1300 1301 err_exit: 1302 close(fd); 1303 if (error == 2) { 1304 errx(error, "Not all files could be added"); 1305 } else { 1306 errx(error, "creation of %s failed", image); 1307 } 1308 } 1309 1310