Module Name:    src
Committed By:   reinoud
Date:           Mon Aug  5 14:11:30 UTC 2013

Modified Files:
        src/sbin/newfs_udf: newfs_udf.8 newfs_udf.c udf_create.c udf_create.h
            udf_write.c udf_write.h
Added Files:
        src/sbin/newfs_udf: unicode.h

Log Message:
Adjust newfs_udf to be sharing code with the new `makefs -t udf' to be
comitted.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sbin/newfs_udf/newfs_udf.8
cvs rdiff -u -r1.14 -r1.15 src/sbin/newfs_udf/newfs_udf.c
cvs rdiff -u -r1.17 -r1.18 src/sbin/newfs_udf/udf_create.c
cvs rdiff -u -r1.3 -r1.4 src/sbin/newfs_udf/udf_create.h
cvs rdiff -u -r1.2 -r1.3 src/sbin/newfs_udf/udf_write.c
cvs rdiff -u -r1.1 -r1.2 src/sbin/newfs_udf/udf_write.h
cvs rdiff -u -r0 -r1.1 src/sbin/newfs_udf/unicode.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/newfs_udf/newfs_udf.8
diff -u src/sbin/newfs_udf/newfs_udf.8:1.12 src/sbin/newfs_udf/newfs_udf.8:1.13
--- src/sbin/newfs_udf/newfs_udf.8:1.12	Sat Jul 20 21:39:58 2013
+++ src/sbin/newfs_udf/newfs_udf.8	Mon Aug  5 14:11:30 2013
@@ -1,4 +1,4 @@
-.\" $NetBSD: newfs_udf.8,v 1.12 2013/07/20 21:39:58 wiz Exp $
+.\" $NetBSD: newfs_udf.8,v 1.13 2013/08/05 14:11:30 reinoud Exp $
 .\"
 .\" Copyright (c) 2008 Reinoud Zandijk
 .\" All rights reserved.
@@ -26,7 +26,7 @@
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\"
-.Dd July 2, 2013
+.Dd August 2, 2013
 .Dt NEWFS_UDF 8
 .Os
 .Sh NAME
@@ -40,6 +40,7 @@
 .Op Fl p Ar percentage
 .Op Fl S Ar sectorsize
 .Op Fl s Ar size
+.Op Fl B Ar blockingsize
 .Op Fl t Ar gmtoff
 .Op Fl V Ar max_udf
 .Op Fl v Ar min_udf
@@ -84,6 +85,10 @@ For strict conformance and interchange, 
 .It Fl s Ar size
 For image files, set the file size to the humanized size
 .Ar size .
+.It Fl B Ar blockingsize
+When creating image files, specify the blocking size or packetsize of the media
+to
+.Ar blockingsize .
 .It Fl t Ar gmtoff
 Use the specified
 .Ar gmtoff

Index: src/sbin/newfs_udf/newfs_udf.c
diff -u src/sbin/newfs_udf/newfs_udf.c:1.14 src/sbin/newfs_udf/newfs_udf.c:1.15
--- src/sbin/newfs_udf/newfs_udf.c:1.14	Thu Jul 18 12:44:21 2013
+++ src/sbin/newfs_udf/newfs_udf.c	Mon Aug  5 14:11:30 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: newfs_udf.c,v 1.14 2013/07/18 12:44:21 reinoud Exp $ */
+/* $NetBSD: newfs_udf.c,v 1.15 2013/08/05 14:11:30 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
@@ -94,6 +94,7 @@ int	 format_flags;			/* format: attribut
 int	 media_accesstype;		/* derived from current mmc cap  */
 int	 check_surface;			/* for rewritables               */
 int	 imagefile_secsize;		/* for files			 */
+int	 emul_packetsize;		/* for discs and files		 */
 
 int	 wrtrack_skew;
 int	 meta_perc = UDF_META_PERC;
@@ -289,8 +290,9 @@ udf_update_discinfo(struct mmc_discinfo 
 		sectors = size / secsize;
 	} else {
 		/*
-		 * disc partition support; note we can't use DIOCGPART in userland so
-		 * get disc label and use the stat info to get the partition number.
+		 * disc partition support; note we can't use DIOCGPART in
+		 * userland so get disc label and use the stat info to get the
+		 * partition number.
 		 */
 		if (ioctl(fd, DIOCGDINFO, &disklab) == -1) {
 			/* failed to get disclabel! */
@@ -303,9 +305,10 @@ udf_update_discinfo(struct mmc_discinfo 
 		partnr = DISKPART(st.st_rdev);
 		dp = &disklab.d_partitions[partnr];
 
-		/* TODO problem with last_possible_lba on resizable VND; request */
+		/* TODO problem with last_possible_lba on resizable VND */
 		if (dp->p_size == 0) {
-			perror("faulty disklabel partition returned, check label\n");
+			perror("faulty disklabel partition returned, "
+				"check label\n");
 			return EIO;
 		}
 
@@ -363,7 +366,7 @@ udf_update_trackinfo(struct mmc_discinfo
 	ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID;
 
 	ti->track_start    = 0;
-	ti->packet_size    = 1;
+	ti->packet_size    = emul_packetsize;
 
 	/* TODO support for resizable vnd */
 	ti->track_size    = di->last_possible_lba;
@@ -722,6 +725,7 @@ main(int argc, char **argv)
 	check_surface = 0;
 	setsize       = 0;
 	imagefile_secsize = 512;	/* minimum allowed sector size */
+	emul_packetsize   = 32;		/* reasonable default */
 
 	srandom((unsigned long) time(NULL));
 	udf_init_create_context();
@@ -740,7 +744,7 @@ main(int argc, char **argv)
 	context.gmtoff = tm->tm_gmtoff;
 
 	/* process options */
-	while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:t:v:V:")) != -1) {
+	while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:B:t:v:V:")) != -1) {
 		switch (ch) {
 		case 'c' :
 			check_surface = 1;
@@ -802,6 +806,12 @@ main(int argc, char **argv)
 			imagefile_secsize = a_num(optarg, "secsize");
 			imagefile_secsize = MAX(512, imagefile_secsize);
 			break;
+		case 'B' :
+			emul_packetsize = a_num(optarg,
+				"blockingnr, packetsize");
+			emul_packetsize = MAX(emul_packetsize, 1);
+			emul_packetsize = MIN(emul_packetsize, 32);
+			break;
 		case 't' :
 			/* time zone overide */
 			context.gmtoff = a_num(optarg, "gmtoff");

Index: src/sbin/newfs_udf/udf_create.c
diff -u src/sbin/newfs_udf/udf_create.c:1.17 src/sbin/newfs_udf/udf_create.c:1.18
--- src/sbin/newfs_udf/udf_create.c:1.17	Wed Dec 23 09:13:21 2009
+++ src/sbin/newfs_udf/udf_create.c	Mon Aug  5 14:11:30 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_create.c,v 1.17 2009/12/23 09:13:21 mbalmer Exp $ */
+/* $NetBSD: udf_create.c,v 1.18 2013/08/05 14:11:30 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -28,11 +28,12 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: udf_create.c,v 1.17 2009/12/23 09:13:21 mbalmer Exp $");
+__RCSID("$NetBSD: udf_create.c,v 1.18 2013/08/05 14:11:30 reinoud Exp $");
 #endif /* not lint */
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <errno.h>
 #include <time.h>
@@ -40,6 +41,7 @@ __RCSID("$NetBSD: udf_create.c,v 1.17 20
 #include <err.h>
 #include <sys/types.h>
 #include <sys/param.h>
+#include "unicode.h"
 #include "udf_create.h"
 
 
@@ -49,6 +51,10 @@ __RCSID("$NetBSD: udf_create.c,v 1.17 20
 #  endif
 #endif
 
+/*
+ * NOTE that there is some overlap between this code and the udf kernel fs.
+ * This is intentially though it might better be factored out one day.
+ */
 
 void
 udf_init_create_context(void)
@@ -82,6 +88,11 @@ udf_init_create_context(void)
 
 	context.num_files       = 0;
 	context.num_directories = 0;
+
+	context.data_part          = 0;
+	context.metadata_part      = 0;
+	context.metadata_alloc_pos = 0;
+	context.data_alloc_pos     = 0;
 }
 
 
@@ -178,7 +189,7 @@ udf_calculate_disc_layout(int format_fla
 
 	/* all non sequential media needs an unallocated space bitmap */
 	layout.alloc_bitmap_dscr_size = 0;
-	if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
+	if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
 		bytes = udf_space_bitmap_len(layout.part_size_lba);
 		layout.alloc_bitmap_dscr_size = udf_bytes_to_sectors(bytes);
 
@@ -208,7 +219,7 @@ udf_calculate_disc_layout(int format_fla
 	 * not updated sporadically
 	 */
 
-	if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
+	if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
 #ifdef DEBUG
 		printf("Lost %d slack sectors at start\n", UDF_ROUNDUP(
 			first_lba - wrtrack_skew, align_blockingnr) -
@@ -218,8 +229,10 @@ udf_calculate_disc_layout(int format_fla
 				first_lba - wrtrack_skew, align_blockingnr));
 #endif
 
-		first_lba = UDF_ROUNDUP( first_lba - wrtrack_skew, align_blockingnr);
-		last_lba  = UDF_ROUNDDOWN(last_lba - wrtrack_skew, align_blockingnr);
+		first_lba = UDF_ROUNDUP( first_lba - wrtrack_skew,
+				align_blockingnr);
+		last_lba  = UDF_ROUNDDOWN(last_lba - wrtrack_skew,
+				align_blockingnr);
 	}
 
 	if ((format_flags & FORMAT_SPARABLE) == 0)
@@ -335,11 +348,13 @@ udf_calculate_disc_layout(int format_fla
 #endif
 
 	kbsize = (uint64_t) last_lba * sector_size;
-	printf("Total space on this medium approx. %"PRIu64" KiB, %"PRIu64" MiB\n",
+	printf("Total space on this medium approx. "
+			"%"PRIu64" KiB, %"PRIu64" MiB\n",
 			kbsize/1024, kbsize/(1024*1024));
-	kbsize = (uint64_t) (layout.part_size_lba - layout.alloc_bitmap_dscr_size
+	kbsize = (uint64_t)(layout.part_size_lba - layout.alloc_bitmap_dscr_size
 		- layout.meta_bitmap_dscr_size) * sector_size;
-	printf("Free space on this volume approx.  %"PRIu64" KiB, %"PRIu64" MiB\n\n",
+	printf("Free space on this volume approx.  "
+			"%"PRIu64" KiB, %"PRIu64" MiB\n\n",
 			kbsize/1024, kbsize/(1024*1024));
 
 	return 0;
@@ -520,8 +535,8 @@ udf_add_app_regid(struct regid *regid)
 
 
 /*
- * Fill in timestamp structure based on clock_gettime(). Time is reported back as a time_t
- * accompanied with a nano second field.
+ * Fill in timestamp structure based on clock_gettime(). Time is reported back
+ * as a time_t accompanied with a nano second field.
  *
  * The husec, usec and csec could be relaxed in type.
  */
@@ -557,13 +572,17 @@ udf_timespec_to_timestamp(struct timespe
 	csec   =  husec / 100;				/* only 0-99 in csec  */
 	husec -=   csec * 100;				/* only 0-99 in husec */
 
+	/* in rare cases there is overflow in csec */
+	csec  = MIN(99, csec);
+	husec = MIN(99, husec);
+	usec  = MIN(99, usec);
+
 	timestamp->centisec	= csec;
 	timestamp->hund_usec	= husec;
 	timestamp->usec		= usec;
 }
 
 
-
 void
 udf_set_timestamp_now(struct timestamp *timestamp)
 {
@@ -574,6 +593,38 @@ udf_set_timestamp_now(struct timestamp *
 }
 
 
+/* some code copied from sys/fs/udf */
+
+static void
+udf_set_timestamp(struct timestamp *timestamp, time_t value)
+{
+	struct timespec t;
+
+	memset(&t, 0, sizeof(struct timespec));
+	t.tv_sec  = value;
+	t.tv_nsec = 0;
+	udf_timespec_to_timestamp(&t, timestamp);
+}
+
+
+static uint32_t
+unix_mode_to_udf_perm(mode_t mode)
+{
+	uint32_t perm;
+	
+	perm  = ((mode & S_IRWXO)     );
+	perm |= ((mode & S_IRWXG) << 2);
+	perm |= ((mode & S_IRWXU) << 4);
+	perm |= ((mode & S_IWOTH) << 3);
+	perm |= ((mode & S_IWGRP) << 5);
+	perm |= ((mode & S_IWUSR) << 7);
+
+	return perm;
+}
+
+/* end of copied code */
+
+
 int
 udf_create_primaryd(void)
 {
@@ -1242,7 +1293,7 @@ udf_mark_allocated(uint32_t start_lb, in
 	uint8_t *bpos;
 	uint32_t cnt, bit;
 
-	/* make not on space used on underlying partition */
+	/* account for space used on underlying partition */
 	context.part_free[partnr] -= blocks;
 #ifdef DEBUG
 	printf("mark allocated : partnr %d, start_lb %d for %d blocks\n",
@@ -1256,6 +1307,10 @@ udf_mark_allocated(uint32_t start_lb, in
 	case UDF_VTOP_TYPE_PHYS:
 	case UDF_VTOP_TYPE_SPARABLE:
 	case UDF_VTOP_TYPE_META:
+		if (context.part_unalloc_bits[context.vtop[partnr]] == NULL) {
+			context.part_free[partnr] = 0;
+			break;
+		}
 #ifdef DEBUG
 		printf("Marking %d+%d as used\n", start_lb, blocks);
 #endif
@@ -1274,9 +1329,7 @@ udf_mark_allocated(uint32_t start_lb, in
 }
 
 
-/* --------------------------------------------------------------------- */
-
-static void
+void
 udf_advance_uniqueid(void)
 {
 	/* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */
@@ -1285,10 +1338,192 @@ udf_advance_uniqueid(void)
 		context.unique_id = 0x10;
 }
 
+/* --------------------------------------------------------------------- */
 
-static int
-udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent,
-	uint64_t unique_id)
+static void
+unix_to_udf_name(char *result, uint8_t *result_len,
+	char const *name, int name_len, struct charspec *chsp)
+{
+	uint16_t   *raw_name;
+	uint16_t   *outchp;
+	const char *inchp;
+	const char *osta_id = "OSTA Compressed Unicode";
+	int         udf_chars, is_osta_typ0, bits;
+	size_t      cnt;
+
+	/* allocate temporary unicode-16 buffer */
+	raw_name = malloc(1024);
+	assert(raw_name);
+
+	/* convert utf8 to unicode-16 */
+	*raw_name = 0;
+	inchp  = name;
+	outchp = raw_name;
+	bits = 8;
+	for (cnt = name_len, udf_chars = 0; cnt;) {
+		*outchp = wget_utf8(&inchp, &cnt);
+		if (*outchp > 0xff)
+			bits=16;
+		outchp++;
+		udf_chars++;
+	}
+	/* null terminate just in case */
+	*outchp++ = 0;
+
+	is_osta_typ0  = (chsp->type == 0);
+	is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0);
+	if (is_osta_typ0) {
+		udf_chars = udf_CompressUnicode(udf_chars, bits,
+				(unicode_t *) raw_name,
+				(byte *) result);
+	} else {
+		printf("unix to udf name: no CHSP0 ?\n");
+		/* XXX assume 8bit char length byte latin-1 */
+		*result++ = 8; udf_chars = 1;
+		strncpy(result, name + 1, name_len);
+		udf_chars += name_len;
+	}
+	*result_len = udf_chars;
+	free(raw_name);
+}
+
+
+#define UDF_SYMLINKBUFLEN    (64*1024)               /* picked */
+int
+udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target)
+{
+	struct charspec osta_charspec;
+	struct pathcomp pathcomp;
+	char *pathbuf, *pathpos, *compnamepos;
+//	char *mntonname;
+//	int   mntonnamelen;
+	int pathlen, len, compnamelen;
+	int error;
+
+	/* process `target' to an UDF structure */
+	pathbuf = malloc(UDF_SYMLINKBUFLEN);
+	assert(pathbuf);
+
+	*pathbufp = NULL;
+	*pathlenp = 0;
+
+	pathpos = pathbuf;
+	pathlen = 0;
+	udf_osta_charset(&osta_charspec);
+
+	if (*target == '/') {
+		/* symlink starts from the root */
+		len = UDF_PATH_COMP_SIZE;
+		memset(&pathcomp, 0, len);
+		pathcomp.type = UDF_PATH_COMP_ROOT;
+
+#if 0
+		/* XXX how to check for in makefs? */
+		/* check if its mount-point relative! */
+		mntonname    = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
+		mntonnamelen = strlen(mntonname);
+		if (strlen(target) >= mntonnamelen) {
+			if (strncmp(target, mntonname, mntonnamelen) == 0) {
+				pathcomp.type = UDF_PATH_COMP_MOUNTROOT;
+				target += mntonnamelen;
+			}
+		} else {
+			target++;
+		}
+#else
+		target++;
+#endif
+
+		memcpy(pathpos, &pathcomp, len);
+		pathpos += len;
+		pathlen += len;
+	}
+
+	error = 0;
+	while (*target) {
+		/* ignore multiple '/' */
+		while (*target == '/') {
+			target++;
+		}
+		if (!*target)
+			break;
+
+		/* extract component name */
+		compnamelen = 0;
+		compnamepos = target;
+		while ((*target) && (*target != '/')) {
+			target++;
+			compnamelen++;
+		}
+
+		/* just trunc if too long ?? (security issue) */
+		if (compnamelen >= 127) {
+			error = ENAMETOOLONG;
+			break;
+		}
+
+		/* convert unix name to UDF name */
+		len = sizeof(struct pathcomp);
+		memset(&pathcomp, 0, len);
+		pathcomp.type = UDF_PATH_COMP_NAME;
+		len = UDF_PATH_COMP_SIZE;
+
+		if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0))
+			pathcomp.type = UDF_PATH_COMP_PARENTDIR;
+		if ((compnamelen == 1) && (*compnamepos == '.'))
+			pathcomp.type = UDF_PATH_COMP_CURDIR;
+
+		if (pathcomp.type == UDF_PATH_COMP_NAME) {
+			unix_to_udf_name(
+				(char *) &pathcomp.ident, &pathcomp.l_ci,
+				compnamepos, compnamelen,
+				&osta_charspec);
+			len = UDF_PATH_COMP_SIZE + pathcomp.l_ci;
+		}
+
+		if (pathlen + len >= UDF_SYMLINKBUFLEN) {
+			error = ENAMETOOLONG;
+			break;
+		}
+
+		memcpy(pathpos, &pathcomp, len);
+		pathpos += len;
+		pathlen += len;
+	}
+
+	if (error) {
+		/* aparently too big */
+		free(pathbuf);
+		return error;
+	}
+
+	/* return status of symlink contents writeout */
+	*pathbufp = (uint8_t *) pathbuf;
+	*pathlenp = pathlen;
+
+	return 0;
+
+}
+#undef UDF_SYMLINKBUFLEN
+
+
+int
+udf_fidsize(struct fileid_desc *fid)
+{
+	uint32_t size;
+
+	if (udf_rw16(fid->tag.id) != TAGID_FID)
+		errx(EINVAL, "got udf_fidsize on non FID\n");
+
+	size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu);
+	size = (size + 3) & ~3;
+
+	return size;
+}
+
+
+int
+udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent)
 {
 	/* the size of an empty FID is 38 but needs to be a multiple of 4 */
 	int fidsize = 40;
@@ -1297,7 +1532,7 @@ udf_create_parentfid(struct fileid_desc 
 	fid->file_version_num = udf_rw16(1);	/* UDF 2.3.4.1 */
 	fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR;
 	fid->icb = *parent;
-	fid->icb.longad_uniqueid = udf_rw32((uint32_t) unique_id);
+	fid->icb.longad_uniqueid = parent->longad_uniqueid;
 	fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
 
 	/* we have to do the fid here explicitly for simplicity */
@@ -1307,6 +1542,102 @@ udf_create_parentfid(struct fileid_desc 
 }
 
 
+void
+udf_create_fid(uint32_t diroff, struct fileid_desc *fid, char *name,
+	int file_char, struct long_ad *ref)
+{
+	struct charspec osta_charspec;
+	uint32_t endfid;
+	uint32_t fidsize, lb_rest;
+
+	memset(fid, 0, sizeof(struct fileid_desc *));
+	udf_inittag(&fid->tag, TAGID_FID, udf_rw32(ref->loc.lb_num));
+	fid->file_version_num = udf_rw16(1);	/* UDF 2.3.4.1 */
+	fid->file_char = file_char;
+	fid->l_iu = udf_rw16(0);
+	fid->icb = *ref;
+	fid->icb.longad_uniqueid = ref->longad_uniqueid;
+
+	udf_osta_charset(&osta_charspec);
+	unix_to_udf_name((char *) fid->data, &fid->l_fi, name, strlen(name),
+			&osta_charspec);
+
+	/*
+	 * OK, tricky part: we need to pad so the next descriptor header won't
+	 * cross the sector boundary
+	 */
+	endfid = diroff + udf_fidsize(fid);
+	lb_rest = context.sector_size - (endfid % context.sector_size);
+	if (lb_rest < sizeof(struct desc_tag)) {
+		/* add at least 32 */
+		fid->l_iu = udf_rw16(32);
+		udf_set_regid((struct regid *) fid->data, context.impl_name);
+		udf_add_impl_regid((struct regid *) fid->data);
+
+		unix_to_udf_name((char *) fid->data + udf_rw16(fid->l_iu),
+			&fid->l_fi, name, strlen(name), &osta_charspec);
+	}
+
+	fidsize = udf_fidsize(fid);
+	fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH);
+
+	/* make sure the header sums stays correct */
+	udf_validate_tag_and_crc_sums((union dscrptr *)fid);
+}
+
+
+static void
+udf_append_parentfid(union dscrptr *dscr, struct long_ad *parent_icb)
+{
+	struct file_entry      *fe;
+	struct extfile_entry   *efe;
+	struct fileid_desc     *fid;
+	uint32_t l_ea;
+	uint32_t fidsize, crclen;
+	uint8_t *bpos, *data;
+
+	fe = NULL;
+	efe = NULL;
+	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
+		fe    = &dscr->fe;
+		data  = fe->data;
+		l_ea  = udf_rw32(fe->l_ea);
+	} else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) {
+		efe   = &dscr->efe;
+		data  = efe->data;
+		l_ea  = udf_rw32(efe->l_ea);
+	} else {
+		errx(1, "Bad tag passed to udf_append_parentfid");
+	}
+
+	/* create '..' */
+	bpos = data + l_ea;
+	fid  = (struct fileid_desc *) bpos;
+	fidsize = udf_create_parentfid(fid, parent_icb);
+
+	/* record fidlength information */
+	if (fe) {
+		fe->inf_len     = udf_rw64(fidsize);
+		fe->l_ad        = udf_rw32(fidsize);
+		fe->logblks_rec = udf_rw64(0);		/* intern */
+		crclen  = sizeof(struct file_entry);
+	} else {
+		efe->inf_len     = udf_rw64(fidsize);
+		efe->obj_size    = udf_rw64(fidsize);
+		efe->l_ad        = udf_rw32(fidsize);
+		efe->logblks_rec = udf_rw64(0);		/* intern */
+		crclen  = sizeof(struct extfile_entry);
+	}
+	crclen -= 1 + UDF_DESC_TAG_LENGTH;
+	crclen += l_ea + fidsize;
+	dscr->tag.desc_crc_len = udf_rw16(crclen);
+
+	/* make sure the header sums stays correct */
+	udf_validate_tag_and_crc_sums(dscr);
+}
+
+
+
 /*
  * Order of extended attributes :
  *   ECMA 167 EAs
@@ -1425,16 +1756,14 @@ udf_extattr_append_internal(union dscrpt
 
 
 int
-udf_create_new_fe(struct file_entry **fep, int file_type,
-	struct long_ad *parent_icb)
+udf_create_new_fe(struct file_entry **fep, int file_type, struct stat *st)
 {
 	struct file_entry      *fe;
 	struct icb_tag         *icb;
 	struct timestamp        birthtime;
 	struct filetimes_extattr_entry *ft_extattr;
-	uint32_t fidsize;
-	uint8_t *bpos;
 	uint32_t crclen;	/* XXX: should be 16; need to detect overflow */
