1 /* $NetBSD: udf.c,v 1.17 2015/06/16 23:04:14 christos Exp $ */
4 * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
28 #if HAVE_NBTOOL_CONFIG_H
29 #include "nbtool_config.h"
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: udf.c,v 1.17 2015/06/16 23:04:14 christos Exp $");
44 #include <sys/types.h>
45 #include <sys/param.h>
49 #if !HAVE_NBTOOL_CONFIG_H
53 #include "udf/cdio_mmc_structs.h"
56 #if !HAVE_NBTOOL_CONFIG_H
57 #define HAVE_STRUCT_TM_TM_GMTOFF
61 #include "udf_create.h"
62 #include "udf_write.h"
63 #include "newfs_udf.h"
66 #define APP_NAME "*NetBSD makefs"
69 * Note: due to the setup of the newfs code, the current state of the program
70 * and its options are helt in a few global variables. The FS specific parts
71 * are in a global `context' structure.
74 /* global variables describing disc and format requests */
75 int fd
; /* device: file descriptor */
76 char *dev
; /* device: name */
77 struct mmc_discinfo mmc_discinfo
; /* device: disc info */
79 char *format_str
; /* format: string representation */
80 int format_flags
; /* format: attribute flags */
81 int media_accesstype
; /* derived from current mmc cap */
82 int check_surface
; /* for rewritables */
83 int imagefile_secsize
; /* for files */
85 int display_progressbar
;
88 float meta_fract
= (float) UDF_META_PERC
/ 100.0;
90 int mmc_profile
; /* emulated profile */
91 int req_enable
, req_disable
;
94 /* --------------------------------------------------------------------- */
97 udf_write_sector(void *sector
, uint64_t location
)
102 wpos
= (uint64_t) location
* context
.sector_size
;
103 ret
= pwrite(fd
, sector
, context
.sector_size
, wpos
);
106 if (ret
< (int) context
.sector_size
)
112 /* not implemented for files */
114 udf_surface_check(void)
121 * mmc_discinfo and mmc_trackinfo readers modified from origional in udf main
122 * code in sys/fs/udf/
127 udf_dump_discinfo(struct mmc_discinfo
*di
)
131 printf("Device/media info :\n");
132 printf("\tMMC profile 0x%02x\n", di
->mmc_profile
);
133 printf("\tderived class %d\n", di
->mmc_class
);
134 printf("\tsector size %d\n", di
->sector_size
);
135 printf("\tdisc state %d\n", di
->disc_state
);
136 printf("\tlast ses state %d\n", di
->last_session_state
);
137 printf("\tbg format state %d\n", di
->bg_format_state
);
138 printf("\tfrst track %d\n", di
->first_track
);
139 printf("\tfst on last ses %d\n", di
->first_track_last_session
);
140 printf("\tlst on last ses %d\n", di
->last_track_last_session
);
141 printf("\tlink block penalty %d\n", di
->link_block_penalty
);
142 snprintb(bits
, sizeof(bits
), MMC_DFLAGS_FLAGBITS
,
143 (uint64_t) di
->disc_flags
);
144 printf("\tdisc flags %s\n", bits
);
145 printf("\tdisc id %x\n", di
->disc_id
);
146 printf("\tdisc barcode %"PRIx64
"\n", di
->disc_barcode
);
148 printf("\tnum sessions %d\n", di
->num_sessions
);
149 printf("\tnum tracks %d\n", di
->num_tracks
);
151 snprintb(bits
, sizeof(bits
), MMC_CAP_FLAGBITS
, di
->mmc_cur
);
152 printf("\tcapabilities cur %s\n", bits
);
153 snprintb(bits
, sizeof(bits
), MMC_CAP_FLAGBITS
, di
->mmc_cap
);
154 printf("\tcapabilities cap %s\n", bits
);
156 printf("\tlast_possible_lba %d\n", di
->last_possible_lba
);
160 #define udf_dump_discinfo(a);
163 /* --------------------------------------------------------------------- */
166 udf_emulate_discinfo(fsinfo_t
*fsopts
, struct mmc_discinfo
*di
,
171 memset(di
, 0, sizeof(*di
));
174 if ((mmc_emuprofile
!= 0x01) && (fsopts
->sectorsize
!= 2048))
175 warnx("cd/dvd/bd sectorsize is not set to default 2048");
177 sectors
= fsopts
->size
/ fsopts
->sectorsize
;
180 di
->mmc_profile
= mmc_emuprofile
;
181 di
->disc_state
= MMC_STATE_CLOSED
;
182 di
->last_session_state
= MMC_STATE_CLOSED
;
183 di
->bg_format_state
= MMC_BGFSTATE_COMPLETED
;
184 di
->link_block_penalty
= 0;
186 di
->disc_flags
= MMC_DFLAGS_UNRESTRICTED
;
188 di
->last_possible_lba
= sectors
- 1;
189 di
->sector_size
= fsopts
->sectorsize
;
191 di
->num_sessions
= 1;
195 di
->first_track_last_session
= di
->last_track_last_session
= 1;
197 di
->mmc_cur
= MMC_CAP_RECORDABLE
| MMC_CAP_ZEROLINKBLK
;
198 switch (mmc_emuprofile
) {
199 case 0x00: /* unknown, treat as CDROM */
200 case 0x08: /* CDROM */
201 case 0x10: /* DVDROM */
202 case 0x40: /* BDROM */
203 req_enable
|= FORMAT_READONLY
;
205 case 0x01: /* disc */
206 /* set up a disc info profile for partitions/files */
207 di
->mmc_class
= MMC_CLASS_DISC
;
208 di
->mmc_cur
|= MMC_CAP_REWRITABLE
| MMC_CAP_HW_DEFECTFREE
;
210 case 0x09: /* CD-R */
211 di
->mmc_class
= MMC_CLASS_CD
;
212 di
->mmc_cur
|= MMC_CAP_SEQUENTIAL
;
213 di
->disc_state
= MMC_STATE_EMPTY
;
215 case 0x0a: /* CD-RW + CD-MRW (regretably) */
216 di
->mmc_class
= MMC_CLASS_CD
;
217 di
->mmc_cur
|= MMC_CAP_REWRITABLE
;
219 case 0x13: /* DVD-RW */
220 di
->mmc_class
= MMC_CLASS_DVD
;
221 di
->mmc_cur
|= MMC_CAP_REWRITABLE
;
223 case 0x11: /* DVD-R */
224 case 0x14: /* DVD-RW sequential */
225 case 0x1b: /* DVD+R */
226 case 0x2b: /* DVD+R DL */
227 case 0x51: /* HD DVD-R */
228 di
->mmc_class
= MMC_CLASS_DVD
;
229 di
->mmc_cur
|= MMC_CAP_SEQUENTIAL
;
230 di
->disc_state
= MMC_STATE_EMPTY
;
232 case 0x41: /* BD-R */
233 di
->mmc_class
= MMC_CLASS_BD
;
234 di
->mmc_cur
|= MMC_CAP_SEQUENTIAL
| MMC_CAP_HW_DEFECTFREE
;
235 di
->disc_state
= MMC_STATE_EMPTY
;
237 case 0x43: /* BD-RE */
238 di
->mmc_class
= MMC_CLASS_BD
;
239 di
->mmc_cur
|= MMC_CAP_REWRITABLE
| MMC_CAP_HW_DEFECTFREE
;
242 err(EINVAL
, "makefs_udf: unknown or unimplemented device type");
245 di
->mmc_cap
= di
->mmc_cur
;
247 udf_dump_discinfo(di
);
253 udf_update_trackinfo(struct mmc_discinfo
*di
, struct mmc_trackinfo
*ti
)
255 /* discs partition support */
256 if (ti
->tracknr
!= 1)
262 ti
->track_mode
= 0; /* XXX */
263 ti
->data_mode
= 0; /* XXX */
264 ti
->flags
= MMC_TRACKINFO_LRA_VALID
| MMC_TRACKINFO_NWA_VALID
;
267 ti
->packet_size
= 32; /* take sensible default */
269 ti
->track_size
= di
->last_possible_lba
;
270 ti
->next_writable
= di
->last_possible_lba
;
271 ti
->last_recorded
= ti
->next_writable
;
277 #define OPT_STR(letter, name, desc) \
278 { letter, name, NULL, OPT_STRBUF, 0, 0, desc }
280 #define OPT_NUM(letter, name, field, min, max, desc) \
281 { letter, name, &context.field, \
282 sizeof(context.field) == 8 ? OPT_INT64 : \
283 (sizeof(context.field) == 4 ? OPT_INT32 : \
284 (sizeof(context.field) == 2 ? OPT_INT16 : OPT_INT8)), \
287 #define OPT_BOOL(letter, name, field, desc) \
288 OPT_NUM(letter, name, field, 0, 1, desc)
291 udf_prep_opts(fsinfo_t
*fsopts
)
296 const option_t udf_options
[] = {
297 OPT_STR('T', "disctype", "disc type (cdrom,dvdrom,bdrom,"
298 "dvdram,bdre,disk,cdr,dvdr,bdr,cdrw,dvdrw)"),
299 OPT_STR('L', "loglabel", "\"logical volume name\""),
300 OPT_STR('P', "discid", "\"[volset name ':']"
301 "physical volume name\""),
302 OPT_NUM('t', "tz", gmtoff
, -24, 24, "timezone"),
303 OPT_STR('v', "minver", "minimum UDF version in either "
304 "``0x201'' or ``2.01'' format"),
306 OPT_STR('V', "maxver", "maximum UDF version in either "
307 "``0x201'' or ``2.01'' format"),
313 format_str
= strdup("");
314 req_enable
= req_disable
= 0;
315 format_flags
= FORMAT_INVALID
;
316 fsopts
->sectorsize
= 512; /* minimum allowed sector size */
318 srandom((unsigned long) time(NULL
));
320 mmc_profile
= 0x01; /* 'disc'/file */
322 udf_init_create_context();
323 context
.app_name
= "*NetBSD makefs";
324 context
.app_version_main
= APP_VERSION_MAIN
;
325 context
.app_version_sub
= APP_VERSION_SUB
;
326 context
.impl_name
= IMPL_NAME
;
328 /* minimum and maximum UDF versions we advise */
329 context
.min_udf
= 0x102;
330 context
.max_udf
= 0x201; /* 0x250 and 0x260 are not ready */
332 /* use user's time zone as default */
334 tm
= localtime(&now
);
335 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
336 context
.gmtoff
= tm
->tm_gmtoff
;
342 fsopts
->fs_specific
= NULL
;
343 fsopts
->fs_options
= copy_opts(udf_options
);
348 udf_cleanup_opts(fsinfo_t
*fsopts
)
350 free(fsopts
->fs_options
);
354 /* ----- included from newfs_udf.c ------ */
358 #define CDRSIZE ((uint64_t) 700*1024*1024) /* small approx */
359 #define CDRWSIZE ((uint64_t) 576*1024*1024) /* small approx */
360 #define DVDRSIZE ((uint64_t) 4488*1024*1024) /* small approx */
361 #define DVDRAMSIZE ((uint64_t) 4330*1024*1024) /* small approx with spare */
362 #define DVDRWSIZE ((uint64_t) 4482*1024*1024) /* small approx */
363 #define BDRSIZE ((uint64_t) 23866*1024*1024) /* small approx */
364 #define BDRESIZE ((uint64_t) 23098*1024*1024) /* small approx */
366 udf_parse_opts(const char *option
, fsinfo_t
*fsopts
)
368 option_t
*udf_options
= fsopts
->fs_options
;
370 uint32_t set_sectorsize
;
371 char buffer
[1024], *buf
, *colon
;
374 assert(option
!= NULL
);
376 if (debug
& DEBUG_FS_PARSE_OPTS
)
377 printf("udf_parse_opts: got `%s'\n", option
);
379 i
= set_option(udf_options
, option
, buffer
, sizeof(buffer
));
383 if (udf_options
[i
].name
== NULL
)
390 switch (udf_options
[i
].letter
) {
392 if (strcmp(buf
, "cdrom") == 0) {
394 } else if (strcmp(buf
, "dvdrom") == 0) {
396 } else if (strcmp(buf
, "bdrom") == 0) {
398 } else if (strcmp(buf
, "dvdram") == 0) {
400 stdsize
= DVDRAMSIZE
;
401 } else if (strcmp(buf
, "bdre") == 0) {
404 } else if (strcmp(buf
, "disk") == 0) {
406 } else if (strcmp(buf
, "cdr") == 0) {
409 } else if (strcmp(buf
, "dvdr") == 0) {
412 } else if (strcmp(buf
, "bdr") == 0) {
415 } else if (strcmp(buf
, "cdrw") == 0) {
418 } else if (strcmp(buf
, "dvdrw") == 0) {
422 errx(EINVAL
, "Unknown or unimplemented disc format");
425 if (mmc_profile
!= 0x01)
426 set_sectorsize
= 2048;
429 if (context
.logvol_name
) free(context
.logvol_name
);
430 context
.logvol_name
= strdup(buf
);
433 if ((colon
= strstr(buf
, ":"))) {
434 if (context
.volset_name
)
435 free(context
.volset_name
);
437 context
.volset_name
= strdup(buf
);
440 if (context
.primary_name
)
441 free(context
.primary_name
);
442 if ((strstr(buf
, ":"))) {
443 errx(EINVAL
, "primary name can't have ':' in its name");
446 context
.primary_name
= strdup(buf
);
449 context
.min_udf
= a_udf_version(buf
, "min_udf");
450 if (context
.min_udf
> 0x201) {
451 errx(EINVAL
, "maximum supported version is UDF 2.01");
454 if (context
.min_udf
> context
.max_udf
)
455 context
.max_udf
= context
.min_udf
;
459 fsopts
->sectorsize
= set_sectorsize
;
461 fsopts
->size
= stdsize
;
465 /* --------------------------------------------------------------------- */
471 uint32_t nmetadatablocks
;
472 uint32_t ndatablocks
;
476 /* node reference administration */
478 udf_inc_link(union dscrptr
*dscr
)
480 struct file_entry
*fe
;
481 struct extfile_entry
*efe
;
483 if (udf_rw16(dscr
->tag
.id
) == TAGID_FENTRY
) {
485 fe
->link_cnt
= udf_rw16(udf_rw16(fe
->link_cnt
) + 1);
486 } else if (udf_rw16(dscr
->tag
.id
) == TAGID_EXTFENTRY
) {
488 efe
->link_cnt
= udf_rw16(udf_rw16(efe
->link_cnt
) + 1);
490 errx(1, "Bad tag passed to udf_inc_link");
496 udf_set_link_cnt(union dscrptr
*dscr
, int num
)
498 struct file_entry
*fe
;
499 struct extfile_entry
*efe
;
501 if (udf_rw16(dscr
->tag
.id
) == TAGID_FENTRY
) {
503 fe
->link_cnt
= udf_rw16(num
);
504 } else if (udf_rw16(dscr
->tag
.id
) == TAGID_EXTFENTRY
) {
506 efe
->link_cnt
= udf_rw16(num
);
508 errx(1, "Bad tag passed to udf_set_link_cnt");
514 udf_datablocks(off_t sz
)
516 /* predictor if it can be written inside the node */
517 if (sz
< context
.sector_size
- UDF_EXTFENTRY_SIZE
- 16)
520 return UDF_ROUNDUP(sz
, context
.sector_size
) / context
.sector_size
;
525 udf_prepare_fids(struct long_ad
*dir_icb
, struct long_ad
*dirdata_icb
,
526 uint8_t *dirdata
, uint32_t dirdata_size
)
528 struct fileid_desc
*fid
;
530 uint32_t fidsize
, offset
;
533 if (udf_datablocks(dirdata_size
) == 0) {
537 /* external blocks to write to */
541 for (offset
= 0; offset
< dirdata_size
; offset
+= fidsize
) {
543 fid
= (struct fileid_desc
*) (dirdata
+ offset
);
544 assert(udf_rw16(fid
->tag
.id
) == TAGID_FID
);
546 location
= udf_rw32(icb
->loc
.lb_num
);
547 location
+= offset
/ context
.sector_size
;
549 fid
->tag
.tag_loc
= udf_rw32(location
);
550 udf_validate_tag_and_crc_sums((union dscrptr
*) fid
);
552 fidsize
= udf_fidsize(fid
);
557 udf_file_inject_blob(union dscrptr
*dscr
, uint8_t *blob
, off_t size
)
560 struct file_entry
*fe
;
561 struct extfile_entry
*efe
;
562 uint64_t inf_len
, obj_size
;
564 uint32_t free_space
, desc_size
;
570 if (udf_rw16(dscr
->tag
.id
) == TAGID_FENTRY
) {
573 l_ea
= udf_rw32(fe
->l_ea
);
574 l_ad
= udf_rw32(fe
->l_ad
);
576 inf_len
= udf_rw64(fe
->inf_len
);
578 desc_size
= sizeof(struct file_entry
);
579 } else if (udf_rw16(dscr
->tag
.id
) == TAGID_EXTFENTRY
) {
582 l_ea
= udf_rw32(efe
->l_ea
);
583 l_ad
= udf_rw32(efe
->l_ad
);
585 inf_len
= udf_rw64(efe
->inf_len
);
586 obj_size
= udf_rw64(efe
->obj_size
);
587 desc_size
= sizeof(struct extfile_entry
);
589 errx(1, "Bad tag passed to udf_file_inject_blob");
591 crclen
= udf_rw16(dscr
->tag
.desc_crc_len
);
593 /* calculate free space */
594 free_space
= context
.sector_size
- (l_ea
+ l_ad
) - desc_size
;
595 if (udf_datablocks(size
)) {
596 #if !defined(NDEBUG) && defined(__minix)
597 assert(free_space
< size
);
599 if (!(free_space
< size
)) {
600 printf("%s:%d not enough free space\n", __FILE__
, __LINE__
);
603 #endif /* !defined(NDEBUG) && defined(__minix) */
609 #if !defined(NDEBUG) && defined(__minix)
610 assert((udf_rw16(icb
->flags
) & UDF_ICB_TAG_FLAGS_ALLOC_MASK
) ==
611 UDF_ICB_INTERN_ALLOC
);
613 if (!((udf_rw16(icb
->flags
) & UDF_ICB_TAG_FLAGS_ALLOC_MASK
) == UDF_ICB_INTERN_ALLOC
)) {
614 printf("%s:%d: allocation flags mismatch\n", __FILE__
, __LINE__
);
617 #endif /* !defined(NDEBUG) && defined(__minix) */
619 // assert(free_space >= size);
620 pos
= data
+ l_ea
+ l_ad
;
621 memcpy(pos
, blob
, size
);
629 fe
->l_ad
= udf_rw32(l_ad
);
630 fe
->inf_len
= udf_rw64(inf_len
);
632 efe
->l_ad
= udf_rw32(l_ad
);
633 efe
->inf_len
= udf_rw64(inf_len
);
634 efe
->obj_size
= udf_rw64(inf_len
);
637 /* make sure the header sums stays correct */
638 dscr
->tag
.desc_crc_len
= udf_rw16(crclen
);
639 udf_validate_tag_and_crc_sums(dscr
);
645 /* XXX no sparse file support */
647 udf_append_file_mapping(union dscrptr
*dscr
, struct long_ad
*piece
)
650 struct file_entry
*fe
;
651 struct extfile_entry
*efe
;
652 struct long_ad
*last_long
, last_piece
;
653 struct short_ad
*last_short
, new_short
;
654 uint64_t inf_len
, obj_size
, logblks_rec
;
655 uint32_t l_ea
, l_ad
, size
;
656 uint32_t last_lb_num
, piece_lb_num
;
657 uint64_t last_len
, piece_len
, last_flags
;
658 uint64_t rest_len
, merge_len
, last_end
;
659 uint16_t last_part_num
, piece_part_num
;
660 uint16_t crclen
, cur_alloc
;
662 const int short_len
= sizeof(struct short_ad
);
663 const int long_len
= sizeof(struct long_ad
);
664 const int sector_size
= context
.sector_size
;
665 const int use_shorts
= (context
.data_part
== context
.metadata_part
);
666 uint64_t max_len
= UDF_ROUNDDOWN(UDF_EXT_MAXLEN
, sector_size
);
670 if (udf_rw16(dscr
->tag
.id
) == TAGID_FENTRY
) {
674 l_ad
= udf_rw32(fe
->l_ad
);
676 inf_len
= udf_rw64(fe
->inf_len
);
677 logblks_rec
= udf_rw64(fe
->logblks_rec
);
679 } else if (udf_rw16(dscr
->tag
.id
) == TAGID_EXTFENTRY
) {
683 l_ad
= udf_rw32(efe
->l_ad
);
685 inf_len
= udf_rw64(efe
->inf_len
);
686 obj_size
= udf_rw64(efe
->obj_size
);
687 logblks_rec
= udf_rw64(efe
->logblks_rec
);
689 errx(1, "Bad tag passed to udf_file_append_blob");
691 crclen
= udf_rw16(dscr
->tag
.desc_crc_len
);
694 cur_alloc
= udf_rw16(icb
->flags
);
695 size
= UDF_EXT_LEN(udf_rw32(piece
->len
));
697 /* extract last entry as a long_ad */
698 memset(&last_piece
, 0, sizeof(last_piece
));
707 #if !defined(NDEBUG) && defined(__minix)
708 assert(cur_alloc
== UDF_ICB_SHORT_ALLOC
);
710 if (!(cur_alloc
== UDF_ICB_SHORT_ALLOC
)) {
711 printf("%s:%d: Expecting UDF_ICB_SHORT_ALLOC allocation\n", __FILE__
, __LINE__
);
714 #endif /* !defined(NDEBUG) && defined(__minix) */
715 pos
+= l_ad
- short_len
;
716 last_short
= (struct short_ad
*) pos
;
717 last_lb_num
= udf_rw32(last_short
->lb_num
);
718 last_part_num
= udf_rw16(piece
->loc
.part_num
);
719 last_len
= UDF_EXT_LEN(udf_rw32(last_short
->len
));
720 last_flags
= UDF_EXT_FLAGS(udf_rw32(last_short
->len
));
722 #if !defined(NDEBUG) && defined(__minix)
723 assert(cur_alloc
== UDF_ICB_LONG_ALLOC
);
725 if (!(cur_alloc
== UDF_ICB_LONG_ALLOC
)) {
726 printf("%s:%d: Expecting UDF_ICB_LONG_ALLOC allocation\n", __FILE__
, __LINE__
);
729 #endif /* !defined(NDEBUG) && defined(__minix) */
730 pos
+= l_ad
- long_len
;
731 last_long
= (struct long_ad
*) pos
;
732 last_lb_num
= udf_rw32(last_long
->loc
.lb_num
);
733 last_part_num
= udf_rw16(last_long
->loc
.part_num
);
734 last_len
= UDF_EXT_LEN(udf_rw32(last_long
->len
));
735 last_flags
= UDF_EXT_FLAGS(udf_rw32(last_long
->len
));
739 piece_len
= UDF_EXT_LEN(udf_rw32(piece
->len
));
740 piece_lb_num
= udf_rw32(piece
->loc
.lb_num
);
741 piece_part_num
= udf_rw16(piece
->loc
.part_num
);
744 rest_len
= max_len
- last_len
;
746 merge_len
= MIN(piece_len
, rest_len
);
747 last_end
= last_lb_num
+ (last_len
/ sector_size
);
749 if ((piece_lb_num
== last_end
) && (last_part_num
== piece_part_num
)) {
751 last_len
+= merge_len
;
752 piece_len
-= merge_len
;
754 /* write back merge result */
756 last_short
->len
= udf_rw32(last_len
| last_flags
);
758 last_long
->len
= udf_rw32(last_len
| last_flags
);
760 piece_lb_num
+= merge_len
/ sector_size
;
764 /* append new entry */
765 pos
= data
+ l_ea
+ l_ad
;
767 icb
->flags
= udf_rw16(UDF_ICB_SHORT_ALLOC
);
768 memset(&new_short
, 0, short_len
);
769 new_short
.len
= udf_rw32(piece_len
);
770 new_short
.lb_num
= udf_rw32(piece_lb_num
);
771 memcpy(pos
, &new_short
, short_len
);
775 icb
->flags
= udf_rw16(UDF_ICB_LONG_ALLOC
);
776 piece
->len
= udf_rw32(piece_len
);
777 piece
->loc
.lb_num
= udf_rw32(piece_lb_num
);
778 memcpy(pos
, piece
, long_len
);
783 piece
->len
= udf_rw32(0);
787 logblks_rec
+= UDF_ROUNDUP(size
, sector_size
) / sector_size
;
789 dscr
->tag
.desc_crc_len
= udf_rw16(crclen
);
790 if (udf_rw16(dscr
->tag
.id
) == TAGID_FENTRY
) {
791 fe
->l_ad
= udf_rw32(l_ad
);
792 fe
->inf_len
= udf_rw64(inf_len
);
793 fe
->logblks_rec
= udf_rw64(logblks_rec
);
794 } else if (udf_rw16(dscr
->tag
.id
) == TAGID_EXTFENTRY
) {
795 efe
->l_ad
= udf_rw32(l_ad
);
796 efe
->inf_len
= udf_rw64(inf_len
);
797 efe
->obj_size
= udf_rw64(inf_len
);
798 efe
->logblks_rec
= udf_rw64(logblks_rec
);
804 udf_append_file_contents(union dscrptr
*dscr
, struct long_ad
*data_icb
,
805 uint8_t *fdata
, off_t flen
)
815 if (udf_file_inject_blob(dscr
, fdata
, flen
) == 0)
818 /* has to be appended in mappings */
820 icb
.len
= udf_rw32(flen
);
821 while (udf_rw32(icb
.len
) > 0)
822 udf_append_file_mapping(dscr
, &icb
);
823 udf_validate_tag_and_crc_sums(dscr
);
825 /* write out data piece */
826 vpart
= udf_rw16(data_icb
->loc
.part_num
);
827 location
= udf_rw32(data_icb
->loc
.lb_num
);
828 sects
= udf_datablocks(flen
);
829 for (cnt
= 0; cnt
< sects
; cnt
++) {
830 bpos
= fdata
+ cnt
*context
.sector_size
;
831 phys
= context
.vtop_offset
[vpart
] + location
+ cnt
;
832 error
= udf_write_sector(bpos
, phys
);
841 udf_create_new_file(struct stat
*st
, union dscrptr
**dscr
,
842 int filetype
, struct long_ad
*icb
)
844 struct file_entry
*fe
;
845 struct extfile_entry
*efe
;
850 if (context
.dscrver
== 2) {
851 error
= udf_create_new_fe(&fe
, filetype
, st
);
853 errx(error
, "can't create fe");
854 *dscr
= (union dscrptr
*) fe
;
855 icb
->longad_uniqueid
= fe
->unique_id
;
857 error
= udf_create_new_efe(&efe
, filetype
, st
);
859 errx(error
, "can't create fe");
860 *dscr
= (union dscrptr
*) efe
;
861 icb
->longad_uniqueid
= efe
->unique_id
;
869 udf_estimate_walk(fsinfo_t
*fsopts
,
870 fsnode
*root
, char *dir
, struct udf_stats
*stats
)
872 struct fileid_desc
*fid
;
873 struct long_ad dummy_ref
;
876 size_t pathlen
= strlen(dir
);
877 char *mydir
= dir
+ pathlen
;
879 uint32_t nblk
, ddoff
;
880 uint32_t softlink_len
;
881 uint8_t *softlink_buf
;
888 * Count number of directory entries and count directory size; needed
889 * for the reservation of enough space for the directory. Pity we
890 * don't keep the FIDs we created. If it turns out to be a issue we
891 * can cache it later.
893 fid
= (struct fileid_desc
*) malloc(context
.sector_size
);
896 ddoff
= 40; /* '..' entry */
897 for (cur
= root
, nentries
= 0; cur
!= NULL
; cur
= cur
->next
) {
898 switch (cur
->type
& S_IFMT
) {
900 /* what kind of nodes? */
904 /* not supported yet */
907 if (strcmp(cur
->name
, ".") == 0)
911 /* create dummy FID to see how long name will become */
912 memset(&dummy_ref
, 0, sizeof(dummy_ref
));
913 udf_create_fid(ddoff
, fid
, cur
->name
, 0, &dummy_ref
);
916 ddoff
+= udf_fidsize(fid
);
921 root
->inode
->st
.st_size
= sz
; /* max now */
922 root
->inode
->flags
|= FI_SIZED
;
924 nblk
= udf_datablocks(sz
);
925 stats
->nmetadatablocks
+= nblk
;
927 /* for each entry in the directory, there needs to be a (E)FE */
928 stats
->nmetadatablocks
+= nentries
+ 1;
931 for (cur
= root
; cur
!= NULL
; cur
= cur
->next
) {
932 switch (cur
->type
& S_IFMT
) {
934 /* what kind of nodes? */
938 /* not supported yet */
942 if (strcmp(cur
->name
, ".") == 0)
948 strncpy(&mydir
[1], cur
->name
, MAXPATHLEN
- pathlen
);
949 udf_estimate_walk(fsopts
, cur
->child
, dir
, stats
);
954 /* don't double-count hard-links */
955 if (!(fnode
->flags
& FI_SIZED
)) {
956 sz
= fnode
->st
.st_size
;
957 nblk
= udf_datablocks(sz
);
958 stats
->ndatablocks
+= nblk
;
960 fnode
->flags
|= FI_SIZED
;
967 /* don't double-count hard-links */
968 if (!(fnode
->flags
& FI_SIZED
)) {
969 error
= udf_encode_symlink(&softlink_buf
,
970 &softlink_len
, cur
->symlink
);
972 printf("SOFTLINK error %d\n", error
);
975 nblk
= udf_datablocks(softlink_len
);
976 stats
->ndatablocks
+= nblk
;
977 fnode
->flags
|= FI_SIZED
;
988 #define UDF_MAX_CHUNK_SIZE (4*1024*1024)
990 udf_copy_file(struct stat
*st
, char *path
, fsnode
*cur
, struct fileid_desc
*fid
,
994 struct long_ad data_icb
;
1004 f
= open(path
, O_RDONLY
);
1006 warn("Can't open file %s for reading", cur
->name
);
1010 /* claim disc space for the (e)fe descriptor for this file */
1011 udf_metadata_alloc(1, icb
);
1012 udf_create_new_file(st
, &dscr
, UDF_ICB_FILETYPE_RANDOMACCESS
, icb
);
1014 sz
= fnode
->st
.st_size
;
1016 chunk
= MIN(sz
, UDF_MAX_CHUNK_SIZE
);
1017 data
= malloc(MAX(chunk
, context
.sector_size
));
1024 rd
= read(f
, data
, chunk
);
1026 warn("Short read of file %s", cur
->name
);
1030 printf("\b%c", "\\|/-"[i
++ % 4]); fflush(stdout
);fflush(stderr
);
1032 nblk
= udf_datablocks(chunk
);
1034 udf_data_alloc(nblk
, &data_icb
);
1035 udf_append_file_contents(dscr
, &data_icb
, data
, chunk
);
1038 chunk
= MIN(sz
, UDF_MAX_CHUNK_SIZE
);
1044 /* write out dscr (e)fe */
1045 udf_set_link_cnt(dscr
, fnode
->nlink
);
1046 udf_write_dscr_virt(dscr
, udf_rw32(icb
->loc
.lb_num
),
1047 udf_rw16(icb
->loc
.part_num
), 1);
1050 /* remember our location for hardlinks */
1051 cur
->inode
->fsuse
= malloc(sizeof(struct long_ad
));
1052 memcpy(cur
->inode
->fsuse
, icb
, sizeof(struct long_ad
));
1059 udf_populate_walk(fsinfo_t
*fsopts
, fsnode
*root
, char *dir
,
1060 struct long_ad
*parent_icb
, struct long_ad
*dir_icb
)
1062 union dscrptr
*dir_dscr
, *dscr
;
1063 struct fileid_desc
*fid
;
1064 struct long_ad icb
, data_icb
, dirdata_icb
;
1067 size_t pathlen
= strlen(dir
);
1069 char *mydir
= dir
+ pathlen
;
1070 uint32_t nblk
, ddoff
;
1071 uint32_t softlink_len
;
1072 uint8_t *softlink_buf
;
1074 int error
, ret
, retval
;
1076 /* claim disc space for the (e)fe descriptor for this dir */
1077 udf_metadata_alloc(1, dir_icb
);
1079 /* create new e(fe) */
1080 udf_create_new_file(&root
->inode
->st
, &dir_dscr
,
1081 UDF_ICB_FILETYPE_DIRECTORY
, dir_icb
);
1083 /* claim space for the directory contents */
1084 dirlen
= root
->inode
->st
.st_size
;
1085 nblk
= udf_datablocks(dirlen
);
1087 /* claim disc space for the dir contents */
1088 udf_data_alloc(nblk
, &dirdata_icb
);
1091 /* allocate memory for the directory contents */
1093 dirdata
= malloc(nblk
* context
.sector_size
);
1095 memset(dirdata
, 0, nblk
* context
.sector_size
);
1097 /* create and append '..' */
1098 fid
= (struct fileid_desc
*) dirdata
;
1099 ddoff
= udf_create_parentfid(fid
, parent_icb
);
1102 udf_inc_link(dir_dscr
);
1106 for (cur
= root
; cur
!= NULL
; cur
= cur
->next
) {
1108 strncpy(&mydir
[1], cur
->name
, MAXPATHLEN
- pathlen
);
1110 fid
= (struct fileid_desc
*) (dirdata
+ ddoff
);
1111 switch (cur
->type
& S_IFMT
) {
1113 /* what kind of nodes? */
1120 warnx("device node %s not supported", dir
);
1123 /* not an empty dir? */
1124 if (strcmp(cur
->name
, ".") == 0)
1128 ret
= udf_populate_walk(fsopts
, cur
->child
,
1129 dir
, dir_icb
, &icb
);
1133 udf_create_fid(ddoff
, fid
, cur
->name
,
1134 UDF_FILE_CHAR_DIR
, &icb
);
1135 udf_inc_link(dir_dscr
);
1136 ddoff
+= udf_fidsize(fid
);
1140 /* don't re-copy hard-links */
1141 if (!(fnode
->flags
& FI_WRITTEN
)) {
1143 error
= udf_copy_file(&fnode
->st
, dir
, cur
,
1146 fnode
->flags
|= FI_WRITTEN
;
1147 udf_create_fid(ddoff
, fid
, cur
->name
,
1149 ddoff
+= udf_fidsize(fid
);
1155 printf("%s (hardlink)\n", dir
);
1156 udf_create_fid(ddoff
, fid
, cur
->name
,
1157 0, (struct long_ad
*) (fnode
->fsuse
));
1158 ddoff
+= udf_fidsize(fid
);
1161 if (fnode
->nlink
== 0)
1167 printf("%s -> %s\n", dir
, cur
->symlink
);
1168 error
= udf_encode_symlink(&softlink_buf
,
1169 &softlink_len
, cur
->symlink
);
1171 printf("SOFTLINK error %d\n", error
);
1176 udf_metadata_alloc(1, &icb
);
1177 udf_create_new_file(&fnode
->st
, &dscr
,
1178 UDF_ICB_FILETYPE_SYMLINK
, &icb
);
1180 nblk
= udf_datablocks(softlink_len
);
1182 udf_data_alloc(nblk
, &data_icb
);
1183 udf_append_file_contents(dscr
, &data_icb
,
1184 softlink_buf
, softlink_len
);
1186 /* write out dscr (e)fe */
1188 udf_write_dscr_virt(dscr
, udf_rw32(icb
.loc
.lb_num
),
1189 udf_rw16(icb
.loc
.part_num
), 1);
1194 udf_create_fid(ddoff
, fid
, cur
->name
, 0, &icb
);
1195 ddoff
+= udf_fidsize(fid
);
1201 /* writeout directory contents */
1202 dirlen
= ddoff
; /* XXX might bite back */
1204 udf_prepare_fids(dir_icb
, &dirdata_icb
, dirdata
, dirlen
);
1205 udf_append_file_contents(dir_dscr
, &dirdata_icb
, dirdata
, dirlen
);
1207 /* write out dir_dscr (e)fe */
1208 udf_write_dscr_virt(dir_dscr
, udf_rw32(dir_icb
->loc
.lb_num
),
1209 udf_rw16(dir_icb
->loc
.part_num
), 1);
1218 udf_populate(const char *dir
, fsnode
*root
, fsinfo_t
*fsopts
,
1219 struct udf_stats
*stats
)
1221 struct long_ad rooticb
;
1222 static char path
[MAXPATHLEN
+1];
1225 /* make sure the root gets the rootdir entry */
1226 context
.metadata_alloc_pos
= layout
.rootdir
;
1227 context
.data_alloc_pos
= layout
.rootdir
;
1229 strncpy(path
, dir
, sizeof(path
));
1230 error
= udf_populate_walk(fsopts
, root
, path
, &rooticb
, &rooticb
);
1237 udf_enumerate_and_estimate(const char *dir
, fsnode
*root
, fsinfo_t
*fsopts
,
1238 struct udf_stats
*stats
)
1240 char path
[MAXPATHLEN
+ 1];
1241 off_t proposed_size
;
1244 strncpy(path
, dir
, sizeof(path
));
1246 /* calculate strict minimal size */
1247 udf_estimate_walk(fsopts
, root
, path
, stats
);
1248 printf("ndirs %d\n", stats
->ndirs
);
1249 printf("nfiles %d\n", stats
->nfiles
);
1250 printf("ndata_blocks %d\n", stats
->ndatablocks
);
1251 printf("nmetadata_blocks %d\n", stats
->nmetadatablocks
);
1254 /* adjust for options : free file nodes */
1255 if (fsopts
->freefiles
) {
1256 /* be mercifull and reserve more for the FID */
1257 stats
->nmetadatablocks
+= fsopts
->freefiles
* 1.5;
1258 } else if ((n
= fsopts
->freefilepc
)) {
1259 stats
->nmetadatablocks
+= (stats
->nmetadatablocks
*n
) / (100-n
);
1262 /* adjust for options : free data blocks */
1263 if (fsopts
->freeblocks
) {
1264 stats
->ndatablocks
+= fsopts
->freeblocks
;
1265 } else if ((n
= fsopts
->freeblockpc
)) {
1266 stats
->ndatablocks
+= (stats
->ndatablocks
* n
) / (100-n
);
1269 /* rough predictor of minimum disc size */
1270 nblk
= stats
->ndatablocks
+ stats
->nmetadatablocks
;
1271 nblk
= (double) nblk
* (1.0 + 1.0/8.0); /* free space map */
1272 nblk
+= 256; /* pre-volume space */
1273 nblk
+= 256; /* post-volume space */
1274 nblk
+= 64; /* safeguard */
1276 /* try to honour minimum size */
1277 n
= fsopts
->minsize
/ fsopts
->sectorsize
;
1279 stats
->ndatablocks
+= (n
- nblk
);
1282 proposed_size
= (off_t
) nblk
* fsopts
->sectorsize
;
1284 if (proposed_size
< 512*1024)
1285 proposed_size
= 512*1024;
1288 if (fsopts
->size
< proposed_size
)
1289 err(EINVAL
, "makefs_udf: won't fit on disc!");
1291 fsopts
->size
= proposed_size
;
1294 fsopts
->inodes
= stats
->nfiles
+ stats
->ndirs
;
1299 udf_makefs(const char *image
, const char *dir
, fsnode
*root
, fsinfo_t
*fsopts
)
1301 struct udf_stats stats
;
1302 uint64_t truncate_len
;
1306 /* determine format */
1307 udf_emulate_discinfo(fsopts
, &mmc_discinfo
, mmc_profile
);
1308 printf("req_enable %d, req_disable %d\n", req_enable
, req_disable
);
1310 context
.sector_size
= fsopts
->sectorsize
;
1311 error
= udf_derive_format(req_enable
, req_disable
, false);
1313 err(EINVAL
, "makefs_udf: can't determine format");
1316 error
= udf_proces_names();
1318 err(EINVAL
, "makefs_udf: bad names given");
1320 /* set return value to 1 indicating error */
1323 /* estimate the amount of space needed */
1324 memset(&stats
, 0, sizeof(stats
));
1325 udf_enumerate_and_estimate(dir
, root
, fsopts
, &stats
);
1327 printf("Calculated size of `%s': %lld bytes, %ld inodes\n",
1328 image
, (long long)fsopts
->size
, (long)fsopts
->inodes
);
1330 /* create file image */
1331 if ((fd
= open(image
, O_RDWR
| O_CREAT
| O_TRUNC
, 0666)) == -1) {
1332 err(EXIT_FAILURE
, "%s", image
);
1334 if (lseek(fd
, fsopts
->size
- 1, SEEK_SET
) == -1) {
1337 if (write(fd
, &fd
, 1) != 1) {
1340 if (lseek(fd
, 0, SEEK_SET
) == -1) {
1345 /* calculate metadata percentage */
1346 meta_fract
= fsopts
->size
/ (stats
.nmetadatablocks
*fsopts
->sectorsize
);
1347 meta_fract
= ((int) ((meta_fract
+ 0.005)*100.0)) / 100;
1349 /* update mmc info but now with correct size */
1350 udf_emulate_discinfo(fsopts
, &mmc_discinfo
, mmc_profile
);
1352 printf("Building disc compatible with UDF version %x to %x\n\n",
1353 context
.min_udf
, context
.max_udf
);
1354 (void)snprintb(scrap
, sizeof(scrap
), FORMAT_FLAGBITS
,
1355 (uint64_t) format_flags
);
1356 printf("UDF properties %s\n", scrap
);
1357 printf("Volume set `%s'\n", context
.volset_name
);
1358 printf("Primary volume `%s`\n", context
.primary_name
);
1359 printf("Logical volume `%s`\n", context
.logvol_name
);
1360 if (format_flags
& FORMAT_META
)
1361 printf("Metadata percentage %d %%\n",
1362 (int) (100.0*stats
.ndatablocks
/stats
.nmetadatablocks
));
1364 udf_do_newfs_prefix();
1366 /* update context */
1367 context
.unique_id
= 0;
1369 /* XXX are the next two needed? or should be re-count them? */
1370 context
.num_files
= stats
.nfiles
;
1371 context
.num_directories
= stats
.ndirs
;
1373 error
= udf_populate(dir
, root
, fsopts
, &stats
);
1375 udf_do_newfs_postfix();
1377 if (format_flags
& FORMAT_VAT
) {
1378 truncate_len
= context
.vtop_offset
[context
.data_part
] +
1379 context
.data_alloc_pos
;
1380 truncate_len
*= context
.sector_size
;
1382 printf("\nTruncing the disc-image to allow for VAT\n");
1383 printf("Free space left on this volume approx. "
1384 "%"PRIu64
" KiB, %"PRIu64
" MiB\n",
1385 (fsopts
->size
- truncate_len
)/1024,
1386 (fsopts
->size
- truncate_len
)/1024/1024);
1387 ftruncate(fd
, truncate_len
);
1391 error
= 2; /* some files couldn't be added */
1401 errx(error
, "Not all files could be added");
1403 errx(error
, "creation of %s failed", image
);