udf.c revision 1.14
1/* $NetBSD: udf.c,v 1.14 2013/10/19 17:16:37 christos Exp $ */
2
3/*
4 * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28#if HAVE_NBTOOL_CONFIG_H
29#include "nbtool_config.h"
30#endif
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: udf.c,v 1.14 2013/10/19 17:16:37 christos Exp $");
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <errno.h>
39#include <time.h>
40#include <assert.h>
41#include <err.h>
42#include <unistd.h>
43#include <fcntl.h>
44#include <sys/types.h>
45#include <sys/param.h>
46#include <sys/stat.h>
47#include <util.h>
48
49#if !HAVE_NBTOOL_CONFIG_H
50#define _EXPOSE_MMC
51#include <sys/cdio.h>
52#else
53#include "udf/cdio_mmc_structs.h"
54#endif
55
56#if !HAVE_NBTOOL_CONFIG_H
57#define HAVE_STRUCT_TM_TM_GMTOFF
58#endif
59
60#include "makefs.h"
61#include "udf_create.h"
62#include "udf_write.h"
63#include "newfs_udf.h"
64
65#undef APP_NAME
66#define APP_NAME "*NetBSD makefs"
67
68/*
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.
72 */
73
74/* global variables describing disc and format requests */
75int	 fd;				/* device: file descriptor */
76char	*dev;				/* device: name		   */
77struct mmc_discinfo mmc_discinfo;	/* device: disc info	   */
78
79char	*format_str;			/* format: string representation */
80int	 format_flags;			/* format: attribute flags	 */
81int	 media_accesstype;		/* derived from current mmc cap  */
82int	 check_surface;			/* for rewritables               */
83int	 imagefile_secsize;		/* for files			 */
84
85int	 display_progressbar;
86
87int	 wrtrack_skew;
88float	 meta_fract = (float) UDF_META_PERC / 100.0;
89
90int	 mmc_profile;			/* emulated profile */
91int	 req_enable, req_disable;
92
93
94/* --------------------------------------------------------------------- */
95
96int
97udf_write_sector(void *sector, uint64_t location)
98{
99	uint64_t wpos;
100	ssize_t ret;
101
102	wpos = (uint64_t) location * context.sector_size;
103	ret = pwrite(fd, sector, context.sector_size, wpos);
104	if (ret == -1)
105		return errno;
106	if (ret < (int) context.sector_size)
107		return EIO;
108	return 0;
109}
110
111
112/* not implemented for files */
113int
114udf_surface_check(void)
115{
116	return 0;
117}
118
119
120/*
121 * mmc_discinfo and mmc_trackinfo readers modified from origional in udf main
122 * code in sys/fs/udf/
123 */
124
125#ifdef DEBUG
126static void
127udf_dump_discinfo(struct mmc_discinfo *di)
128{
129	char bits[128];
130
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);
147
148	printf("\tnum sessions       %d\n", di->num_sessions);
149	printf("\tnum tracks         %d\n", di->num_tracks);
150
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);
155	printf("\n");
156	printf("\tlast_possible_lba  %d\n", di->last_possible_lba);
157	printf("\n");
158}
159#else
160#define udf_dump_discinfo(a);
161#endif
162
163/* --------------------------------------------------------------------- */
164
165static int
166udf_emulate_discinfo(fsinfo_t *fsopts, struct mmc_discinfo *di,
167		int mmc_emuprofile)
168{
169	off_t sectors;
170
171	memset(di, 0, sizeof(*di));
172
173	/* file support */
174	if ((mmc_emuprofile != 0x01) && (fsopts->sectorsize != 2048))
175		warnx("cd/dvd/bd sectorsize is not set to default 2048");
176
177	sectors = fsopts->size / fsopts->sectorsize;
178
179	/* commons */
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;
185
186	di->disc_flags = MMC_DFLAGS_UNRESTRICTED;
187
188	di->last_possible_lba = sectors - 1;
189	di->sector_size       = fsopts->sectorsize;
190
191	di->num_sessions = 1;
192	di->num_tracks   = 1;
193
194	di->first_track  = 1;
195	di->first_track_last_session = di->last_track_last_session = 1;
196
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;
204		/* FALLTROUGH */
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;
209		break;
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;
214		break;
215	case 0x0a:	/* CD-RW + CD-MRW (regretably) */
216		di->mmc_class	= MMC_CLASS_CD;
217		di->mmc_cur    |= MMC_CAP_REWRITABLE;
218		break;
219	case 0x13:	/* DVD-RW */
220		di->mmc_class	= MMC_CLASS_DVD;
221		di->mmc_cur    |= MMC_CAP_REWRITABLE;
222		break;
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;
231		break;
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;
236		break;
237	case 0x43:	/* BD-RE */
238		di->mmc_class   = MMC_CLASS_BD;
239		di->mmc_cur    |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE;
240		break;
241	default:
242		err(EINVAL, "makefs_udf: unknown or unimplemented device type");
243		return EINVAL;
244	}
245	di->mmc_cap    = di->mmc_cur;
246
247	udf_dump_discinfo(di);
248	return 0;
249}
250
251
252int
253udf_update_trackinfo(struct mmc_discinfo *di, struct mmc_trackinfo *ti)
254{
255	/* discs partition support */
256	if (ti->tracknr != 1)
257		return EIO;
258
259	/* create fake ti */
260	ti->sessionnr  = 1;
261
262	ti->track_mode = 0;	/* XXX */
263	ti->data_mode  = 0;	/* XXX */
264	ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
265
266	ti->track_start    = 0;
267	ti->packet_size    = 32;	/* take sensible default */
268
269	ti->track_size    = di->last_possible_lba;
270	ti->next_writable = di->last_possible_lba;
271	ti->last_recorded = ti->next_writable;
272	ti->free_blocks   = 0;
273
274	return 0;
275}
276
277#define OPT_STR(letter, name, desc)  \
278	{ letter, name, NULL, OPT_STRBUF, 0, 0, desc }
279
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)), \
285	  min, max, desc }
286
287#define OPT_BOOL(letter, name, field, desc) \
288	OPT_NUM(letter, name, field, 0, 1, desc)
289
290void
291udf_prep_opts(fsinfo_t *fsopts)
292{
293	struct tm *tm;
294	time_t now;
295
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"),
305#if notyet
306		OPT_STR('V', "maxver", "maximum UDF version in either "
307			"``0x201'' or ``2.01'' format"),
308#endif
309		{ .name = NULL }
310	};
311
312	/* initialise */
313	format_str    = strdup("");
314	req_enable    = req_disable = 0;
315	format_flags  = FORMAT_INVALID;
316	fsopts->sectorsize = 512;	/* minimum allowed sector size */
317
318	srandom((unsigned long) time(NULL));
319
320	mmc_profile = 0x01;		/* 'disc'/file */
321
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;
327
328	/* minimum and maximum UDF versions we advise */
329	context.min_udf = 0x102;
330	context.max_udf = 0x201;	/* 0x250 and 0x260 are not ready */
331
332	/* use user's time zone as default */
333	(void)time(&now);
334	tm = localtime(&now);
335#ifdef HAVE_STRUCT_TM_TM_GMTOFF
336	context.gmtoff = tm->tm_gmtoff;
337#else
338	context.gmtoff = 0;
339#endif
340
341	/* return info */
342	fsopts->fs_specific = NULL;
343	fsopts->fs_options = copy_opts(udf_options);
344}
345
346
347void
348udf_cleanup_opts(fsinfo_t *fsopts)
349{
350	free(fsopts->fs_options);
351}
352
353
354/* ----- included from newfs_udf.c ------ */
355/* ----- */
356
357
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 */
365int
366udf_parse_opts(const char *option, fsinfo_t *fsopts)
367{
368	option_t *udf_options = fsopts->fs_options;
369	uint64_t stdsize;
370	uint32_t set_sectorsize;
371	char buffer[1024], *buf, *colon;
372	int i;
373
374	assert(option != NULL);
375
376	if (debug & DEBUG_FS_PARSE_OPTS)
377		printf("udf_parse_opts: got `%s'\n", option);
378
379	i = set_option(udf_options, option, buffer, sizeof(buffer));
380	if (i == -1)
381		return 0;
382
383	if (udf_options[i].name == NULL)
384		abort();
385
386	set_sectorsize = 0;
387	stdsize = 0;
388
389	buf = buffer;
390	switch (udf_options[i].letter) {
391	case 'T':
392		if (strcmp(buf, "cdrom") == 0) {
393			mmc_profile = 0x00;
394		} else if (strcmp(buf, "dvdrom") == 0) {
395			mmc_profile = 0x10;
396		} else if (strcmp(buf, "bdrom") == 0) {
397			mmc_profile = 0x40;
398		} else if (strcmp(buf, "dvdram") == 0) {
399			mmc_profile = 0x12;
400			stdsize = DVDRAMSIZE;
401		} else if (strcmp(buf, "bdre") == 0) {
402			mmc_profile = 0x43;
403			stdsize = BDRESIZE;
404		} else if (strcmp(buf, "disk") == 0) {
405			mmc_profile = 0x01;
406		} else if (strcmp(buf, "cdr") == 0) {
407			mmc_profile = 0x09;
408			stdsize = CDRSIZE;
409		} else if (strcmp(buf, "dvdr") == 0) {
410			mmc_profile = 0x1b;
411			stdsize = DVDRSIZE;
412		} else if (strcmp(buf, "bdr") == 0) {
413			mmc_profile = 0x41;
414			stdsize = BDRSIZE;
415		} else if (strcmp(buf, "cdrw") == 0) {
416			mmc_profile = 0x0a;
417			stdsize = CDRWSIZE;
418		} else if (strcmp(buf, "dvdrw") == 0) {
419			mmc_profile = 0x13;
420			stdsize = DVDRWSIZE;
421		} else {
422			errx(EINVAL, "Unknown or unimplemented disc format");
423			return 0;
424		}
425		if (mmc_profile != 0x01)
426			set_sectorsize = 2048;
427		break;
428	case 'L':
429		if (context.logvol_name) free(context.logvol_name);
430		context.logvol_name = strdup(buf);
431		break;
432	case 'P':
433		if ((colon = strstr(buf, ":"))) {
434			if (context.volset_name)
435				free(context.volset_name);
436			*colon = 0;
437			context.volset_name = strdup(buf);
438			buf = colon+1;
439		}
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");
444			return 0;
445		}
446		context.primary_name = strdup(buf);
447		break;
448	case 'v':
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");
452			return 0;
453		}
454		if (context.min_udf > context.max_udf)
455			context.max_udf = context.min_udf;
456		break;
457	}
458	if (set_sectorsize)
459		fsopts->sectorsize = set_sectorsize;
460	if (stdsize)
461		fsopts->size = stdsize;
462	return 1;
463}
464
465/* --------------------------------------------------------------------- */
466
467struct udf_stats {
468	uint32_t nfiles;
469	uint32_t ndirs;
470	uint32_t ndescr;
471	uint32_t nmetadatablocks;
472	uint32_t ndatablocks;
473};
474
475
476/* node reference administration */
477static void
478udf_inc_link(union dscrptr *dscr)
479{
480	struct file_entry *fe;
481	struct extfile_entry *efe;
482
483	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
484		fe        = &dscr->fe;
485		fe->link_cnt = udf_rw16(udf_rw16(fe->link_cnt) + 1);
486	} else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
487		efe       = &dscr->efe;
488		efe->link_cnt = udf_rw16(udf_rw16(efe->link_cnt) + 1);
489	} else {
490		errx(1, "Bad tag passed to udf_inc_link");
491	}
492}
493
494
495static void
496udf_set_link_cnt(union dscrptr *dscr, int num)
497{
498	struct file_entry *fe;
499	struct extfile_entry *efe;
500
501	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
502		fe        = &dscr->fe;
503		fe->link_cnt = udf_rw16(num);
504	} else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
505		efe       = &dscr->efe;
506		efe->link_cnt = udf_rw16(num);
507	} else {
508		errx(1, "Bad tag passed to udf_set_link_cnt");
509	}
510}
511
512
513static uint32_t
514udf_datablocks(off_t sz)
515{
516	/* predictor if it can be written inside the node */
517	if (sz < context.sector_size - UDF_EXTFENTRY_SIZE - 16)
518		return 0;
519
520	return UDF_ROUNDUP(sz, context.sector_size) / context.sector_size;
521}
522
523
524static void
525udf_prepare_fids(struct long_ad *dir_icb, struct long_ad *dirdata_icb,
526		uint8_t *dirdata, uint32_t dirdata_size)
527{
528	struct fileid_desc *fid;
529	struct long_ad     *icb;
530	uint32_t fidsize, offset;
531	uint32_t location;
532
533	if (udf_datablocks(dirdata_size) == 0) {
534		/* going internal */
535		icb = dir_icb;
536	} else {
537		/* external blocks to write to */
538		icb = dirdata_icb;
539	}
540
541	for (offset = 0; offset < dirdata_size; offset += fidsize) {
542		/* for each FID: */
543		fid = (struct fileid_desc *) (dirdata + offset);
544		assert(udf_rw16(fid->tag.id) == TAGID_FID);
545
546		location  = udf_rw32(icb->loc.lb_num);
547		location += offset / context.sector_size;
548
549		fid->tag.tag_loc = udf_rw32(location);
550		udf_validate_tag_and_crc_sums((union dscrptr *) fid);
551
552		fidsize = udf_fidsize(fid);
553	}
554}
555
556static int
557udf_file_inject_blob(union dscrptr *dscr,  uint8_t *blob, off_t size)
558{
559	struct icb_tag *icb;
560	struct file_entry *fe;
561	struct extfile_entry *efe;
562	uint64_t inf_len, obj_size;
563	uint32_t l_ea, l_ad;
564	uint32_t free_space, desc_size;
565	uint16_t crclen;
566	uint8_t *data, *pos;
567
568	fe = NULL;
569	efe = NULL;
570	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
571		fe        = &dscr->fe;
572		data      = fe->data;
573		l_ea      = udf_rw32(fe->l_ea);
574		l_ad      = udf_rw32(fe->l_ad);
575		icb       = &fe->icbtag;
576		inf_len   = udf_rw64(fe->inf_len);
577		obj_size  = 0;
578		desc_size = sizeof(struct file_entry);
579	} else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
580		efe       = &dscr->efe;
581		data      = efe->data;
582		l_ea      = udf_rw32(efe->l_ea);
583		l_ad      = udf_rw32(efe->l_ad);
584		icb       = &efe->icbtag;
585		inf_len   = udf_rw64(efe->inf_len);
586		obj_size  = udf_rw64(efe->obj_size);
587		desc_size = sizeof(struct extfile_entry);
588	} else {
589		errx(1, "Bad tag passed to udf_file_inject_blob");
590	}
591	crclen = udf_rw16(dscr->tag.desc_crc_len);
592
593	/* calculate free space */
594	free_space = context.sector_size - (l_ea + l_ad) - desc_size;
595	if (udf_datablocks(size)) {
596		assert(free_space < size);
597		return 1;
598	}
599
600	/* going internal */
601	assert(l_ad == 0);
602	assert((udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) ==
603			UDF_ICB_INTERN_ALLOC);
604
605	// assert(free_space >= size);
606	pos = data + l_ea + l_ad;
607	memcpy(pos, blob, size);
608	l_ad   += size;
609	crclen += size;
610
611	inf_len  += size;
612	obj_size += size;
613
614	if (fe) {
615		fe->l_ad = udf_rw32(l_ad);
616		fe->inf_len = udf_rw64(inf_len);
617	} else if (efe) {
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	}
622
623	/* make sure the header sums stays correct */
624	dscr->tag.desc_crc_len = udf_rw16(crclen);
625	udf_validate_tag_and_crc_sums(dscr);
626
627	return 0;
628}
629
630
631/* XXX no sparse file support */
632static void
633udf_append_file_mapping(union dscrptr *dscr, struct long_ad *piece)
634{
635	struct icb_tag *icb;
636	struct file_entry *fe;
637	struct extfile_entry *efe;
638	struct long_ad *last_long, last_piece;
639	struct short_ad *last_short, new_short;
640	uint64_t inf_len, obj_size, logblks_rec;
641	uint32_t l_ea, l_ad, size;
642	uint32_t last_lb_num, piece_lb_num;
643	uint64_t last_len, piece_len, last_flags;
644	uint64_t rest_len, merge_len, last_end;
645	uint16_t last_part_num, piece_part_num;
646	uint16_t crclen, cur_alloc;
647	uint8_t *data, *pos;
648	const int short_len = sizeof(struct short_ad);
649	const int long_len  = sizeof(struct long_ad);
650	const int sector_size = context.sector_size;
651	const int use_shorts = (context.data_part == context.metadata_part);
652	uint64_t max_len = UDF_ROUNDDOWN(UDF_EXT_MAXLEN, sector_size);
653
654	fe  = NULL;
655	efe = NULL;
656	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
657		fe          = &dscr->fe;
658		data        = fe->data;
659		l_ea        = fe->l_ea;
660		l_ad        = udf_rw32(fe->l_ad);
661		icb         = &fe->icbtag;
662		inf_len     = udf_rw64(fe->inf_len);
663		logblks_rec = udf_rw64(fe->logblks_rec);
664		obj_size = 0;
665	} else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
666		efe         = &dscr->efe;
667		data        = efe->data;
668		l_ea        = efe->l_ea;
669		l_ad        = udf_rw32(efe->l_ad);
670		icb         = &efe->icbtag;
671		inf_len     = udf_rw64(efe->inf_len);
672		obj_size    = udf_rw64(efe->obj_size);
673		logblks_rec = udf_rw64(efe->logblks_rec);
674	} else {
675		errx(1, "Bad tag passed to udf_file_append_blob");
676	}
677	crclen = udf_rw16(dscr->tag.desc_crc_len);
678
679	pos = data + l_ea;
680	cur_alloc = udf_rw16(icb->flags);
681	size = UDF_EXT_LEN(udf_rw32(piece->len));
682
683	/* extract last entry as a long_ad */
684	memset(&last_piece, 0, sizeof(last_piece));
685	last_len      = 0;
686	last_lb_num   = 0;
687	last_part_num = 0;
688	last_flags    = 0;
689	last_short    = NULL;
690	last_long     = NULL;
691	if (l_ad != 0) {
692		if (use_shorts) {
693			assert(cur_alloc == UDF_ICB_SHORT_ALLOC);
694			pos += l_ad - short_len;
695			last_short   = (struct short_ad *) pos;
696			last_lb_num  = udf_rw32(last_short->lb_num);
697			last_part_num = udf_rw16(piece->loc.part_num);
698			last_len     = UDF_EXT_LEN(udf_rw32(last_short->len));
699			last_flags   = UDF_EXT_FLAGS(udf_rw32(last_short->len));
700		} else {
701			assert(cur_alloc == UDF_ICB_LONG_ALLOC);
702			pos += l_ad - long_len;
703			last_long    = (struct long_ad *) pos;
704			last_lb_num  = udf_rw32(last_long->loc.lb_num);
705			last_part_num = udf_rw16(last_long->loc.part_num);
706			last_len     = UDF_EXT_LEN(udf_rw32(last_long->len));
707			last_flags   = UDF_EXT_FLAGS(udf_rw32(last_long->len));
708		}
709	}
710
711	piece_len      = UDF_EXT_LEN(udf_rw32(piece->len));
712	piece_lb_num   = udf_rw32(piece->loc.lb_num);
713	piece_part_num = udf_rw16(piece->loc.part_num);
714
715	/* try merging */
716	rest_len  = max_len - last_len;
717
718	merge_len = MIN(piece_len, rest_len);
719	last_end  = last_lb_num + (last_len / sector_size);
720
721	if ((piece_lb_num == last_end) && (last_part_num == piece_part_num)) {
722		/* we can merge */
723		last_len  += merge_len;
724		piece_len -= merge_len;
725
726		/* write back merge result */
727		if (use_shorts) {
728			last_short->len = udf_rw32(last_len | last_flags);
729		} else {
730			last_long->len  = udf_rw32(last_len | last_flags);
731		}
732		piece_lb_num += merge_len / sector_size;
733	}
734
735	if (piece_len) {
736		/* append new entry */
737		pos = data + l_ea + l_ad;
738		if (use_shorts) {
739			icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC);
740			memset(&new_short, 0, short_len);
741			new_short.len    = udf_rw32(piece_len);
742			new_short.lb_num = udf_rw32(piece_lb_num);
743			memcpy(pos, &new_short, short_len);
744			l_ad += short_len;
745			crclen += short_len;
746		} else {
747			icb->flags = udf_rw16(UDF_ICB_LONG_ALLOC);
748			piece->len        = udf_rw32(piece_len);
749			piece->loc.lb_num = udf_rw32(piece_lb_num);
750			memcpy(pos, piece, long_len);
751			l_ad += long_len;
752			crclen += long_len;
753		}
754	}
755	piece->len = udf_rw32(0);
756
757	inf_len  += size;
758	obj_size += size;
759	logblks_rec += UDF_ROUNDUP(size, sector_size) / sector_size;
760
761	dscr->tag.desc_crc_len = udf_rw16(crclen);
762	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
763		fe->l_ad = udf_rw32(l_ad);
764		fe->inf_len = udf_rw64(inf_len);
765		fe->logblks_rec = udf_rw64(logblks_rec);
766	} else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
767		efe->l_ad = udf_rw32(l_ad);
768		efe->inf_len  = udf_rw64(inf_len);
769		efe->obj_size = udf_rw64(inf_len);
770		efe->logblks_rec = udf_rw64(logblks_rec);
771	}
772}
773
774
775static int
776udf_append_file_contents(union dscrptr *dscr, struct long_ad *data_icb,
777		uint8_t *fdata, off_t flen)
778{
779	struct long_ad icb;
780	uint32_t location;
781	uint64_t phys;
782	uint16_t vpart;
783	uint8_t *bpos;
784	int cnt, sects;
785	int error;
786
787	if (udf_file_inject_blob(dscr, fdata, flen) == 0)
788		return 0;
789
790	/* has to be appended in mappings */
791	icb = *data_icb;
792	icb.len = udf_rw32(flen);
793	while (udf_rw32(icb.len) > 0)
794		udf_append_file_mapping(dscr, &icb);
795	udf_validate_tag_and_crc_sums(dscr);
796
797	/* write out data piece */
798	vpart    = udf_rw16(data_icb->loc.part_num);
799	location = udf_rw32(data_icb->loc.lb_num);
800	sects    = udf_datablocks(flen);
801	for (cnt = 0; cnt < sects; cnt++) {
802		bpos = fdata + cnt*context.sector_size;
803		phys = context.vtop_offset[vpart] + location + cnt;
804		error = udf_write_sector(bpos, phys);
805		if (error)
806			return error;
807	}
808	return 0;
809}
810
811
812static int
813udf_create_new_file(struct stat *st, union dscrptr **dscr,
814	int filetype, struct long_ad *icb)
815{
816	struct file_entry *fe;
817	struct extfile_entry *efe;
818	int error;
819
820	fe = NULL;
821	efe = NULL;
822	if (context.dscrver == 2) {
823		error = udf_create_new_fe(&fe, filetype, st);
824		if (error)
825			errx(error, "can't create fe");
826		*dscr = (union dscrptr *) fe;
827		icb->longad_uniqueid = fe->unique_id;
828	} else {
829		error = udf_create_new_efe(&efe, filetype, st);
830		if (error)
831			errx(error, "can't create fe");
832		*dscr = (union dscrptr *) efe;
833		icb->longad_uniqueid = efe->unique_id;
834	}
835
836	return 0;
837}
838
839
840static void
841udf_estimate_walk(fsinfo_t *fsopts,
842		fsnode *root, char *dir, struct udf_stats *stats)
843{
844	struct fileid_desc *fid;
845	struct long_ad dummy_ref;
846	fsnode *cur;
847	fsinode *fnode;
848	size_t pathlen = strlen(dir);
849	char *mydir = dir + pathlen;
850	off_t sz;
851	uint32_t nblk, ddoff;
852	uint32_t softlink_len;
853	uint8_t *softlink_buf;
854	int nentries;
855	int error;
856
857	stats->ndirs++;
858
859	/*
860	 * Count number of directory entries and count directory size; needed
861	 * for the reservation of enough space for the directory. Pity we
862	 * don't keep the FIDs we created. If it turns out to be a issue we
863	 * can cache it later.
864	 */
865	fid = (struct fileid_desc *) malloc(context.sector_size);
866	assert(fid);
867
868	ddoff = 40;	/* '..' entry */
869	for (cur = root, nentries = 0; cur != NULL; cur = cur->next) {
870		switch (cur->type & S_IFMT) {
871		default:
872			/* what kind of nodes? */
873			break;
874		case S_IFCHR:
875		case S_IFBLK:
876			/* not supported yet */
877			continue;
878		case S_IFDIR:
879			if (strcmp(cur->name, ".") == 0)
880				continue;
881		case S_IFLNK:
882		case S_IFREG:
883			/* create dummy FID to see how long name will become */
884			udf_create_fid(ddoff, fid, cur->name, 0, &dummy_ref);
885
886			nentries++;
887			ddoff += udf_fidsize(fid);
888		}
889	}
890	sz = ddoff;
891
892	root->inode->st.st_size = sz;	/* max now */
893	root->inode->flags |= FI_SIZED;
894
895	nblk = udf_datablocks(sz);
896	stats->nmetadatablocks += nblk;
897
898	/* for each entry in the directory, there needs to be a (E)FE */
899	stats->nmetadatablocks += nentries + 1;
900
901	/* recurse */
902	for (cur = root; cur != NULL; cur = cur->next) {
903		switch (cur->type & S_IFMT) {
904		default:
905			/* what kind of nodes? */
906			break;
907		case S_IFCHR:
908		case S_IFBLK:
909			/* not supported yet */
910			// stats->nfiles++;
911			break;
912		case S_IFDIR:
913			if (strcmp(cur->name, ".") == 0)
914				continue;
915			/* empty dir? */
916			if (!cur->child)
917				break;
918			mydir[0] = '/';
919			strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen);
920			udf_estimate_walk(fsopts, cur->child, dir, stats);
921			mydir[0] = '\0';
922			break;
923		case S_IFREG:
924			fnode = cur->inode;
925			/* don't double-count hard-links */
926			if (!(fnode->flags & FI_SIZED)) {
927				sz = fnode->st.st_size;
928				nblk = udf_datablocks(sz);
929				stats->ndatablocks += nblk;
930				/* ... */
931				fnode->flags |= FI_SIZED;
932			}
933			stats->nfiles++;
934			break;
935		case S_IFLNK:
936			/* softlink */
937			fnode = cur->inode;
938			/* don't double-count hard-links */
939			if (!(fnode->flags & FI_SIZED)) {
940				error = udf_encode_symlink(&softlink_buf,
941						&softlink_len, cur->symlink);
942				if (error) {
943					printf("SOFTLINK error %d\n", error);
944					break;
945				}
946				nblk = udf_datablocks(softlink_len);
947				stats->ndatablocks += nblk;
948				fnode->flags |= FI_SIZED;
949
950				free(softlink_buf);
951			}
952			stats->nfiles++;
953			break;
954		}
955	}
956}
957
958
959#define UDF_MAX_CHUNK_SIZE (4*1024*1024)
960static int
961udf_copy_file(struct stat *st, char *path, fsnode *cur, struct fileid_desc *fid,
962	struct long_ad *icb)
963{
964	union dscrptr *dscr;
965	struct long_ad data_icb;
966	fsinode *fnode;
967	off_t sz, chunk, rd;
968	uint8_t *data;
969	int nblk;
970	int i, f;
971	int error;
972
973	fnode = cur->inode;
974
975	f = open(path, O_RDONLY);
976	if (f < 0) {
977		warn("Can't open file %s for reading", cur->name);
978		return errno;
979	}
980
981	/* claim disc space for the (e)fe descriptor for this file */
982	udf_metadata_alloc(1, icb);
983	udf_create_new_file(st, &dscr, UDF_ICB_FILETYPE_RANDOMACCESS, icb);
984
985	sz = fnode->st.st_size;
986
987	chunk = MIN(sz, UDF_MAX_CHUNK_SIZE);
988	data = malloc(MAX(chunk, context.sector_size));
989	assert(data);
990
991	printf("  ");
992	i = 0;
993	error = 0;
994	while (chunk) {
995		rd = read(f, data, chunk);
996		if (rd != chunk) {
997			warn("Short read of file %s\n", cur->name);
998			error = errno;
999			break;
1000		}
1001		printf("\b%c", "\\|/-"[i++ % 4]); fflush(stdout);fflush(stderr);
1002
1003		nblk = udf_datablocks(chunk);
1004		if (nblk > 0)
1005			udf_data_alloc(nblk, &data_icb);
1006		udf_append_file_contents(dscr, &data_icb, data, chunk);
1007
1008		sz -= chunk;
1009		chunk = MIN(sz, UDF_MAX_CHUNK_SIZE);
1010	}
1011	printf("\b \n");
1012	close(f);
1013	free(data);
1014
1015	/* write out dscr (e)fe */
1016	udf_set_link_cnt(dscr, fnode->nlink);
1017	udf_write_dscr_virt(dscr, udf_rw32(icb->loc.lb_num),
1018		udf_rw16(icb->loc.part_num), 1);
1019	free(dscr);
1020
1021	/* remember our location for hardlinks */
1022	cur->inode->fsuse = malloc(sizeof(struct long_ad));
1023	memcpy(cur->inode->fsuse, icb, sizeof(struct long_ad));
1024
1025	return error;
1026}
1027
1028
1029static int
1030udf_populate_walk(fsinfo_t *fsopts, fsnode *root, char *dir,
1031		struct long_ad *parent_icb, struct long_ad *dir_icb)
1032{
1033	union dscrptr *dir_dscr, *dscr;
1034	struct fileid_desc *fid;
1035	struct long_ad icb, data_icb, dirdata_icb;
1036	fsnode *cur;
1037	fsinode *fnode;
1038	size_t pathlen = strlen(dir);
1039	size_t dirlen;
1040	char *mydir = dir + pathlen;
1041	uint32_t nblk, ddoff;
1042	uint32_t softlink_len;
1043	uint8_t *softlink_buf;
1044	uint8_t *dirdata;
1045	int error, ret, retval;
1046
1047	/* claim disc space for the (e)fe descriptor for this dir */
1048	udf_metadata_alloc(1, dir_icb);
1049
1050	/* create new e(fe) */
1051	udf_create_new_file(&root->inode->st, &dir_dscr,
1052		UDF_ICB_FILETYPE_DIRECTORY, dir_icb);
1053
1054	/* claim space for the directory contents */
1055	dirlen = root->inode->st.st_size;
1056	nblk = udf_datablocks(dirlen);
1057	if (nblk > 0) {
1058		/* claim disc space for the dir contents */
1059		udf_data_alloc(nblk, &dirdata_icb);
1060	}
1061
1062	/* allocate memory for the directory contents */
1063	nblk++;
1064	dirdata = malloc(nblk * context.sector_size);
1065	assert(dirdata);
1066	memset(dirdata, 0, nblk * context.sector_size);
1067
1068	/* create and append '..' */
1069	fid = (struct fileid_desc *) dirdata;
1070	ddoff = udf_create_parentfid(fid, parent_icb);
1071
1072	/* for '..' */
1073	udf_inc_link(dir_dscr);
1074
1075	/* recurse */
1076	retval = 0;
1077	for (cur = root; cur != NULL; cur = cur->next) {
1078		mydir[0] = '/';
1079		strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen);
1080
1081		fid = (struct fileid_desc *) (dirdata + ddoff);
1082		switch (cur->type & S_IFMT) {
1083		default:
1084			/* what kind of nodes? */
1085			retval = 2;
1086			break;
1087		case S_IFCHR:
1088		case S_IFBLK:
1089			/* not supported */
1090			retval = 2;
1091			warnx("device node %s not supported", dir);
1092			break;
1093		case S_IFDIR:
1094			/* not an empty dir? */
1095			if (strcmp(cur->name, ".") == 0)
1096				break;
1097			assert(cur->child);
1098			if (cur->child) {
1099				ret = udf_populate_walk(fsopts, cur->child,
1100					dir, dir_icb, &icb);
1101				if (ret)
1102					retval = 2;
1103			}
1104			udf_create_fid(ddoff, fid, cur->name,
1105					UDF_FILE_CHAR_DIR, &icb);
1106			udf_inc_link(dir_dscr);
1107			ddoff += udf_fidsize(fid);
1108			break;
1109		case S_IFREG:
1110			fnode = cur->inode;
1111			/* don't re-copy hard-links */
1112			if (!(fnode->flags & FI_WRITTEN)) {
1113				printf("%s", dir);
1114				error = udf_copy_file(&fnode->st, dir, cur,
1115					fid, &icb);
1116				if (!error) {
1117					fnode->flags |= FI_WRITTEN;
1118					udf_create_fid(ddoff, fid, cur->name,
1119						0, &icb);
1120					ddoff += udf_fidsize(fid);
1121				} else {
1122					retval = 2;
1123				}
1124			} else {
1125				/* hardlink! */
1126				printf("%s (hardlink)\n", dir);
1127				udf_create_fid(ddoff, fid, cur->name,
1128					0, (struct long_ad *) (fnode->fsuse));
1129				ddoff += udf_fidsize(fid);
1130			}
1131			fnode->nlink--;
1132			if (fnode->nlink == 0)
1133				free(fnode->fsuse);
1134			break;
1135		case S_IFLNK:
1136			/* softlink */
1137			fnode = cur->inode;
1138			printf("%s -> %s\n", dir, cur->symlink);
1139			error = udf_encode_symlink(&softlink_buf,
1140					&softlink_len, cur->symlink);
1141			if (error) {
1142				printf("SOFTLINK error %d\n", error);
1143				retval = 2;
1144				break;
1145			}
1146
1147			udf_metadata_alloc(1, &icb);
1148			udf_create_new_file(&fnode->st, &dscr,
1149				UDF_ICB_FILETYPE_SYMLINK, &icb);
1150
1151			nblk = udf_datablocks(softlink_len);
1152			if (nblk > 0)
1153				udf_data_alloc(nblk, &data_icb);
1154			udf_append_file_contents(dscr, &data_icb,
1155					softlink_buf, softlink_len);
1156
1157			/* write out dscr (e)fe */
1158			udf_inc_link(dscr);
1159			udf_write_dscr_virt(dscr, udf_rw32(icb.loc.lb_num),
1160				udf_rw16(icb.loc.part_num), 1);
1161
1162			free(dscr);
1163			free(softlink_buf);
1164
1165			udf_create_fid(ddoff, fid, cur->name, 0, &icb);
1166			ddoff += udf_fidsize(fid);
1167			break;
1168		}
1169		mydir[0] = '\0';
1170	}
1171
1172	/* writeout directory contents */
1173	dirlen = ddoff;	/* XXX might bite back */
1174
1175	udf_prepare_fids(dir_icb, &dirdata_icb, dirdata, dirlen);
1176	udf_append_file_contents(dir_dscr, &dirdata_icb, dirdata, dirlen);
1177
1178	/* write out dir_dscr (e)fe */
1179	udf_write_dscr_virt(dir_dscr, udf_rw32(dir_icb->loc.lb_num),
1180			udf_rw16(dir_icb->loc.part_num), 1);
1181
1182	free(dirdata);
1183	free(dir_dscr);
1184	return retval;
1185}
1186
1187
1188static int
1189udf_populate(const char *dir, fsnode *root, fsinfo_t *fsopts,
1190		struct udf_stats *stats)
1191{
1192	struct long_ad rooticb;
1193	static char path[MAXPATHLEN+1];
1194	int error;
1195
1196	/* make sure the root gets the rootdir entry */
1197	context.metadata_alloc_pos = layout.rootdir;
1198	context.data_alloc_pos = layout.rootdir;
1199
1200	strncpy(path, dir, sizeof(path));
1201	error = udf_populate_walk(fsopts, root, path, &rooticb, &rooticb);
1202
1203	return error;
1204}
1205
1206
1207static void
1208udf_enumerate_and_estimate(const char *dir, fsnode *root, fsinfo_t *fsopts,
1209		struct udf_stats *stats)
1210{
1211	char path[MAXPATHLEN + 1];
1212	off_t proposed_size;
1213	uint32_t n, nblk;
1214
1215	strncpy(path, dir, sizeof(path));
1216
1217	/* calculate strict minimal size */
1218	udf_estimate_walk(fsopts, root, path, stats);
1219	printf("ndirs            %d\n", stats->ndirs);
1220	printf("nfiles           %d\n", stats->nfiles);
1221	printf("ndata_blocks     %d\n", stats->ndatablocks);
1222	printf("nmetadata_blocks %d\n", stats->nmetadatablocks);
1223	printf("\n");
1224
1225	/* adjust for options : free file nodes */
1226	if (fsopts->freefiles) {
1227		/* be mercifull and reserve more for the FID */
1228		stats->nmetadatablocks += fsopts->freefiles * 1.5;
1229	} else if ((n = fsopts->freefilepc)) {
1230		stats->nmetadatablocks += (stats->nmetadatablocks*n) / (100-n);
1231	}
1232
1233	/* adjust for options : free data blocks */
1234	if (fsopts->freeblocks) {
1235		stats->ndatablocks += fsopts->freeblocks;
1236	} else if ((n = fsopts->freeblockpc)) {
1237		stats->ndatablocks += (stats->ndatablocks * n) / (100-n);
1238	}
1239
1240	/* rough predictor of minimum disc size */
1241	nblk  = stats->ndatablocks + stats->nmetadatablocks;
1242	nblk = (double) nblk * (1.0 + 1.0/8.0);		/* free space map    */
1243	nblk += 256;					/* pre-volume space  */
1244	nblk += 256;					/* post-volume space */
1245	nblk += 64;					/* safeguard	     */
1246
1247	/* try to honour minimum size */
1248	n = fsopts->minsize / fsopts->sectorsize;
1249	if (nblk < n) {
1250		stats->ndatablocks += (n - nblk);
1251		nblk += n - nblk;
1252	}
1253	proposed_size = (off_t) nblk * fsopts->sectorsize;
1254	/* sanity size */
1255	if (proposed_size < 512*1024)
1256		proposed_size = 512*1024;
1257
1258	if (fsopts->size) {
1259		if (fsopts->size < proposed_size)
1260			err(EINVAL, "makefs_udf: won't fit on disc!");
1261	} else {
1262		fsopts->size = proposed_size;
1263	}
1264
1265	fsopts->inodes = stats->nfiles + stats->ndirs;
1266}
1267
1268
1269void
1270udf_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
1271{
1272	struct udf_stats stats;
1273	uint64_t truncate_len;
1274	char scrap[255];
1275	int error;
1276
1277	/* determine format */
1278	udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile);
1279	printf("req_enable %d, req_disable %d\n", req_enable, req_disable);
1280
1281	context.sector_size = fsopts->sectorsize;
1282	error = udf_derive_format(req_enable, req_disable, false);
1283	if (error)
1284		err(EINVAL, "makefs_udf: can't determine format");
1285
1286	/* names */
1287	error = udf_proces_names();
1288	if (error)
1289		err(EINVAL, "makefs_udf: bad names given");
1290
1291	/* set return value to 1 indicating error */
1292	error = 1;
1293
1294	/* estimate the amount of space needed */
1295	memset(&stats, 0, sizeof(stats));
1296	udf_enumerate_and_estimate(dir, root, fsopts, &stats);
1297
1298	printf("Calculated size of `%s': %lld bytes, %ld inodes\n",
1299	    image, (long long)fsopts->size, (long)fsopts->inodes);
1300
1301	/* create file image */
1302	if ((fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
1303		err(EXIT_FAILURE, "%s", image);
1304	}
1305	if (lseek(fd, fsopts->size - 1, SEEK_SET) == -1) {
1306		goto err_exit;
1307	}
1308	if (write(fd, &fd, 1) != 1) {
1309		goto err_exit;
1310	}
1311	if (lseek(fd, 0, SEEK_SET) == -1) {
1312		goto err_exit;
1313	}
1314	fsopts->fd = fd;
1315
1316	/* calculate metadata percentage */
1317	meta_fract = fsopts->size / (stats.nmetadatablocks*fsopts->sectorsize);
1318	meta_fract = ((int) ((meta_fract + 0.005)*100.0)) / 100;
1319
1320	/* update mmc info but now with correct size */
1321	udf_emulate_discinfo(fsopts, &mmc_discinfo, mmc_profile);
1322
1323	printf("Building disc compatible with UDF version %x to %x\n\n",
1324		context.min_udf, context.max_udf);
1325	(void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS,
1326	    (uint64_t) format_flags);
1327	printf("UDF properties       %s\n", scrap);
1328	printf("Volume set          `%s'\n", context.volset_name);
1329	printf("Primary volume      `%s`\n", context.primary_name);
1330	printf("Logical volume      `%s`\n", context.logvol_name);
1331	if (format_flags & FORMAT_META)
1332		printf("Metadata percentage  %d %%\n",
1333			(int) (100.0*stats.ndatablocks/stats.nmetadatablocks));
1334	printf("\n");
1335	udf_do_newfs_prefix();
1336
1337	/* update context */
1338	context.unique_id = 0;
1339
1340	/* XXX are the next two needed? or should be re-count them? */
1341	context.num_files = stats.nfiles;
1342	context.num_directories = stats.ndirs;
1343
1344	error = udf_populate(dir, root, fsopts, &stats);
1345
1346	udf_do_newfs_postfix();
1347
1348	if (format_flags & FORMAT_VAT) {
1349		truncate_len = context.vtop_offset[context.data_part] +
1350			context.data_alloc_pos;
1351		truncate_len *= context.sector_size;
1352
1353		printf("\nTruncing the disc-image to allow for VAT\n");
1354		printf("Free space left on this volume approx. "
1355			"%"PRIu64" KiB, %"PRIu64" MiB\n",
1356			(fsopts->size - truncate_len)/1024,
1357			(fsopts->size - truncate_len)/1024/1024);
1358		ftruncate(fd, truncate_len);
1359	}
1360
1361	if (error) {
1362		error = 2;	/* some files couldn't be added */
1363		goto err_exit;
1364	}
1365
1366	close(fd);
1367	return;
1368
1369err_exit:
1370	close(fd);
1371	if (error == 2) {
1372		errx(error, "Not all files could be added");
1373	} else {
1374		errx(error, "creation of %s failed", image);
1375	}
1376}
1377
1378