+	uint16_t icbflags;
 
 	*fep = NULL;
 	fe = calloc(1, context.sector_size);
@@ -1457,14 +1786,41 @@ udf_create_new_fe(struct file_entry **fe
 	fe->link_cnt = udf_rw16(0);		/* explicit setting */
 
 	fe->ckpoint  = udf_rw32(1);		/* user supplied file version */
+
 	udf_set_timestamp_now(&birthtime);
 	udf_set_timestamp_now(&fe->atime);
 	udf_set_timestamp_now(&fe->attrtime);
 	udf_set_timestamp_now(&fe->mtime);
 
+	/* set attributes */
+	if (st) {
+		udf_set_timestamp(&birthtime,    st->st_birthtime);
+		udf_set_timestamp(&fe->atime,    st->st_atime);
+		udf_set_timestamp(&fe->attrtime, st->st_ctime);
+		udf_set_timestamp(&fe->mtime,    st->st_mtime);
+		fe->uid  = udf_rw32(st->st_uid);
+		fe->gid  = udf_rw32(st->st_gid);
+
+		fe->perm = unix_mode_to_udf_perm(st->st_mode);
+
+		icbflags = udf_rw16(fe->icbtag.flags);
+		icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
+		icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
+		icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
+		if (st->st_mode & S_ISUID)
+			icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
+		if (st->st_mode & S_ISGID)
+			icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
+		if (st->st_mode & S_ISVTX)
+			icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
+		fe->icbtag.flags  = udf_rw16(icbflags);
+	}
+
 	udf_set_regid(&fe->imp_id, context.impl_name);
 	udf_add_impl_regid(&fe->imp_id);
 	fe->unique_id = udf_rw64(context.unique_id);
+	udf_advance_uniqueid();
+
 	fe->l_ea = udf_rw32(0);
 
 	/* create extended attribute to record our creation time */
@@ -1480,24 +1836,17 @@ udf_create_new_fe(struct file_entry **fe
 		(struct extattr_entry *) ft_extattr);
 	free(ft_extattr);
 
-	/* if its a directory, create '..' */
-	bpos = (uint8_t *) fe->data + udf_rw32(fe->l_ea);
-	fidsize = 0;
-	if (file_type == UDF_ICB_FILETYPE_DIRECTORY) {
-		fidsize = udf_create_parentfid((struct fileid_desc *) bpos,
-			parent_icb, context.unique_id);
-	}
-	udf_advance_uniqueid();
-
 	/* record fidlength information */
-	fe->inf_len = udf_rw64(fidsize);
-	fe->l_ad    = udf_rw32(fidsize);
+	fe->inf_len = udf_rw64(0);
+	fe->l_ad    = udf_rw32(0);
 	fe->logblks_rec = udf_rw64(0);		/* intern */
 
 	crclen  = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
-	crclen += udf_rw32(fe->l_ea) + fidsize;
-/* XXX ensure crclen doesn't exceed UINT16_MAX ? */
+	crclen += udf_rw32(fe->l_ea);
+
+	/* make sure the header sums stays correct */
 	fe->tag.desc_crc_len = udf_rw16(crclen);
+	udf_validate_tag_and_crc_sums((union dscrptr *) fe);
 
 	*fep = fe;
 	return 0;
@@ -1505,13 +1854,13 @@ udf_create_new_fe(struct file_entry **fe
 
 
 int
-udf_create_new_efe(struct extfile_entry **efep, int file_type,
-	struct long_ad *parent_icb)
+udf_create_new_efe(struct extfile_entry **efep, int file_type, struct stat *st)
 {
 	struct extfile_entry *efe;
 	struct icb_tag       *icb;
 	uint32_t fidsize;
 	uint32_t crclen;	/* XXX: should be 16; need to detect overflow */
+	uint16_t icbflags;
 
 	*efep = NULL;
 	efe = calloc(1, context.sector_size);
@@ -1534,32 +1883,54 @@ udf_create_new_efe(struct extfile_entry 
 	efe->link_cnt = udf_rw16(0);		/* explicit setting */
 
 	efe->ckpoint  = udf_rw32(1);		/* user supplied file version */
+
 	udf_set_timestamp_now(&efe->ctime);
 	udf_set_timestamp_now(&efe->atime);
 	udf_set_timestamp_now(&efe->attrtime);
 	udf_set_timestamp_now(&efe->mtime);
 
+	/* set attributes */
+	if (st) {
+		udf_set_timestamp(&efe->ctime,    st->st_birthtime);
+		udf_set_timestamp(&efe->atime,    st->st_atime);
+		udf_set_timestamp(&efe->attrtime, st->st_ctime);
+		udf_set_timestamp(&efe->mtime,    st->st_mtime);
+		efe->uid = udf_rw32(st->st_uid);
+		efe->gid = udf_rw32(st->st_gid);
+
+		efe->perm = unix_mode_to_udf_perm(st->st_mode);
+
+		icbflags = udf_rw16(efe->icbtag.flags);
+		icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID;
+		icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID;
+		icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY;
+		if (st->st_mode & S_ISUID)
+			icbflags |= UDF_ICB_TAG_FLAGS_SETUID;
+		if (st->st_mode & S_ISGID)
+			icbflags |= UDF_ICB_TAG_FLAGS_SETGID;
+		if (st->st_mode & S_ISVTX)
+			icbflags |= UDF_ICB_TAG_FLAGS_STICKY;
+		efe->icbtag.flags = udf_rw16(icbflags);
+	}
+
 	udf_set_regid(&efe->imp_id, context.impl_name);
 	udf_add_impl_regid(&efe->imp_id);
 
 	fidsize = 0;
 	efe->unique_id = udf_rw64(context.unique_id);
-	if (file_type == UDF_ICB_FILETYPE_DIRECTORY) {
-		fidsize = udf_create_parentfid((struct fileid_desc *) efe->data,
-			parent_icb, context.unique_id);
-	}
 	udf_advance_uniqueid();
 
 	/* record fidlength information */
-	efe->inf_len  = udf_rw64(fidsize);
-	efe->obj_size = udf_rw64(fidsize);
-	efe->l_ad     = udf_rw32(fidsize);
+	efe->inf_len  = udf_rw64(0);
+	efe->obj_size = udf_rw64(0);
+	efe->l_ad     = udf_rw32(0);
 	efe->logblks_rec = udf_rw64(0);
 
 	crclen  = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH;
-	crclen += fidsize;
-/* XXX ensure crclen doesn't exceed UINT16_MAX ? */
+
+	/* make sure the header sums stays correct */
 	efe->tag.desc_crc_len = udf_rw16(crclen);
+	udf_validate_tag_and_crc_sums((union dscrptr *) efe);
 
 	*efep = efe;
 	return 0;
@@ -1567,8 +1938,10 @@ udf_create_new_efe(struct extfile_entry 
 
 /* --------------------------------------------------------------------- */
 
+/* for METADATA file appending only */
 static void
-udf_append_mapping_part_to_efe(struct extfile_entry *efe, struct short_ad *mapping)
+udf_append_meta_mapping_part_to_efe(struct extfile_entry *efe,
+		struct short_ad *mapping)
 {
 	struct icb_tag *icb;
 	uint64_t inf_len, obj_size, logblks_rec;
@@ -1606,8 +1979,10 @@ udf_append_mapping_part_to_efe(struct ex
 }
 
 
+/* for METADATA file appending only */
 static void
-udf_append_meta_mapping_to_efe(struct extfile_entry *efe, uint16_t partnr, uint32_t lb_num,
+udf_append_meta_mapping_to_efe(struct extfile_entry *efe,
+		uint16_t partnr, uint32_t lb_num,
 	uint64_t len)
 {
 	struct short_ad mapping;
@@ -1624,7 +1999,7 @@ udf_append_meta_mapping_to_efe(struct ex
 		mapping.lb_num   = udf_rw32(lb_num);
 		mapping.len      = udf_rw32(part_len);
 
-		udf_append_mapping_part_to_efe(efe, &mapping);
+		udf_append_meta_mapping_part_to_efe(efe, &mapping);
 
 		lb_num += part_len / context.sector_size;
 		len    -= part_len;
@@ -1650,7 +2025,7 @@ udf_create_meta_files(void)
 	/* create metadata file */
 	meta_icb.loc.lb_num   = udf_rw32(layout.meta_file);
 	filetype = UDF_ICB_FILETYPE_META_MAIN;
-	error = udf_create_new_efe(&efe, filetype, &meta_icb);
+	error = udf_create_new_efe(&efe, filetype, NULL);
 	if (error)
 		return error;
 	context.meta_file = efe;
@@ -1658,7 +2033,7 @@ udf_create_meta_files(void)
 	/* create metadata mirror file */
 	meta_icb.loc.lb_num   = udf_rw32(layout.meta_mirror);
 	filetype = UDF_ICB_FILETYPE_META_MIRROR;
-	error = udf_create_new_efe(&efe, filetype, &meta_icb);
+	error = udf_create_new_efe(&efe, filetype, NULL);
 	if (error)
 		return error;
 	context.meta_mirror = efe;
@@ -1666,7 +2041,7 @@ udf_create_meta_files(void)
 	/* create metadata bitmap file */
 	meta_icb.loc.lb_num   = udf_rw32(layout.meta_bitmap);
 	filetype = UDF_ICB_FILETYPE_META_BITMAP;
-	error = udf_create_new_efe(&efe, filetype, &meta_icb);
+	error = udf_create_new_efe(&efe, filetype, NULL);
 	if (error)
 		return error;
 	context.meta_bitmap = efe;
@@ -1717,16 +2092,19 @@ udf_create_new_rootdir(union dscrptr **d
 
 	filetype = UDF_ICB_FILETYPE_DIRECTORY;
 	if (context.dscrver == 2) {
-		error = udf_create_new_fe(&fe, filetype, &root_icb);
+		error = udf_create_new_fe(&fe, filetype, NULL);
 		*dscr = (union dscrptr *) fe;
 	} else {
-		error = udf_create_new_efe(&efe, filetype, &root_icb);
+		error = udf_create_new_efe(&efe, filetype, NULL);
 		*dscr = (union dscrptr *) efe;
 	}
 	if (error)
 		return error;
 
-	/* Rootdir has explicit only one link on creation; '..' is no link */
+	/* append '..' */
+	udf_append_parentfid(*dscr, &root_icb);
+
+	/* rootdir has explicit only one link on creation; '..' is no link */
 	if (context.dscrver == 2) {
 		fe->link_cnt  = udf_rw16(1);
 	} else {
@@ -1740,22 +2118,120 @@ udf_create_new_rootdir(union dscrptr **d
 }
 
 
+void
+udf_prepend_VAT_file(void)
+{
+	/* old style VAT has no prepend */
+	if (context.dscrver == 2) {
+		context.vat_start = 0;
+		context.vat_size  = 0;
+		return;
+	}
+
+	context.vat_start = offsetof(struct udf_vat, data);
+	context.vat_size  = offsetof(struct udf_vat, data);
+}
+
+
+void
+udf_vat_update(uint32_t virt, uint32_t phys)
+{
+	uint32_t *vatpos;
+	uint32_t new_size;
+
+	if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT)
+		return;
+ 
+	new_size = MAX(context.vat_size,
+		(context.vat_start + (virt+1)*sizeof(uint32_t)));
+
+	if (new_size > context.vat_allocated) {
+		context.vat_allocated = 
+			UDF_ROUNDUP(new_size, context.sector_size);
+		context.vat_contents = realloc(context.vat_contents,
+			context.vat_allocated);
+		assert(context.vat_contents);
+		/* XXX could also report error */
+	}
+	vatpos  = (uint32_t *) (context.vat_contents + context.vat_start);
+	vatpos[virt] = udf_rw32(phys);
+
+	context.vat_size = MAX(context.vat_size,
+		(context.vat_start + (virt+1)*sizeof(uint32_t)));
+}
+
+
 int
-udf_create_new_VAT(union dscrptr **vat_dscr)
+udf_append_VAT_file(void)
+{
+	struct udf_oldvat_tail *oldvat_tail;
+	struct udf_vat *vathdr;
+	int32_t len_diff;
+
+	/* new style VAT has VAT LVInt analog in front */
+	if (context.dscrver == 3) {
+		/* set up VATv2 descriptor */
+		vathdr = (struct udf_vat *) context.vat_contents;
+		vathdr->header_len      = udf_rw16(sizeof(struct udf_vat) - 1);
+		vathdr->impl_use_len    = udf_rw16(0);
+		memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128);
+		vathdr->prev_vat        = udf_rw32(UDF_NO_PREV_VAT);
+		vathdr->num_files       = udf_rw32(context.num_files);
+		vathdr->num_directories = udf_rw32(context.num_directories);
+
+		vathdr->min_udf_readver  = udf_rw16(context.min_udf);
+		vathdr->min_udf_writever = udf_rw16(context.min_udf);
+		vathdr->max_udf_writever = udf_rw16(context.max_udf);
+
+		return 0;
+	}
+
+	/* old style VAT has identifier appended */
+
+	/* append "*UDF Virtual Alloc Tbl" id and prev. VAT location */
+	len_diff = context.vat_allocated - context.vat_size;
+	assert(len_diff >= 0);
+	if (len_diff < (int32_t) sizeof(struct udf_oldvat_tail)) {
+		context.vat_allocated += context.sector_size;
+		context.vat_contents = realloc(context.vat_contents,
+			context.vat_allocated);
+		assert(context.vat_contents);
+		/* XXX could also report error */
+	}
+
+	oldvat_tail = (struct udf_oldvat_tail *) (context.vat_contents +
+			context.vat_size);
+
+	udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl");
+	udf_add_udf_regid(&oldvat_tail->id);
+	oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
+
+	context.vat_size += sizeof(struct udf_oldvat_tail);
+
+	return 0;
+}
+
+
+int
+udf_create_VAT(union dscrptr **vat_dscr)
 {
 	struct file_entry *fe;
 	struct extfile_entry *efe;
 	struct impl_extattr_entry *implext;
 	struct vatlvext_extattr_entry *vatlvext;
-	struct udf_oldvat_tail *oldvat_tail;
-	struct udf_vat *vathdr;
-	uint32_t *vat_pos;
+	struct long_ad dataloc, *allocpos;
 	uint8_t *bpos, *extattr;
-	uint32_t ea_len, inf_len, vat_len;
+	uint32_t ea_len, inf_len, vat_len, blks;
 	int filetype;
 	int error;
 
 	assert((layout.rootdir < 2) && (layout.fsd < 2));
+
+	memset(&dataloc, 0, sizeof(struct long_ad));
+	dataloc.len = udf_rw32(context.vat_size);
+	dataloc.loc.part_num = udf_rw16(context.data_part);
+	dataloc.loc.lb_num   = udf_rw32(layout.vat);
+
 	if (context.dscrver == 2) {
 		/* old style VAT */
 		filetype = UDF_ICB_FILETYPE_UNKNOWN;
@@ -1785,32 +2261,29 @@ udf_create_new_VAT(union dscrptr **vat_d
 		vatlvext->unique_id_chk = udf_rw64(fe->unique_id);
 		vatlvext->num_files = udf_rw32(context.num_files);
 		vatlvext->num_directories = udf_rw32(context.num_directories);
-		memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id, 128);
+		memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id,128);
 
 		udf_extattr_append_internal((union dscrptr *) fe,
 			(struct extattr_entry *) extattr);
 
 		free(extattr);
 
-		/* writeout VAT locations (partition offsets) */
-		vat_pos = (uint32_t *) (fe->data + udf_rw32(fe->l_ea));
-		vat_pos[layout.rootdir] = udf_rw32(layout.rootdir); 
-		vat_pos[layout.fsd    ] = udf_rw32(layout.fsd);
-
-		/* Append "*UDF Virtual Alloc Tbl" id and prev. VAT location */
-		oldvat_tail = (struct udf_oldvat_tail *) (vat_pos + 2);
-		udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl");
-		udf_add_udf_regid(&oldvat_tail->id);
-		oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT);
+		fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
+
+		allocpos = (struct long_ad *) (fe->data + udf_rw32(fe->l_ea));
+		*allocpos = dataloc;
 
 		/* set length */
-		inf_len = 2 * 4 + sizeof(struct udf_oldvat_tail);
+		inf_len = context.vat_size;
 		fe->inf_len = udf_rw64(inf_len);
-		fe->l_ad    = udf_rw32(inf_len);
+		fe->l_ad    = udf_rw32(sizeof(struct long_ad));
+		blks = UDF_ROUNDUP(inf_len, context.sector_size) /
+			context.sector_size;
+		fe->logblks_rec = udf_rw32(blks);
 
 		/* update vat descriptor's CRC length */
-		vat_len = inf_len + udf_rw32(fe->l_ea) +
-			sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
+		vat_len  = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH;
+		vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea);
 		fe->tag.desc_crc_len = udf_rw16(vat_len);
 
 		*vat_dscr = (union dscrptr *) fe;
@@ -1821,33 +2294,22 @@ udf_create_new_VAT(union dscrptr **vat_d
 		if (error)
 			return error;
 
-		/* set up VATv2 descriptor */
-		vathdr = (struct udf_vat *) efe->data;
-		vathdr->header_len      = udf_rw16(sizeof(struct udf_vat) - 1);
-		vathdr->impl_use_len    = udf_rw16(0);
-		memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128);
-		vathdr->prev_vat        = udf_rw32(UDF_NO_PREV_VAT);
-		vathdr->num_files       = udf_rw32(context.num_files);
-		vathdr->num_directories = udf_rw32(context.num_directories);
-
-		vathdr->min_udf_readver  = udf_rw16(context.min_udf);
-		vathdr->min_udf_writever = udf_rw16(context.min_udf);
-		vathdr->max_udf_writever = udf_rw16(context.max_udf);
+		efe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC);
 
-		/* writeout VAT locations */
-		vat_pos = (uint32_t *) vathdr->data;
-		vat_pos[layout.rootdir] = udf_rw32(layout.rootdir);
-		vat_pos[layout.fsd    ] = udf_rw32(layout.fsd);
+		allocpos = (struct long_ad *) efe->data;
+		*allocpos = dataloc;
 
 		/* set length */
-		inf_len  = 2 * 4 + sizeof(struct udf_vat) - 1;
+		inf_len = context.vat_size;
 		efe->inf_len     = udf_rw64(inf_len);
 		efe->obj_size    = udf_rw64(inf_len);
-		efe->l_ad        = udf_rw32(inf_len);
-		efe->logblks_rec = udf_rw32(0);
+		efe->l_ad        = udf_rw32(sizeof(struct long_ad));
+		blks = UDF_ROUNDUP(inf_len, context.sector_size) /
+			context.sector_size;
+		efe->logblks_rec = udf_rw32(blks);
 
 		vat_len  = sizeof(struct extfile_entry)-1 - UDF_DESC_TAG_LENGTH;
-		vat_len += inf_len;
+		vat_len += udf_rw32(efe->l_ad);
 		efe->tag.desc_crc_len = udf_rw16(vat_len);
 
 		*vat_dscr = (union dscrptr *) efe;

Index: src/sbin/newfs_udf/udf_create.h
diff -u src/sbin/newfs_udf/udf_create.h:1.3 src/sbin/newfs_udf/udf_create.h:1.4
--- src/sbin/newfs_udf/udf_create.h:1.3	Sun Jan 18 00:18:41 2009
+++ src/sbin/newfs_udf/udf_create.h	Mon Aug  5 14:11:30 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_create.h,v 1.3 2009/01/18 00:18:41 lukem Exp $ */
+/* $NetBSD: udf_create.h,v 1.4 2013/08/05 14:11:30 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -30,6 +30,7 @@
 #define _FS_UDF_UDF_CREATE_H_
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <fs/udf/ecma167-udf.h>
 #include "udf_bswap.h"
 #include "udf_osta.h"
@@ -46,9 +47,10 @@
 #define FORMAT_WORM		0x00080
 #define FORMAT_TRACK512		0x00100
 #define FORMAT_INVALID		0x00200
+#define FORMAT_READONLY		0x00400
 #define FORMAT_FLAGBITS \
     "\10\1WRITEONCE\2SEQUENTIAL\3REWRITABLE\4SPARABLE\5META\6LOW" \
-    "\7VAT\10WORM\11TRACK512\12INVALID"
+    "\7VAT\10WORM\11TRACK512\12INVALID\13READONLY"
 
 
 /* structure space */
@@ -77,10 +79,10 @@
 
 /* handys */
 #define UDF_ROUNDUP(val, gran) \
-	((gran) * (((val) + (gran)-1) / (gran)))
+	((gran) * (((uint64_t)(val) + (gran)-1) / (gran)))
 
 #define UDF_ROUNDDOWN(val, gran) \
-	((gran) * (((val)) / (gran)))
+	((gran) * (((uint64_t)(val)) / (gran)))
 
 
 /* disc offsets for various structures and their sizes */
@@ -163,6 +165,10 @@ struct udf_create_context {
 	int	data_part;
 	int	metadata_part;
 
+	/* block numbers as offset in partition */
+	uint32_t metadata_alloc_pos;
+	uint32_t data_alloc_pos;
+
 	/* derived; points *into* other structures */
 	struct udf_logvol_info	*logvol_info;		/* inside integrity  */
 
@@ -177,6 +183,12 @@ struct udf_create_context {
 	/* sparable */
 	struct udf_sparing_table*sparing_table;		/* replacements      */
 
+	/* VAT file */
+	uint32_t		 vat_size;		/* length */
+	uint32_t		 vat_allocated;		/* allocated length */
+	uint32_t		 vat_start;		/* offset 1st entry */
+	uint8_t			*vat_contents;		/* the VAT */
+
 	/* meta data partition */
 	struct extfile_entry	*meta_file;
 	struct extfile_entry	*meta_mirror;
@@ -221,7 +233,6 @@ int  udf_validate_tag_and_crc_sums(union
 
 void udf_set_timestamp_now(struct timestamp *timestamp);
 
-
 void udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc);
 int udf_create_anchor(int num);
 
@@ -242,13 +253,25 @@ int udf_register_bad_block(uint32_t loca
 void udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks);
 
 int udf_create_new_fe(struct file_entry **fep, int file_type,
-	struct long_ad *parent_icb);
+	struct stat *st);
 int udf_create_new_efe(struct extfile_entry **efep, int file_type,
-	struct long_ad *parent_icb);
+	struct stat *st);
+
+int udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target);
+
+void udf_advance_uniqueid(void);
+int udf_fidsize(struct fileid_desc *fid);
+void udf_create_fid(uint32_t diroff, struct fileid_desc *fid,
+	char *name, int namelen, struct long_ad *ref);
+int udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent);
 
 int udf_create_meta_files(void);
 int udf_create_new_rootdir(union dscrptr **dscr);
-int udf_create_new_VAT(union dscrptr **vat_dscr);
+
+int udf_create_VAT(union dscrptr **vat_dscr);
+void udf_prepend_VAT_file(void);
+void udf_vat_update(uint32_t virt, uint32_t phys);
+int udf_append_VAT_file(void);
 
 #endif /* _FS_UDF_UDF_CREATE_H_ */
 

Index: src/sbin/newfs_udf/udf_write.c
diff -u src/sbin/newfs_udf/udf_write.c:1.2 src/sbin/newfs_udf/udf_write.c:1.3
--- src/sbin/newfs_udf/udf_write.c:1.2	Thu Jul 18 12:50:51 2013
+++ src/sbin/newfs_udf/udf_write.c	Mon Aug  5 14:11:30 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_write.c,v 1.2 2013/07/18 12:50:51 reinoud Exp $ */
+/* $NetBSD: udf_write.c,v 1.3 2013/08/05 14:11:30 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: udf_write.c,v 1.2 2013/07/18 12:50:51 reinoud Exp $");
+__RCSID("$NetBSD: udf_write.c,v 1.3 2013/08/05 14:11:30 reinoud Exp $");
 #endif /* not lint */
 
 #define _EXPOSE_MMC
@@ -53,18 +53,14 @@ union dscrptr *terminator_dscr;
 
 
 static int
-udf_write_dscr_phys(union dscrptr *dscr, uint32_t location,
-	uint32_t sects)
+udf_write_phys(void *blob, uint32_t location, uint32_t sects)
 {
 	uint32_t phys, cnt;
 	uint8_t *bpos;
 	int error;
 
-	dscr->tag.tag_loc = udf_rw32(location);
-	(void) udf_validate_tag_and_crc_sums(dscr);
-
 	for (cnt = 0; cnt < sects; cnt++) {
-		bpos  = (uint8_t *) dscr;
+		bpos  = (uint8_t *) blob;
 		bpos += context.sector_size * cnt;
 
 		phys = location + cnt;
@@ -77,15 +73,24 @@ udf_write_dscr_phys(union dscrptr *dscr,
 
 
 static int
+udf_write_dscr_phys(union dscrptr *dscr, uint32_t location,
+	uint32_t sects)
+{
+	dscr->tag.tag_loc = udf_rw32(location);
+	(void) udf_validate_tag_and_crc_sums(dscr);
+
+	return udf_write_phys(dscr, location, sects);
+}
+
+
+int
 udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint32_t vpart,
 	uint32_t sects)
 {
 	struct file_entry *fe;
 	struct extfile_entry *efe;
 	struct extattrhdr_desc *extattrhdr;
-	uint32_t phys, cnt;
-	uint8_t *bpos;
-	int error;
+	uint32_t phys;
 
 	extattrhdr = NULL;
 	if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) {
@@ -106,20 +111,52 @@ udf_write_dscr_virt(union dscrptr *dscr,
 	dscr->tag.tag_loc = udf_rw32(location);
 	udf_validate_tag_and_crc_sums(dscr);
 
-	for (cnt = 0; cnt < sects; cnt++) {
-		bpos  = (uint8_t *) dscr;
-		bpos += context.sector_size * cnt;
+	/* determine physical location */
+	phys = context.vtop_offset[vpart];
+	if (context.vtop_tp[vpart] == UDF_VTOP_TYPE_VIRT) {
+		udf_vat_update(location, context.data_alloc_pos);
+		phys += context.data_alloc_pos++;
+	} else {
+		phys += location;
+	}
 
-		/* NOTE linear mapping assumed in the ranges used */
-		phys = context.vtop_offset[vpart] + location + cnt;
+	return udf_write_phys(dscr, phys, sects);
+}
 
-		error = udf_write_sector(bpos, phys);
-		if (error)
-			return error;
-	}
-	return 0;
+
+void
+udf_metadata_alloc(int nblk, struct long_ad *pos)
+{
+	memset(pos, 0, sizeof(struct long_ad));
+	pos->len	  = udf_rw32(nblk * context.sector_size);
+	pos->loc.lb_num   = udf_rw32(context.metadata_alloc_pos);
+	pos->loc.part_num = udf_rw16(context.metadata_part);
+
+	udf_mark_allocated(context.metadata_alloc_pos, context.metadata_part,
+		nblk);
+
+	context.metadata_alloc_pos += nblk;
+	if (context.metadata_part == context.data_part)
+		context.data_alloc_pos = context.metadata_alloc_pos;
 }
 
+
+void
+udf_data_alloc(int nblk, struct long_ad *pos)
+{
+	memset(pos, 0, sizeof(struct long_ad));
+	pos->len	  = udf_rw32(nblk * context.sector_size);
+	pos->loc.lb_num   = udf_rw32(context.data_alloc_pos);
+	pos->loc.part_num = udf_rw16(context.data_part);
+
+	udf_mark_allocated(context.data_alloc_pos, context.data_part, nblk);
+	context.data_alloc_pos += nblk;
+	if (context.metadata_part == context.data_part)
+		context.metadata_alloc_pos = context.data_alloc_pos;
+}
+
+
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -198,14 +235,13 @@ udf_derive_format(int req_enable, int re
 		format_flags &= ~(FORMAT_META | FORMAT_LOW);
 		req_disable  &= ~FORMAT_META;
 	}
-	if (req_disable || req_enable) {
-		(void)printf("Internal error\n");
-		(void)printf("\tunrecognised enable/disable req.\n");
-		return EIO;
-	}
 	if ((format_flags & FORMAT_VAT) & UDF_512_TRACK)
 		format_flags |= FORMAT_TRACK512;
 
+	if (req_enable & FORMAT_READONLY) {
+		format_flags |= FORMAT_READONLY;
+	}
+
 	/* determine partition/media access type */
 	media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED;
 	if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) {
@@ -219,6 +255,12 @@ udf_derive_format(int req_enable, int re
 	if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE)
 		media_accesstype = UDF_ACCESSTYPE_PSEUDO_OVERWITE;
 
+	/* patch up media accesstype */
+	if (req_enable & FORMAT_READONLY) {
+		/* better now */
+		media_accesstype = UDF_ACCESSTYPE_READ_ONLY;
+	}
+
 	/* adjust minimum version limits */
 	if (format_flags & FORMAT_VAT)
 		context.min_udf = MAX(context.min_udf, 0x0150);
@@ -432,6 +474,7 @@ udf_do_newfs_prefix(void)
 			blockingnr = 32;	/* UDF requirement */
 			break;
 		case 0x11 : /* DVD-R (DL) */
+		case 0x12 : /* DVD-RAM */
 		case 0x1b : /* DVD+R      */
 		case 0x2b : /* DVD+R Dual layer */
 		case 0x13 : /* DVD-RW restricted overwrite */
@@ -439,7 +482,10 @@ udf_do_newfs_prefix(void)
 			blockingnr = 16;	/* SCSI definition */
 			break;
 		case 0x41 : /* BD-R Sequential recording (SRM) */
+		case 0x42 : /* BD-R Random recording (RRM) */
+		case 0x43 : /* BD-RE */
 		case 0x51 : /* HD DVD-R   */
+		case 0x52 : /* HD DVD-RW  */
 			blockingnr = 32;	/* SCSI definition */
 			break;
 		default:
@@ -637,7 +683,7 @@ udf_do_newfs_prefix(void)
 	 * media report their own free/used space; no free/used space tables
 	 * should be recorded for these.
 	 */
-	if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
+	if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
 		error = udf_create_space_bitmap(
 				layout.alloc_bitmap_dscr_size,
 				layout.part_size_lba,
@@ -697,6 +743,15 @@ udf_do_newfs_prefix(void)
 	if (error)
 		return error;
 
+	/* create VAT if needed */
+	if (format_flags & FORMAT_VAT) {
+		context.vat_allocated = context.sector_size;
+		context.vat_contents  = malloc(context.vat_allocated);
+		assert(context.vat_contents);
+
+		udf_prepend_VAT_file();
+	}
+
 	/* create FSD and writeout */
 	if ((error = udf_create_fsd()))
 		return error;
@@ -722,9 +777,9 @@ udf_do_rootdir(void) {
 		return error;
 	udf_mark_allocated(layout.rootdir, context.metadata_part, 1);
 
-	error = udf_write_dscr_virt(root_dscr, layout.rootdir, context.metadata_part, 1);
+	error = udf_write_dscr_virt(root_dscr,
+		layout.rootdir, context.metadata_part, 1);
 
-	/* XXX the place to add more files */
 	return error;
 }
 
@@ -734,7 +789,8 @@ udf_do_newfs_postfix(void)
 {
 	union dscrptr *vat_dscr;
 	union dscrptr *dscr;
-	uint32_t loc, len;
+	struct long_ad vatdata_pos;
+	uint32_t loc, len, phys, sects;
 	int data_part, metadata_part;
 	int error;
 
@@ -761,7 +817,7 @@ udf_do_newfs_postfix(void)
 	}
 
 	/* write out unallocated space bitmap on non sequential media */
-	if ((format_flags & FORMAT_SEQUENTIAL) == 0) {
+	if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) {
 		/* writeout unallocated space bitmap */
 		loc  = layout.unalloc_space;
 		dscr = (union dscrptr *) (context.part_unalloc_bits[data_part]);
@@ -792,7 +848,8 @@ udf_do_newfs_postfix(void)
 
 		/* writeout unallocated space bitmap */
 		loc  = layout.meta_bitmap_space;
-		dscr = (union dscrptr *) (context.part_unalloc_bits[metadata_part]);
+		dscr = (union dscrptr *)
+			(context.part_unalloc_bits[metadata_part]);
 		len  = layout.meta_bitmap_dscr_size;
 		error = udf_write_dscr_virt(dscr, loc, data_part, len);
 		if (error)
@@ -805,11 +862,31 @@ udf_do_newfs_postfix(void)
 		/* update lvint to reflect the newest values (no writeout) */
 		udf_update_lvintd(UDF_INTEGRITY_CLOSED);
 
-		error = udf_create_new_VAT(&vat_dscr);
+		error = udf_append_VAT_file();
+		if (error)
+			return error;
+
+		/* write out VAT data */
+		sects = UDF_ROUNDUP(context.vat_size, context.sector_size) /
+			context.sector_size;
+		layout.vat = context.data_alloc_pos;
+		udf_data_alloc(sects, &vatdata_pos);
+
+		loc = udf_rw32(vatdata_pos.loc.lb_num);
+		phys = context.vtop_offset[context.data_part] + loc;
+
+		error = udf_write_phys(context.vat_contents, phys, sects);
 		if (error)
 			return error;
+		loc += sects;
+
+		/* create new VAT descriptor */
+		error = udf_create_VAT(&vat_dscr);
+		if (error)
+			return error;
+		context.data_alloc_pos++;
+		loc++;
 
-		loc = layout.vat;
 		error = udf_write_dscr_virt(vat_dscr, loc, metadata_part, 1);
 		if (error)
 			return error;

Index: src/sbin/newfs_udf/udf_write.h
diff -u src/sbin/newfs_udf/udf_write.h:1.1 src/sbin/newfs_udf/udf_write.h:1.2
--- src/sbin/newfs_udf/udf_write.h:1.1	Thu Jul 18 12:44:21 2013
+++ src/sbin/newfs_udf/udf_write.h	Mon Aug  5 14:11:30 2013
@@ -32,6 +32,11 @@
 
 /* prototypes */
 
+int udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint32_t vpart,
+	uint32_t sects);
+void udf_metadata_alloc(int nblk, struct long_ad *pos);
+void udf_data_alloc(int nblk, struct long_ad *pos);
+
 int udf_derive_format(int req_enable, int req_disable, int force);
 int udf_proces_names(void);
 

Added files:

Index: src/sbin/newfs_udf/unicode.h
diff -u /dev/null src/sbin/newfs_udf/unicode.h:1.1
--- /dev/null	Mon Aug  5 14:11:30 2013
+++ src/sbin/newfs_udf/unicode.h	Mon Aug  5 14:11:30 2013
@@ -0,0 +1,161 @@
+/* $NetBSD: unicode.h,v 1.1 2013/08/05 14:11:30 reinoud Exp $ */
+
+/*-
+ * Copyright (c) 2001, 2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Routines for handling Unicode encoded in UTF-8 form, code derived from
+ * src/lib/libc/locale/utf2.c.
+ */
+static u_int16_t wget_utf8(const char **, size_t *) __unused;
+static int wput_utf8(char *, size_t, u_int16_t) __unused;
+
+/*
+ * Read one UTF8-encoded character off the string, shift the string pointer
+ * and return the character.
+ */
+static u_int16_t
+wget_utf8(const char **str, size_t *sz)
+{
+	unsigned int c;
+	u_int16_t rune = 0;
+	const char *s = *str;
+	static const int _utf_count[16] = {
+		1, 1, 1, 1, 1, 1, 1, 1,
+		0, 0, 0, 0, 2, 2, 3, 0,
+	};
+
+	/* must be called with at least one byte remaining */
+	assert(*sz > 0);
+
+	c = _utf_count[(s[0] & 0xf0) >> 4];
+	if (c == 0 || c > *sz) {
+    decoding_error:
+		/*
+		 * The first character is in range 128-255 and doesn't
+		 * mark valid a valid UTF-8 sequence. There is not much
+		 * we can do with this, so handle by returning
+		 * the first character as if it would be a correctly
+		 * encoded ISO-8859-1 character.
+		 */
+		c = 1;
+	}
+
+	switch (c) {
+	case 1:
+		rune = s[0] & 0xff;
+		break;
+	case 2:
+		if ((s[1] & 0xc0) != 0x80)
+			goto decoding_error;
+		rune = ((s[0] & 0x1F) << 6) | (s[1] & 0x3F);
+		break;
+	case 3:
+		if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80)
+			goto decoding_error;
+		rune = ((s[0] & 0x0F) << 12) | ((s[1] & 0x3F) << 6)
+		    | (s[2] & 0x3F);
+		break;
+	}
+
+	*str += c;
+	*sz -= c;
+	return rune;
+}
+
+/*
+ * Encode wide character and write it to the string. 'n' specifies
+ * how much buffer space remains in 's'. Returns number of bytes written
+ * to the target string 's'.
+ */
+static int
+wput_utf8(char *s, size_t n, u_int16_t wc)
+{
+	if (wc & 0xf800) {
+		if (n < 3) {
+			/* bound check failure */
+			return 0;
+		}
+
+		s[0] = 0xE0 | (wc >> 12);
+		s[1] = 0x80 | ((wc >> 6) & 0x3F);
+		s[2] = 0x80 | ((wc) & 0x3F);
+		return 3;
+	} else if (wc & 0x0780) {
+		if (n < 2) {
+			/* bound check failure */
+			return 0;
+		}
+
+		s[0] = 0xC0 | (wc >> 6);
+		s[1] = 0x80 | ((wc) & 0x3F);
+		return 2;
+	} else {
+		if (n < 1) {
+			/* bound check failure */
+			return 0;
+		}
+
+		s[0] = wc;
+		return 1;
+	}
+}

Reply via email to