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