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