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