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