Skip to content

Instantly share code, notes, and snippets.

@waitman
Last active May 31, 2022 20:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waitman/07849a747d0d633a7009 to your computer and use it in GitHub Desktop.
Save waitman/07849a747d0d633a7009 to your computer and use it in GitHub Desktop.
UDF2 diff against FreeBSD-11.0-Current source r285141
--- sbin/Makefile 2015-07-04 07:26:20.000000000 -0700
+++ updates/src/sbin/Makefile 2015-07-04 10:47:16.664406000 -0700
@@ -49,6 +49,7 @@
mount_nfs \
mount_nullfs \
mount_udf \
+ mount_udf2 \
mount_unionfs \
newfs \
newfs_msdos \
--- sbin/mount/mount.c 2015-07-04 07:26:15.000000000 -0700
+++ updates/sbin/mount/mount.c 2015-07-04 08:41:35.000000000 -0700
@@ -144,7 +144,7 @@
unsigned int i;
const char *fs[] = {
"cd9660", "mfs", "msdosfs", "nfs",
- "nullfs", "smbfs", "udf", "unionfs",
+ "nullfs", "smbfs", "udf", "udf2", "unionfs",
NULL
};
--- sbin/mount_udf2/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ updates/sbin/mount_udf2/Makefile 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,23 @@
+# $FreeBSD: src/sbin/mount_udf/Makefile,v 1.6 2006/07/17 20:53:25 stefanf Exp $
+
+PROG= mount_udf2
+SRCS= mount_udf.c getmntopts.c
+MAN= mount_udf2.8
+DPADD= ${LIBKICONV}
+LDADD= -lkiconv
+
+#MOUNT= ${.CURDIR}/../mount
+#CFLAGS+= -I${MOUNT} -I${.CURDIR}/../../sys
+#.PATH: ${MOUNT}
+WARNS?= 1
+
+# Needs to be dynamically linked for optional dlopen() access to
+# userland libiconv
+NO_SHARED?= NO
+
+BINDIR=/sbin
+
+CFLAGS+=-g
+CXXFLAGS+=-g
+
+.include <bsd.prog.mk>
--- sbin/mount_udf2/getmntopts.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sbin/mount_udf2/getmntopts.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)getmntopts.c 8.3 (Berkeley) 3/29/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sbin/mount/getmntopts.c,v 1.19 2008/12/26 22:55:38 obrien Exp $");
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "mntopts.h"
+
+int getmnt_silent = 0;
+
+void
+getmntopts(const char *options, const struct mntopt *m0, int *flagp,
+ int *altflagp)
+{
+ const struct mntopt *m;
+ int negative, len;
+ char *opt, *optbuf, *p;
+ int *thisflagp;
+
+ /* Copy option string, since it is about to be torn asunder... */
+ if ((optbuf = strdup(options)) == NULL)
+ err(1, NULL);
+
+ for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
+ /* Check for "no" prefix. */
+ if (opt[0] == 'n' && opt[1] == 'o') {
+ negative = 1;
+ opt += 2;
+ } else
+ negative = 0;
+
+ /*
+ * for options with assignments in them (ie. quotas)
+ * ignore the assignment as it's handled elsewhere
+ */
+ p = strchr(opt, '=');
+ if (p != NULL)
+ *++p = '\0';
+
+ /* Scan option table. */
+ for (m = m0; m->m_option != NULL; ++m) {
+ len = strlen(m->m_option);
+ if (strncasecmp(opt, m->m_option, len) == 0)
+ if (opt[len] == '\0' || opt[len] == '=')
+ break;
+ }
+
+ /* Save flag, or fail if option is not recognized. */
+ if (m->m_option) {
+ thisflagp = m->m_altloc ? altflagp : flagp;
+ if (negative == m->m_inverse)
+ *thisflagp |= m->m_flag;
+ else
+ *thisflagp &= ~m->m_flag;
+ } else if (!getmnt_silent) {
+ errx(1, "-o %s: option not supported", opt);
+ }
+ }
+
+ free(optbuf);
+}
+
+void
+rmslashes(char *rrpin, char *rrpout)
+{
+ char *rrpoutstart;
+
+ *rrpout = *rrpin;
+ for (rrpoutstart = rrpout; *rrpin != '\0'; *rrpout++ = *rrpin++) {
+
+ /* skip all double slashes */
+ while (*rrpin == '/' && *(rrpin + 1) == '/')
+ rrpin++;
+ }
+
+ /* remove trailing slash if necessary */
+ if (rrpout - rrpoutstart > 1 && *(rrpout - 1) == '/')
+ *(rrpout - 1) = '\0';
+ else
+ *rrpout = '\0';
+}
+
+void
+checkpath(const char *path, char *resolved)
+{
+ struct stat sb;
+
+ if (realpath(path, resolved) != NULL && stat(resolved, &sb) == 0) {
+ if (!S_ISDIR(sb.st_mode))
+ errx(EX_USAGE, "%s: not a directory", resolved);
+ } else
+ errx(EX_USAGE, "%s: %s", resolved, strerror(errno));
+}
+
+void
+build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
+ size_t len)
+{
+ int i;
+
+ if (*iovlen < 0)
+ return;
+ i = *iovlen;
+ *iov = realloc(*iov, sizeof **iov * (i + 2));
+ if (*iov == NULL) {
+ *iovlen = -1;
+ return;
+ }
+ (*iov)[i].iov_base = strdup(name);
+ (*iov)[i].iov_len = strlen(name) + 1;
+ i++;
+ (*iov)[i].iov_base = val;
+ if (len == (size_t)-1) {
+ if (val != NULL)
+ len = strlen(val) + 1;
+ else
+ len = 0;
+ }
+ (*iov)[i].iov_len = (int)len;
+ *iovlen = ++i;
+}
+
+/*
+ * This function is needed for compatibility with parameters
+ * which used to use the mount_argf() command for the old mount() syscall.
+ */
+void
+build_iovec_argf(struct iovec **iov, int *iovlen, const char *name,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char val[255] = { 0 };
+
+ va_start(ap, fmt);
+ vsnprintf(val, sizeof(val), fmt, ap);
+ va_end(ap);
+ build_iovec(iov, iovlen, name, strdup(val), (size_t)-1);
+}
--- sbin/mount_udf2/mntopts.h 1969-12-31 16:00:00.000000000 -0800
+++ updates/sbin/mount_udf2/mntopts.h 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. 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.
+ * 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.
+ *
+ * @(#)mntopts.h 8.7 (Berkeley) 3/29/95
+ * $FreeBSD: src/sbin/mount/mntopts.h,v 1.30 2009/12/21 19:39:10 trasz Exp $
+ */
+
+struct mntopt {
+ const char *m_option; /* option name */
+ int m_inverse; /* if a negative option, e.g. "atime" */
+ int m_flag; /* bit to set, e.g. MNT_RDONLY */
+ int m_altloc; /* 1 => set bit in altflags */
+};
+
+/* User-visible MNT_ flags. */
+#define MOPT_ASYNC { "async", 0, MNT_ASYNC, 0 }
+#define MOPT_NOATIME { "atime", 1, MNT_NOATIME, 0 }
+#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC, 0 }
+#define MOPT_NOSUID { "suid", 1, MNT_NOSUID, 0 }
+#define MOPT_NOSYMFOLLOW { "symfollow", 1, MNT_NOSYMFOLLOW, 0 }
+#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 }
+#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 }
+#define MOPT_UNION { "union", 0, MNT_UNION, 0 }
+#define MOPT_USERQUOTA { "userquota", 0, 0, 0 }
+#define MOPT_GROUPQUOTA { "groupquota", 0, 0, 0 }
+#define MOPT_NOCLUSTERR { "clusterr", 1, MNT_NOCLUSTERR, 0 }
+#define MOPT_NOCLUSTERW { "clusterw", 1, MNT_NOCLUSTERW, 0 }
+#define MOPT_SUIDDIR { "suiddir", 0, MNT_SUIDDIR, 0 }
+#define MOPT_SNAPSHOT { "snapshot", 0, MNT_SNAPSHOT, 0 }
+#define MOPT_MULTILABEL { "multilabel", 0, MNT_MULTILABEL, 0 }
+#define MOPT_ACLS { "acls", 0, MNT_ACLS, 0 }
+#define MOPT_NFS4ACLS { "nfsv4acls", 0, MNT_NFS4ACLS, 0 }
+
+/* Control flags. */
+#define MOPT_FORCE { "force", 0, MNT_FORCE, 0 }
+#define MOPT_UPDATE { "update", 0, MNT_UPDATE, 0 }
+#define MOPT_RO { "ro", 0, MNT_RDONLY, 0 }
+#define MOPT_RW { "rw", 1, MNT_RDONLY, 0 }
+
+/* This is parsed by mount(8), but is ignored by specific mount_*(8)s. */
+#define MOPT_AUTO { "auto", 0, 0, 0 }
+
+/* A handy macro as terminator of MNT_ array. */
+#define MOPT_END { NULL, 0, 0, 0 }
+
+#define MOPT_FSTAB_COMPAT \
+ MOPT_RO, \
+ MOPT_RW, \
+ MOPT_AUTO
+
+/* Standard options which all mounts can understand. */
+#define MOPT_STDOPTS \
+ MOPT_USERQUOTA, \
+ MOPT_GROUPQUOTA, \
+ MOPT_FSTAB_COMPAT, \
+ MOPT_NOATIME, \
+ MOPT_NOEXEC, \
+ MOPT_SUIDDIR, /* must be before MOPT_NOSUID */ \
+ MOPT_NOSUID, \
+ MOPT_NOSYMFOLLOW, \
+ MOPT_RDONLY, \
+ MOPT_UNION, \
+ MOPT_NOCLUSTERR, \
+ MOPT_NOCLUSTERW, \
+ MOPT_MULTILABEL, \
+ MOPT_ACLS, \
+ MOPT_NFS4ACLS
+
+void getmntopts(const char *, const struct mntopt *, int *, int *);
+void rmslashes(char *, char *);
+void checkpath(const char *, char resolved_path[]);
+extern int getmnt_silent;
+void build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val, size_t len);
+void build_iovec_argf(struct iovec **iov, int *iovlen, const char *name, const char *fmt, ...);
--- sbin/mount_udf2/mount_udf.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sbin/mount_udf2/mount_udf.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,388 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Scott Long
+ * Copyright (c) 2012 Will DeVries
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * 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.
+ * 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.
+ *
+ * $FreeBSD: src/sbin/mount_udf/mount_udf.c,v 1.13 2005/06/10 09:51:43 delphij Exp $
+ */
+
+/*
+ * This is just a rip-off of mount_iso9660.c. It's been vastly simplified
+ * because UDF doesn't take any options at this time.
+ */
+
+#include <sys/cdio.h>
+#include <sys/file.h>
+#include <sys/iconv.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/endian.h>
+#include <sys/ioctl.h>
+#include <sys/udfio.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "mntopts.h"
+
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ MOPT_UPDATE,
+ MOPT_END
+};
+
+static void get_session_info(char *dev, struct udf_session_info *usi,
+ int session_num);
+static void print_session_info(char *dev, int session_num);
+static int set_charset(char *, const char *);
+static void usage(void);
+static int get_uid(char *u, uid_t *uid);
+static int get_gid(char *g, gid_t *gid);
+static int get_mode(char *m, mode_t *mode);
+
+int
+main(int argc, char **argv)
+{
+ struct udf_session_info usi;
+ struct iovec *iov;
+ struct passwd *nobody;
+ long session_num;
+ gid_t anon_gid, override_gid;
+ int iovlen, ch, mntflags, opts, sessioninfo;
+ uid_t anon_uid, override_uid;
+ mode_t mode, dirmode;
+ char cs_local[ICONV_CSNMAXLEN];
+ char *dev, *dir, *endp, mntpath[MAXPATHLEN];
+ uint8_t use_nobody_gid, use_nobody_uid;
+ uint8_t use_override_gid, use_override_uid;
+ uint8_t use_mode, use_dirmode;
+
+ cs_local[0] = '\0';
+ session_num = 0;
+ sessioninfo = 0;
+ use_nobody_uid = use_nobody_gid = 1;
+ use_override_uid = use_override_gid = 0;
+ use_mode = use_dirmode = 0;
+ iov = NULL;
+ iovlen = 0;
+ mntflags = opts = 0;
+
+ while ((ch = getopt(argc, argv, "C:G:g:M:m:o:ps:U:u:")) != -1)
+ switch (ch) {
+ case 'C':
+ set_charset(cs_local, optarg);
+ break;
+ case 'G':
+ if (get_gid(optarg, &anon_gid) == -1)
+ errx(EX_USAGE, "invalid gid in option G: %s",
+ optarg);
+ use_nobody_gid = 0;
+ break;
+ case 'g':
+ if (get_gid(optarg, &override_gid) == -1)
+ errx(EX_USAGE, "invalid gid in option g: %s",
+ optarg);
+ use_override_gid = 1;
+ break;
+ case 'M':
+ if (get_mode(optarg, &dirmode) == -1)
+ errx(EX_USAGE, "invalid mode in option M: %s",
+ optarg);
+ use_dirmode = 1;
+ break;
+ case 'm':
+ if (get_mode(optarg, &mode) == -1)
+ errx(EX_USAGE, "invalid mode in option m: %s",
+ optarg);
+ use_mode = 1;
+ break;
+ case 'o':
+ getmntopts(optarg, mopts, &mntflags, &opts);
+ break;
+ case 'p':
+ sessioninfo = 1;
+ break;
+ case 's':
+ session_num = strtol(optarg, &endp, 10);
+ if (optarg == endp || *endp != '\0')
+ errx(EX_USAGE, "invalid number in option s: %s",
+ optarg);
+ break;
+ case 'U':
+ if (get_uid(optarg, &anon_uid) == -1)
+ errx(EX_USAGE, "invalid uid in option U: %s",
+ optarg);
+ use_nobody_uid = 0;
+ break;
+ case 'u':
+ if (get_uid(optarg, &override_uid) == -1)
+ errx(EX_USAGE, "invalid uid in option u: %s",
+ optarg);
+ use_override_uid = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (sessioninfo == 1) {
+ if (argc != 1)
+ usage();
+ print_session_info(argv[0], session_num);
+ }
+
+ if (argc != 2)
+ usage();
+
+ dev = argv[0];
+ dir = argv[1];
+
+ /*
+ * Resolve the mountpoint with realpath(3) and remove unnecessary
+ * slashes from the devicename if there are any.
+ */
+ (void)checkpath(dir, mntpath);
+ (void)rmslashes(dev, dev);
+
+ /*
+ * Get session info from device
+ */
+ get_session_info(dev, &usi, session_num);
+
+
+ /*
+ * Use nobody for uid and gid if not given above.
+ */
+ if (use_nobody_gid == 1 && use_override_gid == 0) {
+ if (get_gid("nobody", &anon_gid) == -1)
+ errx(EX_USAGE, "There is no group 'nobody'; use the G "
+ "option to specify a default gid.");
+ } else if (use_override_gid == 1)
+ anon_gid = override_gid;
+
+ if (use_nobody_uid == 1 && use_override_uid == 0) {
+ if (get_uid("nobody", &anon_uid) == -1)
+ errx(EX_USAGE, "There is no user 'nobody'; use the U "
+ "option to specify a default uid.");
+ } else if (use_override_uid == 1)
+ anon_uid = override_uid;
+
+ /* UDF file systems are not writeable. */
+ mntflags |= MNT_RDONLY;
+
+ build_iovec(&iov, &iovlen, "fstype", "udf2", (size_t) - 1);
+ build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t) - 1);
+ build_iovec(&iov, &iovlen, "from", dev, (size_t) - 1);
+ build_iovec(&iov, &iovlen, "uid", &anon_uid, sizeof(anon_uid));
+ if (use_override_uid == 1)
+ build_iovec(&iov, &iovlen, "override_uid", NULL, 0);
+ build_iovec(&iov, &iovlen, "gid", &anon_gid, sizeof(anon_gid));
+ if (use_override_gid == 1)
+ build_iovec(&iov, &iovlen, "override_gid", NULL, 0);
+ if (use_mode)
+ build_iovec(&iov, &iovlen, "mode", &mode, sizeof(mode_t));
+ if (use_dirmode)
+ build_iovec(&iov, &iovlen, "dirmode", &dirmode, sizeof(mode_t));
+
+ build_iovec(&iov, &iovlen, "first_trackblank",
+ &usi.session_first_track_blank, sizeof(uint8_t));
+ build_iovec(&iov, &iovlen, "session_start_addr",
+ &usi.session_start_addr, sizeof(uint32_t));
+ build_iovec(&iov, &iovlen, "session_end_addr", &usi.session_end_addr,
+ sizeof(uint32_t));
+ build_iovec(&iov, &iovlen, "session_last_written",
+ &usi.session_last_written, sizeof(uint32_t));
+
+ if (cs_local[0] != '\0') {
+ build_iovec(&iov, &iovlen, "cs_local", cs_local, (size_t) - 1);
+ }
+
+ if (nmount(iov, iovlen, mntflags) < 0)
+ err(1, "%s", dev);
+
+ free(iov);
+ exit(0);
+}
+
+static int
+get_uid(char *u, uid_t *uid)
+{
+ struct passwd *usr;
+ char *endp;
+
+ usr = getpwnam(u);
+ if (usr != NULL)
+ *uid = usr->pw_gid;
+ else {
+ *uid = strtoul(u, &endp, 10);
+
+ if (u == endp || *endp != '\0')
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+get_gid(char *g, gid_t *gid)
+{
+ struct group *grp;
+ char *endp;
+
+ grp = getgrnam(g);
+ if (grp != NULL)
+ *gid = grp->gr_gid;
+ else {
+ *gid = strtoul(g, &endp, 10);
+
+ if (g == endp || *endp != '\0')
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+get_mode(char *m, mode_t *mode)
+{
+ char *endp;
+
+ *mode = strtoul(m, &endp, 8);
+ if (m == endp || *endp != '\0')
+ return (-1);
+ return (0);
+}
+
+static int
+set_charset(char *cs_local, const char *localcs)
+{
+ int error;
+
+ if (modfind("udf2_iconv") < 0)
+ if (kldload("udf2_iconv") < 0 || modfind("udf2_iconv") < 0) {
+ errx(EX_OSERR, "cannot find or load \"udf2_iconv\" "
+ "kernel module");
+ }
+
+ strncpy(cs_local, localcs, ICONV_CSNMAXLEN);
+ error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local);
+ if (error != 0)
+ err(EX_OSERR, "udf2_iconv");
+
+ return (0);
+}
+
+static void
+get_session_info(char *dev, struct udf_session_info *usi, int session_num)
+{
+ int fd, error;
+ unsigned int out;
+
+ fd = open(dev, O_RDONLY, 0);
+ if (fd < 0)
+ err(1, "open");
+
+ bzero(usi, sizeof(struct udf_session_info));
+ usi->session_num = session_num;
+ error = ioctl(fd, UDFIOREADSESSIONINFO, usi);
+ if (error != 0) {
+ if (session_num != 0)
+ errx(EX_USAGE, "Cannot mount selected session. This "
+ "device does not properly support multi-sessions "
+ "disc.");
+
+ /* Other fatal errors besides EIO and ENXIO may exist, but
+ trying to mount an invalid device shouldn't result in anything
+ to bad. */
+ if (errno == EIO)
+ errx(EX_IOERR, "Device not ready.");
+ else if (errno == ENXIO)
+ errx(EX_IOERR, "No media present.");
+ else
+ warnx("Warning, this device does not properly support "
+ "multi-sessions disc.");
+
+ /* We populate the end address inside the kernel. */
+ usi->session_start_addr = 0;
+ usi->session_end_addr = 0;
+ }
+
+ close(fd);
+}
+
+static void
+print_session_info(char *dev, int session_num)
+{
+ struct udf_session_info usi;
+
+ rmslashes(dev, dev);
+ get_session_info(dev, &usi, session_num);
+
+ printf("Number of Sessions: %u\n", usi.num_sessions);
+ printf("Number of Tracks: %u\n", usi.num_tracks);
+ printf("First Track Number: %u\n", usi.first_track);
+ printf("Sector Size: %u\n", usi.sector_size);
+
+ printf("Session Number: %u\n", usi.session_num);
+ printf("Session Start Address: %u\n", usi.session_start_addr);
+ printf("Session End Address: %u\n", usi.session_end_addr);
+ printf("Last Written Address in Session: %u\n", usi.session_last_written);
+ printf("First Track Number of Session: %u\n", usi.session_first_track);
+ printf("Last Track of Session: %u\n", usi.session_last_track);
+
+ exit(0);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: mount_udf [-v] [-C charset] [-G gid] "
+ "[-o options] [-s session] [-U uid] special node\n");
+ (void)fprintf(stderr, "usage: mount_udf [-p] [-s session] special\n");
+ exit(EX_USAGE);
+}
--- sbin/mount_udf2/mount_udf2.8 1969-12-31 16:00:00.000000000 -0800
+++ updates/sbin/mount_udf2/mount_udf2.8 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,128 @@
+.\" Copyright (c) 2002
+.\" Scott Long <scottl@FreeBSD.org>
+.\" Jeroen Ruigrok van der Werven <asmodai@wxs.nl>
+.\" 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 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.
+.\"
+.\" $FreeBSD: src/sbin/mount_udf/mount_udf.8,v 1.6 2005/02/10 09:19:31 ru Exp $
+.\"
+.Dd January 13, 2013
+.Dt MOUNT_UDF2 8
+.Os
+.Sh NAME
+.Nm mount_udf2
+.Nd mount a UDF file system
+.Sh SYNOPSIS
+.Nm
+.Op Fl o Ar options
+.Op Fl C Ar charset
+.Op Fl G Ar gid
+.Op Fl g Ar gid
+.Op Fl M Ar permissions
+.Op Fl m Ar permissions
+.Op Fl s Ar session
+.Op Fl U Ar uid
+.Op Fl u Ar uid
+.Ar special node
+.Nm
+.Op Fl p
+.Op Fl s Ar session
+.Ar special
+.Sh DESCRIPTION
+The
+.Nm
+utility attaches the UDF file system residing on the device
+.Pa special
+to the global file system namespace at the location indicated by
+.Ar node .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl C Ar charset
+Specify local
+.Ar charset
+to convert Unicode file names. By default UTF-8 is used.
+.It Fl G Ar gid
+Set the group used for files and directories without defined groups to
+.Ar gid .
+By default this is set to the 'nobody' group. (UDF allows for files
+and directories without groups.)
+.It Fl g Ar gid
+Set the group for all files and directories in the file system to
+.Ar gid .
+If this option is specified, the
+.Fl G
+option has no effect.
+.It Fl M Ar permissions
+Set the mode used for all directories in the file system to
+.Ar permissions .
+This value should be specified as an octal number according to the rules in
+chmod(1).
+.It Fl m Ar permissions
+Set the mode used for all files in the file system to
+.Ar permissions .
+This value should be specified as an octal number according to the rules in
+chmod(1).
+.It Fl o
+Options are specified with a
+.Fl o
+flag followed by a comma separated string of options.
+See the
+.Xr mount 8
+man page for possible options and their meanings.
+.It Fl p
+Print information about sessions on cd. This option may be used to determine
+the number of sessions on the disk. Sessions are numbered starting with 1, and
+by default information will be displayed for the largest non-empty session.
+.It Fl s Ar session
+Specify the
+.Ar session
+to mount or display information about.
+This must be a positive integer greater than zero. Valid values may be
+determined using the
+.Fl p
+option.
+.It Fl U Ar uid
+Set the user used for files and directories without defined owners to
+.Ar uid .
+By default this is set to the user 'nobody'. (UDF allows for files
+and directories without owners.)
+.It Fl u Ar uid
+Set the owner for all files and directories in the file system to
+.Ar uid .
+If this option is specified, the
+.Fl U
+option has no effect.
+
+.El
+.Sh SEE ALSO
+.Xr cdcontrol 1 ,
+.Xr mount 2 ,
+.Xr unmount 2 ,
+.Xr fstab 5 ,
+.Xr mount 8
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 5.0 .
--- sys/fs/udf2/ecma167-udf.h 1969-12-31 16:00:00.000000000 -0800
+++ udpates/sys/fs/udf2/ecma167-udf.h 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,833 @@
+/*-
+ * Copyright (c) 2003, 2004, 2005, 2006, 2008, 2009
+ * Reinoud Zandijk * <reinoud@NetBSD.org>
+ * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ *
+ * Extended and adapted for UDFv2.50+ bij Reinoud Zandijk based on the
+ * origional by Scott Long.
+ *
+ * 20030508 Made some small typo and explainatory comments
+ * 20030510 Added UDF 2.01 structures
+ * 20030519 Added/correct comments on multi-partitioned logical volume space
+ * 20050616 Added pseudo overwrite
+ * 20050624 Added the missing extended attribute types and `magic values'.
+ * 20051106 Reworked some implementation use parts
+ *
+ */
+
+
+#ifndef _FS_UDF_ECMA167_UDF_H_
+#define _FS_UDF_ECMA167_UDF_H_
+
+
+/*
+ * in case of an older gcc versions, define the __packed as explicit
+ * attribute
+ */
+
+/*
+ * You may specify the `aligned' and `transparent_union' attributes either in
+ * a `typedef' declaration or just past the closing curly brace of a complete
+ * enum, struct or union type _definition_ and the `packed' attribute only
+ * past the closing brace of a definition. You may also specify attributes
+ * between the enum, struct or union tag and the name of the type rather than
+ * after the closing brace.
+*/
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+
+/* ecma167-udf.h */
+
+/* Volume recognition sequence ECMA 167 rev. 3 16.1 */
+struct vrs_desc {
+ uint8_t struct_type;
+ uint8_t identifier[5];
+ uint8_t version;
+ uint8_t data[2041];
+} __packed;
+
+
+#define VRS_NSR02 "NSR02"
+#define VRS_NSR03 "NSR03"
+#define VRS_BEA01 "BEA01"
+#define VRS_TEA01 "TEA01"
+#define VRS_CD001 "CD001"
+#define VRS_CDW02 "CDW02"
+
+
+/* Structure/definitions/constants a la ECMA 167 rev. 3 */
+
+
+#define MAX_TAGID_VOLUMES 9
+/* Tag identifiers */
+enum {
+ TAGID_SPARING_TABLE = 0,
+ TAGID_PRI_VOL = 1,
+ TAGID_ANCHOR = 2,
+ TAGID_VOL = 3,
+ TAGID_IMP_VOL = 4,
+ TAGID_PARTITION = 5,
+ TAGID_LOGVOL = 6,
+ TAGID_UNALLOC_SPACE = 7,
+ TAGID_TERM = 8,
+ TAGID_LOGVOL_INTEGRITY= 9,
+ TAGID_FSD = 256,
+ TAGID_FID = 257,
+ TAGID_ALLOCEXTENT = 258,
+ TAGID_INDIRECTENTRY = 259,
+ TAGID_ICB_TERM = 260,
+ TAGID_FENTRY = 261,
+ TAGID_EXTATTR_HDR = 262,
+ TAGID_UNALL_SP_ENTRY = 263,
+ TAGID_SPACE_BITMAP = 264,
+ TAGID_PART_INTEGRETY = 265,
+ TAGID_EXTFENTRY = 266,
+ TAGID_MAX = 266
+};
+
+
+enum {
+ UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT = 1,
+ UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT = 2
+};
+
+
+enum {
+ UDF_ACCESSTYPE_NOT_SPECIFIED = 0, /* unknown */
+ UDF_ACCESSTYPE_PSEUDO_OVERWITE = 0, /* Pseudo overwritable, f.e. BD-R's LOW */
+ UDF_ACCESSTYPE_READ_ONLY = 1, /* really only readable */
+ UDF_ACCESSTYPE_WRITE_ONCE = 2, /* write once and you're done */
+ UDF_ACCESSTYPE_REWRITEABLE = 3, /* may need extra work to rewrite */
+ UDF_ACCESSTYPE_OVERWRITABLE = 4 /* no limits on rewriting; harddisc f.e.*/
+};
+
+
+/* Descriptor tag [3/7.2] */
+struct desc_tag {
+ uint16_t id;
+ uint16_t descriptor_ver;
+ uint8_t cksum;
+ uint8_t reserved;
+ uint16_t serial_num;
+ uint16_t desc_crc;
+ uint16_t desc_crc_len;
+ uint32_t tag_loc;
+} __packed;
+#define UDF_DESC_TAG_LENGTH 16
+
+
+/* Recorded Address [4/7.1] */
+struct lb_addr { /* within partition space */
+ uint32_t lb_num;
+ uint16_t part_num;
+} __packed;
+
+
+/* Extent Descriptor [3/7.1] */
+struct extent_ad {
+ uint32_t len;
+ uint32_t loc;
+} __packed;
+
+
+/* Short Allocation Descriptor [4/14.14.1] */
+struct short_ad {
+ uint32_t len;
+ uint32_t lb_num;
+} __packed;
+
+
+/* Long Allocation Descriptor [4/14.14.2] */
+struct UDF_ADImp_use {
+ uint16_t flags;
+ uint32_t unique_id;
+} __packed;
+#define UDF_ADIMP_FLAGS_EXTENT_ERASED 1
+
+
+struct long_ad {
+ uint32_t len;
+ struct lb_addr loc; /* within a logical volume mapped partition space !! */
+ union {
+ uint8_t bytes[6];
+ struct UDF_ADImp_use im_used;
+ } impl;
+} __packed;
+#define longad_uniqueid impl.im_used.unique_id
+
+
+/* Extended Allocation Descriptor [4/14.14.3] ; identifies an extent of allocation descriptors ; also in UDF ? */
+struct ext_ad {
+ uint32_t ex_len;
+ uint32_t rec_len;
+ uint32_t inf_len;
+ struct lb_addr ex_loc;
+ uint8_t reserved[2];
+} __packed;
+
+
+/* ICB : Information Control Block; positioning */
+union icb {
+ struct short_ad s_ad;
+ struct long_ad l_ad;
+ struct ext_ad e_ad;
+};
+
+
+/* short/long/ext extent have flags encoded in length */
+#define UDF_EXT_ALLOCATED (0<<30)
+#define UDF_EXT_FREED (1<<30)
+#define UDF_EXT_ALLOCATED_BUT_NOT_USED (1<<30)
+#define UDF_EXT_FREE (2<<30)
+#define UDF_EXT_REDIRECT (3<<30)
+#define UDF_EXT_FLAGS(len) ((len) & (3<<30))
+#define UDF_EXT_LEN(len) ((len) & ((1<<30)-1))
+#define UDF_EXT_MAXLEN ((1<<30)-1)
+
+
+/* Character set spec [1/7.2.1] */
+struct charspec {
+ uint8_t type;
+ uint8_t inf[63];
+} __packed;
+
+
+struct pathcomp {
+ uint8_t type;
+ uint8_t l_ci;
+ uint16_t comp_filever;
+ uint8_t ident[256];
+} __packed;
+#define UDF_PATH_COMP_SIZE 4
+#define UDF_PATH_COMP_RESERVED 0
+#define UDF_PATH_COMP_ROOT 1
+#define UDF_PATH_COMP_MOUNTROOT 2
+#define UDF_PATH_COMP_PARENTDIR 3
+#define UDF_PATH_COMP_CURDIR 4
+#define UDF_PATH_COMP_NAME 5
+
+
+/* Timestamp [1/7.3] */
+struct timestamp {
+ uint16_t type_tz;
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint8_t centisec;
+ uint8_t hund_usec;
+ uint8_t usec;
+} __packed;
+#define UDF_TIMESTAMP_SIZE 12
+
+
+/* Entity Identifier [1/7.4] */
+#define UDF_REGID_ID_SIZE 23
+struct regid {
+ uint8_t flags;
+ uint8_t id[UDF_REGID_ID_SIZE];
+ uint8_t id_suffix[8];
+} __packed;
+
+
+/* ICB Tag [4/14.6] */
+struct icb_tag {
+ uint32_t prev_num_dirs;
+ uint16_t strat_type;
+ uint8_t strat_param[2];
+ uint16_t max_num_entries;
+ uint8_t reserved;
+ uint8_t file_type;
+ struct lb_addr parent_icb;
+ uint16_t flags;
+} __packed;
+#define UDF_ICB_TAG_FLAGS_ALLOC_MASK 0x03
+#define UDF_ICB_SHORT_ALLOC 0x00
+#define UDF_ICB_LONG_ALLOC 0x01
+#define UDF_ICB_EXT_ALLOC 0x02
+#define UDF_ICB_INTERN_ALLOC 0x03
+
+#define UDF_ICB_TAG_FLAGS_DIRORDERED (1<< 3)
+#define UDF_ICB_TAG_FLAGS_NONRELOC (1<< 4)
+#define UDF_ICB_TAG_FLAGS_CONTIGUES (1<< 9)
+#define UDF_ICB_TAG_FLAGS_MULTIPLEVERS (1<<12)
+
+#define UDF_ICB_TAG_FLAGS_SETUID (1<< 6)
+#define UDF_ICB_TAG_FLAGS_SETGID (1<< 7)
+#define UDF_ICB_TAG_FLAGS_STICKY (1<< 8)
+
+#define UDF_ICB_FILETYPE_UNKNOWN 0
+#define UDF_ICB_FILETYPE_UNALLOCSPACE 1
+#define UDF_ICB_FILETYPE_PARTINTEGRITY 2
+#define UDF_ICB_FILETYPE_INDIRECTENTRY 3
+#define UDF_ICB_FILETYPE_DIRECTORY 4
+#define UDF_ICB_FILETYPE_RANDOMACCESS 5
+#define UDF_ICB_FILETYPE_BLOCKDEVICE 6
+#define UDF_ICB_FILETYPE_CHARDEVICE 7
+#define UDF_ICB_FILETYPE_EXTATTRREC 8
+#define UDF_ICB_FILETYPE_FIFO 9
+#define UDF_ICB_FILETYPE_SOCKET 10
+#define UDF_ICB_FILETYPE_TERM 11
+#define UDF_ICB_FILETYPE_SYMLINK 12
+#define UDF_ICB_FILETYPE_STREAMDIR 13
+#define UDF_ICB_FILETYPE_VAT 248
+#define UDF_ICB_FILETYPE_REALTIME 249
+#define UDF_ICB_FILETYPE_META_MAIN 250
+#define UDF_ICB_FILETYPE_META_MIRROR 251
+#define UDF_ICB_FILETYPE_META_BITMAP 252
+
+
+/* Anchor Volume Descriptor Pointer [3/10.2] */
+struct anchor_vdp {
+ struct desc_tag tag;
+ struct extent_ad main_vds_ex; /* to main volume descriptor set ; 16 sectors min */
+ struct extent_ad reserve_vds_ex; /* copy of main volume descriptor set ; 16 sectors min */
+} __packed;
+
+
+/* Volume Descriptor Pointer [3/10.3] */
+struct vol_desc_ptr {
+ struct desc_tag tag; /* use for extending the volume descriptor space */
+ uint32_t vds_number;
+ struct extent_ad next_vds_ex; /* points to the next block for volume descriptor space */
+} __packed;
+
+
+/* Primary Volume Descriptor [3/10.1] */
+struct pri_vol_desc {
+ struct desc_tag tag;
+ uint32_t seq_num; /* MAX prevail */
+ uint32_t pvd_num; /* assigned by author; 0 is special as in it may only occure once */
+ char vol_id[32]; /* KEY ; main identifier of this disc */
+ uint16_t vds_num; /* volume descriptor number; i.e. what volume number is it */
+ uint16_t max_vol_seq; /* maximum volume descriptor number known */
+ uint16_t ichg_lvl;
+ uint16_t max_ichg_lvl;
+ uint32_t charset_list;
+ uint32_t max_charset_list;
+ char volset_id[128]; /* KEY ; if part of a multi-disc set or a band of volumes */
+ struct charspec desc_charset; /* KEY according to ECMA 167 */
+ struct charspec explanatory_charset;
+ struct extent_ad vol_abstract;
+ struct extent_ad vol_copyright;
+ struct regid app_id;
+ struct timestamp time;
+ struct regid imp_id;
+ uint8_t imp_use[64];
+ uint32_t prev_vds_loc; /* location of predecessor _lov ? */
+ uint16_t flags; /* bit 0 : if set indicates volume set name is meaningfull */
+ uint8_t reserved[22];
+} __packed;
+
+
+/* UDF specific implementation use part of the implementation use volume descriptor */
+struct udf_lv_info {
+ struct charspec lvi_charset;
+ char logvol_id[128];
+
+ char lvinfo1[36];
+ char lvinfo2[36];
+ char lvinfo3[36];
+
+ struct regid impl_id;
+ uint8_t impl_use[128];
+} __packed;
+
+
+/* Implementation use Volume Descriptor */
+struct impvol_desc {
+ struct desc_tag tag;
+ uint32_t seq_num;
+ struct regid impl_id;
+ union {
+ struct udf_lv_info lv_info;
+ char impl_use[460];
+ } _impl_use;
+} __packed;
+
+
+/* Logical Volume Descriptor [3/10.6] */
+struct logvol_desc {
+ struct desc_tag tag;
+ uint32_t seq_num; /* MAX prevail */
+ struct charspec desc_charset; /* KEY */
+ char logvol_id[128]; /* KEY */
+ uint32_t lb_size;
+ struct regid domain_id;
+ union {
+ struct long_ad fsd_loc; /* to fileset descriptor SEQUENCE */
+ uint8_t logvol_content_use[16];
+ } _lvd_use;
+ uint32_t mt_l; /* Partition map length */
+ uint32_t n_pm; /* Number of partition maps */
+ struct regid imp_id;
+ uint8_t imp_use[128];
+ struct extent_ad integrity_seq_loc;
+ uint8_t maps[1];
+} __packed;
+#define lv_fsd_loc _lvd_use.fsd_loc
+
+#define UDF_INTEGRITY_OPEN 0
+#define UDF_INTEGRITY_CLOSED 1
+
+
+#define UDF_PMAP_SIZE 64
+
+/* Type 1 Partition Map [3/10.7.2] */
+struct part_map_1 {
+ uint8_t type;
+ uint8_t len;
+ uint16_t vol_seq_num;
+ uint16_t part_num;
+} __packed;
+
+
+/* Type 2 Partition Map [3/10.7.3] */
+struct part_map_2 {
+ uint8_t type;
+ uint8_t len;
+ uint8_t reserved[2];
+ struct regid part_id;
+ uint16_t vol_seq_num;
+ uint16_t part_num;
+ uint8_t reserved2[24];
+} __packed;
+
+
+/* Virtual Partition Map [UDF 2.01/2.2.8] */
+struct part_map_virt {
+ uint8_t type;
+ uint8_t len;
+ uint8_t reserved[2];
+ struct regid id;
+ uint16_t vol_seq_num;
+ uint16_t part_num;
+ uint8_t reserved1[24];
+} __packed;
+
+
+/* Sparable Partition Map [UDF 2.01/2.2.9] */
+struct part_map_spare {
+ uint8_t type;
+ uint8_t len;
+ uint8_t reserved[2];
+ struct regid id;
+ uint16_t vol_seq_num;
+ uint16_t part_num;
+ uint16_t packet_len;
+ uint8_t n_st; /* Number of redundant sparing tables range 1-4 */
+ uint8_t reserved1;
+ uint32_t st_size; /* size of EACH sparing table */
+ uint32_t st_loc[1]; /* locations of sparing tables */
+} __packed;
+
+
+/* Metadata Partition Map [UDF 2.50/2.2.10] */
+struct part_map_meta {
+ uint8_t type;
+ uint8_t len;
+ uint8_t reserved[2];
+ struct regid id;
+ uint16_t vol_seq_num;
+ uint16_t part_num;
+ uint32_t meta_file_lbn; /* logical block number for file entry within part_num */
+ uint32_t meta_mirror_file_lbn;
+ uint32_t meta_bitmap_file_lbn;
+ uint32_t alloc_unit_size; /* allocation unit size in blocks */
+ uint16_t alignment_unit_size; /* alignment nessisary in blocks */
+ uint8_t flags;
+ uint8_t reserved1[5];
+} __packed;
+#define METADATA_DUPLICATED 1
+
+
+union udf_pmap {
+ uint8_t data[UDF_PMAP_SIZE];
+ struct part_map_1 pm1;
+ struct part_map_2 pm2;
+ struct part_map_virt pmv;
+ struct part_map_spare pms;
+ struct part_map_meta pmm;
+};
+
+
+/* Sparing Map Entry [UDF 2.01/2.2.11] */
+struct spare_map_entry {
+ uint32_t org; /* partition relative address */
+ uint32_t map; /* absolute disc address (!) can be in partition, but doesn't have to be */
+} __packed;
+
+
+/* Sparing Table [UDF 2.01/2.2.11] */
+struct udf_sparing_table {
+ struct desc_tag tag;
+ struct regid id;
+ uint16_t rt_l; /* Relocation Table len */
+ uint8_t reserved[2];
+ uint32_t seq_num;
+ struct spare_map_entry entries[1];
+} __packed;
+
+
+#define UDF_NO_PREV_VAT 0xffffffff
+/* UDF 1.50 VAT suffix [UDF 2.2.10 (UDF 1.50 spec)] */
+struct udf_oldvat_tail {
+ struct regid id; /* "*UDF Virtual Alloc Tbl" */
+ uint32_t prev_vat;
+} __packed;
+
+
+/* VAT table [UDF 2.0.1/2.2.10] */
+struct udf_vat {
+ uint16_t header_len;
+ uint16_t impl_use_len;
+ char logvol_id[128]; /* newer version of the LVD one */
+ uint32_t prev_vat;
+ uint32_t num_files;
+ uint32_t num_directories;
+ uint16_t min_udf_readver;
+ uint16_t min_udf_writever;
+ uint16_t max_udf_writever;
+ uint16_t reserved;
+ uint8_t data[1]; /* impl.use followed by VAT entries (uint32_t) */
+} __packed;
+
+
+/* Space bitmap descriptor as found in the partition header descriptor */
+struct space_bitmap_desc {
+ struct desc_tag tag; /* TagId 264 */
+ uint32_t num_bits; /* number of bits */
+ uint32_t num_bytes; /* bytes that contain it */
+ uint8_t data[1];
+} __packed;
+
+
+/* Unalloc space entry as found in the partition header descriptor */
+struct space_entry_desc {
+ struct desc_tag tag; /* TagId 263 */
+ struct icb_tag icbtag; /* type 1 */
+ uint32_t l_ad; /* in bytes */
+ uint8_t entry[1];
+} __packed;
+
+
+/* Partition header descriptor; in the contents_use of part_desc */
+struct part_hdr_desc {
+ struct short_ad unalloc_space_table;
+ struct short_ad unalloc_space_bitmap;
+ struct short_ad part_integrety_table; /* has to be ZERO for UDF */
+ struct short_ad freed_space_table;
+ struct short_ad freed_space_bitmap;
+ uint8_t reserved[88];
+} __packed;
+
+
+/* Partition Descriptor [3/10.5] */
+struct part_desc {
+ struct desc_tag tag;
+ uint32_t seq_num; /* MAX prevailing */
+ uint16_t flags; /* bit 0 : if set the space is allocated */
+ uint16_t part_num; /* KEY */
+ struct regid contents;
+ union {
+ struct part_hdr_desc part_hdr;
+ uint8_t contents_use[128];
+ } _impl_use;
+ uint32_t access_type; /* R/W, WORM etc. */
+ uint32_t start_loc; /* start of partition with given length */
+ uint32_t part_len;
+ struct regid imp_id;
+ uint8_t imp_use[128];
+ uint8_t reserved[156];
+} __packed;
+#define pd_part_hdr _impl_use.part_hdr
+#define UDF_PART_FLAG_ALLOCATED 1
+
+
+/* Unallocated Space Descriptor (UDF 2.01/2.2.5) */
+struct unalloc_sp_desc {
+ struct desc_tag tag;
+ uint32_t seq_num; /* MAX prevailing */
+ uint32_t alloc_desc_num;
+ struct extent_ad alloc_desc[1];
+} __packed;
+
+
+/* Logical Volume Integrity Descriptor [3/30.10] */
+struct logvolhdr {
+ uint64_t next_unique_id;
+ /* rest reserved */
+} __packed;
+
+
+struct udf_logvol_info {
+ struct regid impl_id;
+ uint32_t num_files;
+ uint32_t num_directories;
+ uint16_t min_udf_readver;
+ uint16_t min_udf_writever;
+ uint16_t max_udf_writever;
+} __packed;
+
+
+struct logvol_int_desc {
+ struct desc_tag tag;
+ struct timestamp time;
+ uint32_t integrity_type;
+ struct extent_ad next_extent;
+ union {
+ struct logvolhdr logvolhdr;
+ int8_t reserved[32];
+ } _impl_use;
+ uint32_t num_part;
+ uint32_t l_iu;
+ uint32_t tables[1]; /* Freespace table, Sizetable, Implementation use */
+} __packed;
+#define lvint_next_unique_id _impl_use.logvolhdr.next_unique_id
+
+
+/* File Set Descriptor [4/14.1] */
+struct fileset_desc {
+ struct desc_tag tag;
+ struct timestamp time;
+ uint16_t ichg_lvl;
+ uint16_t max_ichg_lvl;
+ uint32_t charset_list;
+ uint32_t max_charset_list;
+ uint32_t fileset_num; /* key! */
+ uint32_t fileset_desc_num;
+ struct charspec logvol_id_charset;
+ char logvol_id[128]; /* for recovery */
+ struct charspec fileset_charset;
+ char fileset_id[32]; /* Mountpoint !! */
+ char copyright_file_id[32];
+ char abstract_file_id[32];
+ struct long_ad rootdir_icb; /* to rootdir; icb->virtual ? */
+ struct regid domain_id;
+ struct long_ad next_ex; /* to the next fileset_desc extent */
+ struct long_ad streamdir_icb; /* streamdir; needed? */
+ uint8_t reserved[32];
+} __packed;
+
+
+/* File Identifier Descriptor [4/14.4] */
+struct fileid_desc {
+ struct desc_tag tag;
+ uint16_t file_version_num;
+ uint8_t file_char;
+ uint8_t l_fi; /* Length of file identifier area */
+ struct long_ad icb;
+ uint16_t l_iu; /* Length of implementation use area */
+ uint8_t data[0];
+} __packed;
+#define UDF_FID_SIZE 38
+#define UDF_FILE_CHAR_VIS (1 << 0) /* Invisible */
+#define UDF_FILE_CHAR_DIR (1 << 1) /* Directory */
+#define UDF_FILE_CHAR_DEL (1 << 2) /* Deleted */
+#define UDF_FILE_CHAR_PAR (1 << 3) /* Parent Directory */
+#define UDF_FILE_CHAR_META (1 << 4) /* Stream metadata */
+
+
+/* Extended attributes [4/14.10.1] */
+struct extattrhdr_desc {
+ struct desc_tag tag;
+ uint32_t impl_attr_loc; /* offsets within this descriptor */
+ uint32_t appl_attr_loc; /* ditto */
+} __packed;
+#define UDF_IMPL_ATTR_LOC_NOT_PRESENT 0xffffffff
+#define UDF_APPL_ATTR_LOC_NOT_PRESENT 0xffffffff
+
+
+/* Extended attribute entry [4/48.10.2] */
+struct extattr_entry {
+ uint32_t type;
+ uint8_t subtype;
+ uint8_t reserved[3];
+ uint32_t a_l;
+} __packed;
+
+
+/* Extended attribute entry; type 2048 [4/48.10.8] */
+struct impl_extattr_entry {
+ struct extattr_entry hdr;
+ uint32_t iu_l;
+ struct regid imp_id;
+ uint8_t data[1];
+} __packed;
+
+
+/* Extended attribute entry; type 65 536 [4/48.10.9] */
+struct appl_extattr_entry {
+ struct extattr_entry hdr;
+ uint32_t au_l;
+ struct regid appl_id;
+ uint8_t data[1];
+} __packed;
+
+
+/* File Times attribute entry; type 5 or type 6 [4/48.10.5], [4/48.10.6] */
+struct filetimes_extattr_entry {
+ struct extattr_entry hdr;
+ uint32_t d_l; /* length of times[] data following */
+ uint32_t existence; /* bitmask */
+ struct timestamp times[1]; /* in order of assending bits */
+} __packed;
+#define UDF_FILETIMES_ATTR_NO 5
+#define UDF_FILETIMES_FILE_CREATION 1
+#define UDF_FILETIMES_FILE_DELETION 4
+#define UDF_FILETIMES_FILE_EFFECTIVE 8
+#define UDF_FILETIMES_FILE_BACKUPED 16
+#define UDF_FILETIMES_ATTR_SIZE(no) (20 + (no)*sizeof(struct timestamp))
+
+
+/* Device Specification Extended Attribute [4/4.10.7] */
+struct device_extattr_entry {
+ struct extattr_entry hdr;
+ uint32_t iu_l; /* length of implementation use */
+ uint32_t major;
+ uint32_t minor;
+ uint8_t data[1]; /* UDF: if nonzero length, contain developer ID regid */
+} __packed;
+#define UDF_DEVICESPEC_ATTR_NO 12
+
+
+/* VAT LV extension Extended Attribute [UDF 3.3.4.5.1.3] 1.50 errata */
+struct vatlvext_extattr_entry {
+ uint64_t unique_id_chk; /* needs to be copy of ICB's */
+ uint32_t num_files;
+ uint32_t num_directories;
+ char logvol_id[128]; /* replaces logvol name */
+} __packed;
+
+
+/* File Entry [4/14.9] */
+struct file_entry {
+ struct desc_tag tag;
+ struct icb_tag icbtag;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t perm;
+ uint16_t link_cnt;
+ uint8_t rec_format;
+ uint8_t rec_disp_attr;
+ uint32_t rec_len;
+ uint64_t inf_len;
+ uint64_t logblks_rec;
+ struct timestamp atime;
+ struct timestamp mtime;
+ struct timestamp attrtime;
+ uint32_t ckpoint;
+ struct long_ad ex_attr_icb;
+ struct regid imp_id;
+ uint64_t unique_id;
+ uint32_t l_ea; /* Length of extended attribute area */
+ uint32_t l_ad; /* Length of allocation descriptors */
+ uint8_t data[1];
+} __packed;
+#define UDF_FENTRY_SIZE 176
+#define UDF_FENTRY_PERM_USER_MASK 0x07
+#define UDF_FENTRY_PERM_GRP_MASK 0xE0
+#define UDF_FENTRY_PERM_OWNER_MASK 0x1C00
+
+
+/* Extended File Entry [4/48.17] */
+struct extfile_entry {
+ struct desc_tag tag;
+ struct icb_tag icbtag;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t perm;
+ uint16_t link_cnt;
+ uint8_t rec_format;
+ uint8_t rec_disp_attr;
+ uint32_t rec_len;
+ uint64_t inf_len;
+ uint64_t obj_size;
+ uint64_t logblks_rec;
+ struct timestamp atime;
+ struct timestamp mtime;
+ struct timestamp ctime;
+ struct timestamp attrtime;
+ uint32_t ckpoint;
+ uint32_t reserved1;
+ struct long_ad ex_attr_icb;
+ struct long_ad streamdir_icb;
+ struct regid imp_id;
+ uint64_t unique_id;
+ uint32_t l_ea; /* Length of extended attribute area */
+ uint32_t l_ad; /* Length of allocation descriptors */
+ uint8_t data[1];
+} __packed;
+#define UDF_EXTFENTRY_SIZE 216
+
+
+/* Indirect entry [ecma 48.7] */
+struct indirect_entry {
+ struct desc_tag tag;
+ struct icb_tag icbtag;
+ struct long_ad indirect_icb;
+} __packed;
+
+
+/* Allocation extent descriptor [ecma 48.5] */
+struct alloc_ext_entry {
+ struct desc_tag tag;
+ uint32_t prev_entry;
+ uint32_t l_ad;
+ uint8_t data[1];
+} __packed;
+
+
+union dscrptr {
+ struct desc_tag tag;
+ struct anchor_vdp avdp;
+ struct vol_desc_ptr vdp;
+ struct pri_vol_desc pvd;
+ struct logvol_desc lvd;
+ struct unalloc_sp_desc usd;
+ struct logvol_int_desc lvid;
+ struct impvol_desc ivd;
+ struct part_desc pd;
+ struct fileset_desc fsd;
+ struct fileid_desc fid;
+ struct file_entry fe;
+ struct extfile_entry efe;
+ struct extattrhdr_desc eahd;
+ struct indirect_entry inde;
+ struct alloc_ext_entry aee;
+ struct udf_sparing_table spt;
+ struct space_bitmap_desc sbd;
+ struct space_entry_desc sed;
+};
+
+
+#endif /* !_FS_UDF_ECMA167_UDF_H_ */
+
--- sys/fs/udf2/udf.h 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf.h 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 2006, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#ifndef _FS_UDF_UDF_H_
+#define _FS_UDF_UDF_H_
+
+#include "udf_osta.h"
+
+/* constants to identify what kind of identifier we are dealing with */
+#define UDF_REGID_DOMAIN 1
+#define UDF_REGID_UDF 2
+#define UDF_REGID_IMPLEMENTATION 3
+#define UDF_REGID_APPLICATION 4
+#define UDF_REGID_NAME 99
+
+/* Configuration values */
+#define UDF_VAT_ALLOC_LIMIT 104857600 /* picked at random */
+#define UDF_VAT_CHUNKSIZE (64*1024) /* picked */
+#define UDF_SYMLINKBUFLEN (64*1024) /* picked */
+
+#define UDF_DISC_SLACK (128) /* picked, at least 64 kb or 128 */
+
+/* structure space */
+#define UDF_ANCHORS 4 /* 256, 512, N-256, N */
+#define UDF_PARTITIONS 4 /* overkill */
+#define UDF_PMAPS 5 /* overkill */
+#define UDF_MAX_ALLOC_EXTENTS 50 /* overkill */
+
+/* constants */
+#define UDF_MAX_NAMELEN 255 /* as per SPEC */
+#define UDF_TRAN_EXTERNAL 0
+#define UDF_TRAN_INTERN 1
+#define UDF_TRAN_ZERO 2
+
+/* RW content hint for allocation and other purposes */
+#define UDF_C_DSCR 2 /* update sectornr and CRC */
+
+/* virtual to physical mapping types */
+#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
+
+#define UDF_VTOP_TYPE_RAW 0
+#define UDF_VTOP_TYPE_UNKNOWN 0
+#define UDF_VTOP_TYPE_PHYS 1
+#define UDF_VTOP_TYPE_VIRT 2
+#define UDF_VTOP_TYPE_SPARABLE 3
+#define UDF_VTOP_TYPE_META 4
+
+/* logical volume error handling actions */
+#define UDF_UPDATE_TRACKINFO 0x01 /* update trackinfo and re-shedule */
+#define UDF_REMAP_BLOCK 0x02 /* remap the failing block length */
+
+/* mounting options */
+#define UDFMNT_KICONV 1
+#define UDFMNT_OVERRIDE_UID 2
+#define UDFMNT_OVERRIDE_GID 4
+#define UDFMNT_USE_MASK 8
+#define UDFMNT_USE_DIRMASK 16
+
+/* malloc pools */
+MALLOC_DECLARE(M_UDFTEMP);
+
+struct udf_node;
+
+struct udf_lvintq {
+ uint32_t start;
+ uint32_t end;
+ uint32_t pos;
+ uint32_t wpos;
+};
+
+struct udf_mount {
+ struct mount *vfs_mountp;
+ struct vnode *devvp;
+ struct g_consumer *geomcp;
+ uint32_t sector_size;
+ uint64_t flags;
+ uid_t anon_uid;
+ gid_t anon_gid;
+ void *iconv_d2l; /* disk to local */
+ mode_t mode;
+ mode_t dirmode;
+
+ /* Used in mounting */
+ uint32_t first_trackblank;
+ uint32_t session_start;
+ uint32_t session_end;
+ uint32_t session_last_written;
+
+ /* format descriptors */
+ struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */
+ struct pri_vol_desc *primary_vol; /* identification */
+ struct logvol_desc *logical_vol; /* main mapping v->p */
+ struct unalloc_sp_desc *unallocated; /* free UDF space */
+ struct impvol_desc *implementation; /* likely reduntant */
+ struct logvol_int_desc *logvol_integrity; /* current integrity */
+ struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */
+ /* logvol_info is derived; points *into* other structures */
+ struct udf_logvol_info *logvol_info; /* integrity descr. */
+
+ /* fileset and root directories */
+ struct fileset_desc *fileset_desc; /* normally one */
+
+ /* logical to physical translations */
+ int vtop[UDF_PMAPS+1]; /* vpartnr trans */
+ int vtop_tp[UDF_PMAPS+1]; /* type of trans */
+
+ /* VAT */
+ uint32_t first_possible_vat_location;
+ uint32_t last_possible_vat_location;
+ uint32_t vat_entries;
+ uint32_t vat_offset; /* offset in table */
+ uint32_t vat_table_alloc_len;
+ uint8_t *vat_table;
+
+ /* sparable */
+ uint32_t sparable_packet_size;
+ struct udf_sparing_table *sparing_table;
+
+ /* meta */
+ struct udf_node *metadata_node; /* system node */
+};
+
+/*
+ * UDF node describing a file/directory.
+ *
+ * BUGALERT claim node_mutex before reading/writing to prevent inconsistencies !
+ */
+struct udf_node {
+ struct vnode *vnode; /* vnode associated */
+ struct udf_mount *ump;
+
+ ino_t hash_id; /* should contain inode */
+ int diroff; /* used in lookup */
+
+ /* one of `fe' or `efe' can be set, not both (UDF file entry dscr.) */
+ struct file_entry *fe;
+ struct extfile_entry *efe;
+ struct alloc_ext_entry *ext[UDF_MAX_ALLOC_EXTENTS];
+ int num_extensions;
+
+ /* location found, recording location & hints */
+ struct long_ad loc; /* FID/hash loc. */
+};
+
+struct udf_fid {
+ u_short len; /* length of data in bytes */
+ u_short padding; /* force longword alignment */
+ ino_t ino;
+};
+
+#endif /* !_FS_UDF_UDF_H_ */
--- sys/fs/udf2/udf_allocation.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_allocation.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,443 @@
+/*-
+ * Copyright (c) 2012 Will DeVries
+ * Copyright (c) 2006, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+
+#include "ecma167-udf.h"
+#include "udf.h"
+#include "udf_subr.h"
+
+
+void
+udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks,
+ uint64_t *freeblks)
+{
+ struct logvol_int_desc *lvid;
+ int num_vpart, vpart;
+ uint32_t *pos1, *pos2;
+
+ lvid = ump->logvol_integrity;
+ *freeblks = *sizeblks = 0;
+
+ /*
+ * Sequentials media report free space directly (CD/DVD/BD-R), for the
+ * other media we need the logical volume integrity.
+ *
+ * We sum all free space up here regardless of type.
+ */
+
+ num_vpart = le32toh(lvid->num_part);
+
+#if 0
+ if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
+ /* use track info directly summing if there are 2 open */
+ /* XXX assumption at most two tracks open */
+ *freeblks = ump->data_track.free_blocks;
+ if (ump->data_track.tracknr != ump->metadata_track.tracknr)
+ *freeblks += ump->metadata_track.free_blocks;
+ *sizeblks = ump->discinfo.last_possible_lba;
+ } else {
+#endif
+ /* free and used space for mountpoint based on logvol integrity */
+ for (vpart = 0; vpart < num_vpart; vpart++) {
+ pos1 = &lvid->tables[0] + vpart;
+ pos2 = &lvid->tables[0] + num_vpart + vpart;
+ if (le32toh(*pos1) != (uint32_t) -1) {
+ *freeblks += le32toh(*pos1);
+ *sizeblks += le32toh(*pos2);
+ }
+ }
+#if 0
+ }
+#endif
+
+ if (*freeblks > UDF_DISC_SLACK)
+ *freeblks -= UDF_DISC_SLACK;
+ else
+ *freeblks = 0;
+}
+
+int
+udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
+ uint32_t *lb_numres, uint32_t *extres)
+{
+ struct part_desc *pdesc;
+ struct spare_map_entry *sme;
+ struct long_ad s_icb_loc;
+ uint64_t end_foffset, foffset;
+ int eof, error, flags, part, rel, slot;
+ uint32_t lb_num, lb_packet, lb_rel, lb_size, len;
+ uint32_t ext_offset, udf_rw32_lbmap;
+ uint16_t vpart;
+
+ KASSERT(ump && icb_loc && lb_numres,("ump && icb_loc && lb_numres"));
+
+ vpart = le16toh(icb_loc->loc.part_num);
+ lb_num = le32toh(icb_loc->loc.lb_num);
+ if (vpart > UDF_VTOP_RAWPART)
+ return (EINVAL);
+
+translate_again:
+ part = ump->vtop[vpart];
+ pdesc = ump->partitions[part];
+
+ switch (ump->vtop_tp[vpart]) {
+ case UDF_VTOP_TYPE_RAW:
+ /* 1:1 to the end of the device */
+ *lb_numres = lb_num;
+ *extres = INT_MAX;
+ return (0);
+ case UDF_VTOP_TYPE_PHYS:
+ /* transform into its disc logical block */
+ if (lb_num > le32toh(pdesc->part_len))
+ return (EINVAL);
+ *lb_numres = lb_num + le32toh(pdesc->start_loc);
+
+ /* extent from here to the end of the partition */
+ *extres = le32toh(pdesc->part_len) - lb_num;
+ return (0);
+ case UDF_VTOP_TYPE_VIRT:
+ /* only maps one logical block, lookup in VAT */
+ if (lb_num >= ump->vat_entries) /* XXX > or >= ? */
+ return (EINVAL);
+
+ /* lookup in virtual allocation table file */
+ error = udf_vat_read(ump, (uint8_t *)&udf_rw32_lbmap, 4,
+ ump->vat_offset + lb_num * 4);
+ if (error != 0)
+ return (error);
+
+ lb_num = le32toh(udf_rw32_lbmap);
+
+ /* transform into its disc logical block */
+ if (lb_num > le32toh(pdesc->part_len))
+ return (EINVAL);
+ *lb_numres = lb_num + le32toh(pdesc->start_loc);
+
+ /* just one logical block */
+ *extres = 1;
+ return (0);
+ case UDF_VTOP_TYPE_SPARABLE:
+ /* check if the packet containing the lb_num is remapped */
+ lb_packet = lb_num / ump->sparable_packet_size;
+ lb_rel = lb_num % ump->sparable_packet_size;
+
+ for (rel = 0; rel < le16toh(ump->sparing_table->rt_l); rel++) {
+ sme = &ump->sparing_table->entries[rel];
+ if (lb_packet == le32toh(sme->org)) {
+ /* NOTE maps to absolute disc logical block! */
+ *lb_numres = le32toh(sme->map) + lb_rel;
+ *extres = ump->sparable_packet_size - lb_rel;
+ return (0);
+ }
+ }
+
+ /* transform into its disc logical block */
+ if (lb_num > le32toh(pdesc->part_len))
+ return (EINVAL);
+ *lb_numres = lb_num + le32toh(pdesc->start_loc);
+
+ /* rest of block */
+ *extres = ump->sparable_packet_size - lb_rel;
+ return (0);
+ case UDF_VTOP_TYPE_META:
+ /* we have to look into the file's allocation descriptors */
+
+ /* use metadatafile allocation mutex */
+ lb_size = le32toh(ump->logical_vol->lb_size);
+
+ UDF_LOCK_NODE(ump->metadata_node, 0);
+
+ /* get first overlapping extent */
+ foffset = 0;
+ slot = 0;
+ for (;;) {
+ udf_get_adslot(ump->metadata_node, slot, &s_icb_loc,
+ &eof);
+ if (eof) {
+ UDF_UNLOCK_NODE(ump->metadata_node, 0);
+ return (EINVAL);
+ }
+ len = le32toh(s_icb_loc.len);
+ flags = UDF_EXT_FLAGS(len);
+ len = UDF_EXT_LEN(len);
+
+ if (flags == UDF_EXT_REDIRECT) {
+ slot++;
+ continue;
+ }
+
+ end_foffset = foffset + len;
+
+ if (end_foffset > lb_num * lb_size)
+ break; /* found */
+ foffset = end_foffset;
+ slot++;
+ }
+ /* found overlapping slot */
+ ext_offset = lb_num * lb_size - foffset;
+
+ /* process extent offset */
+ lb_num = le32toh(s_icb_loc.loc.lb_num);
+ vpart = le16toh(s_icb_loc.loc.part_num);
+ lb_num += (ext_offset + lb_size -1) / lb_size;
+ ext_offset = 0;
+
+ UDF_UNLOCK_NODE(ump->metadata_node, 0);
+ if (flags != UDF_EXT_ALLOCATED)
+ return (EINVAL);
+
+ /*
+ * vpart and lb_num are updated, translate again since we
+ * might be mapped on sparable media
+ */
+ goto translate_again;
+ default:
+ printf("UDF vtop translation scheme %d unimplemented yet\n",
+ ump->vtop_tp[vpart]);
+ }
+
+ return (EINVAL);
+}
+
+/*
+ * This is a simplified version of the udf_translate_file_extent function.
+ */
+int
+udf_bmap_translate(struct udf_node *udf_node, uint32_t block,
+ int *exttype, uint64_t *lsector, uint32_t *maxblks)
+{
+ struct udf_mount *ump;
+ struct icb_tag *icbtag;
+ struct long_ad s_ad, t_ad;
+ uint64_t foffset, new_foffset;
+ int addr_type, eof, error, flags, icbflags, slot;
+ uint32_t ext_offset, ext_remain, lb_num, lb_size, len, transsec32;
+ uint32_t translen;
+ uint16_t vpart_num;
+
+
+ if (udf_node == NULL)
+ return (ENOENT);
+
+ KASSERT(num_lb > 0,("num_lb > 0"));
+
+ UDF_LOCK_NODE(udf_node, 0);
+
+ /* initialise derivative vars */
+ ump = udf_node->ump;
+ lb_size = le32toh(ump->logical_vol->lb_size);
+
+ if (udf_node->fe != NULL)
+ icbtag = &udf_node->fe->icbtag;
+ else
+ icbtag = &udf_node->efe->icbtag;
+
+ icbflags = le16toh(icbtag->flags);
+ addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
+
+ /* do the work */
+ if (addr_type == UDF_ICB_INTERN_ALLOC) {
+ *exttype = UDF_TRAN_INTERN;
+ *maxblks = 1;
+ UDF_UNLOCK_NODE(udf_node, 0);
+ return (0);
+ }
+
+ /* find first overlapping extent */
+ foffset = 0;
+ slot = 0;
+ for (;;) {
+ udf_get_adslot(udf_node, slot, &s_ad, &eof);
+ if (eof) {
+ UDF_UNLOCK_NODE(udf_node, 0);
+ return (EINVAL);
+ }
+ len = le32toh(s_ad.len);
+ flags = UDF_EXT_FLAGS(len);
+ len = UDF_EXT_LEN(len);
+
+ if (flags == UDF_EXT_REDIRECT) {
+ slot++;
+ continue;
+ }
+
+ new_foffset = foffset + len;
+
+ if (new_foffset > block * lb_size)
+ break; /* found */
+ foffset = new_foffset;
+ slot++;
+ }
+ /* found overlapping slot */
+
+ lb_num = le32toh(s_ad.loc.lb_num);
+ vpart_num = le16toh(s_ad.loc.part_num);
+
+ ext_offset = block * lb_size - foffset;
+ lb_num += (ext_offset + lb_size - 1) / lb_size;
+ ext_remain = (len - ext_offset + lb_size - 1) / lb_size;
+
+ /*
+ * note that the while(){} is nessisary for the extent that
+ * the udf_translate_vtop() returns doens't have to span the
+ * whole extent.
+ */
+ switch (flags) {
+ case UDF_EXT_FREE:
+ case UDF_EXT_ALLOCATED_BUT_NOT_USED:
+ *exttype = UDF_TRAN_ZERO;
+ *maxblks = ext_remain;
+ break;
+ case UDF_EXT_ALLOCATED:
+ *exttype = UDF_TRAN_EXTERNAL;
+ t_ad.loc.lb_num = htole32(lb_num);
+ t_ad.loc.part_num = htole16(vpart_num);
+ error = udf_translate_vtop(ump, &t_ad, &transsec32, &translen);
+ if (error != 0) {
+ UDF_UNLOCK_NODE(udf_node, 0);
+ return (error);
+ }
+ *lsector = transsec32;
+ *maxblks = MIN(ext_remain, translen);
+ break;
+ default:
+ UDF_UNLOCK_NODE(udf_node, 0);
+ return (EINVAL);
+ }
+
+ UDF_UNLOCK_NODE(udf_node, 0);
+
+ return (0);
+}
+
+void
+udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb,
+ int *eof) {
+ struct file_entry *fe;
+ struct extfile_entry *efe;
+ struct alloc_ext_entry *ext;
+ struct icb_tag *icbtag;
+ struct short_ad *short_ad;
+ struct long_ad *long_ad, l_icb;
+ int addr_type, adlen, extnr, icbflags;
+ uint32_t dscr_size, flags, lb_size, l_ad, l_ea, offset;
+ uint8_t *data_pos;
+
+ /* determine what descriptor we are in */
+ lb_size = le32toh(udf_node->ump->logical_vol->lb_size);
+
+ fe = udf_node->fe;
+ efe = udf_node->efe;
+ if (fe != NULL) {
+ icbtag = &fe->icbtag;
+ dscr_size = sizeof(struct file_entry) -1;
+ l_ea = le32toh(fe->l_ea);
+ l_ad = le32toh(fe->l_ad);
+ data_pos = (uint8_t *)fe + dscr_size + l_ea;
+ } else {
+ icbtag = &efe->icbtag;
+ dscr_size = sizeof(struct extfile_entry) -1;
+ l_ea = le32toh(efe->l_ea);
+ l_ad = le32toh(efe->l_ad);
+ data_pos = (uint8_t *)efe + dscr_size + l_ea;
+ }
+
+ icbflags = le16toh(icbtag->flags);
+ addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
+
+ /* just in case we're called on an intern, its EOF */
+ if (addr_type == UDF_ICB_INTERN_ALLOC) {
+ memset(icb, 0, sizeof(struct long_ad));
+ *eof = 1;
+ return;
+ }
+
+ adlen = 0;
+ if (addr_type == UDF_ICB_SHORT_ALLOC)
+ adlen = sizeof(struct short_ad);
+ else if (addr_type == UDF_ICB_LONG_ALLOC)
+ adlen = sizeof(struct long_ad);
+
+ /* if offset too big, we go to the allocation extensions */
+ offset = slot * adlen;
+ extnr = -1;
+ while (offset >= l_ad) {
+ /* check if our last entry is a redirect */
+ if (addr_type == UDF_ICB_SHORT_ALLOC) {
+ short_ad = (struct short_ad *)(data_pos + l_ad-adlen);
+ l_icb.len = short_ad->len;
+ l_icb.loc.part_num = udf_node->loc.loc.part_num;
+ l_icb.loc.lb_num = short_ad->lb_num;
+ } else {
+ KASSERT(addr_type == UDF_ICB_LONG_ALLOC,
+ ("addr_type == UDF_ICB_LONG_ALLOC"));
+ long_ad = (struct long_ad *)(data_pos + l_ad-adlen);
+ l_icb = *long_ad;
+ }
+ flags = UDF_EXT_FLAGS(le32toh(l_icb.len));
+ if (flags != UDF_EXT_REDIRECT) {
+ l_ad = 0; /* force EOF */
+ break;
+ }
+
+ /* advance to next extent */
+ extnr++;
+ if (extnr >= udf_node->num_extensions) {
+ l_ad = 0; /* force EOF */
+ break;
+ }
+ offset = offset - l_ad;
+ ext = udf_node->ext[extnr];
+ dscr_size = sizeof(struct alloc_ext_entry) - 1;
+ l_ad = le32toh(ext->l_ad);
+ data_pos = (uint8_t *)ext + dscr_size;
+ }
+
+ /* XXX l_ad == 0 should be enough to check */
+ *eof = (offset >= l_ad) || (l_ad == 0);
+ if (*eof) {
+ memset(icb, 0, sizeof(struct long_ad));
+ return;
+ }
+
+ /* get the element */
+ if (addr_type == UDF_ICB_SHORT_ALLOC) {
+ short_ad = (struct short_ad *)(data_pos + offset);
+ icb->len = short_ad->len;
+ icb->loc.part_num = udf_node->loc.loc.part_num;
+ icb->loc.lb_num = short_ad->lb_num;
+ } else if (addr_type == UDF_ICB_LONG_ALLOC) {
+ long_ad = (struct long_ad *)(data_pos + offset);
+ *icb = *long_ad;
+ }
+}
--- sys/fs/udf2/udf_filenames.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_filenames.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,276 @@
+/*-
+ * Copyright (c) 2012 Will DeVries
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/iconv.h>
+#include <sys/systm.h>
+
+#include "ecma167-udf.h"
+#include "udf.h"
+#include "udf_subr.h"
+
+extern struct iconv_functions *udf2_iconv;
+
+static int
+udf_to_utf8(char **result, size_t *rrem, uint32_t ch)
+{
+ int n = 0;
+ char *rp = *result;
+
+ if ((ch & 0xFFFFFF80) == 0) {
+ if (*rrem < 1)
+ return (0);
+
+ n = 1;
+ rp[0] = ch & 0x7F;
+ } else if ((ch & 0xFFFFF800) == 0) {
+ if (*rrem < 2)
+ return (0);
+
+ n = 2;
+ rp[0] = 0xC0 | (ch >> 6);
+ rp[1] = 0x80 | (0x3F & ch);
+ } else if ((ch & 0xFFFF0000) == 0) {
+ if (*rrem < 3)
+ return (0);
+
+ n = 3;
+ rp[0] = 0xE0 | (ch >> 12);
+ rp[1] = 0x80 | (0x3F & (ch >> 6));
+ rp[2] = 0x80 | (0x3F & ch);
+ } else if ((ch & 0xFFE00000) == 0) {
+ if (*rrem < 4)
+ return (0);
+
+ n = 4;
+ rp[0] = 0xF0 | (ch >> 18);
+ rp[1] = 0x80 | (0x3F & (ch >> 12));
+ rp[2] = 0x80 | (0x3F & (ch >> 6));
+ rp[3] = 0x80 | (0x3F & ch);
+ } else {
+ /* do not convert points above 21 bits. */
+ return (0);
+ }
+
+ *rrem -= n;
+ *result += n;
+ return (n);
+}
+
+static void
+udf_convert_str(struct udf_mount *ump, char *result, int *result_len,
+ uint8_t *id, int id_len, uint16_t *index, int *needsCRC, int *extloc,
+ int eightbit)
+{
+ size_t chrem, rrem;
+ int endi, i, invalid;
+ uint32_t uch;
+ char ch[2], *rp;
+ const char *chp;
+
+ if (eightbit)
+ endi = id_len;
+ else
+ endi = (id_len - 1 > 0) ? id_len - 1 : 0;
+
+ *extloc = 0;
+ *needsCRC = 0;
+ invalid = 0;
+ rp = result;
+ rrem = *result_len - 1; /* for the null */
+ for (i = 0; i < endi;) {
+ if (eightbit) {
+ uch = id[i];
+ if (index)
+ index[i] = *result_len - 1 - rrem;
+ } else {
+ uch = id[i] << 8 | id[i+1];
+ if (index)
+ index[i/2] = *result_len - 1 - rrem;
+ }
+
+ //id[i] starts at this place in result
+
+ if (rrem == 0) {
+ /* no more space, we need to truncate it. */
+ *needsCRC = 1;
+ } else if (uch == 0 || uch == 0x2F) {
+ /* do not allow nulls or slashes */
+ invalid++;
+ } else if (ump->flags & UDFMNT_KICONV && udf2_iconv) {
+ /* it might be a valid character */
+ chrem = 2;
+ chp = ch;
+ ch[0] = uch >> 8;
+ ch[1] = uch & 0x00FF;
+ udf2_iconv->convchr(ump->iconv_d2l, &chp, &chrem, &rp,
+ &rrem);
+ if (chrem > 0) {
+ /* not printable or doesn't fit */
+ invalid++;
+ *needsCRC = 1;
+ } else
+ invalid = 0;
+ } else {
+ /* utf8 output */
+ /* it is a valid character */
+ if (udf_to_utf8(&rp, &rrem, uch) == 0) {
+ /* doesn't fit or too large */
+ invalid++;
+ *needsCRC = 1;
+ } else
+ invalid = 0;
+ }
+
+ if (uch == 0x002E && i != 1) {
+ /* record locations of periods where they occur within
+ 5 char of the end, but not at the end or start */
+ if (eightbit && id_len - 6 < i && i + 1 != endi)
+ *extloc = i;
+ else if (!eightbit && id_len - 12 < i && i + 2 != endi)
+ *extloc = i;
+ }
+
+ if (rrem > 0 && invalid == 1) {
+ uch = 0x5F; // underscore
+
+ /* if the result doesn't have space this may not fit */
+ if (ump->flags & UDFMNT_KICONV && udf2_iconv) {
+ chrem = 2;
+ chp = ch;
+ ch[0] = uch >> 8;
+ ch[1] = uch & 0x00FF;
+ udf2_iconv->convchr(ump->iconv_d2l, &chp,
+ &chrem, &rp, &rrem);
+ } else
+ udf_to_utf8(&rp, &rrem, uch);
+
+ invalid++;
+ }
+
+ if (eightbit)
+ i++;
+ else
+ i += 2;
+ }
+
+ // this is the null placement
+ if (index) {
+ if (eightbit)
+ index[i] = *result_len - 1 - rrem;
+ else
+ index[i/2] = *result_len - 1 - rrem;
+ }
+
+ *rp = '\0';
+ *result_len -= rrem;
+}
+
+/*
+ * The result_len is assumed to include the zero.
+ * id_len - 1 is character, not \0.
+ */
+void
+udf_to_unix_name(struct udf_mount *ump, char *result, int result_len,
+ uint8_t *id, int id_len)
+{
+ int crclen, eightbit, extlen, extloc, i, junkloc, mainlen, maxmainlen;
+ int maxnpart, needsCRC;
+ uint16_t crcsum, *index;
+ char *crc, crcbuf[6], *ext;
+
+ if (id[0] != 8 && id[0] != 16) {
+ /* this is either invalid or an empty string */
+ result_len = 0;
+ return;
+ }
+
+ if (id[0] == 8)
+ eightbit = 1;
+ else
+ eightbit = 0;
+
+ /* remove marker byte from start of string */
+ id++;
+ id_len--;
+
+ index = malloc((id_len + 1) * sizeof(uint16_t), M_UDFTEMP, M_WAITOK);
+
+ mainlen = result_len;
+ udf_convert_str(ump, result, &mainlen, id, id_len, index, &needsCRC,
+ &extloc, eightbit);
+
+ if (needsCRC) {
+ if (extloc) {
+ //build ext
+ ext = malloc(result_len, M_UDFTEMP, M_WAITOK | M_ZERO);
+ extlen = result_len;
+ udf_convert_str(ump, ext, &extlen, id + extloc,
+ id_len - extloc, NULL, &needsCRC, &junkloc,
+ eightbit);
+ } else {
+ ext = NULL;
+ extlen = 1;
+ }
+
+ crcsum = udf_cksum(id, id_len);
+ crcbuf[0] = '#';
+ crcbuf[1] = "0123456789ABCDEF"[(crcsum >> 12) & 0x000F];
+ crcbuf[2] = "0123456789ABCDEF"[(crcsum >> 8) & 0x000F];
+ crcbuf[3] = "0123456789ABCDEF"[(crcsum >> 4) & 0x000F];
+ crcbuf[4] = "0123456789ABCDEF"[crcsum & 0x000F];
+ crcbuf[5] = '\0';
+
+ crc = malloc(result_len, M_UDFTEMP, M_WAITOK | M_ZERO);
+ crclen = result_len;
+ udf_convert_str(ump, crc, &crclen, crcbuf, 5, NULL, &needsCRC,
+ &junkloc, 1);
+
+ // find index of last character to be written into filename.
+ maxnpart = result_len - crclen - extlen - 3;
+ if (extloc)
+ maxmainlen = (eightbit) ? extloc : extloc / 2;
+ else
+ maxmainlen = (eightbit) ? id_len : id_len / 2;
+
+ for (i = 0; i < maxmainlen; i++)
+ if (index[i + 1] - 1 > maxnpart)
+ break;
+ i--;
+
+ memcpy(result + index[i + 1], crc, crclen - 1);
+ if (ext)
+ memcpy(result + index[i + 1] + crclen - 1, ext, extlen);
+ result[index[i + 1] + crclen + extlen - 2] = '\0';
+
+ if (ext)
+ free(ext, M_UDFTEMP);
+ free(crc, M_UDFTEMP);
+ }
+
+ free(index, M_UDFTEMP);
+}
--- sys/fs/udf2/udf_iconv.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_iconv.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2003 Ryuichiro Imura
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/fs/udf/udf_iconv.c,v 1.1 2003/11/05 06:56:08 scottl Exp $");
+
+#include <sys/param.h>
+#include <sys/iconv.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+
+VFS_DECLARE_ICONV(udf2);
--- sys/fs/udf2/udf_osta.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_osta.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,92 @@
+/*
+ * Various routines from the OSTA 2.01 specs. Copyrights are included with
+ * each code segment. Slight whitespace modifications have been made for
+ * formatting purposes. Typos/bugs have been fixed.
+ *
+ * Copyright to this code held by AT&T.
+ */
+
+#include "udf_osta.h"
+
+/*
+ * CRC 010041
+ */
+static uint16_t crc_table[256] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+uint16_t
+udf_cksum(unsigned char *s, int n)
+{
+ uint16_t crc = 0;
+
+ while (n-- > 0)
+ crc = crc_table[(crc >> 8 ^ *s++) & 0xff] ^ (crc << 8);
+
+ return (crc);
+}
+
+/*
+ * Calculates a 16-bit checksum of the Implementation Use
+ * Extended Attribute header or Application Use Extended Attribute
+ * header. The fields AttributeType through ImplementationIdentifier
+ * (or ApplicationIdentifier) inclusively represent the
+ * data covered by the checksum (48 bytes).
+ *
+ */
+uint16_t udf_ea_cksum(uint8_t *data) {
+ int count;
+ uint16_t checksum = 0;
+
+ for (count = 0; count < 48; count++)
+ checksum += *data++;
+
+ return (checksum);
+}
+
+#ifdef MAIN
+unsigned char bytes[] = { 0x70, 0x6A, 0x77 };
+
+main(void)
+{
+ unsigned short x;
+
+ x = udf_cksum(bytes, sizeof bytes);
+ printf("checksum: calculated=%4.4x, correct=%4.4x\en", x, 0x3299);
+
+ exit(0);
+}
+#endif
+
+
--- sys/fs/udf2/udf_osta.h 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_osta.h 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,14 @@
+/*
+ * Prototypes for the OSTA functions
+ */
+
+
+#ifndef _FS_UDF_OSTA_H_
+#define _FS_UDF_OSTA_H_
+
+#include <sys/types.h>
+
+unsigned short udf_cksum(unsigned char *, int);
+uint16_t udf_ea_cksum(uint8_t *data);
+
+#endif /* _FS_UDF_OSTA_H_ */
--- sys/fs/udf2/udf_readwrite.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_readwrite.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,234 @@
+/*-
+ * Copyright (c) 2012 Will DeVries
+ * Copyright (c) 2007, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/buf.h>
+#include <sys/malloc.h>
+
+#include "ecma167-udf.h"
+#include "udf.h"
+#include "udf_subr.h"
+
+
+static int udf_read_phys_sectors(struct udf_mount *ump, int what,
+ void *blob, uint32_t start, uint32_t sectors);
+
+/*
+ * Set of generic descriptor readers and writers and their helper functions.
+ * Descriptors inside `logical space' i.e. inside logically mapped partitions
+ * can never be longer than one logical sector.
+ *
+ * NOTE that these functions *can* be used by the sheduler backends to read
+ * node descriptors too.
+ *
+ * For reading, the size of allocated piece is returned in multiple of sector
+ * size due to udf_calc_udf_malloc_size().
+ */
+int
+udf_read_node(struct udf_node *unode, uint8_t *blob, off_t start, int length)
+{
+ struct vnode *devvp = unode->ump->devvp;
+ struct buf *bp;
+ uint64_t file_size, lsect;
+ int addr_type, exttype, error, icbflags;
+ uint32_t blkinsect, fileblk, fileblkoff, numb, numlsect, sector_size;
+ uint8_t *pos;
+
+ error = 0;
+ sector_size = unode->ump->sector_size;
+ blkinsect = sector_size / DEV_BSIZE;
+
+ if (unode->fe != NULL) {
+ pos = &unode->fe->data[0] + le32toh(unode->fe->l_ea);
+ icbflags = le16toh(unode->fe->icbtag.flags);
+ file_size = le64toh(unode->fe->inf_len);
+ } else {
+ pos = &unode->efe->data[0] + le32toh(unode->efe->l_ea);
+ icbflags = le16toh(unode->efe->icbtag.flags);
+ file_size = le64toh(unode->efe->inf_len);
+ }
+
+ length = min(file_size - start, length);
+ fileblk = start / sector_size;
+ fileblkoff = start % sector_size;
+
+ addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
+ if (addr_type == UDF_ICB_INTERN_ALLOC) {
+ numb = min(length, file_size - fileblkoff);
+ memcpy(blob, pos + fileblkoff, numb);
+ return (error);
+ }
+
+ while (length) {
+ error = udf_bmap_translate(unode, fileblk, &exttype, &lsect,
+ &numlsect);
+ if (error != 0)
+ return (error);
+
+ if (exttype == UDF_TRAN_ZERO) {
+ numb = min(length, sector_size * numlsect - fileblkoff);
+ memset(blob, 0, numb);
+ length -= numb;
+ blob += numb;
+ fileblkoff = 0;
+ } else if (exttype == UDF_TRAN_INTERN)
+ return (EDOOFUS);
+ else {
+ while (numlsect > 0) {
+ error = bread(devvp, lsect * blkinsect,
+ sector_size, NOCRED, &bp);
+ if (error != 0) {
+ if (buf != NULL)
+ brelse(bp);
+ return (error);
+ }
+
+ numb = min(length, sector_size - fileblkoff);
+ bcopy(bp->b_data + fileblkoff, blob, numb);
+ brelse(bp);
+ bp = NULL;
+
+ blob += numb;
+ length -= numb;
+ lsect++;
+ numlsect--;
+ fileblkoff = 0;
+ }
+ }
+
+ fileblk += numlsect;
+ }
+
+ return (0);
+}
+
+/* SYNC reading of n blocks from specified sector */
+static int
+udf_read_phys_sectors(struct udf_mount *ump, int what, void *blob,
+ uint32_t start, uint32_t sectors)
+{
+ struct vnode *devvp = ump->devvp;
+ struct buf *bp;
+ int error = 0;
+ uint32_t blks, sector_size;
+
+ sector_size = ump->sector_size;
+ blks = sector_size / DEV_BSIZE;
+
+ while (sectors > 0 && error == 0) {
+ error = bread(devvp, start * blks, sector_size, NOCRED, &bp);
+ if (error != 0) {
+ if (buf != NULL)
+ brelse(bp);
+ return (error);
+ }
+
+ bcopy(bp->b_data, blob, sector_size);
+ brelse(bp);
+ bp = NULL;
+
+ blob = (void *)((uint8_t *)blob + sector_size);
+ start++;
+ sectors--;
+ }
+
+ return (0);
+}
+
+/* synchronous generic descriptor read */
+int
+udf_read_phys_dscr(struct udf_mount *ump, uint32_t sector,
+ struct malloc_type *mtype, union dscrptr **dstp)
+{
+ union dscrptr *dst, *new_dst;
+ int dscrlen, error, i, sectors, sector_size;
+ uint8_t *pos;
+
+ sector_size = ump->sector_size;
+
+ *dstp = dst = NULL;
+ dscrlen = sector_size;
+
+ /* read initial piece */
+ dst = malloc(sector_size, mtype, M_WAITOK);
+ error = udf_read_phys_sectors(ump, UDF_C_DSCR, dst, sector, 1);
+
+ if (error == 0) {
+ /* check if its a valid tag */
+ error = udf_check_tag(dst);
+ if (error != 0) {
+ /* check if its an empty block */
+ pos = (uint8_t *)dst;
+ for (i = 0; i < sector_size; i++, pos++)
+ if (*pos)
+ break;
+
+ if (i == sector_size) {
+ /* return no error but with no dscrptr */
+ /* dispose first block */
+ free(dst, mtype);
+ return (0);
+ }
+ }
+ /* calculate descriptor size */
+ dscrlen = udf_tagsize(dst, sector_size);
+ }
+
+ if (!error && (dscrlen > sector_size)) {
+ /*
+ * Read the rest of descriptor. Since it is only used at mount
+ * time its overdone to define and use a specific udf_intbreadn
+ * for this alone.
+ */
+
+ new_dst = realloc(dst, dscrlen, mtype, M_WAITOK);
+ if (new_dst == NULL) {
+ free(dst, mtype);
+ return (ENOMEM);
+ }
+ dst = new_dst;
+
+ sectors = (dscrlen + sector_size - 1) / sector_size;
+
+ pos = (uint8_t *)dst + sector_size;
+ error = udf_read_phys_sectors(ump, UDF_C_DSCR, pos, sector + 1,
+ sectors - 1);
+ }
+ if (error == 0)
+ error = udf_check_tag_payload(dst, dscrlen);
+ if (error && dst) {
+ free(dst, mtype);
+ dst = NULL;
+ }
+ *dstp = dst;
+
+ return (error);
+}
--- sys/fs/udf2/udf_subr.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_subr.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,1929 @@
+/*-
+ * Copyright (c) 2012 Will DeVries
+ * Copyright (c) 2006, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+
+#include <sys/cdefs.h>
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/iconv.h>
+
+#include "ecma167-udf.h"
+#include "udf.h"
+#include "udf_subr.h"
+
+#define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
+
+static int udf_leapyear(int year);
+
+/*
+ * Check if the blob starts with a good UDF tag. Tags are protected by a
+ * checksum over the reader except one byte at position 4 that is the checksum
+ * itself.
+ */
+int
+udf_check_tag(void *blob)
+{
+ struct desc_tag *tag = blob;
+ uint8_t cnt, *pos, sum;
+
+ /* check TAG header checksum */
+ pos = (uint8_t *)tag;
+ sum = 0;
+
+ for (cnt = 0; cnt < 16; cnt++) {
+ if (cnt != 4)
+ sum += *pos;
+ pos++;
+ }
+ if (sum != tag->cksum) {
+ /* bad tag header checksum; this is not a valid tag */
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * check tag payload will check descriptor CRC as specified.
+ * If the descriptor is too long, it will return EIO otherwise EINVAL.
+ */
+int
+udf_check_tag_payload(void *blob, uint32_t max_length)
+{
+ struct desc_tag *tag = blob;
+ uint16_t crc, crc_len;
+
+ crc_len = le16toh(tag->desc_crc_len);
+
+ /* check payload CRC if applicable */
+ if (crc_len == 0)
+ return (0);
+
+ if (crc_len > max_length)
+ return (EIO);
+
+ crc = udf_cksum(((uint8_t *)tag) + UDF_DESC_TAG_LENGTH, crc_len);
+ if (crc != le16toh(tag->desc_crc)) {
+ /* bad payload CRC; this is a broken tag */
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+#if 0
+void
+udf_validate_tag_sum(void *blob)
+{
+ struct desc_tag *tag = blob;
+ uint8_t cnt, *pos, sum;
+
+ /* calculate TAG header checksum */
+ pos = (uint8_t *)tag;
+ sum = 0;
+
+ for (cnt = 0; cnt < 16; cnt++) {
+ if (cnt != 4) sum += *pos;
+ pos++;
+ }
+ tag->cksum = sum; /* 8 bit */
+}
+
+/* assumes sector number of descriptor to be saved already present */
+void
+udf_validate_tag_and_crc_sums(void *blob)
+{
+ struct desc_tag *tag = blob;
+ uint16_t crc, crc_len;
+ uint8_t *btag = (uint8_t *)tag;
+
+ crc_len = le16toh(tag->desc_crc_len);
+
+ /* check payload CRC if applicable */
+ if (crc_len > 0) {
+ crc = udf_cksum(btag + UDF_DESC_TAG_LENGTH, crc_len);
+ tag->desc_crc = htole16(crc);
+ }
+
+ /* calculate TAG header checksum */
+ udf_validate_tag_sum(blob);
+}
+#endif
+
+/*
+ * XXX note the different semantics from udfclient: for FIDs it still rounds
+ * up to sectors. Use udf_fidsize() for a correct length.
+ */
+int
+udf_tagsize(union dscrptr *dscr, uint32_t lb_size)
+{
+ uint32_t elmsz, num_lb, size, tag_id;
+
+ tag_id = le16toh(dscr->tag.id);
+
+ switch (tag_id) {
+ case TAGID_LOGVOL:
+ size = sizeof(struct logvol_desc) - 1;
+ size += le32toh(dscr->lvd.mt_l);
+ break;
+ case TAGID_UNALLOC_SPACE:
+ elmsz = sizeof(struct extent_ad);
+ size = sizeof(struct unalloc_sp_desc) - elmsz;
+ size += le32toh(dscr->usd.alloc_desc_num) * elmsz;
+ break;
+ case TAGID_FID:
+ size = UDF_FID_SIZE + dscr->fid.l_fi + le16toh(dscr->fid.l_iu);
+ size = (size + 3) & ~3;
+ break;
+ case TAGID_LOGVOL_INTEGRITY:
+ size = sizeof(struct logvol_int_desc) - sizeof(uint32_t);
+ size += le32toh(dscr->lvid.l_iu);
+ size += (2 * le32toh(dscr->lvid.num_part) * sizeof(uint32_t));
+ break;
+ case TAGID_SPACE_BITMAP:
+ size = sizeof(struct space_bitmap_desc) - 1;
+ size += le32toh(dscr->sbd.num_bytes);
+ break;
+ case TAGID_SPARING_TABLE:
+ elmsz = sizeof(struct spare_map_entry);
+ size = sizeof(struct udf_sparing_table) - elmsz;
+ size += le16toh(dscr->spt.rt_l) * elmsz;
+ break;
+ case TAGID_FENTRY:
+ size = sizeof(struct file_entry);
+ size += le32toh(dscr->fe.l_ea) + le32toh(dscr->fe.l_ad)-1;
+ break;
+ case TAGID_EXTFENTRY:
+ size = sizeof(struct extfile_entry);
+ size += le32toh(dscr->efe.l_ea) + le32toh(dscr->efe.l_ad)-1;
+ break;
+ case TAGID_FSD:
+ size = sizeof(struct fileset_desc);
+ break;
+ default:
+ size = sizeof(union dscrptr);
+ break;
+ }
+
+ if ((size == 0) || (lb_size == 0))
+ return (0);
+
+ if (lb_size == 1)
+ return (size);
+
+ /* round up in sectors */
+ num_lb = (size + lb_size -1) / lb_size;
+
+ return (num_lb * lb_size);
+}
+
+int
+udf_fidsize(struct fileid_desc *fid)
+{
+ uint32_t size;
+
+ if (le16toh(fid->tag.id) != TAGID_FID)
+ panic("got udf_fidsize on non FID\n");
+
+ size = UDF_FID_SIZE + fid->l_fi + le16toh(fid->l_iu);
+ size = (size + 3) & ~3;
+
+ /* We know this value will fit in an int. */
+ return (size);
+}
+
+void
+udf_lock_node(struct udf_node *udf_node, int flag, char const *fname,
+ const int lineno)
+{
+#if 0
+ int ret;
+
+ mutex_enter(&udf_node->node_mutex);
+ /* wait until free */
+ while (udf_node->i_flags & IN_LOCKED) {
+ ret = cv_timedwait(&udf_node->node_lock, &udf_node->node_mutex, hz/8);
+ /* TODO check if we should return error; abort */
+ if (ret == EWOULDBLOCK) {
+ DPRINTF(LOCKING, ( "udf_lock_node: udf_node %p would block "
+ "wanted at %s:%d, previously locked at %s:%d\n",
+ udf_node, fname, lineno,
+ udf_node->lock_fname, udf_node->lock_lineno));
+ }
+ }
+ /* grab */
+ udf_node->i_flags |= IN_LOCKED | flag;
+ /* debug */
+ udf_node->lock_fname = fname;
+ udf_node->lock_lineno = lineno;
+
+ mutex_exit(&udf_node->node_mutex);
+#endif
+}
+
+void
+udf_unlock_node(struct udf_node *udf_node, int flag)
+{
+#if 0
+ mutex_enter(&udf_node->node_mutex);
+ udf_node->i_flags &= ~(IN_LOCKED | flag);
+ cv_broadcast(&udf_node->node_lock);
+ mutex_exit(&udf_node->node_mutex);
+#endif
+}
+
+static int
+udf_read_anchor(struct udf_mount *ump, uint32_t sector, struct anchor_vdp **dst)
+{
+ int error;
+
+ error = udf_read_phys_dscr(ump, sector, M_UDFTEMP,
+ (union dscrptr **)dst);
+ if (error == 0) {
+ /* blank terminator blocks are not allowed here */
+ if (*dst == NULL)
+ return (ENOENT);
+ if (le16toh((*dst)->tag.id) != TAGID_ANCHOR) {
+ error = ENOENT;
+ free(*dst, M_UDFTEMP);
+ *dst = NULL;
+ }
+ }
+
+ return (error);
+}
+
+int
+udf_read_anchors(struct udf_mount *ump)
+{
+ struct anchor_vdp **anchorsp;
+ int first_anchor, anch, error, ok;
+ uint32_t positions[4], session_end, session_start;
+
+ session_start = ump->session_start;
+ session_end = ump->session_end;
+
+ /* read anchors start+256, start+512, end-256, end */
+ positions[0] = session_start + 256;
+ positions[1] = session_end - 256;
+ positions[2] = session_end;
+ /* XXX shouldn't +512 be prefered above +256 for compat with Roxio CD */
+ positions[3] = session_start + 512; /* [UDF 2.60/6.11.2] */
+
+ ok = 0;
+ anchorsp = ump->anchors;
+ first_anchor = 0;
+ if (ump->first_trackblank)
+ first_anchor = 1;
+ for (anch = first_anchor; anch < 4; anch++) {
+ if (positions[anch] <= session_end) {
+ error = udf_read_anchor(ump, positions[anch], anchorsp);
+ if (error == 0) {
+ anchorsp++;
+ ok++;
+ }
+ }
+ }
+
+ return (ok);
+}
+
+/* we dont try to be smart; we just record the parts */
+#define UDF_UPDATE_DSCR(name, dscr) \
+ if (name) \
+ free(name, M_UDFTEMP); \
+ name = dscr;
+
+static int
+udf_process_vds_descriptor(struct udf_mount *ump, union dscrptr *dscr)
+{
+ struct part_desc *part;
+ uint16_t phys_part, raw_phys_part;
+
+ switch (le16toh(dscr->tag.id)) {
+ case TAGID_PRI_VOL: /* primary partition */
+ UDF_UPDATE_DSCR(ump->primary_vol, &dscr->pvd);
+ break;
+ case TAGID_LOGVOL: /* logical volume */
+ UDF_UPDATE_DSCR(ump->logical_vol, &dscr->lvd);
+ break;
+ case TAGID_UNALLOC_SPACE: /* unallocated space */
+ UDF_UPDATE_DSCR(ump->unallocated, &dscr->usd);
+ break;
+ case TAGID_IMP_VOL: /* implementation */
+ /* XXX do we care about multiple impl. descr ? */
+ UDF_UPDATE_DSCR(ump->implementation, &dscr->ivd);
+ break;
+ case TAGID_PARTITION: /* physical partition */
+ /* not much use if its not allocated */
+ if ((le16toh(dscr->pd.flags) & UDF_PART_FLAG_ALLOCATED) == 0) {
+ free(dscr, M_UDFTEMP);
+ break;
+ }
+
+ /*
+ * BUGALERT: some rogue implementations use random physical
+ * partition numbers to break other implementations so lookup
+ * the number.
+ */
+ raw_phys_part = le16toh(dscr->pd.part_num);
+ for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
+ part = ump->partitions[phys_part];
+ if (part == NULL)
+ break;
+ if (le16toh(part->part_num) == raw_phys_part)
+ break;
+ }
+ if (phys_part == UDF_PARTITIONS) {
+ free(dscr, M_UDFTEMP);
+ return (EINVAL);
+ }
+
+ UDF_UPDATE_DSCR(ump->partitions[phys_part], &dscr->pd);
+ break;
+ case TAGID_VOL: /* volume space extender; rare */
+ free(dscr, M_UDFTEMP);
+ break;
+ default:
+ free(dscr, M_UDFTEMP);
+ }
+
+ return (0);
+}
+#undef UDF_UPDATE_DSCR
+
+static int
+udf_read_vds_extent(struct udf_mount *ump, uint32_t loc, uint32_t len)
+{
+ union dscrptr *dscr;
+ int error;
+ uint32_t dscr_size, sector_size;
+
+ sector_size = ump->sector_size;
+
+ /* loc is sectornr, len is in bytes */
+ error = EIO;
+ while (len > 0) {
+ error = udf_read_phys_dscr(ump, loc, M_UDFTEMP, &dscr);
+ if (error != 0) {
+ if (!dscr)
+ free(dscr, M_UDFTEMP);
+ return (error);
+ }
+
+ /* blank block is a terminator */
+ if (dscr == NULL)
+ return (0);
+
+ /* TERM descriptor is a terminator */
+ if (le16toh(dscr->tag.id) == TAGID_TERM) {
+ free(dscr, M_UDFTEMP);
+ return (0);
+ }
+
+ /* process all others */
+ dscr_size = udf_tagsize(dscr, sector_size);
+
+ /* dscr is assigned into ump */
+ error = udf_process_vds_descriptor(ump, dscr);
+ if (error != 0)
+ break;
+
+ len -= dscr_size;
+ loc += dscr_size / sector_size;
+ }
+
+ return (error);
+}
+
+int
+udf_read_vds_space(struct udf_mount *ump)
+{
+ /* struct udf_args *args = &ump->mount_args; */
+ struct anchor_vdp *anchor, *anchor2;
+ size_t size;
+ int error;
+ uint32_t main_len, main_loc, reserve_len, reserve_loc;
+
+ /*
+ * read in VDS space provided by the anchors; if one descriptor read
+ * fails, try the mirror sector.
+ *
+ * check if 2nd anchor is different from 1st; if so, go for 2nd. This
+ * avoids the `compatibility features' of DirectCD that may confuse
+ * stuff completely.
+ */
+
+ anchor = ump->anchors[0];
+ anchor2 = ump->anchors[1];
+
+ if (anchor2) {
+ size = sizeof(struct extent_ad);
+ if (memcmp(&anchor->main_vds_ex, &anchor2->main_vds_ex, size))
+ anchor = anchor2;
+ /* reserve is specified to be a literal copy of main */
+ }
+
+ main_loc = le32toh(anchor->main_vds_ex.loc);
+ main_len = le32toh(anchor->main_vds_ex.len);
+
+ reserve_loc = le32toh(anchor->reserve_vds_ex.loc);
+ reserve_len = le32toh(anchor->reserve_vds_ex.len);
+
+ error = udf_read_vds_extent(ump, main_loc, main_len);
+ if (error != 0) {
+ printf("UDF mount: reading in reserve VDS extent\n");
+ error = udf_read_vds_extent(ump, reserve_loc, reserve_len);
+ }
+
+ return (error);
+}
+
+/*
+ * Read in the logical volume integrity sequence pointed to by our logical
+ * volume descriptor. Its a sequence that can be extended using fields in the
+ * integrity descriptor itself. On sequential media only one is found, on
+ * rewritable media a sequence of descriptors can be found as a form of
+ * history keeping and on non sequential write-once media the chain is vital
+ * to allow more and more descriptors to be written. The last descriptor
+ * written in an extent needs to claim space for a new extent.
+ *
+ * Note: this may not return in the media is malformed.
+ */
+static int
+udf_retrieve_lvint(struct udf_mount *ump)
+{
+ union dscrptr *dscr;
+ struct logvol_int_desc *lvint;
+ int dscr_type, error;
+ uint32_t lbnum, lb_size, len;
+
+ lb_size = le32toh(ump->logical_vol->lb_size);
+ len = le32toh(ump->logical_vol->integrity_seq_loc.len);
+ lbnum = le32toh(ump->logical_vol->integrity_seq_loc.loc);
+
+ lvint = NULL;
+ dscr = NULL;
+ error = 0;
+ while (len > 0) {
+ /* read in our integrity descriptor */
+ error = udf_read_phys_dscr(ump, lbnum, M_UDFTEMP, &dscr);
+ if (error == 0) {
+ if (dscr == NULL)
+ break; /* empty terminates */
+ dscr_type = le16toh(dscr->tag.id);
+ if (dscr_type == TAGID_TERM)
+ break; /* clean terminator */
+ if (dscr_type != TAGID_LOGVOL_INTEGRITY) {
+ printf("UDF mount: Invalid logical volume "
+ "integrity sequence entry found.\n");
+#if 0
+ /* fatal... corrupt disc */
+ error = ENOENT;
+#endif
+ break;
+ }
+ if (lvint)
+ free(lvint, M_UDFTEMP);
+ lvint = &dscr->lvid;
+ dscr = NULL;
+ } /* else hope for the best... maybe the next is ok */
+
+ /* proceed sequential */
+ lbnum += 1;
+ len -= lb_size;
+
+ /* are we linking to a new piece? */
+ if (dscr && lvint->next_extent.len) {
+ len = le32toh(lvint->next_extent.len);
+ lbnum = le32toh(lvint->next_extent.loc);
+ }
+ }
+
+ /* clean up the mess, esp. when there is an error */
+ if (dscr)
+ free(dscr, M_UDFTEMP);
+
+ if (error != 0 && lvint != NULL) {
+ free(lvint, M_UDFTEMP);
+ lvint = NULL;
+ } else if (lvint == NULL) {
+ printf("UDF mount: No logical volume integrity sequence entries"
+ " found.\n");
+ error = ENOENT;
+ }
+
+ ump->logvol_integrity = lvint;
+
+ return (error);
+}
+
+/*
+ * Checks if ump's vds information is correct and complete
+ */
+int
+udf_process_vds(struct udf_mount *ump) {
+ /* struct udf_args *args = &ump->mount_args; */
+ union udf_pmap *mapping;
+ struct logvol_int_desc *lvint;
+ struct part_desc *part;
+ struct udf_logvol_info *lvinfo;
+ int error, log_part, phys_part, pmap_size, pmap_stype, pmap_type;
+ int len, n_meta, n_phys, n_spar, n_virt, raw_phys_part;
+ uint32_t mt_l, n_pm;
+ char *domain_name, *map_name; /* bits[128]; */
+ const char *check_name;
+ uint8_t *pmap_pos;
+
+ /* we need at least one primary and one logical volume descriptor */
+ if ((ump->primary_vol == NULL) || (ump->logical_vol) == NULL)
+ return (EINVAL);
+
+ /* we need at least one partition descriptor */
+ if (ump->partitions[0] == NULL)
+ return (EINVAL);
+
+ /* check logical volume sector size verses device sector size */
+ if (le32toh(ump->logical_vol->lb_size) != ump->sector_size) {
+ printf("UDF mount: format violation, lb_size != sector size\n");
+ return (EINVAL);
+ }
+
+ /* check domain name */
+ domain_name = ump->logical_vol->domain_id.id;
+ if (strncmp(domain_name, "*OSTA UDF Compliant", 20)) {
+ printf("UDF mount: disc not OSTA UDF Compliant, aborting\n");
+ return (EINVAL);
+ }
+
+ /*
+ * We need at least one logvol integrity descriptor recorded. Note
+ * that its OK to have an open logical volume integrity here. The VAT
+ * will close/update the integrity.
+ */
+ error = udf_retrieve_lvint(ump);
+ if (error != 0)
+ return (EINVAL); // previously it always returned this on error.
+
+ /* process derived structures */
+ n_pm = le32toh(ump->logical_vol->n_pm); /* num partmaps */
+ lvint = ump->logvol_integrity;
+ lvinfo = (struct udf_logvol_info *)(&lvint->tables[2 * n_pm]);
+ ump->logvol_info = lvinfo;
+
+ /* TODO check udf versions? */
+
+ /*
+ * check logvol mappings: effective virt->log partmap translation
+ * check and recording of the mapping results. Saves expensive
+ * strncmp() in tight places.
+ */
+ n_pm = le32toh(ump->logical_vol->n_pm); /* num partmaps */
+ mt_l = le32toh(ump->logical_vol->mt_l); /* partmaps data length */
+ pmap_pos = ump->logical_vol->maps;
+
+ if (n_pm > UDF_PMAPS) {
+ printf("UDF mount: too many mappings\n");
+ return (EINVAL);
+ }
+
+ /* count types and set partition numbers */
+ n_phys = n_virt = n_spar = n_meta = 0;
+ for (log_part = 0; log_part < n_pm; log_part++) {
+ mapping = (union udf_pmap *)pmap_pos;
+ pmap_stype = pmap_pos[0];
+ pmap_size = pmap_pos[1];
+
+ switch (pmap_stype) {
+ case 1: /* physical mapping */
+ /* volseq = le16toh(mapping->pm1.vol_seq_num); */
+ raw_phys_part = le16toh(mapping->pm1.part_num);
+ pmap_type = UDF_VTOP_TYPE_PHYS;
+ n_phys++;
+ break;
+ case 2: /* virtual/sparable/meta mapping */
+ map_name = mapping->pm2.part_id.id;
+ /* volseq = le16toh(mapping->pm2.vol_seq_num); */
+ raw_phys_part = le16toh(mapping->pm2.part_num);
+ pmap_type = UDF_VTOP_TYPE_UNKNOWN;
+ len = UDF_REGID_ID_SIZE;
+
+ check_name = "*UDF Virtual Partition";
+ if (strncmp(map_name, check_name, len) == 0) {
+ pmap_type = UDF_VTOP_TYPE_VIRT;
+ n_virt++;
+ break;
+ }
+ check_name = "*UDF Sparable Partition";
+ if (strncmp(map_name, check_name, len) == 0) {
+ pmap_type = UDF_VTOP_TYPE_SPARABLE;
+ n_spar++;
+ break;
+ }
+ check_name = "*UDF Metadata Partition";
+ if (strncmp(map_name, check_name, len) == 0) {
+ pmap_type = UDF_VTOP_TYPE_META;
+ n_meta++;
+ break;
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /*
+ * BUGALERT: some rogue implementations use random physical
+ * partition numbers to break other implementations so lookup
+ * the number.
+ */
+ for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) {
+ part = ump->partitions[phys_part];
+ if (part == NULL)
+ continue;
+ if (le16toh(part->part_num) == raw_phys_part)
+ break;
+ }
+
+ if (phys_part == UDF_PARTITIONS)
+ return (EINVAL);
+ if (pmap_type == UDF_VTOP_TYPE_UNKNOWN)
+ return (EINVAL);
+
+ ump->vtop[log_part] = phys_part;
+ ump->vtop_tp[log_part] = pmap_type;
+
+ pmap_pos += pmap_size;
+ }
+ /* not winning the beauty contest */
+ ump->vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW;
+
+ /* test some basic UDF assertions/requirements */
+ if ((n_virt > 1) || (n_spar > 1) || (n_meta > 1))
+ return (EINVAL);
+
+ if (n_virt) {
+ if ((n_phys == 0) || n_spar || n_meta)
+ return (EINVAL);
+ }
+ if (n_spar + n_phys == 0)
+ return (EINVAL);
+
+ /* signal its OK for now */
+ return (0);
+}
+
+/*
+ * Update logical volume name in all structures that keep a record of it. We
+ * use memmove since each of them might be specified as a source.
+ *
+ * Note that it doesn't update the VAT structure!
+ */
+static void
+udf_update_logvolname(struct udf_mount *ump, char *logvol_id)
+{
+ struct logvol_desc *lvd = NULL;
+ struct fileset_desc *fsd = NULL;
+ struct udf_lv_info *lvi = NULL;
+
+ lvd = ump->logical_vol;
+ fsd = ump->fileset_desc;
+ if (ump->implementation)
+ lvi = &ump->implementation->_impl_use.lv_info;
+
+ /* logvol's id might be specified as origional so use memmove here */
+ memmove(lvd->logvol_id, logvol_id, 128);
+ if (fsd)
+ memmove(fsd->logvol_id, logvol_id, 128);
+ if (lvi)
+ memmove(lvi->logvol_id, logvol_id, 128);
+}
+
+/*
+ * Extended attribute support. UDF knows of 3 places for extended attributes:
+ *
+ * (a) inside the file's (e)fe in the length of the extended attribute area
+ * before the allocation descriptors/filedata
+ *
+ * (b) in a file referenced by (e)fe->ext_attr_icb and
+ *
+ * (c) in the e(fe)'s associated stream directory that can hold various
+ * sub-files. In the stream directory a few fixed named subfiles are reserved
+ * for NT/Unix ACL's and OS/2 attributes.
+ *
+ * NOTE: Extended attributes are read randomly but allways written
+ * *atomicaly*. For ACL's this interface is propably different but not known
+ * to me yet.
+ *
+ * Order of extended attributes in a space :
+ * ECMA 167 EAs
+ * Non block aligned Implementation Use EAs
+ * Block aligned Implementation Use EAs
+ * Application Use EAs
+ */
+
+static int
+udf_impl_extattr_check(struct impl_extattr_entry *implext)
+{
+ uint16_t *spos;
+
+ if (strncmp(implext->imp_id.id, "*UDF", 4) == 0) {
+ /* checksum valid? */
+ spos = (uint16_t *)implext->data;
+ if (le16toh(*spos) != udf_ea_cksum((uint8_t *)implext))
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static void
+udf_calc_impl_extattr_checksum(struct impl_extattr_entry *implext)
+{
+ uint16_t *spos;
+
+ if (strncmp(implext->imp_id.id, "*UDF", 4) == 0) {
+ /* set checksum */
+ spos = (uint16_t *)implext->data;
+ *spos = le16toh(udf_ea_cksum((uint8_t *)implext));
+ }
+}
+
+int
+udf_extattr_search_intern(struct udf_node *node, uint32_t sattr,
+ char const *sattrname, uint32_t *offsetp, uint32_t *lengthp)
+{
+ struct extattrhdr_desc *eahdr;
+ struct extattr_entry *attrhdr;
+ struct impl_extattr_entry *implext;
+ int error;
+ int32_t l_ea;
+ uint32_t a_l, offset, sector_size;
+ uint8_t *pos;
+
+ /* get mountpoint */
+ sector_size = node->ump->sector_size;
+
+ /* get information from fe/efe */
+ if (node->fe != NULL) {
+ l_ea = le32toh(node->fe->l_ea);
+ eahdr = (struct extattrhdr_desc *) node->fe->data;
+ } else {
+ l_ea = le32toh(node->efe->l_ea);
+ eahdr = (struct extattrhdr_desc *) node->efe->data;
+ }
+
+ /* something recorded here? */
+ if (l_ea == 0)
+ return (ENOENT);
+
+ /* check extended attribute tag; what to do if it fails? */
+ error = udf_check_tag(eahdr);
+ if (error != 0)
+ return (EINVAL);
+ if (le16toh(eahdr->tag.id) != TAGID_EXTATTR_HDR)
+ return (EINVAL);
+ error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc));
+ if (error != 0)
+ return (EINVAL);
+
+ /* looking for Ecma-167 attributes? */
+ offset = sizeof(struct extattrhdr_desc);
+
+ /* looking for either implemenation use or application use */
+ if (sattr == 2048) { /* [4/48.10.8] */
+ offset = le32toh(eahdr->impl_attr_loc);
+ if (offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT)
+ return (ENOENT);
+ }
+ if (sattr == 65536) { /* [4/48.10.9] */
+ offset = le32toh(eahdr->appl_attr_loc);
+ if (offset == UDF_APPL_ATTR_LOC_NOT_PRESENT)
+ return (ENOENT);
+ }
+
+ /* paranoia check offset and l_ea */
+ if (l_ea + offset >= sector_size - sizeof(struct extattr_entry))
+ return (EINVAL);
+
+ /* find our extended attribute */
+ l_ea -= offset;
+ pos = (uint8_t *)eahdr + offset;
+
+ while (l_ea >= sizeof(struct extattr_entry)) {
+ attrhdr = (struct extattr_entry *)pos;
+ implext = (struct impl_extattr_entry *)pos;
+
+ /* get complete attribute length and check for roque values */
+ a_l = le32toh(attrhdr->a_l);
+ if ((a_l == 0) || (a_l > l_ea))
+ return (EINVAL);
+
+ if (attrhdr->type != sattr)
+ goto next_attribute;
+
+ /* we might have found it! */
+ if (attrhdr->type < 2048) { /* Ecma-167 attribute */
+ *offsetp = offset;
+ *lengthp = a_l;
+ return (0); /* success */
+ }
+
+ /*
+ * Implementation use and application use extended attributes
+ * have a name to identify. They share the same structure only
+ * UDF implementation use extended attributes have a checksum
+ * we need to check
+ */
+
+ if (strcmp(implext->imp_id.id, sattrname) == 0) {
+ /* we have found our appl/implementation attribute */
+ *offsetp = offset;
+ *lengthp = a_l;
+ return (0); /* success */
+ }
+
+next_attribute:
+ /* next attribute */
+ pos += a_l;
+ l_ea -= a_l;
+ offset += a_l;
+ }
+ /* not found */
+ return (ENOENT);
+}
+
+static int
+udf_update_lvid_from_vat_extattr(struct udf_node *vat_node)
+{
+ struct impl_extattr_entry *implext;
+ struct vatlvext_extattr_entry lvext;
+ struct udf_mount *ump;
+ struct udf_logvol_info *lvinfo;
+ uint64_t vat_uniqueid;
+ int error;
+ uint32_t a_l, offset;
+ const char *extstr = "*UDF VAT LVExtension";
+ uint8_t *ea_start, *lvextpos;
+
+ /* get mountpoint and lvinfo */
+ ump = vat_node->ump;
+ lvinfo = ump->logvol_info;
+
+ /* get information from fe/efe */
+ if (vat_node->fe != NULL) {
+ vat_uniqueid = le64toh(vat_node->fe->unique_id);
+ ea_start = vat_node->fe->data;
+ } else {
+ vat_uniqueid = le64toh(vat_node->efe->unique_id);
+ ea_start = vat_node->efe->data;
+ }
+
+ error = udf_extattr_search_intern(vat_node, 2048, extstr, &offset,
+ &a_l);
+ if (error !=0)
+ return (error);
+
+ implext = (struct impl_extattr_entry *)(ea_start + offset);
+ error = udf_impl_extattr_check(implext);
+ if (error != 0)
+ return (error);
+
+ /* paranoia */
+ if (a_l != sizeof(*implext) - 1 + le32toh(implext->iu_l) +
+ sizeof(lvext))
+ return (EINVAL);
+
+ /*
+ * we have found our "VAT LVExtension attribute. BUT due to a
+ * bug in the specification it might not be word aligned so
+ * copy first to avoid panics on some machines (!!)
+ */
+ lvextpos = implext->data + le32toh(implext->iu_l);
+ memcpy(&lvext, lvextpos, sizeof(lvext));
+
+ /* check if it was updated the last time */
+ if (le64toh(lvext.unique_id_chk) == vat_uniqueid) {
+ lvinfo->num_files = lvext.num_files;
+ lvinfo->num_directories = lvext.num_directories;
+ udf_update_logvolname(ump, lvext.logvol_id);
+ } else {
+ /* replace VAT LVExt by free space EA */
+ memset(implext->imp_id.id, 0, UDF_REGID_ID_SIZE);
+ strcpy(implext->imp_id.id, "*UDF FreeEASpace");
+ udf_calc_impl_extattr_checksum(implext);
+ }
+
+ return (0);
+}
+
+int
+udf_vat_read(struct udf_mount *ump, uint8_t *blob, int size,
+ uint32_t offset)
+{
+/* mutex_enter(&ump->allocate_mutex); */
+ if (offset + size > ump->vat_offset + ump->vat_entries * 4)
+ return (EINVAL);
+ memcpy(blob, ump->vat_table + offset, size);
+/* mutex_exit(&ump->allocate_mutex); */
+
+ return (0);
+}
+
+/*
+ * Read in relevant pieces of VAT file and check if its indeed a VAT file
+ * descriptor. If OK, read in complete VAT file.
+ */
+
+static int
+udf_check_for_vat(struct udf_node *vat_node)
+{
+ struct udf_mount *ump;
+ struct icb_tag *icbtag;
+ struct timestamp *mtime;
+ struct udf_vat *vat;
+ struct udf_oldvat_tail *oldvat_tl;
+ struct udf_logvol_info *lvinfo;
+ uint64_t unique_id;
+ int error, filetype;
+ uint32_t vat_entries, vat_length, vat_offset, vat_table_alloc_len;
+ uint32_t *raw_vat, sector_size;
+ char *regid_name;
+ uint8_t *vat_table;
+
+ /* vat_length is really 64 bits though impossible */
+
+ if (vat_node == NULL)
+ return (ENOENT);
+
+ /* get mount info */
+ ump = vat_node->ump;
+ sector_size = le32toh(ump->logical_vol->lb_size);
+
+ /* get information from fe/efe */
+ if (vat_node->fe != NULL) {
+ vat_length = le64toh(vat_node->fe->inf_len);
+ icbtag = &vat_node->fe->icbtag;
+ mtime = &vat_node->fe->mtime;
+ unique_id = le64toh(vat_node->fe->unique_id);
+ } else {
+ vat_length = le64toh(vat_node->efe->inf_len);
+ icbtag = &vat_node->efe->icbtag;
+ mtime = &vat_node->efe->mtime;
+ unique_id = le64toh(vat_node->efe->unique_id);
+ }
+
+ /* Check icb filetype! it has to be 0 or UDF_ICB_FILETYPE_VAT */
+ filetype = icbtag->file_type;
+ if ((filetype != 0) && (filetype != UDF_ICB_FILETYPE_VAT))
+ return (ENOENT);
+
+ vat_table_alloc_len =
+ ((vat_length + UDF_VAT_CHUNKSIZE - 1) / UDF_VAT_CHUNKSIZE)
+ * UDF_VAT_CHUNKSIZE;
+
+ if (vat_table_alloc_len > UDF_VAT_ALLOC_LIMIT) {
+ printf("UDF mount: VAT table length of %d bytes exceeds "
+ "implementation limit.\n", vat_table_alloc_len);
+ return (ENOMEM);
+ }
+ vat_table = malloc(vat_table_alloc_len, M_UDFTEMP, M_WAITOK);
+
+ /* allocate piece to read in head or tail of VAT file */
+ raw_vat = malloc(sector_size, M_UDFTEMP, M_WAITOK);
+
+ /*
+ * check contents of the file if its the old 1.50 VAT table format.
+ * Its notoriously broken and allthough some implementations support an
+ * extention as defined in the UDF 1.50 errata document, its doubtfull
+ * to be useable since a lot of implementations don't maintain it.
+ */
+ lvinfo = ump->logvol_info;
+
+ if (filetype == 0) {
+ /* definition */
+ vat_offset = 0;
+ vat_entries = (vat_length - 36) / 4;
+
+ /* read in tail of virtual allocation table file */
+ error = udf_read_node(vat_node, (uint8_t *)raw_vat,
+ vat_entries * 4, sizeof(struct udf_oldvat_tail));
+ if (error != 0)
+ goto out;
+
+ /* check 1.50 VAT */
+ oldvat_tl = (struct udf_oldvat_tail *)raw_vat;
+ regid_name = (char *)oldvat_tl->id.id;
+ error = strncmp(regid_name, "*UDF Virtual Alloc Tbl", 22);
+ if (error != 0) {
+ error = ENOENT;
+ goto out;
+ }
+
+ /*
+ * update LVID from "*UDF VAT LVExtension" extended attribute
+ * if present.
+ */
+ udf_update_lvid_from_vat_extattr(vat_node);
+ } else {
+ /* read in head of virtual allocation table file */
+ error = udf_read_node(vat_node, (uint8_t *)raw_vat, 0,
+ sizeof(struct udf_vat));
+ if (error != 0)
+ goto out;
+
+ /* definition */
+ vat = (struct udf_vat *)raw_vat;
+ vat_offset = vat->header_len;
+ vat_entries = (vat_length - vat_offset) / 4;
+
+ lvinfo->num_files = vat->num_files;
+ lvinfo->num_directories = vat->num_directories;
+ lvinfo->min_udf_readver = vat->min_udf_readver;
+ lvinfo->min_udf_writever = vat->min_udf_writever;
+ lvinfo->max_udf_writever = vat->max_udf_writever;
+
+ udf_update_logvolname(ump, vat->logvol_id);
+ }
+
+ /* read in complete VAT file */
+ error = udf_read_node(vat_node, vat_table, 0, vat_length);
+ if (error != 0)
+ printf("UDF mount: Error reading in of complete VAT file."
+ " (error %d)\n", error);
+ if (error != 0)
+ goto out;
+
+ ump->logvol_integrity->lvint_next_unique_id = htole64(unique_id);
+ ump->logvol_integrity->integrity_type = htole32(UDF_INTEGRITY_CLOSED);
+ ump->logvol_integrity->time = *mtime;
+
+ ump->vat_table_alloc_len = vat_table_alloc_len;
+ ump->vat_table = vat_table;
+ ump->vat_offset = vat_offset;
+ ump->vat_entries = vat_entries;
+
+out:
+ if (error != 0) {
+ if (vat_table != NULL)
+ free(vat_table, M_UDFTEMP);
+ }
+ free(raw_vat, M_UDFTEMP);
+
+ return (error);
+}
+
+static int
+udf_search_vat(struct udf_mount *ump)
+{
+ union dscrptr *dscr;
+ struct long_ad icb_loc;
+ struct udf_node *vat_node;
+ int error;
+ uint32_t early_vat_loc, vat_loc;
+ uint16_t tagid;
+ uint8_t file_type;
+
+ vat_node = NULL;
+
+ early_vat_loc = ump->first_possible_vat_location;
+ vat_loc = ump->last_possible_vat_location;
+
+ /* start looking from the end of the range */
+ do {
+ error = udf_read_phys_dscr(ump, vat_loc, M_UDFTEMP, &dscr);
+ if (!error && dscr) { /* dscr will be null if zeros were read */
+ tagid = le16toh(dscr->tag.id);
+ file_type = 0;
+ if (tagid == TAGID_FENTRY)
+ file_type = dscr->fe.icbtag.file_type;
+ else if (tagid == TAGID_EXTFENTRY)
+ file_type = dscr->efe.icbtag.file_type;
+ free(dscr, M_UDFTEMP);
+
+ if (file_type == 248)
+ {
+ icb_loc.loc.part_num =
+ htole16(UDF_VTOP_RAWPART);
+ icb_loc.loc.lb_num = htole32(vat_loc);
+ error = udf_get_node(ump, icb_loc, &vat_node);
+ if (error == 0)
+ error = udf_check_for_vat(vat_node);
+ if (error == 0) {
+ udf_dispose_node(vat_node);
+ break;
+ }
+ }
+ }
+
+ if (vat_node != NULL) {
+ udf_dispose_node(vat_node);
+ vat_node = NULL;
+ }
+
+ if (vat_loc == ump->last_possible_vat_location)
+ printf("UDF mount: VAT not found at last written "
+ "location\n");
+
+ vat_loc--;
+ } while (vat_loc >= early_vat_loc);
+
+ return (error);
+}
+
+static int
+udf_read_sparables(struct udf_mount *ump, union udf_pmap *mapping)
+{
+ union dscrptr *dscr;
+ struct part_map_spare *pms = &mapping->pms;
+ int error, spar;
+ uint32_t lb_num;
+
+ /*
+ * The partition mapping passed on to us specifies the information we
+ * need to locate and initialise the sparable partition mapping
+ * information we need.
+ */
+
+ ump->sparable_packet_size = le16toh(pms->packet_len);
+
+ for (spar = 0; spar < pms->n_st; spar++) {
+ lb_num = pms->st_loc[spar];
+ error = udf_read_phys_dscr(ump, lb_num, M_UDFTEMP, &dscr);
+ if (!error && dscr) {
+ if (le16toh(dscr->tag.id) == TAGID_SPARING_TABLE) {
+ if (ump->sparing_table)
+ free(ump->sparing_table, M_UDFTEMP);
+ ump->sparing_table = &dscr->spt;
+ dscr = NULL;
+ break; /* we're done */
+ }
+ }
+ if (dscr)
+ free(dscr, M_UDFTEMP);
+ }
+
+ if (ump->sparing_table)
+ return (0);
+
+ return (ENOENT);
+}
+
+static int
+udf_read_metadata_nodes(struct udf_mount *ump, union udf_pmap *mapping)
+{
+ struct part_map_meta *pmm = &mapping->pmm;
+ struct long_ad icb_loc;
+ int error = 0;
+ char *windows_id = "*Microsoft Windows";
+
+ /*
+ * The mappings come from the logical volume descripor, and Windows does
+ * not write a usable partion number into the metadata map descriptor.
+ */
+ if (strncmp(windows_id, ump->logical_vol->imp_id.id, 23) == 0)
+ icb_loc.loc.part_num = 0;
+ else
+ icb_loc.loc.part_num = pmm->part_num;
+
+ icb_loc.loc.lb_num = pmm->meta_file_lbn;
+ udf_get_node(ump, icb_loc, &ump->metadata_node);
+
+ if (ump->metadata_node == NULL) {
+ icb_loc.loc.lb_num = pmm->meta_mirror_file_lbn;
+ if (icb_loc.loc.lb_num != -1)
+ udf_get_node(ump, icb_loc, &ump->metadata_node);
+
+ if (ump->metadata_node != NULL)
+ printf("UDF mount: Metadata file not readable, "
+ "substituting Metadata copy file\n");
+ }
+
+ /* if we're mounting read-only we relax the requirements */
+ if (ump->metadata_node == NULL)
+ error = EFAULT;
+
+ return (error);
+}
+
+int
+udf_read_vds_tables(struct udf_mount *ump)
+{
+ union udf_pmap *mapping;
+ int pmap_size, error;
+ uint32_t log_part, mt_l, n_pm;
+ uint8_t *pmap_pos;
+
+ error = 0;
+
+ /* Iterate (again) over the part mappings for locations */
+ n_pm = le32toh(ump->logical_vol->n_pm); /* num partmaps */
+ mt_l = le32toh(ump->logical_vol->mt_l); /* partmaps data length */
+ pmap_pos = ump->logical_vol->maps;
+
+ for (log_part = 0; log_part < n_pm; log_part++) {
+ mapping = (union udf_pmap *) pmap_pos;
+ switch (ump->vtop_tp[log_part]) {
+ case UDF_VTOP_TYPE_PHYS:
+ /* nothing */
+ break;
+ case UDF_VTOP_TYPE_VIRT:
+ /* search and load VAT */
+ error = udf_search_vat(ump);
+ if (error != 0)
+ return (ENOENT);
+ break;
+ case UDF_VTOP_TYPE_SPARABLE:
+ /* load one of the sparable tables */
+ error = udf_read_sparables(ump, mapping);
+ if (error != 0)
+ return (ENOENT);
+ break;
+ case UDF_VTOP_TYPE_META:
+ /* load the associated file descriptors */
+ error = udf_read_metadata_nodes(ump, mapping);
+ if (error != 0)
+ return (ENOENT);
+ break;
+ default:
+ break;
+ }
+ pmap_size = pmap_pos[1];
+ pmap_pos += pmap_size;
+ }
+
+ return (0);
+}
+
+int
+udf_read_rootdirs(struct udf_mount *ump)
+{
+ union dscrptr *dscr;
+ struct mount *mp;
+ struct vnode *rootdir_node, *streamdir_node;
+ struct long_ad *dir_loc, fsd_loc;
+ ino_t ino;
+ int dscr_type, error;
+ uint32_t dummy, fsd_len, lb_num;
+
+ mp = ump->vfs_mountp;
+
+ /* TODO implement FSD reading in separate function like integrity? */
+ /* get fileset descriptor sequence */
+ fsd_loc = ump->logical_vol->lv_fsd_loc;
+ fsd_len = le32toh(fsd_loc.len);
+
+ dscr = NULL;
+ error = 0;
+ while (fsd_len > 0 || error != 0) {
+ /* translate fsd_loc to lb_num */
+ error = udf_translate_vtop(ump, &fsd_loc, &lb_num, &dummy);
+ if (error != 0)
+ break;
+ error = udf_read_phys_dscr(ump, lb_num, M_UDFTEMP, &dscr);
+ /* end markers */
+ if (error != 0 || dscr == NULL)
+ break;
+
+ /* analyse */
+ dscr_type = le16toh(dscr->tag.id);
+ if (dscr_type == TAGID_TERM)
+ break;
+ if (dscr_type != TAGID_FSD) {
+ free(dscr, M_UDFTEMP);
+ return (ENOENT);
+ }
+
+ /*
+ * TODO check for multiple fileset descriptors; its only
+ * picking the last now. Also check for FSD
+ * correctness/interpretability
+ */
+
+ /* update */
+ if (ump->fileset_desc != NULL) {
+ free(ump->fileset_desc, M_UDFTEMP);
+ }
+ ump->fileset_desc = &dscr->fsd;
+ dscr = NULL;
+
+ /* continue to the next fsd */
+ fsd_len -= ump->sector_size;
+ fsd_loc.loc.lb_num = htole32(le32toh(fsd_loc.loc.lb_num) + 1);
+
+ /* follow up to fsd->next_ex (long_ad) if its not null */
+ if (le32toh(ump->fileset_desc->next_ex.len)) {
+ fsd_loc = ump->fileset_desc->next_ex;
+ fsd_len = le32toh(ump->fileset_desc->next_ex.len);
+ }
+ }
+ if (dscr != NULL)
+ free(dscr, M_UDFTEMP);
+
+ /* there has to be one */
+ if (ump->fileset_desc == NULL)
+ return (ENOENT);
+
+ udf_update_logvolname(ump, ump->logical_vol->logvol_id);
+
+ /*
+ * Now the FSD is known, read in the rootdirectory and if one exists,
+ * the system stream dir. Some files in the system streamdir are not
+ * wanted in this implementation since they are not maintained. If
+ * writing is enabled we'll delete these files if they exist.
+ */
+
+ rootdir_node = streamdir_node = NULL;
+ dir_loc = NULL;
+
+ /* try to read in the rootdir */
+ dir_loc = &ump->fileset_desc->rootdir_icb;
+ error = udf_get_node_id(*dir_loc, &ino);
+ if (error == 0)
+ error = udf_vget(mp, ino, LK_EXCLUSIVE, &rootdir_node);
+ if (error != 0)
+ return (ENOENT);
+
+ /*
+ * Try the system stream directory; not very likely in the ones we
+ * test, but for completeness.
+ */
+ dir_loc = &ump->fileset_desc->streamdir_icb;
+ if (le32toh(dir_loc->len)) {
+ error = udf_get_node_id(*dir_loc, &ino);
+ if (error == 0)
+ error = udf_vget(mp, ino, LK_EXCLUSIVE,
+ &streamdir_node);
+ if (error != 0)
+ printf("UDF mount: streamdir defined but error in "
+ "streamdir reading\n");
+#if 0
+ else {
+ printf("UDF mount: streamdir defined but ignored\n");
+ /*
+ * TODO process streamdir `baddies' i.e. files we dont
+ * want if R/W
+ */
+ }
+#endif
+ }
+
+ /* release the vnodes again; they'll be auto-recycled later */
+ if (streamdir_node != NULL) {
+ /* This is not used later. */
+ vgone(streamdir_node);
+ vput(streamdir_node);
+ }
+ if (rootdir_node != NULL) {
+ /* Vnodes are not initialized correctly until mounting is
+ complete. */
+ vgone(rootdir_node);
+ vput(rootdir_node);
+ }
+
+ return (0);
+}
+
+/*
+ * To make absolutely sure we are NOT returning zero, add one. This can fail,
+ * but in final version should probably never fail.
+ */
+int
+udf_get_node_id(const struct long_ad icbptr, ino_t *ino)
+{
+ uint32_t blkn;
+ uint16_t part;
+
+ /* Just for now, this should be done in another way. */
+ blkn = le32toh(icbptr.loc.lb_num);
+ part = le16toh(icbptr.loc.part_num);
+
+ if ((blkn + 1) & 0xE0000000) {
+ printf("UDF: Block number too large to convert to inode "
+ "number.\n");
+ return EDOOFUS;
+ }
+ if (part & 0xFFF8) {
+ printf("UDF: Partition number too large to convert to inode "
+ "number.\n");
+ return EDOOFUS;
+ }
+
+ *ino = (blkn + 1) | (part << 29);
+
+ return (0);
+}
+
+void
+udf_get_node_longad(const ino_t ino, struct long_ad *icbptr)
+{
+ uint32_t blkn, ino2;
+ uint16_t part;
+
+ /* Just for now, this should be done in another way. */
+ ino2 = ino;
+ blkn = (ino2 & 0x1FFFFFFF) - 1;
+ part = (ino2 & 0xE0000000) >> 29;
+
+ icbptr->loc.lb_num = htole32(blkn);
+ icbptr->loc.part_num = htole16(part);
+}
+
+/* UDF<->unix converters */
+
+static mode_t
+udf_perm_to_unix_mode(uint32_t perm)
+{
+ mode_t mode;
+
+ mode = ((perm & UDF_FENTRY_PERM_USER_MASK));
+ mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
+ mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
+
+ return (mode);
+}
+
+static uint32_t
+udf_icb_to_unix_filetype(uint32_t icbftype)
+{
+ switch (icbftype) {
+ case UDF_ICB_FILETYPE_DIRECTORY:
+ case UDF_ICB_FILETYPE_STREAMDIR:
+ return (S_IFDIR);
+ case UDF_ICB_FILETYPE_FIFO:
+ return (S_IFIFO);
+ case UDF_ICB_FILETYPE_CHARDEVICE:
+ return (S_IFCHR);
+ case UDF_ICB_FILETYPE_BLOCKDEVICE:
+ return (S_IFBLK);
+ case UDF_ICB_FILETYPE_RANDOMACCESS:
+ case UDF_ICB_FILETYPE_REALTIME:
+ return (S_IFREG);
+ case UDF_ICB_FILETYPE_SYMLINK:
+ return (S_IFLNK);
+ case UDF_ICB_FILETYPE_SOCKET:
+ return (S_IFSOCK);
+ }
+ /* no idea what this is */
+ return (0);
+}
+
+/* These timestamp_to_timespec functions are done. */
+
+static int
+udf_leapyear(int year)
+{
+ int i;
+
+ i = (year % 400 == 0) ? 1 : 0;
+ i |= (year % 100 == 0) ? 0 : 1;
+ i &= (year % 4 == 0) ? 1 : 0;
+
+ return (i);
+}
+
+void
+udf_timestamp_to_timespec(struct udf_mount *ump,
+ struct timestamp *timestamp,
+ struct timespec *timespec)
+{
+ time_t secs;
+ const int days_to_mon[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243,
+ 273, 304, 334};
+ uint32_t nsecs, usecs;
+ uint16_t tz, year;
+
+ year = le16toh(timestamp->year);
+ if (year < 1970 || timestamp->month < 1 || timestamp->month > 12) {
+ timespec->tv_sec = 0;
+ timespec->tv_nsec = 0;
+ return;
+ }
+
+ secs = timestamp->second;
+ secs += timestamp->minute * 60;
+ secs += timestamp->hour * 3600;
+ secs += (timestamp->day - 1) * 3600 * 24;
+ secs += days_to_mon[timestamp->month - 1] * 3600 * 24;
+
+ secs += (year - 1970) * 365 * 3600 * 24;
+ secs += ((year - 1 - 1968) / 4) * 3600 * 24;
+
+ if (year > 2100) {
+ secs -= (((year - 1 - 2100) / 100) + 1) * 3600 * 24;
+ }
+ if (year > 2400) {
+ secs += (((year - 1 - 2400) / 400) + 1) * 3600 * 24;
+ }
+ if (timestamp->month > 2) {
+ secs += (time_t)udf_leapyear(year) * 3600 * 24;
+ }
+
+ usecs = timestamp->usec + 100 * timestamp->hund_usec +
+ 10000 * timestamp->centisec;
+ nsecs = usecs * 1000;
+
+ /*
+ * Calculate the time zone. The timezone is 12 bit signed 2's
+ * compliment, so we gotta do some extra magic to handle it right.
+ */
+ tz = le16toh(timestamp->type_tz);
+ tz &= 0x0fff; /* only lower 12 bits are significant */
+ if (tz & 0x0800) /* sign extention */
+ tz |= 0xf000;
+
+ /*
+ * TODO check timezone conversion
+ * check if we are specified a timezone to convert
+ */
+ if (le16toh(timestamp->type_tz) & 0x1000) {
+ if ((int16_t)tz != -2047)
+ secs -= (int16_t)tz * 60;
+ } /* else {
+ secs -= ump->mount_args.gmtoff;
+ } */
+
+ timespec->tv_sec = secs;
+ timespec->tv_nsec = nsecs;
+}
+
+/*
+ * Attribute and filetypes converters with get/set pairs
+ */
+
+uint32_t
+udf_getaccessmode(struct udf_node *udf_node)
+{
+ struct file_entry *fe = udf_node->fe;
+ struct extfile_entry *efe = udf_node->efe;
+ uint32_t ftype, icbftype, mode, udf_perm;
+ uint16_t icbflags;
+
+ UDF_LOCK_NODE(udf_node, 0);
+
+ if (fe != NULL) {
+ udf_perm = le32toh(fe->perm);
+ icbftype = fe->icbtag.file_type;
+ icbflags = le16toh(fe->icbtag.flags);
+ } else {
+ /*assert(udf_node->efe != NULL); */
+ udf_perm = le32toh(efe->perm);
+ icbftype = efe->icbtag.file_type;
+ icbflags = le16toh(efe->icbtag.flags);
+ }
+
+ mode = udf_perm_to_unix_mode(udf_perm);
+ ftype = udf_icb_to_unix_filetype(icbftype);
+
+ /* set suid, sgid, sticky from flags in fe/efe */
+ if (icbflags & UDF_ICB_TAG_FLAGS_SETUID)
+ mode |= S_ISUID;
+ if (icbflags & UDF_ICB_TAG_FLAGS_SETGID)
+ mode |= S_ISGID;
+ if (icbflags & UDF_ICB_TAG_FLAGS_STICKY)
+ mode |= S_ISVTX;
+
+ UDF_UNLOCK_NODE(udf_node, 0);
+
+ return (mode | ftype);
+}
+
+/*
+ * Each node can have an attached streamdir node though not recursively. These
+ * are otherwise known as named substreams/named extended attributes that have
+ * no size limitations.
+ *
+ * `Normal' extended attributes are indicated with a number and are recorded
+ * in either the fe/efe descriptor itself for small descriptors or recorded in
+ * the attached extended attribute file. Since these spaces can get
+ * fragmented, care ought to be taken.
+ *
+ * Since the size of the space reserved for allocation descriptors is limited,
+ * there is a mechanim provided for extending this space; this is done by a
+ * special extent to allow schrinking of the allocations without breaking the
+ * linkage to the allocation extent descriptor.
+ */
+
+int
+udf_get_node(struct udf_mount *ump, struct long_ad icb_loc,
+ struct udf_node **ppunode)
+{
+ union dscrptr *dscr;
+ struct long_ad last_fe_icb_loc;
+ struct udf_node *udf_node;
+ uint64_t file_size;
+ int dscr_type, eof, error, slot, strat, strat4096;
+ uint32_t dummy, lb_size, sector;
+ uint8_t *file_data;
+
+ /* garbage check: translate udf_node_icb_loc to sectornr */
+ error = udf_translate_vtop(ump, &icb_loc, &sector, &dummy);
+ if (error != 0)
+ return (EINVAL);
+
+ /* initialise crosslinks, note location of fe/efe for hashing */
+ udf_node = udf_alloc_node();
+ udf_node->ump = ump;
+ udf_node->loc = icb_loc;
+/* mutex_init(&udf_node->node_mutex, MUTEX_DEFAULT, IPL_NONE); */
+/* cv_init(&udf_node->node_lock, "udf_nlk"); */
+
+ /* safe to unlock, the entry is in the hash table, vnode is locked */
+/* mutex_exit(&ump->get_node_lock); */
+
+ strat4096 = 0;
+ file_size = 0;
+ file_data = NULL;
+ lb_size = le32toh(ump->logical_vol->lb_size);
+
+ do {
+ /* try to read in fe/efe */
+ error = udf_translate_vtop(ump, &icb_loc, &sector, &dummy);
+ if (error == 0)
+ error = udf_read_phys_dscr(ump, sector, M_UDFTEMP,
+ &dscr);
+
+ /* blank sector marks end of sequence, check this */
+ if (dscr == NULL && strat4096 == 0)
+ error = ENOENT;
+
+ /* break if read error or blank sector */
+ if (error != 0 || dscr == NULL)
+ break;
+
+ /* process descriptor based on the descriptor type */
+ dscr_type = le16toh(dscr->tag.id);
+
+ /* if dealing with an indirect entry, follow the link */
+ if (dscr_type == TAGID_INDIRECTENTRY) {
+ free(dscr, M_UDFTEMP);
+ icb_loc = dscr->inde.indirect_icb;
+ continue;
+ }
+
+ /* only file entries and extended file entries allowed here */
+ if ((dscr_type != TAGID_FENTRY) &&
+ (dscr_type != TAGID_EXTFENTRY)) {
+ free(dscr, M_UDFTEMP);
+ error = ENOENT;
+ break;
+ }
+
+ /* choose this one */
+ last_fe_icb_loc = icb_loc;
+
+ /* record and process/update (ext)fentry */
+ file_data = NULL;
+ if (dscr_type == TAGID_FENTRY) {
+ if (udf_node->fe != NULL)
+ free(udf_node->fe, M_UDFTEMP);
+ udf_node->fe = &dscr->fe;
+ strat = le16toh(udf_node->fe->icbtag.strat_type);
+ file_size = le64toh(udf_node->fe->inf_len);
+ file_data = udf_node->fe->data;
+ } else {
+ if (udf_node->efe != NULL)
+ free(udf_node->efe, M_UDFTEMP);
+ udf_node->efe = &dscr->efe;
+ strat = le16toh(udf_node->efe->icbtag.strat_type);
+ file_size = le64toh(udf_node->efe->inf_len);
+ file_data = udf_node->efe->data;
+ }
+
+ /* check recording strategy (structure) */
+
+ /*
+ * Strategy 4096 is a daisy linked chain terminating with an
+ * unrecorded sector or a TERM descriptor. The next
+ * descriptor is to be found in the sector that follows the
+ * current sector.
+ */
+ if (strat == 4096) {
+ strat4096 = 1;
+ icb_loc.loc.lb_num = le32toh(icb_loc.loc.lb_num) + 1;
+ }
+
+ /*
+ * Strategy 4 is the normal strategy and terminates, but if
+ * we're in strategy 4096, we can't have strategy 4 mixed in
+ */
+
+ if (strat == 4) {
+ if (strat4096 != 0) {
+ error = EINVAL;
+ break;
+ }
+ break; /* done */
+ }
+ } while (!error);
+
+ /* first round of cleanup code */
+ if (error != 0) {
+ udf_dispose_node(udf_node);
+ return (EINVAL);
+ }
+
+ /*
+ * Go trough all allocations extents of this descriptor and when
+ * encountering a redirect read in the allocation extension. These are
+ * daisy-chained.
+ */
+ UDF_LOCK_NODE(udf_node, 0);
+ udf_node->num_extensions = 0;
+
+ error = 0;
+ slot = 0;
+ for (;;) {
+ udf_get_adslot(udf_node, slot, &icb_loc, &eof);
+ if (eof != 0)
+ break;
+ slot++;
+
+ if (UDF_EXT_FLAGS(le32toh(icb_loc.len)) != UDF_EXT_REDIRECT)
+ continue;
+
+ if (udf_node->num_extensions >= UDF_MAX_ALLOC_EXTENTS) {
+ error = EINVAL;
+ break;
+ }
+
+ /* length can only be *one* lb : UDF 2.50/2.3.7.1 */
+ if (UDF_EXT_LEN(le32toh(icb_loc.len)) != lb_size) {
+ error = EINVAL;
+ break;
+ }
+
+ /* load in allocation extent */
+ error = udf_translate_vtop(ump, &icb_loc, &sector, &dummy);
+ if (error == 0)
+ error = udf_read_phys_dscr(ump, sector, M_UDFTEMP,
+ &dscr);
+ if (error != 0 || dscr == NULL)
+ break;
+
+ /* process read-in descriptor */
+ dscr_type = le16toh(dscr->tag.id);
+
+ if (dscr_type != TAGID_ALLOCEXTENT) {
+ free(dscr, M_UDFTEMP);
+ error = ENOENT;
+ break;
+ }
+
+ udf_node->ext[udf_node->num_extensions] = &dscr->aee;
+
+ udf_node->num_extensions++;
+
+ } /* while */
+ UDF_UNLOCK_NODE(udf_node, 0);
+
+ /* second round of cleanup code */
+ if (error != 0) {
+ /* recycle udf_node */
+ udf_dispose_node(udf_node);
+ return (EINVAL); /* error code ok? */
+ }
+
+ /* TODO ext attr and streamdir udf_nodes */
+
+ *ppunode = udf_node;
+
+ return (0);
+}
+
+int
+udf_dispose_node(struct udf_node *udf_node)
+{
+ int extnr;
+
+ if (udf_node == NULL)
+ return (0);
+
+ /* TODO extended attributes and streamdir */
+
+ /* free associated memory and the node itself */
+ for (extnr = 0; extnr < udf_node->num_extensions; extnr++) {
+ free(udf_node->ext[extnr], M_UDFTEMP);
+ udf_node->ext[extnr] = (void *)0xdeadcccc;
+ }
+
+ if (udf_node->fe != NULL)
+ free(udf_node->fe, M_UDFTEMP);
+
+ if (udf_node->efe != NULL)
+ free(udf_node->efe, M_UDFTEMP);
+
+ udf_node->fe = (void *)0xdeadaaaa;
+ udf_node->efe = (void *)0xdeadbbbb;
+ udf_node->ump = (void *)0xdeadbeef;
+ udf_free_node(udf_node);
+
+ return (0);
+}
+
+/*
+ * Read one fid and process it into a dirent and advance to the next (*fid)
+ * has to be allocated a logical block in size, (*dirent) struct dirent length
+ */
+
+int
+udf_validate_fid(struct fileid_desc *fid, int *realsize)
+{
+ int error, fid_size;
+
+ /* check if our FID header is OK */
+ if ((error = udf_check_tag(fid)) != 0)
+ goto brokendir;
+
+ if (le16toh(fid->tag.id) != TAGID_FID) {
+ error = EIO;
+ goto brokendir;
+ }
+
+ /* check for length */
+ fid_size = udf_fidsize(fid);
+ if (*realsize < fid_size) {
+ error = EIO;
+ goto brokendir;
+ }
+
+ /* check FID contents */
+ error = udf_check_tag_payload((union dscrptr *)fid, *realsize);
+
+ *realsize = fid_size;
+brokendir:
+ if (error != 0)
+ return (EIO);
+
+ return (error);
+}
+
+/*
+ * Read and write file extent in/from the buffer.
+ *
+ * The splitup of the extent into seperate request-buffers is to minimise
+ * copying around as much as possible.
+ *
+ * block based file reading and writing
+ */
+
+int
+udf_read_internal(struct udf_node *node, uint8_t *blob)
+{
+ struct file_entry *fe = node->fe;
+ struct extfile_entry *efe = node->efe;
+ struct udf_mount *ump;
+ uint64_t inflen;
+ int addr_type, icbflags;
+ uint32_t sector_size;
+ uint8_t *pos;
+
+ /* get extent and do some paranoia checks */
+ ump = node->ump;
+ sector_size = ump->sector_size;
+
+ if (fe != NULL) {
+ inflen = le64toh(fe->inf_len);
+ pos = &fe->data[0] + le32toh(fe->l_ea);
+ icbflags = le16toh(fe->icbtag.flags);
+ } else {
+ inflen = le64toh(efe->inf_len);
+ pos = &efe->data[0] + le32toh(efe->l_ea);
+ icbflags = le16toh(efe->icbtag.flags);
+ }
+ addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
+
+ /* copy out info */
+ memset(blob, 0, sector_size);
+ memcpy(blob, pos, inflen);
+
+ return (0);
+}
--- sys/fs/udf2/udf_subr.h 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_subr.h 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2006, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#ifndef _FS_UDF_UDF_SUBR_H_
+#define _FS_UDF_UDF_SUBR_H_
+
+/* handies */
+#define VFSTOUDF(mp) ((struct udf_mount *)mp->mnt_data)
+#define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
+
+struct buf;
+struct long_ad;
+
+/* tags operations */
+int udf_fidsize(struct fileid_desc *fid);
+int udf_check_tag(void *blob);
+int udf_check_tag_payload(void *blob, uint32_t max_length);
+void udf_validate_tag_sum(void *blob);
+void udf_validate_tag_and_crc_sums(void *blob);
+int udf_tagsize(union dscrptr *dscr, uint32_t udf_sector_size);
+
+/* read/write descriptors */
+int udf_read_phys_dscr(struct udf_mount *ump, uint32_t sector,
+ struct malloc_type *mtype, union dscrptr **dstp);
+
+/* volume descriptors readers and checkers */
+int udf_read_anchors(struct udf_mount *ump);
+int udf_read_vds_space(struct udf_mount *ump);
+int udf_process_vds(struct udf_mount *ump);
+int udf_read_vds_tables(struct udf_mount *ump);
+int udf_read_rootdirs(struct udf_mount *ump);
+
+/* open/close and sync volumes */
+int udf_open_logvol(struct udf_mount *ump);
+int udf_close_logvol(struct udf_mount *ump, int mntflags);
+
+/* translation services */
+int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
+ uint32_t *lb_numres, uint32_t *extres);
+int udf_bmap_translate(struct udf_node *udf_node, uint32_t block,
+ int *exttype, uint64_t *lsector, uint32_t *maxblks);
+void udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb,
+ int *eof);
+int udf_append_adslot(struct udf_node *udf_node, int *slot,
+ struct long_ad *icb);
+
+int udf_vat_read(struct udf_mount *ump, uint8_t *blob, int size,
+ uint32_t offset);
+
+/* disc allocation */
+int udf_get_c_type(struct udf_node *udf_node);
+int udf_get_record_vpart(struct udf_mount *ump, int udf_c_type);
+void udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks,
+ uint64_t *freeblks);
+
+/* node readers and writers */
+#define UDF_LOCK_NODE(udf_node, flag) udf_lock_node(udf_node, (flag), __FILE__, __LINE__)
+#define UDF_UNLOCK_NODE(udf_node, flag) udf_unlock_node(udf_node, (flag))
+void udf_lock_node(struct udf_node *udf_node, int flag, char const *fname,
+ const int lineno);
+void udf_unlock_node(struct udf_node *udf_node, int flag);
+
+int udf_get_node(struct udf_mount *ump, struct long_ad icb_loc,
+ struct udf_node **ppunode);
+int udf_dispose_node(struct udf_node *node);
+
+/* node ops */
+int udf_extattr_search_intern(struct udf_node *node, uint32_t sattr,
+ char const *sattrname, uint32_t *offsetp, uint32_t *lengthp);
+
+/* node data buffer read/write */
+void udf_read_filebuf(struct udf_node *node, struct buf *buf);
+
+/* directory operations and helpers */
+void udf_osta_charset(struct charspec *charspec);
+int udf_validate_fid(struct fileid_desc *fid, int *realsize);
+int udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen,
+ struct long_ad *icb_loc, int *found);
+
+/* helpers and converters */
+int udf_get_node_id(const struct long_ad icbptr, ino_t *ino);
+void udf_get_node_longad(const ino_t ino, struct long_ad *icbptr);
+uint32_t udf_getaccessmode(struct udf_node *node);
+void udf_to_unix_name(struct udf_mount *ump, char *result, int result_len,
+ uint8_t *id, int len);
+void udf_timestamp_to_timespec(struct udf_mount *ump,
+ struct timestamp *timestamp, struct timespec *timespec);
+
+/* vnode operations */
+int udf_getanode(struct mount *mp, struct vnode **vpp);
+int udf_read_internal(struct udf_node *node, uint8_t *blob);
+
+/* Created by for testing */
+struct udf_node * udf_alloc_node(void);
+void udf_free_node(struct udf_node *unode);
+int udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp);
+int udf_read_node(struct udf_node *unode, uint8_t *blob, off_t start,
+ int length);
+#endif /* !_FS_UDF_UDF_SUBR_H_ */
--- sys/fs/udf2/udf_vfsops.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_vfsops.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,774 @@
+/*-
+ * Copyright (c) 2012 Will DeVries
+ * Copyright (c) 2006, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/cdefs.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/conf.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/iconv.h>
+#include <sys/stat.h>
+#if 0
+#include <sys/udfio.h>
+#endif
+#include <geom/geom.h>
+#include <geom/geom_vfs.h>
+
+#include "ecma167-udf.h"
+#include "udf.h"
+#include "udf_subr.h"
+
+MALLOC_DEFINE(M_UDFTEMP, "UDF temp", "UDF allocation space");
+uma_zone_t udf_zone_node = NULL;
+
+struct iconv_functions *udf2_iconv = NULL;
+
+static int udf_mountfs(struct vnode *, struct mount *);
+
+
+/* predefine vnode-op list descriptor */
+
+static vfs_fhtovp_t udf_fhtovp;
+static vfs_init_t udf_init;
+static vfs_mount_t udf_mount;
+static vfs_root_t udf_root;
+static vfs_statfs_t udf_statfs;
+static vfs_uninit_t udf_uninit;
+static vfs_unmount_t udf_unmount;
+
+static struct vfsops udf_vfsops = {
+ .vfs_init = udf_init,
+ .vfs_uninit = udf_uninit,
+ .vfs_mount = udf_mount,
+ .vfs_root = udf_root,
+ .vfs_statfs = udf_statfs,
+ .vfs_unmount = udf_unmount,
+ .vfs_fhtovp = udf_fhtovp,
+ .vfs_vget = udf_vget
+};
+VFS_SET(udf_vfsops, udf2, VFCF_READONLY);
+
+MODULE_VERSION(udf2, 1);
+
+
+static int
+udf_init(struct vfsconf *notused)
+{
+ /* init node pools */
+ udf_zone_node = uma_zcreate("UDF Node Pool Zone",
+ sizeof(struct udf_node), NULL, NULL, NULL, NULL, 0, 0);
+
+ if (udf_zone_node == NULL) {
+ printf("UDF mount: Cannot create node pool zone.");
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
+static int
+udf_uninit(struct vfsconf *notused)
+{
+ /* remove pools */
+ if (udf_zone_node != NULL) {
+ uma_zdestroy(udf_zone_node);
+ udf_zone_node = NULL;
+ }
+
+ return (0);
+}
+
+#define MPFREE(a, lst) \
+ if ((a)) free((a), lst);
+static void
+free_udf_mountinfo(struct mount *mp)
+{
+ struct udf_mount *ump;
+ int i;
+
+ if (mp == NULL)
+ return;
+
+ ump = VFSTOUDF(mp);
+ if (ump != NULL) {
+ /* Metadata partition support */
+ if (ump->metadata_node != NULL)
+ udf_dispose_node(ump->metadata_node);
+
+ /* clear our data */
+ for (i = 0; i < UDF_ANCHORS; i++)
+ MPFREE(ump->anchors[i], M_UDFTEMP);
+ MPFREE(ump->primary_vol, M_UDFTEMP);
+ MPFREE(ump->logical_vol, M_UDFTEMP);
+ MPFREE(ump->unallocated, M_UDFTEMP);
+ MPFREE(ump->implementation, M_UDFTEMP);
+ MPFREE(ump->logvol_integrity, M_UDFTEMP);
+ for (i = 0; i < UDF_PARTITIONS; i++) {
+ MPFREE(ump->partitions[i], M_UDFTEMP);
+ }
+ MPFREE(ump->fileset_desc, M_UDFTEMP);
+ MPFREE(ump->sparing_table, M_UDFTEMP);
+ MPFREE(ump->vat_table, M_UDFTEMP);
+
+ free(ump, M_UDFTEMP);
+ }
+}
+#undef MPFREE
+
+static int
+udf_mount(struct mount *mp)
+{
+ struct thread *td;
+ struct vnode *devvp;
+ struct nameidata nd;
+ int error, len;
+ char *fspec;
+
+ td = curthread;
+
+ MNT_ILOCK(mp);
+ mp->mnt_flag |= MNT_RDONLY;
+ MNT_IUNLOCK(mp);
+
+ if (mp->mnt_flag & MNT_ROOTFS)
+ return (ENOTSUP);
+
+ /* handle request for updating mount parameters */
+ /* TODO can't update my mountpoint yet */
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (0);
+
+ fspec = NULL;
+ error = vfs_getopt(mp->mnt_optnew, "from", (void **)&fspec, &len);
+ if (!error && fspec[len - 1] != '\0')
+ return (EINVAL);
+ if (fspec == NULL)
+ return (EINVAL);
+
+ /* lookup name to get its vnode */
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td);
+ if ((error = namei(&nd)))
+ return (error);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ devvp = nd.ni_vp;
+ if (vn_isdisk(devvp, &error) == 0) {
+ vput(devvp);
+ return (error);
+ }
+
+ error = VOP_ACCESS(devvp, VREAD, td->td_ucred, td);
+ if (error != 0)
+ error = priv_check(td, PRIV_VFS_MOUNT_PERM);
+ if (error != 0) {
+ vput(devvp);
+ return (error);
+ }
+
+ /*
+ * Open device and try to mount it!
+ */
+ error = udf_mountfs(devvp, mp);
+ if (error != 0) {
+ vrele(devvp);
+ return (error);
+ }
+
+ vfs_mountedfrom(mp, fspec);
+ return (0);
+}
+
+
+int
+udf_unmount(struct mount *mp, int mntflags)
+{
+ struct udf_mount *ump;
+ int error, flags;
+
+ ump = VFSTOUDF(mp);
+ if (ump == NULL)
+ panic("UDF unmount: empty ump\n");
+
+ flags = (mntflags & MNT_FORCE) ? FORCECLOSE : 0;
+
+ error = vflush(mp, 0, flags, curthread);
+ if (error != 0)
+ return (error);
+
+ if (ump->iconv_d2l != NULL)
+ udf2_iconv->close(ump->iconv_d2l);
+
+ DROP_GIANT();
+ g_topology_lock();
+ g_vfs_close(ump->geomcp);
+ g_topology_unlock();
+ PICKUP_GIANT();
+ vrele(ump->devvp);
+ dev_rel(ump->devvp->v_rdev);
+
+ /* free our ump */
+ free_udf_mountinfo(mp);
+
+ /* free ump struct references */
+ mp->mnt_data = NULL;
+ MNT_ILOCK(mp);
+ mp->mnt_flag &= ~MNT_LOCAL;
+ MNT_IUNLOCK(mp);
+
+ return (0);
+}
+
+#if 0
+static int
+get_session_info(struct g_consumer *cp, struct udf_session_info *usi,
+ int session_num)
+{
+ int error;
+
+ bzero(usi, sizeof(struct udf_session_info));
+ usi->session_num = session_num;
+
+ error = cp->provider->geom->ioctl(cp->provider, UDFIOREADSESSIONINFO,
+ usi, 0, curthread);
+ if (error != 0) {
+ if (session_num != 0)
+ printf("Cannot mount selected session. This "
+ "device does not properly support multi-sessions "
+ "disc.");
+
+ printf("Warning, this device does not properly support "
+ "multi-sessions disc.");
+
+ return (error);
+ }
+
+ printf("Number of Sessions: %u\n", usi->num_sessions);
+ printf("Number of Tracks: %u\n", usi->num_tracks);
+ printf("First Track Number: %u\n", usi->first_track);
+ printf("Sector Size: %u\n", usi->sector_size);
+
+ printf("Session Number: %u\n", usi->session_num);
+ printf("Session Start Address: %u\n", usi->session_start_addr);
+ printf("Session End Address: %u\n", usi->session_end_addr);
+ printf("Last Written Address in Session: %u\n", usi->session_last_written);
+ printf("First Track Number of Session: %u\n", usi->session_first_track);
+ printf("Last Track of Session: %u\n", usi->session_last_track);
+
+ return (0);
+}
+#endif
+
+/*
+ * Helper function of udf_mount() that actually mounts the disc.
+ */
+static int
+udf_mountfs(struct vnode *devvp, struct mount *mp)
+{
+ struct g_consumer *cp;
+ struct udf_mount *ump = NULL;
+#if 0
+ struct udf_session_info usi;
+#endif
+ int error, len, num_anchors;
+ uint32_t bshift, logvol_integrity, numsecs; /*lb_size,*/
+ char *cs_local;
+ void *optdata = NULL;
+
+ /* Open a consumer. */
+ dev_ref(devvp->v_rdev);
+ DROP_GIANT();
+ g_topology_lock();
+ error = g_vfs_open(devvp, &cp, "udf2", 0);
+ g_topology_unlock();
+ PICKUP_GIANT();
+ VOP_UNLOCK(devvp, 0);
+ if (error != 0)
+ goto fail;
+
+ /* setup basic mount information */
+ mp->mnt_stat.f_fsid.val[0] = dev2udev(devvp->v_rdev);
+ mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
+ mp->mnt_stat.f_namemax = UDF_MAX_NAMELEN;
+ if (devvp->v_rdev->si_iosize_max != 0)
+ mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
+ if (mp->mnt_iosize_max > MAXPHYS)
+ mp->mnt_iosize_max = MAXPHYS;
+ MNT_ILOCK(mp);
+ mp->mnt_flag |= MNT_LOCAL;
+#if __FreeBSD__ < 10
+ mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
+ MNTK_EXTENDED_SHARED;
+#else
+ mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
+#endif
+ MNT_IUNLOCK(mp);
+
+ ump = malloc(sizeof(struct udf_mount), M_UDFTEMP, M_WAITOK | M_ZERO);
+
+#if 0
+ /* init locks */
+ mutex_init(&ump->logvol_mutex, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&ump->ihash_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&ump->get_node_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&ump->allocate_mutex, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&ump->dirtynodes_cv, "udfsync2");
+#endif
+
+ /* set up linkage */
+ mp->mnt_data = ump;
+ ump->vfs_mountp = mp;
+ ump->devvp = devvp;
+ ump->geomcp = cp;
+
+ /* read in options */
+ error = vfs_getopt(mp->mnt_optnew, "uid", &optdata, &len);
+ if (error != 0 || len != sizeof(uid_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->anon_uid = *(uid_t *)optdata;
+
+ vfs_flagopt(mp->mnt_optnew, "override_uid", &ump->flags,
+ UDFMNT_OVERRIDE_UID);
+
+ error = vfs_getopt(mp->mnt_optnew, "gid", &optdata, &len);
+ if (error != 0 || len != sizeof(gid_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->anon_gid = *(gid_t *)optdata;
+
+ vfs_flagopt(mp->mnt_optnew, "override_gid", &ump->flags,
+ UDFMNT_OVERRIDE_GID);
+
+ if (vfs_getopt(mp->mnt_optnew, "mode", &optdata, &len) == 0) {
+ if (len != sizeof(mode_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->mode = *(gid_t *)optdata & ALLPERMS;
+ ump->flags |= UDFMNT_USE_MASK;
+ }
+
+ if (vfs_getopt(mp->mnt_optnew, "dirmode", &optdata, &len) == 0) {
+ if (len != sizeof(mode_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->dirmode = *(gid_t *)optdata & ALLPERMS;
+ ump->flags |= UDFMNT_USE_DIRMASK;
+ }
+
+#if 0
+ printf("si_name: %s\n", devvp->v_rdev->si_name);
+ if (devvp->v_rdev->si_name[0] == 'c' &&
+ devvp->v_rdev->si_name[1] == 'd')
+ {
+ error = get_session_info(cp, &usi, 0);
+ if (error != 0)
+ goto fail;
+
+ ump->first_trackblank = usi.session_first_track_blank;
+ ump->session_start = usi.session_start_addr;
+ ump->session_end = usi.session_end_addr;
+ ump->session_last_written = usi.session_last_written;
+ } else {
+ ump->first_trackblank = 0;
+ ump->session_start = 0;
+ numsecs = cp->provider->mediasize / cp->provider->sectorsize;
+ ump->session_end = numsecs;
+ ump->session_last_written = numsecs;
+ }
+#endif
+
+ error = vfs_getopt(mp->mnt_optnew, "first_trackblank", &optdata, &len);
+ if (error != 0 || len != sizeof(uint8_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->first_trackblank = *(uint8_t *)optdata;
+
+ error = vfs_getopt(mp->mnt_optnew, "session_start_addr", &optdata,
+ &len);
+ if (error != 0 || len != sizeof(uint32_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->session_start = *(uint32_t *)optdata;
+
+ error = vfs_getopt(mp->mnt_optnew, "session_end_addr", &optdata, &len);
+ if (error != 0 || len != sizeof(uint32_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->session_end = *(uint32_t *)optdata;
+
+ error = vfs_getopt(mp->mnt_optnew, "session_last_written", &optdata,
+ &len);
+ if (error != 0 || len != sizeof(uint32_t)) {
+ error = EINVAL;
+ goto fail;
+ }
+ ump->session_last_written = *(uint32_t *)optdata;
+
+ /* We do not want the session_end value to be zero. */
+ numsecs = cp->provider->mediasize / cp->provider->sectorsize;
+ if (ump->session_end == 0)
+ ump->session_end = numsecs;
+
+ /* We should only need to search one, so this is also a hack. */
+ if (ump->session_end - ump->session_start > 25)
+ ump->first_possible_vat_location = ump->session_last_written -
+ 25;
+ else
+ ump->first_possible_vat_location = ump->session_start;
+ ump->last_possible_vat_location = ump->session_last_written;
+
+ error = vfs_getopt(mp->mnt_optnew, "cs_local", (void **)&cs_local,
+ &len);
+ if (error == 0 && udf2_iconv != NULL) {
+ ump->flags |= UDFMNT_KICONV;
+
+ if (cs_local[len-1] != '\0') {
+ error = EINVAL;
+ goto fail;
+ }
+
+ udf2_iconv->open(cs_local, "UTF-16BE", &ump->iconv_d2l);
+ }
+
+ /* inspect sector size */
+ ump->sector_size = cp->provider->sectorsize;
+
+ bshift = 1;
+ while ((1 << bshift) < ump->sector_size)
+ bshift++;
+ if ((1 << bshift) != ump->sector_size) {
+ printf("UDF mount: hit implementation fence on sector size\n");
+ return (EIO);
+ }
+
+ /* temporary check to overcome sectorsize >= 8192 bytes panic */
+ if (ump->sector_size >= 8192) {
+ printf("UDF mount: hit implementation limit, sectorsize to "
+ "big\n");
+ return (EIO);
+ }
+
+
+ /* read all anchors to get volume descriptor sequence */
+ num_anchors = udf_read_anchors(ump);
+ if (num_anchors == 0) {
+ printf("UDF mount: error reading anchors\n");
+ error = EINVAL;
+ goto fail;
+ }
+
+ /* read in volume descriptor sequence */
+ error = udf_read_vds_space(ump);
+ if (error != 0) {
+ printf("UDF mount: error reading volume space\n");
+ goto fail;
+ }
+
+ /* check consistency and completeness */
+ error = udf_process_vds(ump);
+ if (error != 0) {
+ printf( "UDF mount: disc not properly formatted (bad VDS)\n");
+ goto fail;
+ }
+
+ /* note that the mp info needs to be initialised for reading! */
+ /* read vds support tables like VAT, sparable etc. */
+ error = udf_read_vds_tables(ump);
+ if (error != 0) {
+ printf("UDF mount: error in format or damaged disc "
+ "(VDS tables failing)\n");
+ goto fail;
+ }
+
+ /* check if volume integrity is closed otherwise its dirty */
+ logvol_integrity = le32toh(ump->logvol_integrity->integrity_type);
+ if (logvol_integrity != UDF_INTEGRITY_CLOSED) {
+ printf("UDF mount: file system was not cleanly unmounted.\n");
+#if 0
+ error = EPERM;
+ goto fail;
+#endif
+ }
+
+ /* read root directory */
+ error = udf_read_rootdirs(ump);
+ if (error != 0) {
+ printf("UDF mount: disc not properly formatted or damaged disc "
+ "(rootdirs failing)\n");
+ goto fail;
+ }
+
+ /* success! */
+ return (0);
+
+fail:
+ if (cp != NULL) {
+ DROP_GIANT();
+ g_topology_lock();
+ g_vfs_close(cp);
+ g_topology_unlock();
+ PICKUP_GIANT();
+ }
+ dev_rel(devvp->v_rdev);
+ if (ump != NULL)
+ free_udf_mountinfo(mp);
+
+ return (error);
+}
+
+int
+udf_root(struct mount *mp, int flags, struct vnode **vpp)
+{
+ struct udf_mount *ump = VFSTOUDF(mp);
+ ino_t ino;
+ int error;
+
+ error = udf_get_node_id(ump->fileset_desc->rootdir_icb, &ino);
+ if (error == 0)
+ error = udf_vget(mp, ino, flags, vpp);
+ if (error != 0 && ((*vpp)->v_vflag & VV_ROOT) == 0) {
+ printf("UDF: Internal error: invalid root node.");
+ return (EDOOFUS);
+ }
+
+ return (error);
+}
+
+int
+udf_statfs(struct mount *mp, struct statfs *sbp)
+{
+ struct udf_mount *ump = VFSTOUDF(mp);
+ struct logvol_int_desc *lvid;
+ struct udf_logvol_info *impl;
+ uint64_t files, freeblks, sizeblks;
+ int num_part;
+
+ udf_calc_freespace(ump, &sizeblks, &freeblks);
+
+ files = 0;
+ lvid = ump->logvol_integrity;
+ num_part = le32toh(lvid->num_part);
+ impl = (struct udf_logvol_info *)(lvid->tables + 2 * num_part);
+ if (impl != NULL) {
+ files = le32toh(impl->num_files);
+ files += le32toh(impl->num_directories);
+ }
+
+ sbp->f_version = STATFS_VERSION; /* structure version number */
+ /*uint32_t f_type;*/ /* type of filesystem */
+ sbp->f_flags = mp->mnt_flag; /* copy of mount exported flags */
+ sbp->f_bsize = ump->sector_size; /* filesystem fragment size */
+ sbp->f_iosize = ump->sector_size; /* optimal transfer block size */
+ sbp->f_blocks = sizeblks; /* total data blocks in filesystem */
+ sbp->f_bfree = freeblks; /* free blocks in filesystem */
+ sbp->f_bavail = 0; /* free blocks avail to non-superuser */
+ sbp->f_files = files; /* total file nodes in filesystem */
+ sbp->f_ffree = 0; /* free nodes avail to non-superuser */
+ /*uint64_t f_syncwrites;*/ /* count of sync writes since mount */
+ /*uint64_t f_asyncwrites;*/ /* count of async writes since mount */
+ /*uint64_t f_syncreads;*/ /* count of sync reads since mount */
+ /*uint64_t f_asyncreads;*/ /* count of async reads since mount */
+ /*uint64_t f_spare[10];*/ /* unused spare */
+ /*uint32_t f_namemax;*/ /* maximum filename length */
+ /*uid_t f_owner;*/ /* user that mounted the filesystem */
+ /*fsid_t f_fsid;*/ /* filesystem id */
+ /*char f_charspare[80];*/ /* spare string space */
+ /*char f_fstypename[MFSNAMELEN];*/ /* filesystem type name */
+ /*char f_mntfromname[MNAMELEN];*/ /* mounted filesystem */
+ /*char f_mntonname[MNAMELEN];*/ /* directory on which mounted */
+
+ return (0);
+}
+
+struct udf_node *
+udf_alloc_node()
+{
+ return (uma_zalloc(udf_zone_node, M_WAITOK | M_ZERO));
+}
+
+void
+udf_free_node(struct udf_node *unode)
+{
+ uma_zfree(udf_zone_node, unode);
+}
+
+/*
+ * Get vnode for the file system type specific file id ino for the fs. Its
+ * used for reference to files by unique ID and for NFSv3.
+ * (optional) TODO lookup why some sources state NFSv3
+ */
+int
+udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
+{
+ struct vnode *nvp;
+ struct udf_node *unode;
+ struct udf_mount *ump;
+ struct long_ad icb;
+ int error, udf_file_type;
+
+ error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
+ if (error != 0 || *vpp != NULL)
+ return (error);
+
+ if ((flags & LK_TYPE_MASK) == LK_SHARED) {
+ flags &= ~LK_TYPE_MASK;
+ flags |= LK_EXCLUSIVE;
+ }
+
+ ump = VFSTOUDF(mp);
+ error = udf_getanode(mp, &nvp);
+ if (error != 0)
+ return (error);
+
+ lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
+ error = insmntque(nvp, mp);
+ if (error != 0)
+ return (error);
+
+ error = vfs_hash_insert(nvp, ino, flags, curthread, vpp, NULL, NULL);
+ if (error != 0 || *vpp != NULL)
+ return (error);
+
+ /*
+ * Load read and set up the unode structure.
+ */
+ udf_get_node_longad(ino, &icb);
+ error = udf_get_node(ump, icb, &unode);
+ if (error != 0) {
+ vput(nvp);
+ return (error);
+ }
+ nvp->v_data = unode;
+ unode->vnode = nvp;
+ unode->hash_id = ino;
+
+ /* mark the root node as such */
+ if (ump->fileset_desc &&
+ icb.loc.lb_num == ump->fileset_desc->rootdir_icb.loc.lb_num &&
+ icb.loc.part_num == ump->fileset_desc->rootdir_icb.loc.part_num)
+ nvp->v_vflag |= VV_ROOT;
+
+ /*
+ * Translate UDF filetypes into vnode types.
+ *
+ * Systemfiles like the meta main and mirror files are not treated as
+ * normal files, so we type them as having no type. UDF dictates that
+ * they are not allowed to be visible.
+ */
+ if (unode->fe != NULL)
+ udf_file_type = unode->fe->icbtag.file_type;
+ else
+ udf_file_type = unode->efe->icbtag.file_type;
+
+ switch (udf_file_type) {
+ case UDF_ICB_FILETYPE_DIRECTORY:
+ case UDF_ICB_FILETYPE_STREAMDIR:
+ nvp->v_type = VDIR;
+ break;
+ case UDF_ICB_FILETYPE_BLOCKDEVICE:
+ nvp->v_type = VBLK;
+ break;
+ case UDF_ICB_FILETYPE_CHARDEVICE:
+ nvp->v_type = VCHR;
+ break;
+ case UDF_ICB_FILETYPE_SOCKET:
+ nvp->v_type = VSOCK;
+ break;
+ case UDF_ICB_FILETYPE_FIFO:
+ nvp->v_type = VFIFO;
+ break;
+ case UDF_ICB_FILETYPE_SYMLINK:
+ nvp->v_type = VLNK;
+ break;
+ case UDF_ICB_FILETYPE_VAT:
+ case UDF_ICB_FILETYPE_META_MAIN:
+ case UDF_ICB_FILETYPE_META_MIRROR:
+ nvp->v_type = VNON;
+ break;
+ case UDF_ICB_FILETYPE_RANDOMACCESS:
+ case UDF_ICB_FILETYPE_REALTIME:
+ nvp->v_type = VREG;
+ break;
+ default:
+ /* YIKES, something else */
+ nvp->v_type = VNON;
+ }
+
+ if (nvp->v_type != VFIFO)
+ VN_LOCK_ASHARE(nvp);
+
+ *vpp = nvp;
+
+ return (0);
+}
+
+/*
+ * Lookup vnode for file handle specified
+ */
+int
+udf_fhtovp(struct mount *mp, struct fid *fhp, int flags,
+ struct vnode **vpp)
+{
+ struct vnode *vp;
+ struct udf_fid *ufid = (struct udf_fid*)fhp;
+ struct udf_node *udf_node;
+ uint64_t filelen;
+ int error;
+
+ error = VFS_VGET(mp, ufid->ino, LK_EXCLUSIVE, &vp);
+ if (error != 0) {
+ *vpp = NULLVP;
+ return (error);
+ }
+
+ udf_node = VTOI(vp);
+ if (udf_node->efe != NULL)
+ filelen = le64toh(udf_node->efe->inf_len);
+ else
+ filelen = le64toh(udf_node->fe->inf_len);
+
+ vnode_create_vobject(vp, filelen, curthread);
+ *vpp = vp;
+
+ return (0);
+}
+
--- sys/fs/udf2/udf_vnops.c 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/fs/udf2/udf_vnops.c 2014-11-16 16:27:23.000000000 -0800
@@ -0,0 +1,1337 @@
+/*-
+ * Copyright (c) 2013 Will DeVries
+ * Copyright (c) 2006, 2008 Reinoud Zandijk
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ * Generic parts are derived from software contributed to The NetBSD Foundation
+ * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
+ * 2005 program.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/buf.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/unistd.h>
+#include <sys/bio.h>
+#include <sys/stat.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+
+#if __FreeBSD__ < 10
+#include <fs/fifofs/fifo.h>
+#endif
+
+#include "ecma167-udf.h"
+#include "udf.h"
+#include "udf_subr.h"
+
+static int udf_pbuf_freecnt = -1;
+
+static vop_access_t udf_access;
+static vop_bmap_t udf_bmap;
+static vop_cachedlookup_t udf_cachedlookup;
+static vop_getattr_t udf_getattr;
+static vop_ioctl_t udf_ioctl;
+static vop_open_t udf_open;
+static vop_pathconf_t udf_pathconf;
+static vop_print_t udf_print;
+static vop_read_t udf_read;
+static vop_readdir_t udf_readdir;
+static vop_readlink_t udf_readlink;
+static vop_reclaim_t udf_reclaim;
+static vop_setattr_t udf_setattr;
+static vop_strategy_t udf_strategy;
+static vop_vptofh_t udf_vptofh;
+static vop_getpages_t udf_getpages;
+
+static struct vop_vector udf_vnodeops = {
+ .vop_default = &default_vnodeops,
+ .vop_access = udf_access,
+ .vop_getattr = udf_getattr,
+ .vop_open = udf_open,
+ .vop_ioctl = udf_ioctl,
+ .vop_pathconf = udf_pathconf,
+ .vop_print = udf_print,
+ .vop_read = udf_read,
+ .vop_readdir = udf_readdir,
+ .vop_readlink = udf_readlink,
+ .vop_setattr = udf_setattr,
+ .vop_strategy = udf_strategy,
+ .vop_bmap = udf_bmap,
+ .vop_cachedlookup = udf_cachedlookup,
+ .vop_reclaim = udf_reclaim,
+ .vop_vptofh = udf_vptofh,
+ .vop_lookup = vfs_cache_lookup,
+ .vop_getpages = udf_getpages
+};
+
+struct vop_vector udf_fifoops = {
+ .vop_access = udf_access,
+ .vop_getattr = udf_getattr,
+ .vop_print = udf_print,
+ .vop_setattr = udf_setattr,
+ .vop_reclaim = udf_reclaim,
+ .vop_vptofh = udf_vptofh,
+ .vop_default = &fifo_specops,
+};
+
+/* implementations of vnode functions; table follows at end */
+
+
+int
+udf_getanode(struct mount *mp, struct vnode **vpp)
+{
+ return (getnewvnode("udf2", mp, &udf_vnodeops, vpp));
+}
+
+static int
+udf_reclaim(struct vop_reclaim_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct udf_node *udf_node = VTOI(vp);
+
+ vnode_destroy_vobject(vp);
+
+ if (udf_node == NULL)
+ return (0);
+
+ /* dispose all node knowledge */
+ vfs_hash_remove(vp);
+ udf_dispose_node(udf_node);
+ vp->v_data = NULL;
+
+ return (0);
+}
+
+static int
+udf_read(struct vop_read_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct buf *bp;
+ struct udf_node *udf_node = VTOI(vp);
+ uint64_t fsize;
+ int seqcount, lbn, n, on, sector_size;
+ int error = 0;
+ uint8_t *zerobuf;
+
+ /* can this happen? some filingsystems have this check */
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ if (uio->uio_resid == 0)
+ return (0);
+
+#ifdef INVARIANTS
+ /* As in ffs_read() */
+ if (vp->v_type != VDIR && vp->v_type != VREG)
+ panic("udf_read: type %d", vp->v_type);
+#endif
+
+ /* get file/directory filesize */
+ if (udf_node->fe != NULL)
+ fsize = le64toh(udf_node->fe->inf_len);
+ else
+ fsize = le64toh(udf_node->efe->inf_len);
+
+ sector_size = udf_node->ump->sector_size;
+
+ seqcount = ap->a_ioflag >> IO_SEQSHIFT;
+
+ while (error == 0 && uio->uio_resid > 0 && fsize > uio->uio_offset) {
+ lbn = uio->uio_offset / sector_size;
+ on = uio->uio_offset % sector_size;
+
+ n = min(sector_size - on, uio->uio_resid);
+ n = min(n, fsize - uio->uio_offset);
+
+ if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 &&
+ sector_size * (lbn + 1) < fsize) {
+#if __FreeBSD__ < 10
+ error = cluster_read(vp, fsize, lbn, sector_size,
+ NOCRED, on + uio->uio_resid, seqcount, &bp);
+#else
+ error = cluster_read(vp, fsize, lbn, sector_size,
+ NOCRED, on + uio->uio_resid, seqcount, 0, &bp);
+#endif
+ } else {
+ error = bread(vp, lbn, sector_size, NOCRED, &bp);
+ }
+
+ n = min(n, sector_size - bp->b_resid);
+
+ if (error == 0)
+ error = uiomove(bp->b_data + on, n, uio);
+
+ brelse(bp);
+ }
+
+ if (vp->v_type == VDIR && fsize <= uio->uio_offset &&
+ uio->uio_resid > 0) {
+ zerobuf = malloc(2048, M_UDFTEMP, M_WAITOK | M_ZERO);
+ while (error == 0 && uio->uio_resid > 0) {
+ n = min(2048, uio->uio_resid);
+ error = uiomove(zerobuf, n, uio);
+ }
+ free(zerobuf, M_UDFTEMP);
+ }
+
+ return (error);
+}
+
+static int
+udf_bmap(struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct bufobj **a_bop;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct udf_node *udf_node = VTOI(vp);
+ uint64_t lsector;
+ int error, exttype;
+ uint32_t maxblks;
+
+ if (ap->a_bop != NULL)
+ *ap->a_bop = &ap->a_vp->v_bufobj;
+
+ if (ap->a_bnp == NULL)
+ return (0);
+
+ /* get logical block and run */
+ error = udf_bmap_translate(udf_node, ap->a_bn, &exttype, &lsector,
+ &maxblks);
+ if (error != 0)
+ return (error);
+
+ /* convert to dev blocks */
+ if (exttype == UDF_TRAN_INTERN)
+ *ap->a_bnp = INT64_MAX - 2;
+ else if (exttype == UDF_TRAN_ZERO)
+ *ap->a_bnp = INT64_MAX - 1; /* zero the buffer */
+ else
+ *ap->a_bnp = lsector * (udf_node->ump->sector_size/DEV_BSIZE);
+
+ /* set runlength of maximum block size */
+ if (ap->a_runp != NULL)
+ *ap->a_runp = maxblks - 1;
+
+ if (ap->a_runb != NULL)
+ *ap->a_runb = 0;
+
+ /* return success */
+ return (0);
+}
+
+static int
+udf_strategy(struct vop_strategy_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct buf *bp = ap->a_bp;
+ struct udf_node *udf_node = VTOI(vp);
+ struct bufobj *bo = &udf_node->ump->devvp->v_bufobj;
+ uint64_t lsector;
+ int error, exttype;
+ uint32_t sector_size, maxblks;
+
+ if (vp->v_type == VBLK || vp->v_type == VCHR)
+ panic("udf_strategy: spec");
+
+ /* get sector size */
+ sector_size = udf_node->ump->sector_size;
+
+
+ /* get logical block and run */
+ if (bp->b_blkno == bp->b_lblkno) {
+ error = udf_bmap_translate(udf_node, bp->b_lblkno, &exttype,
+ &lsector, &maxblks);
+
+ if (error != 0) {
+ bp->b_error = error;
+ bp->b_ioflags |= BIO_ERROR;
+ bufdone(bp);
+ return (error);
+ }
+
+ if (exttype == UDF_TRAN_ZERO) {
+ bp->b_blkno = INT64_MAX - 1;
+ vfs_bio_clrbuf(bp);
+ }
+ else if (exttype == UDF_TRAN_INTERN)
+ bp->b_blkno = INT64_MAX - 2;
+ else
+ bp->b_blkno = lsector * (sector_size / DEV_BSIZE);
+ }
+
+ if ((bp->b_iocmd & BIO_READ) == 0)
+ return (ENOTSUP);
+
+ if (bp->b_blkno == INT64_MAX - 1) {
+ bufdone(bp);
+//printf("UDF: Hole in file found. (This is a debuging statement, not an error.\n");
+ } else if (bp->b_blkno == INT64_MAX - 2) {
+ error = udf_read_internal(udf_node, (uint8_t *)bp->b_data);
+ if (error != 0) {
+ bp->b_error = error;
+ bp->b_ioflags |= BIO_ERROR;
+ }
+ bufdone(bp);
+ } else {
+ bp->b_iooffset = dbtob(bp->b_blkno);
+ BO_STRATEGY(bo, bp);
+ }
+
+ return (bp->b_error);
+}
+
+static int
+udf_readdir(struct vop_readdir_args *ap)
+{
+ struct uio *uio;
+ struct vnode *vp;
+ struct fileid_desc *fid;
+ struct dirent *dirent;
+ struct udf_mount *ump;
+ struct udf_node *udf_node;
+ uint64_t file_size;
+ u_long *cookies, *cookiesp;
+ off_t diroffset, transoffset;
+ int acookies, error, ncookies, size;
+ uint32_t lb_size;
+ uint8_t *fid_name;
+
+ error = 0;
+ uio = ap->a_uio;
+ vp = ap->a_vp;
+ udf_node = VTOI(vp);
+ ump = udf_node->ump;
+ transoffset = uio->uio_offset;
+
+ /* This operation only makes sense on directory nodes. */
+ if (vp->v_type != VDIR)
+ return (ENOTDIR);
+
+ /* get directory filesize */
+ if (udf_node->fe != NULL)
+ file_size = le64toh(udf_node->fe->inf_len);
+ else
+ file_size = le64toh(udf_node->efe->inf_len);
+
+ dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK | M_ZERO);
+ if (ap->a_ncookies != NULL) {
+ /* is this the max number possible? */
+ ncookies = uio->uio_resid / 8;
+ if (ncookies > 1024)
+ ncookies = 1024;
+ cookies = malloc(sizeof(u_long) * ncookies, M_TEMP,
+ M_WAITOK | M_ZERO);
+ cookiesp = cookies;
+ } else {
+ ncookies = 0;
+ cookies = NULL;
+ cookiesp = NULL;
+ }
+ acookies = 0;
+
+ /* The directory '.' is not in the fid stream. */
+ if (transoffset == 0) {
+ memset(dirent, 0, sizeof(struct dirent));
+ dirent->d_fileno = udf_node->hash_id;
+ dirent->d_type = DT_DIR;
+ dirent->d_name[0] = '.';
+ dirent->d_name[1] = '\0';
+ dirent->d_namlen = 1;
+ dirent->d_reclen = GENERIC_DIRSIZ(dirent);
+
+ if (uio->uio_resid >= dirent->d_reclen)
+ {
+ if (cookiesp != NULL) {
+ acookies++;
+ *cookiesp++ = 1; // next one
+ }
+ error = uiomove(dirent, dirent->d_reclen, uio);
+ if (error != 0)
+ goto bail;
+
+ transoffset = 1;
+ }
+ }
+
+ /* allocate temporary space for fid */
+ lb_size = ump->sector_size;
+ fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
+
+ /* we are called just as long as we keep on pushing data in */
+ if (transoffset == 1)
+ diroffset = 0;
+ else
+ diroffset = transoffset;
+
+ while (diroffset < file_size) {
+ /* transfer a new fid/dirent */
+ memset(fid, 0, lb_size);
+ size = MIN(file_size - diroffset, lb_size);
+
+ error = vn_rdwr(UIO_READ, vp, fid, size, diroffset,
+ UIO_SYSSPACE, IO_NODELOCKED, FSCRED, NULL, NULL,
+ curthread);
+ if (error != 0) {
+ printf("UDF: Error reading fid: %d\n", error);
+ break;
+ }
+
+ error = udf_validate_fid(fid, &size);
+ if (error != 0) {
+ printf("UDF: Invalid fid found: %d\n", error);
+ break;
+ }
+
+ diroffset += size;
+
+ /* skip deleted and not visible files */
+ if (fid->file_char & UDF_FILE_CHAR_DEL ||
+ fid->file_char & UDF_FILE_CHAR_VIS) {
+ transoffset = diroffset;
+ if (cookiesp != NULL && acookies > 0)
+ *(cookiesp - 1) = transoffset;
+ continue;
+ }
+
+ /* create resulting dirent structure */
+ memset(dirent, 0, sizeof(struct dirent));
+ error = udf_get_node_id(fid->icb, &dirent->d_fileno); /* inode hash XXX */
+ if (error != 0)
+ break;
+
+ /* Going for the filetypes now is too expensive. */
+ dirent->d_type = DT_UNKNOWN;
+ if (fid->file_char & UDF_FILE_CHAR_DIR)
+ dirent->d_type = DT_DIR;
+
+ /* '..' has no name, so provide one */
+ if (fid->file_char & UDF_FILE_CHAR_PAR) {
+ dirent->d_name[0] = '.';
+ dirent->d_name[1] = '.';
+ dirent->d_name[2] = '\0';
+ dirent->d_namlen = 2;
+ } else {
+ fid_name = fid->data + le16toh(fid->l_iu);
+ udf_to_unix_name(ump, dirent->d_name, MAXNAMLEN,
+ fid_name, fid->l_fi);
+ dirent->d_namlen = strlen(dirent->d_name);
+ }
+
+ dirent->d_reclen = GENERIC_DIRSIZ(dirent);
+
+ /*
+ * If there isn't enough space in the uio to return a
+ * whole dirent, break off read
+ */
+ if (uio->uio_resid < dirent->d_reclen)
+ break;
+
+ /* copy dirent to the caller */
+ if (cookiesp != NULL) {
+ if (acookies + 1 > ncookies)
+ break;
+ acookies++;
+ *cookiesp++ = diroffset;
+ }
+
+ /* remember the last entry we transfered */
+ transoffset = diroffset;
+
+ error = uiomove(dirent, dirent->d_reclen, uio);
+ if (error != 0)
+ break;
+ }
+
+ /* pass on last transfered offset */
+ /* We lied for '.', so tell more lies. */
+ free(fid, M_UDFTEMP);
+
+ uio->uio_offset = transoffset;
+
+bail:
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = uio->uio_offset >= file_size;
+
+ if (ap->a_ncookies != NULL) {
+ if (error != 0)
+ free(cookies, M_UDFTEMP);
+ else {
+ *ap->a_ncookies = acookies;
+ *ap->a_cookies = cookies;
+ }
+ }
+ free(dirent, M_UDFTEMP);
+
+ return (error);
+}
+
+static int
+udf_cachedlookup(struct vop_cachedlookup_args *ap)
+{
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *tdp = NULL;
+ struct componentname *cnp = ap->a_cnp;
+ struct fileid_desc *fid;
+ struct udf_node *dir_node;
+ struct udf_mount *ump;
+ uint64_t file_size, offset;
+ ino_t id = 0;
+ int error, islastcn, ltype, mounted_ro, nameiop, numpasses, unix_len;
+ int size;
+ uint8_t *fid_name;
+ char *unix_name;
+
+ dir_node = VTOI(dvp);
+ ump = dir_node->ump;
+ *vpp = NULL;
+ error = 0;
+
+ /* simplify/clarification flags */
+ nameiop = cnp->cn_nameiop;
+ islastcn = cnp->cn_flags & ISLASTCN;
+ mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY;
+
+ /*
+ * If requesting a modify on the last path element on a read-only
+ * filingsystem, reject lookup; XXX why is this repeated in every FS ?
+ */
+ if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME))
+ return (EROFS);
+
+ /* get directory filesize */
+ if (dir_node->fe != NULL)
+ file_size = le64toh(dir_node->fe->inf_len);
+ else
+ file_size = le64toh(dir_node->efe->inf_len);
+
+ if (nameiop != LOOKUP || dir_node->diroff == 0 ||
+ dir_node->diroff > file_size) {
+ offset = 0;
+ numpasses = 1;
+ }
+ else {
+ offset = dir_node->diroff;
+ numpasses = 2;
+ nchstats.ncs_2passes++;
+ }
+
+ fid = malloc(ump->sector_size, M_UDFTEMP, M_WAITOK);
+ unix_name = malloc(MAXNAMLEN, M_UDFTEMP, M_WAITOK);
+lookuploop:
+ while (offset < file_size) {
+ /* transfer a new fid/dirent */
+ memset(fid, 0, ump->sector_size);
+ size = MIN(file_size - offset, ump->sector_size);
+
+ error = vn_rdwr(UIO_READ, dvp, fid, size, offset, UIO_SYSSPACE,
+ IO_NODELOCKED, FSCRED, NULL, NULL, curthread);
+ if (error != 0) {
+ printf("UDF: Error reading fid: %d\n", error);
+ break;
+ }
+
+ error = udf_validate_fid(fid, &size);
+ if (error != 0) {
+ printf("UDF: Invalid fid found: %d\n", error);
+ break;
+ }
+
+ offset += size;
+
+ /* skip deleted entries */
+ if (fid->file_char & UDF_FILE_CHAR_DEL)
+ continue;
+
+ /* skip not visible files */
+ if (fid->file_char & UDF_FILE_CHAR_VIS)
+ continue;
+
+ if (fid->file_char & UDF_FILE_CHAR_PAR) {
+ if (cnp->cn_flags & ISDOTDOT) {
+ error = udf_get_node_id(fid->icb, &id);
+ break;
+ }
+ }
+ else {
+ fid_name = fid->data + le16toh(fid->l_iu);
+ udf_to_unix_name(ump, unix_name, MAXNAMLEN, fid_name,
+ fid->l_fi);
+ unix_len = strlen(unix_name);
+
+ if (unix_len == cnp->cn_namelen) {
+ if (!strncmp(unix_name, cnp->cn_nameptr,
+ cnp->cn_namelen)) {
+ error = udf_get_node_id(fid->icb, &id);
+ break;
+ }
+ }
+ }
+ }
+
+ if (error != 0)
+ goto exit;
+
+ if (id != 0) {
+ if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == LOOKUP)
+ dir_node->diroff = offset;
+ if (numpasses == 2)
+ nchstats.ncs_pass2++;
+
+ if (cnp->cn_flags & ISDOTDOT)
+ vn_vget_ino(dvp, id, cnp->cn_lkflags, &tdp);
+ else if (dir_node->hash_id == id) {
+ /* through a glass darkly... */
+ VREF(dvp);
+ ltype = cnp->cn_lkflags & LK_TYPE_MASK;
+ if (ltype != VOP_ISLOCKED(dvp)) {
+ if (ltype == LK_EXCLUSIVE)
+ vn_lock(dvp, LK_UPGRADE | LK_RETRY);
+ else
+ vn_lock(dvp, LK_DOWNGRADE | LK_RETRY);
+ }
+ tdp = dvp;
+ } else
+ error = udf_vget(ump->vfs_mountp, id, cnp->cn_lkflags,
+ &tdp);
+
+ if (error == 0) {
+ *vpp = tdp;
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, *vpp, cnp);
+ }
+ }
+ else {
+ if (numpasses-- == 2) {
+ offset = 0;
+ goto lookuploop;
+ }
+
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, *vpp, cnp);
+
+ if ((cnp->cn_flags & ISLASTCN) &&
+ (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
+ error = EROFS;
+ else
+ error = ENOENT;
+ }
+
+exit:
+ free(fid, M_UDFTEMP);
+ free(unix_name, M_UDFTEMP);
+
+ return (error);
+}
+
+static int
+udf_getattr(struct vop_getattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct udf_node *udf_node = VTOI(vp);
+ struct file_entry *fe = udf_node->fe;
+ struct extfile_entry *efe = udf_node->efe;
+ struct filetimes_extattr_entry *ft_extattr;
+ struct device_extattr_entry *devattr;
+ struct vattr *vap = ap->a_vap;
+ struct timestamp *atime, *attrtime, *creatime, *mtime;
+ struct udf_mount *ump = udf_node->ump;
+ uint64_t blkssize, filesize;
+ gid_t gid;
+ int error;
+ uid_t uid;
+ uint32_t a_l, nlink, offset;
+ uint8_t *filedata;
+
+ /* get descriptor information */
+ if (fe != NULL) {
+ nlink = le16toh(fe->link_cnt);
+ uid = (uid_t)le32toh(fe->uid);
+ gid = (gid_t)le32toh(fe->gid);
+ filesize = le64toh(fe->inf_len);
+ blkssize = le64toh(fe->logblks_rec);
+ atime = &fe->atime;
+ mtime = &fe->mtime;
+ attrtime = &fe->attrtime;
+ filedata = fe->data;
+
+ /* initial guess */
+ creatime = mtime;
+
+ /* check our extended attribute if present */
+ error = udf_extattr_search_intern(udf_node,
+ UDF_FILETIMES_ATTR_NO, "", &offset, &a_l);
+ if (error == 0) {
+ ft_extattr = (struct filetimes_extattr_entry *)
+ (filedata + offset);
+ if (ft_extattr->existence & UDF_FILETIMES_FILE_CREATION)
+ creatime = &ft_extattr->times[0];
+ }
+ } else {
+ nlink = le16toh(efe->link_cnt);
+ uid = (uid_t)le32toh(efe->uid);
+ gid = (gid_t)le32toh(efe->gid);
+ filesize = le64toh(efe->inf_len); /* XXX or obj_size? */
+ blkssize = le64toh(efe->logblks_rec);
+ atime = &efe->atime;
+ mtime = &efe->mtime;
+ attrtime = &efe->attrtime;
+ creatime = &efe->ctime;
+ filedata = efe->data;
+ }
+
+ /* do the uid/gid translation game */
+ if (uid == (uid_t)-1 || ump->flags & UDFMNT_OVERRIDE_UID)
+ uid = ump->anon_uid;
+ if (gid == (gid_t)-1 || ump->flags & UDFMNT_OVERRIDE_GID)
+ gid = ump->anon_gid;
+
+ /*
+ * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add
+ * 1 to the link count if its a directory we're requested attributes
+ * of.
+ */
+ if (vp->v_type == VDIR) {
+ nlink++;
+
+ /* directories should be at least a single block? */
+ if (blkssize != 0)
+ filesize = blkssize * ump->sector_size;
+ else
+ filesize = ump->sector_size;
+ }
+
+ /* fill in struct vattr with values from the node */
+ vattr_null(vap);
+ vap->va_type = vp->v_type;
+ vap->va_mode = udf_getaccessmode(udf_node);
+ if (vap->va_type == VDIR && ump->flags & UDFMNT_USE_DIRMASK)
+ vap->va_mode = (vap->va_mode & ~ALLPERMS) | ump->dirmode;
+ else if (vap->va_type != VDIR && ump->flags & UDFMNT_USE_MASK)
+ vap->va_mode = (vap->va_mode & ~ALLPERMS) | ump->mode;
+ vap->va_nlink = nlink;
+ vap->va_uid = uid;
+ vap->va_gid = gid;
+ vap->va_fsid = dev2udev(ump->devvp->v_rdev);
+ vap->va_fileid = udf_node->hash_id;
+ vap->va_size = filesize;
+ vap->va_blocksize = ump->sector_size; /* wise? */
+
+ /* access times */
+ udf_timestamp_to_timespec(ump, atime, &vap->va_atime);
+ udf_timestamp_to_timespec(ump, mtime, &vap->va_mtime);
+ udf_timestamp_to_timespec(ump, attrtime, &vap->va_ctime);
+ udf_timestamp_to_timespec(ump, creatime, &vap->va_birthtime);
+
+ vap->va_gen = 1; /* no multiple generations yes (!?) */
+ vap->va_flags = 0;
+ vap->va_bytes = blkssize * ump->sector_size;
+ vap->va_filerev = 0; /* TODO file revision numbers? */
+ vap->va_vaflags = 0;
+ /* TODO get vaflags from the extended attributes? */
+
+ if (vap->va_type == VBLK || vap->va_type == VCHR) {
+ error = udf_extattr_search_intern(udf_node,
+ UDF_DEVICESPEC_ATTR_NO, "", &offset, &a_l);
+ /* if error, deny access */
+ if (error != 0 || filedata == NULL)
+ vap->va_mode = 0; /* or v_type = VNON? */
+ else {
+ devattr = (struct device_extattr_entry *)filedata +
+ offset;
+ vap->va_rdev = makedev(le32toh(devattr->major),
+ le32toh(devattr->minor));
+ /* TODO we could check the implementator */
+ }
+ }
+
+ return (0);
+}
+
+static int
+udf_setattr(struct vop_setattr_args *ap)
+{
+ struct vattr *vap = ap->a_vap;
+
+ /* Abort if any unsettable attribute is given. */
+ if (vap->va_type != VNON ||
+ vap->va_nlink != VNOVAL ||
+ vap->va_fsid != VNOVAL ||
+ vap->va_fileid != VNOVAL ||
+ vap->va_blocksize != VNOVAL ||
+ vap->va_gen != VNOVAL ||
+ vap->va_rdev != VNOVAL ||
+ vap->va_bytes != VNOVAL)
+ return (EINVAL);
+
+ if (vap->va_flags != VNOVAL ||
+ vap->va_mode != (mode_t)VNOVAL ||
+ vap->va_atime.tv_sec != VNOVAL ||
+ vap->va_mtime.tv_sec != VNOVAL ||
+ vap->va_uid != VNOVAL ||
+ vap->va_gid != VNOVAL) {
+ return (EROFS);
+ }
+
+ if (vap->va_size != VNOVAL) {
+ if (vap->va_type == VDIR)
+ return (EISDIR);
+ if (vap->va_type == VLNK || vap->va_type == VREG)
+ return (EROFS);
+ }
+
+ return (0);
+}
+
+/*
+ * Return POSIX pathconf information for UDF file systems.
+ */
+static int
+udf_pathconf(struct vop_pathconf_args *ap)
+{
+ switch (ap->a_name) {
+ case _PC_LINK_MAX:
+ *ap->a_retval = (1 << 16) - 1; /* 16 bits */
+ return (0);
+ case _PC_NAME_MAX:
+ *ap->a_retval = NAME_MAX;
+ return (0);
+ case _PC_PATH_MAX:
+ *ap->a_retval = PATH_MAX;
+ return (0);
+ case _PC_PIPE_BUF:
+ *ap->a_retval = PIPE_BUF;
+ return (0);
+ case _PC_CHOWN_RESTRICTED:
+ *ap->a_retval = 1;
+ return (0);
+ case _PC_NO_TRUNC:
+ *ap->a_retval = 1;
+ return (0);
+ case _PC_SYNC_IO:
+ *ap->a_retval = 0; /* synchronised is off for performance */
+ return (0);
+ case _PC_FILESIZEBITS:
+ /* 64 bit file offsets -> 2+floor(2log(2^64-1)) = 2 + 63 = 65 */
+ *ap->a_retval = 64; /* XXX ought to deliver 65 */
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+udf_open(struct vop_open_args *ap)
+{
+ struct udf_node *udf_node;
+ off_t file_size;
+
+ udf_node = VTOI(ap->a_vp);
+
+ if (udf_node->fe != NULL)
+ file_size = le64toh(udf_node->fe->inf_len);
+ else
+ file_size = le64toh(udf_node->efe->inf_len);
+
+ vnode_create_vobject(ap->a_vp, file_size, ap->a_td);
+
+ return (0);
+}
+
+static int
+udf_access(struct vop_access_args *ap)
+{
+ struct vnode *vp;
+ struct udf_node *udf_node;
+ struct udf_mount *ump;
+ accmode_t accmode;
+ gid_t gid;
+ mode_t mode;
+ uid_t uid;
+
+ vp = ap->a_vp;
+ udf_node = VTOI(vp);
+ accmode = ap->a_accmode;
+ ump = udf_node->ump;
+
+ /* check if we are allowed to write */
+ switch (vp->v_type) {
+ case VDIR:
+ case VLNK:
+ case VREG:
+ /*
+ * normal nodes: check if we're on a read-only mounted
+ * filingsystem and bomb out if we're trying to write.
+ */
+ if (accmode & VWRITE)
+ return (EROFS); /* check that this works */
+ break;
+ case VBLK:
+ case VCHR:
+ case VSOCK:
+ case VFIFO:
+ /*
+ * special nodes: even on read-only mounted filingsystems
+ * these are allowed to be written to if permissions allow.
+ */
+ break;
+ default:
+ /* no idea what this is */
+ return (EINVAL);
+ }
+
+ mode = udf_getaccessmode(udf_node);
+ if (vp->v_type == VDIR && ump->flags & UDFMNT_USE_DIRMASK)
+ mode = (mode & ~ALLPERMS) | ump->dirmode;
+ else if (vp->v_type != VDIR && ump->flags & UDFMNT_USE_MASK)
+ mode = (mode & ~ALLPERMS) | ump->mode;
+
+ if (udf_node->fe != NULL) {
+ uid = udf_node->fe->uid;
+ gid = udf_node->fe->gid;
+ }
+ else {
+ uid = udf_node->efe->uid;
+ gid = udf_node->efe->gid;
+ }
+
+ return (vaccess(vp->v_type, mode, uid, gid, accmode, ap->a_cred, NULL));
+}
+
+int
+udf_readlink(struct vop_readlink_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct pathcomp pathcomp;
+ struct udf_node *udf_node;
+ int error, filelen, first, len, l_ci, mntonnamelen, namelen, pathlen;
+ int targetlen;
+ char *mntonname;
+ uint8_t *pathbuf, *pathpos, *targetbuf, *targetpos, *tmpname;
+
+ udf_node = VTOI(vp);
+
+ if (udf_node->efe != NULL)
+ filelen = le64toh(udf_node->efe->inf_len);
+ else
+ filelen = le64toh(udf_node->fe->inf_len);
+
+ if (UDF_SYMLINKBUFLEN - 1 < filelen)
+ return (EINVAL);
+
+ /* claim temporary buffers for translation */
+ pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK);
+ targetbuf = malloc(PATH_MAX + 1, M_UDFTEMP, M_WAITOK);
+ tmpname = malloc(PATH_MAX + 1, M_UDFTEMP, M_WAITOK);
+ memset(pathbuf, 0, UDF_SYMLINKBUFLEN);
+ memset(targetbuf, 0, PATH_MAX + 1);
+
+ /* read contents of file in our temporary buffer */
+ error = vn_rdwr(UIO_READ, vp, pathbuf, filelen, 0, UIO_SYSSPACE,
+ IO_NODELOCKED, FSCRED, NULL, NULL, curthread);
+ if (error != 0) {
+ /* failed to read in symlink contents */
+ free(pathbuf, M_UDFTEMP);
+ free(targetbuf, M_UDFTEMP);
+ free(tmpname, M_UDFTEMP);
+ return (error);
+ }
+
+ /* convert to a unix path */
+ pathpos = pathbuf;
+ pathlen = 0;
+ targetpos = targetbuf;
+ targetlen = PATH_MAX;
+ mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
+ mntonnamelen = strlen(mntonname);
+
+ error = 0;
+ first = 1;
+ while (filelen - pathlen >= UDF_PATH_COMP_SIZE) {
+ len = UDF_PATH_COMP_SIZE;
+ memcpy(&pathcomp, pathpos, len);
+ l_ci = pathcomp.l_ci;
+ switch (pathcomp.type) {
+ case UDF_PATH_COMP_ROOT:
+ /* XXX should check for l_ci; bugcompatible now */
+ if (targetlen < 1 || first == 0) {
+ error = EINVAL;
+ break;
+ }
+ *targetpos++ = '/';
+ targetlen--;
+ break;
+ case UDF_PATH_COMP_MOUNTROOT:
+ /* XXX what should it be if l_ci > 0 ? [4/48.16.1.2] */
+ if (l_ci || targetlen < mntonnamelen + 1 || !first) {
+ error = EINVAL;
+ break;
+ }
+ memcpy(targetpos, mntonname, mntonnamelen);
+ targetpos += mntonnamelen;
+ targetlen -= mntonnamelen;
+ if (filelen - pathlen > UDF_PATH_COMP_SIZE + l_ci) {
+ /* more follows, so must be directory */
+ *targetpos++ = '/';
+ targetlen--;
+ }
+ break;
+ case UDF_PATH_COMP_PARENTDIR:
+ /* XXX should check for l_ci; bugcompatible now */
+ if (targetlen < 3) {
+ error = EINVAL;
+ break;
+ }
+ *targetpos++ = '.';
+ targetlen--;
+ *targetpos++ = '.';
+ targetlen--;
+ *targetpos++ = '/';
+ targetlen--;
+ break;
+ case UDF_PATH_COMP_CURDIR:
+ /* XXX should check for l_ci; bugcompatible now */
+ if (targetlen < 2) {
+ error = EINVAL;
+ break;
+ }
+ *targetpos++ = '.';
+ targetlen--;
+ *targetpos++ = '/';
+ targetlen--;
+ break;
+ case UDF_PATH_COMP_NAME:
+ if (l_ci == 0) {
+ error = EINVAL;
+ break;
+ }
+ memset(tmpname, 0, PATH_MAX);
+ memcpy(&pathcomp, pathpos, len + l_ci);
+ udf_to_unix_name(udf_node->ump, tmpname, MAXPATHLEN,
+ pathcomp.ident, l_ci);
+ namelen = strlen(tmpname);
+ if (targetlen < namelen + 1) {
+ error = EINVAL;
+ break;
+ }
+ memcpy(targetpos, tmpname, namelen);
+ targetpos += namelen;
+ targetlen -= namelen;
+ if (filelen-pathlen > UDF_PATH_COMP_SIZE + l_ci) {
+ /* more follows, so must be directory */
+ *targetpos++ = '/';
+ targetlen--;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ first = 0;
+ if (error != 0)
+ break;
+ pathpos += UDF_PATH_COMP_SIZE + l_ci;
+ pathlen += UDF_PATH_COMP_SIZE + l_ci;
+
+ }
+ /* all processed? */
+ if (filelen - pathlen > 0)
+ error = EINVAL;
+
+ /* uiomove() to destination */
+ if (error == 0)
+ uiomove(targetbuf, PATH_MAX - targetlen, uio);
+
+ free(pathbuf, M_UDFTEMP);
+ free(targetbuf, M_UDFTEMP);
+ free(tmpname, M_UDFTEMP);
+
+ return (error);
+}
+
+static int
+udf_ioctl(struct vop_ioctl_args *ap)
+{
+ return (ENOTTY);
+}
+
+static int
+udf_print(struct vop_print_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct udf_node *udf_node = VTOI(vp);
+
+ printf(" ino %u, on dev %s", (uint32_t)udf_node->hash_id,
+ devtoname(udf_node->ump->devvp->v_rdev));
+ if (vp->v_type == VFIFO)
+ fifo_printinfo(vp);
+ printf("\n");
+
+ return (0);
+}
+
+static int
+udf_vptofh(struct vop_vptofh_args *ap)
+{
+ struct udf_node *udf_node = VTOI(ap->a_vp);
+ struct udf_fid *ufid = (struct udf_fid *)ap->a_fhp;
+
+ ufid->len = sizeof(struct udf_fid);
+ ufid->ino = udf_node->hash_id;
+
+ return (0);
+}
+
+static int
+udf_getpages(struct vop_getpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_reqpage;
+ vm_ooffset_t a_offset;
+ } */ *ap)
+{
+ struct buf *bp;
+ struct bufobj *bo;
+ struct vnode *vp = ap->a_vp;
+ vm_page_t *pages;
+ daddr_t startreq, lastreq, firstblk, vblock, address;
+ off_t filesize, foff, tfoff;
+ vm_offset_t kva, curdata;
+ int blksperpage, bsize, error, i, numblks, pagecnt, size;
+ int curpage, fpage, npage;
+
+ error = 0;
+ bsize = vp->v_mount->mnt_stat.f_iosize;
+ filesize = vp->v_object->un_pager.vnp.vnp_size;
+ pages = ap->a_m;
+ pagecnt = btoc(ap->a_count);
+ blksperpage = PAGE_SIZE / bsize;
+
+ /*
+ * Free other pages, if requested page is valid. If only part of a page
+ * is marked as valid, we overwrite it below. This approch would not
+ * work, if the filesystem implemented write support.
+ */
+#if __FreeBSD__ < 10
+ VM_OBJECT_LOCK(vp->v_object);
+#else
+ VM_OBJECT_WLOCK(vp->v_object);
+#endif
+ if (pages[ap->a_reqpage]->valid == VM_PAGE_BITS_ALL) {
+ for (i = 0; i < pagecnt; i++)
+ if (i != ap->a_reqpage) {
+ vm_page_lock(pages[i]);
+ vm_page_free(pages[i]);
+ vm_page_unlock(pages[i]);
+ }
+#if __FreeBSD__ < 10
+ VM_OBJECT_UNLOCK(vp->v_object);
+#else
+ VM_OBJECT_WUNLOCK(vp->v_object);
+#endif
+ return VM_PAGER_OK;
+ }
+#if __FreeBSD__ < 10
+ VM_OBJECT_UNLOCK(vp->v_object);
+#else
+ VM_OBJECT_WUNLOCK(vp->v_object);
+#endif
+
+ /* Map all memory pages, and then use a single buf object for all
+ bstrategy calls. */
+ bp = getpbuf(&udf_pbuf_freecnt);
+ bp->b_iocmd = BIO_READ;
+ bp->b_iodone = bdone;
+ bp->b_rcred = crhold(curthread->td_ucred);
+ bp->b_wcred = crhold(curthread->td_ucred);
+
+ curdata = kva = (vm_offset_t)bp->b_data;
+ pmap_qenter(kva, pages, pagecnt);
+
+ firstblk = pages[0]->pindex * blksperpage;
+ startreq = pages[ap->a_reqpage]->pindex * blksperpage;
+ lastreq = startreq + blksperpage - 1;
+ if ((lastreq + 1) * bsize > filesize)
+ lastreq = (filesize - 1) / bsize;
+ fpage = -1;
+
+ for (curpage = 0, vblock = firstblk; vblock <= lastreq; ) {
+ error = VOP_BMAP(vp, vblock, &bo, &address, &numblks, NULL);
+ if (error)
+ goto error;
+
+ numblks++;
+ if (vblock + numblks <= startreq) {
+ vblock += numblks - 1; /* last block of run */
+ npage = (vblock - firstblk) / blksperpage + 1;
+ vblock = pages[npage]->pindex * blksperpage;
+ curdata = kva + IDX_TO_OFF(pages[npage]->pindex);
+ continue;
+ }
+
+ curpage = ((vblock - firstblk) * bsize) / PAGE_SIZE;
+
+ /* find number of blocks to readahead */
+ numblks = MIN(numblks,
+ blksperpage * pagecnt - (vblock - firstblk));
+ if (vblock + numblks - 1 > lastreq)
+ numblks -= (vblock - firstblk + numblks) % blksperpage;
+ size = bsize * numblks;
+
+ /* from initpbuf() */
+ bp->b_qindex = 0;
+ bp->b_xflags = 0;
+ bp->b_flags = 0;
+ bp->b_ioflags = 0;
+ bp->b_iodone = NULL;
+ bp->b_error = 0;
+
+ /* setup the buffer for this run */
+ if (fpage == -1) {
+ pbgetbo(bo, bp);
+ bp->b_vp = vp;
+ fpage = curpage;
+ }
+
+ bp->b_data = (caddr_t)curdata;
+ bp->b_blkno = address;
+ bp->b_lblkno = vblock;
+ bp->b_bcount = size; /* this is the current read size. */
+ bp->b_bufsize = size;
+ bp->b_runningbufspace = bp->b_bufsize;
+ atomic_add_long(&runningbufspace, bp->b_runningbufspace);
+
+ bp->b_iooffset = dbtob(bp->b_blkno);
+ bstrategy(bp);
+
+ bwait(bp, PVM, "udfvnread");
+
+ if ((bp->b_ioflags & BIO_ERROR) != 0) {
+ error = EIO;
+ goto error;
+ }
+
+ vblock = vblock + numblks;
+ curdata += size;
+ }
+
+ /* it should error out before here if vblock == firstblk */
+ npage = (vblock - 1 - firstblk) / blksperpage + 1;
+
+ if ((vblock - firstblk) % blksperpage != 0) {
+ bzero((caddr_t) curdata,
+ ((vblock - firstblk) % blksperpage) * bsize);
+ }
+
+error:
+ pmap_qremove(kva, pagecnt);
+
+ bp->b_vp = NULL;
+ pbrelbo(bp);
+ relpbuf(bp, &vnode_pbuf_freecnt);
+
+ if (error != 0) {
+#if __FreeBSD__ < 10
+ VM_OBJECT_LOCK(vp->v_object);
+#else
+ VM_OBJECT_WLOCK(vp->v_object);
+#endif
+ for (i = 0; i < pagecnt; i++)
+ if (i != ap->a_reqpage) {
+ vm_page_lock(pages[i]);
+ vm_page_free(pages[i]);
+ vm_page_unlock(pages[i]);
+ }
+#if __FreeBSD__ < 10
+ VM_OBJECT_UNLOCK(vp->v_object);
+#else
+ VM_OBJECT_WUNLOCK(vp->v_object);
+#endif
+ return (VM_PAGER_ERROR);
+ }
+
+#if __FreeBSD__ < 10
+ VM_OBJECT_LOCK(vp->v_object);
+#else
+ VM_OBJECT_WLOCK(vp->v_object);
+#endif
+ /* remove all pages before first loaded page. */
+ for (i = 0; i < fpage; i++) {
+ vm_page_lock(pages[i]);
+ vm_page_free(pages[i]);
+ vm_page_unlock(pages[i]);
+ }
+
+ /* mark filled pages. */
+ foff = IDX_TO_OFF(pages[fpage]->pindex);
+ for (i = fpage, tfoff = foff; i < npage; i++, tfoff += PAGE_SIZE) {
+ /* We only read complete pages above. */
+ if (tfoff + PAGE_SIZE <= filesize)
+ pages[i]->valid = VM_PAGE_BITS_ALL;
+ else {
+#if __FreeBSD__ < 10
+ vm_page_set_valid(pages[i], 0, filesize - tfoff);
+#else
+ vm_page_set_valid_range(pages[i], 0, filesize - tfoff);
+#endif
+ }
+
+ if (i != ap->a_reqpage)
+ vm_page_readahead_finish(pages[i]);
+ }
+
+ /* remove all pages after last loaded page. */
+ for (i = npage; i < pagecnt; i++) {
+ vm_page_lock(pages[i]);
+ vm_page_free(pages[i]);
+ vm_page_unlock(pages[i]);
+ }
+#if __FreeBSD__ < 10
+ VM_OBJECT_UNLOCK(vp->v_object);
+#else
+ VM_OBJECT_WUNLOCK(vp->v_object);
+#endif
+
+ return (VM_PAGER_OK);
+}
+
--- sys/kern/kern_sysctl.c 2015-07-04 07:20:46.000000000 -0700
+++ updates/sys/kern/kern_sysctl.c 2015-07-04 06:45:19.000000000 -0700
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/kern/kern_sysctl.c 285131 2015-07-04 14:44:39Z mjg $");
+__FBSDID("$FreeBSD: head/sys/kern/kern_sysctl.c 285126 2015-07-04 07:01:43Z mjg $");
#include "opt_capsicum.h"
#include "opt_compat.h"
@@ -113,6 +113,26 @@
static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t);
static int sysctl_new_kernel(struct sysctl_req *, void *, size_t);
+static void
+sysctl_lock(struct rm_priotracker *tracker)
+{
+
+ if (tracker != NULL)
+ SYSCTL_RLOCK(tracker);
+ else
+ SYSCTL_WLOCK();
+}
+
+static void
+sysctl_unlock(struct rm_priotracker *tracker)
+{
+
+ if (tracker != NULL)
+ SYSCTL_RUNLOCK(tracker);
+ else
+ SYSCTL_WUNLOCK();
+}
+
static struct sysctl_oid *
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
{
@@ -154,11 +174,7 @@
if (oid->oid_kind & CTLFLAG_DYN)
atomic_add_int(&oid->oid_running, 1);
-
- if (tracker != NULL)
- SYSCTL_RUNLOCK(tracker);
- else
- SYSCTL_WUNLOCK();
+ sysctl_unlock(tracker);
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
mtx_lock(&Giant);
@@ -166,11 +182,7 @@
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
mtx_unlock(&Giant);
- if (tracker != NULL)
- SYSCTL_RLOCK(tracker);
- else
- SYSCTL_WLOCK();
-
+ sysctl_lock(tracker);
if (oid->oid_kind & CTLFLAG_DYN) {
if (atomic_fetchadd_int(&oid->oid_running, -1) == 1 &&
(oid->oid_kind & CTLFLAG_DYING) != 0)
--- sys/modules/Makefile 2015-07-04 07:18:25.000000000 -0700
+++ updates/sys/modules/Makefile 2015-07-04 07:09:05.000000000 -0700
@@ -347,6 +347,8 @@
ubsec \
udf \
udf_iconv \
+ udf2 \
+ udf2_iconv \
ufs \
unionfs \
usb \
--- sys/modules/udf2/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/modules/udf2/Makefile 2015-07-04 07:02:31.000000000 -0700
@@ -0,0 +1,12 @@
+# $FreeBSD: src/sys/modules/udf/Makefile,v 1.5 2004/01/13 11:28:50 ru Exp $
+
+.PATH: ${.CURDIR}/../../fs/udf2
+
+KMOD= udf2
+
+SRCS= udf_readwrite.c udf_subr.c udf_allocation.c \
+ udf_osta.c udf_vfsops.c udf_vnops.c udf_filenames.c
+SRCS+= vnode_if.h
+EXPORT_SYMS= udf_iconv
+
+.include <bsd.kmod.mk>
--- sys/modules/udf2_iconv/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/modules/udf2_iconv/Makefile 2015-07-04 07:04:57.000000000 -0700
@@ -0,0 +1,9 @@
+# $FreeBSD: src/sys/modules/udf_iconv/Makefile,v 1.1 2003/11/07 09:38:05 scottl Exp $
+
+.PATH: ${.CURDIR}/../../fs/udf2
+KMOD= udf2_iconv
+SRCS= udf_iconv.c
+
+CFLAGS+= -I${.CURDIR}/../../
+
+.include <bsd.kmod.mk>
--- sys/sys/udfio.h 1969-12-31 16:00:00.000000000 -0800
+++ updates/sys/sys/udfio.h 2014-11-16 17:05:03.000000000 -0800
@@ -0,0 +1,29 @@
+
+
+/* Shared between kernel & process */
+
+#ifndef _SYS_UDFIO_H_
+#define _SYS_UDFIO_H_
+
+#ifndef _KERNEL
+#include <sys/types.h>
+#endif
+#include <sys/ioccom.h>
+
+struct udf_session_info {
+ uint16_t num_sessions;
+ uint16_t sector_size;
+ uint16_t num_tracks;
+ uint8_t first_track;
+
+ uint32_t session_num;
+ uint32_t session_start_addr;
+ uint32_t session_end_addr;
+ uint32_t session_last_written;
+ uint16_t session_first_track;
+ uint8_t session_first_track_blank;
+ uint16_t session_last_track;
+};
+#define UDFIOREADSESSIONINFO _IOWR('c',300, struct udf_session_info)
+
+#endif /* !_SYS_UDFIO_H_ */
--- sys/cam/scsi/scsi_cd.c 2015-07-04 07:22:35.000000000 -0700
+++ updates/sys/cam/scsi/scsi_cd.c 2015-07-04 06:45:21.000000000 -0700
@@ -60,6 +60,7 @@
#include <sys/cdio.h>
#include <sys/cdrio.h>
#include <sys/dvdio.h>
+#include <sys/udfio.h>
#include <sys/devicestat.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
@@ -264,6 +265,19 @@
struct dvd_struct *dvdstruct);
static timeout_t cdmediapoll;
+/* added for UDF */
+static int udfreaddiscinfo(struct cam_periph *periph,
+ struct udf_session_info *usi);
+static int cdgetconf(struct cam_periph *periph, u_int8_t *data,
+ u_int32_t len, uint8_t rt,
+ uint16_t startfeature, u_int32_t sense_flags);
+static int cdreaddiscinfo(struct cam_periph *periph, uint8_t *data,
+ uint32_t len, uint32_t sense_flags);
+static int cdreadtrackinfo(struct cam_periph *periph,
+ uint8_t *data, uint32_t len,
+ uint32_t trackno,
+ uint32_t sense_flags);
+
static struct periph_driver cddriver =
{
cdinit, "cd",
@@ -2139,6 +2153,18 @@
break;
}
+ case UDFIOREADSESSIONINFO: {
+ struct udf_session_info *usi;
+
+ usi = (struct udf_session_info *)addr;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
+ ("trying to do UDFIOREADDISCINFO\n"));
+
+ error = udfreaddiscinfo(periph, usi);
+
+ break;
+ }
default:
cam_periph_lock(periph);
error = cam_periph_ioctl(periph, cmd, addr, cderror);
@@ -2158,6 +2184,252 @@
return (error);
}
+/* Added for UDF. */
+static int
+udfreaddiscinfo(struct cam_periph *periph, struct udf_session_info *usi)
+{
+ struct scsi_read_disc_info_data *rdi;
+ struct scsi_read_track_info_data *ti;
+ struct scsi_get_conf_header *gch;
+ struct scsi_get_conf_feature_inc_stream_write *lf;
+ int error, linksize, lra_valid, nwa_valid, diskstate;
+ int sessionstatus;
+ uint32_t track_start_addr, track_size, free_blocks, nwa, lra;
+ uint16_t track, sessret;
+ uint8_t lsb, msb;
+
+ rdi = malloc(sizeof(*rdi), M_SCSICD, M_WAITOK | M_ZERO);
+ ti = malloc(sizeof(*ti), M_SCSICD, M_WAITOK | M_ZERO);
+ gch = malloc(sizeof(*gch) + sizeof(*lf), M_SCSICD, M_WAITOK | M_ZERO);
+
+ cam_periph_lock(periph);
+
+ /* Get link size. */
+ linksize = 7; // for CD-Roms
+
+ error = cdgetconf(periph, (u_int8_t *)gch, sizeof(*gch) + sizeof(*lf),
+ GC_RT_ONEFEATURE, GC_FC_INCR_STREAMING_WRITABLE, SF_NO_PRINT);
+ lf = (struct scsi_get_conf_feature_inc_stream_write *)(gch + 1);
+ if (error)
+ goto out;
+
+ if (lf->byte3 & GC_CURRENT)
+ if (lf->num_link_sizes > 0)
+ linksize = lf->first_linksize;
+
+ /* Read get config and header data. */
+ error = cdreaddiscinfo(periph, (uint8_t *)rdi, sizeof (*rdi),
+ SF_NO_PRINT);
+ if (error != 0)
+ goto out;
+
+ usi->num_sessions = rdi->num_sessions_lsb |
+ (rdi->num_sessions_msb << 8);
+
+ if (usi->session_num == 0) {
+ diskstate = rdi->byte2 & 0x3;
+ sessionstatus = (rdi->byte2 >> 2) & 0x3;
+
+ // if the session is empty, we don't want to read it.
+ if (diskstate < 2 && sessionstatus == 0 &&
+ usi->num_sessions > 1)
+ usi->session_num = usi->num_sessions - 1;
+ else
+ usi->session_num = usi->num_sessions;
+ }
+
+ usi->first_track = rdi->num_first_track;
+
+ lsb = rdi->last_track_last_session_lsb;
+ msb = rdi->last_track_last_session_msb;
+ usi->num_tracks = ((msb << 8) | lsb) - usi->first_track + 1;
+
+ usi->session_first_track = 0;
+ usi->session_last_track = 0;
+ usi->session_start_addr = 0;
+ track_start_addr = 0;
+ track_size = 0;
+ free_blocks = 0;
+ nwa = 0;
+ lra = 0;
+ lra_valid = 0;
+ nwa_valid = 0;
+ for (track = usi->first_track; track <= usi->num_tracks; track++) {
+ error = cdreadtrackinfo(periph, (uint8_t *)ti, sizeof(*ti),
+ track, /*sense_flags*/SF_NO_PRINT);
+ if (error != 0) {
+ goto out;
+ }
+ sessret = (ti->session_num_msb << 8) | ti->session_num_lsb;
+ if (sessret == usi->session_num) {
+ if (usi->session_first_track == 0) {
+ usi->session_first_track = track;
+ usi->session_start_addr =
+ scsi_4btoul(ti->track_start_addr);
+ usi->session_first_track_blank =
+ ti->track_info2 & READ_TRACK_BLANK ? 1 : 0;
+ }
+ usi->session_last_track = track;
+ track_start_addr = scsi_4btoul(ti->track_start_addr);
+ track_size = scsi_4btoul(ti->track_size);
+ free_blocks = scsi_4btoul(ti->free_blocks);
+ lra_valid = ti->valid_data & READ_TRACK_INFO_LRA_V;
+ lra = scsi_4btoul(ti->last_recorded_addr);
+ nwa_valid = ti->valid_data & READ_TRACK_INFO_NWA_V;
+ nwa = scsi_4btoul(ti->next_writable_addr);
+ } else if (usi->session_first_track != 0)
+ break;
+ }
+
+ if (usi->session_first_track == 0 || usi->session_last_track == 0) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /* Calculate end address of session. */
+ usi->session_end_addr = track_start_addr + track_size - 1;
+
+ /* Only needed for sequentially written disk, but populate it anyway.*/
+ if (lra_valid != 0)
+ usi->session_last_written = lra;
+ /* else if (nwa_valid != 0)
+ usi->session_last_written = nwa - linksize; */
+ else {
+ usi->session_last_written = usi->session_end_addr;
+ if (free_blocks)
+ usi->session_last_written -= free_blocks + linksize;
+ }
+
+ usi->sector_size = 2048; /* Almost all CDs have this block size. */
+out:
+ cam_periph_unlock(periph);
+ free(rdi, M_SCSICD);
+ free(ti, M_SCSICD);
+ free(gch, M_SCSICD);
+
+ if (error != 0)
+ error = ENODEV;
+
+ return (error);
+}
+
+static int
+cdgetconf(struct cam_periph *periph, uint8_t *data, uint32_t len,
+ uint8_t rt, uint16_t startfeature, uint32_t sense_flags)
+{
+ struct scsi_get_conf *scsi_cmd;
+ struct ccb_scsiio *csio;
+ union ccb *ccb;
+ int error;
+
+ error = 0;
+ ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
+ csio = &ccb->csio;
+
+ cam_fill_csio(csio,
+ /* retries */ cd_retry_count,
+ /* cbfcnp */ cddone,
+ /* flags */ CAM_DIR_IN,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* data_ptr */ data,
+ /* dxfer_len */ len,
+ /* sense_len */ SSD_FULL_SIZE,
+ sizeof(struct scsi_get_conf),
+ /* timeout */ 50000);
+
+ scsi_cmd = (struct scsi_get_conf *)&csio->cdb_io.cdb_bytes;
+ bzero (scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->op_code = GET_CONFIGURATION;
+ scsi_cmd->byte2 = rt;
+ scsi_ulto2b(startfeature, scsi_cmd->start_feature);
+ scsi_ulto2b(len, scsi_cmd->alloc_len);
+
+ error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
+ /*sense_flags*/SF_RETRY_UA | sense_flags);
+
+ xpt_release_ccb(ccb);
+
+ return (error);
+}
+
+static int
+cdreaddiscinfo(struct cam_periph *periph, uint8_t *data, uint32_t len,
+ uint32_t sense_flags)
+{
+ struct scsi_read_disc_info *scsi_cmd;
+ struct ccb_scsiio *csio;
+ union ccb *ccb;
+ int error;
+
+ error = 0;
+ ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
+ csio = &ccb->csio;
+
+ cam_fill_csio(csio,
+ /* retries */ cd_retry_count,
+ /* cbfcnp */ cddone,
+ /* flags */ CAM_DIR_IN,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* data_ptr */ data,
+ /* dxfer_len */ len,
+ /* sense_len */ SSD_FULL_SIZE,
+ sizeof(struct scsi_read_disc_info),
+ /* timeout */ 50000);
+
+ scsi_cmd = (struct scsi_read_disc_info *)&csio->cdb_io.cdb_bytes;
+ bzero (scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->op_code = READ_DISC_INFO;
+ scsi_ulto2b(len, scsi_cmd->alloc_len);
+
+ error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
+ /*sense_flags*/SF_RETRY_UA | sense_flags);
+
+ xpt_release_ccb(ccb);
+
+ return (error);
+}
+
+static int
+cdreadtrackinfo(struct cam_periph *periph, uint8_t *data, uint32_t len,
+ uint32_t trackno, uint32_t sense_flags)
+{
+ struct scsi_read_track_info *scsi_cmd;
+ struct ccb_scsiio *csio;
+ union ccb *ccb;
+ int error;
+
+ error = 0;
+ ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
+ csio = &ccb->csio;
+
+ cam_fill_csio(csio,
+ /* retries */ cd_retry_count,
+ /* cbfcnp */ cddone,
+ /* flags */ CAM_DIR_IN,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* data_ptr */ data,
+ /* dxfer_len */ len,
+ /* sense_len */ SSD_FULL_SIZE,
+ sizeof(struct scsi_read_track_info),
+ /* timeout */ 50000);
+
+ scsi_cmd = (struct scsi_read_track_info *)&csio->cdb_io.cdb_bytes;
+ bzero (scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->op_code = READ_TRACK_INFO;
+ scsi_cmd->byte2 = READ_TRACK_INFO_AT_TRACK;
+ scsi_ulto4b(trackno, scsi_cmd->address);
+ scsi_ulto2b(len, scsi_cmd->alloc_len);
+
+ error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
+ /*sense_flags*/SF_RETRY_UA | sense_flags);
+
+ xpt_release_ccb(ccb);
+
+ return (error);
+}
+/* End of UDF code. */
+
+
static void
cdprevent(struct cam_periph *periph, int action)
{
--- sys/cam/scsi/scsi_cd.h 2015-07-04 07:22:35.000000000 -0700
+++ updates/sys/cam/scsi/scsi_cd.h 2014-11-16 17:03:59.000000000 -0800
@@ -56,6 +56,109 @@
* SCSI command format
*/
+
+/* Used in UDF */
+#define GET_CONFIGURATION 0x46 /* cdrom read TOC */
+struct scsi_get_conf
+{
+ uint8_t op_code;
+ uint8_t byte2;
+#define GC_RT_ONEFEATURE 0x02 /* Return header and zero or one feature. */
+ uint8_t start_feature[2];
+#define GC_FC_INCR_STREAMING_WRITABLE 0x0021
+ uint8_t reserved[3];
+ uint8_t alloc_len[2];
+ uint8_t control;
+};
+
+struct scsi_get_conf_header
+{
+ uint8_t data_len[4];
+ uint8_t reserved[2];
+ uint8_t cur_profile[2];
+};
+
+struct scsi_get_conf_feature_inc_stream_write
+{
+ uint8_t feature_code[2];
+ uint8_t byte3;
+#define GC_CURRENT 0x1
+ uint8_t additional_len;
+ uint8_t data_block_types_supported[2];
+ uint8_t byte7;
+ uint8_t num_link_sizes;
+ uint8_t first_linksize;
+ uint8_t other_linksizes[1]; /* one byte each, most return 1. */
+};
+
+#define READ_DISC_INFO 0x51
+struct scsi_read_disc_info
+{
+ uint8_t op_code;
+ uint8_t byte2;
+ uint8_t reserved[5];
+ uint8_t alloc_len[2];
+ uint8_t control;
+};
+
+struct scsi_read_disc_info_data
+{
+ uint8_t disc_info_len[2];
+ uint8_t byte2;
+ uint8_t num_first_track;
+ uint8_t num_sessions_lsb;
+ uint8_t first_track_last_session_lsb;
+ uint8_t last_track_last_session_lsb;
+ uint8_t byte8;
+ uint8_t disc_type;
+ uint8_t num_sessions_msb;
+ uint8_t first_track_last_session_msb;
+ uint8_t last_track_last_session_msb;
+ uint8_t disc_id[4];
+ uint8_t leadin_start_last_session[4];
+ uint8_t last_start_time_leadout[4];
+ uint8_t disc_bar_code[8];
+ uint8_t reserved;
+ uint8_t num_opc_entries;
+ uint8_t opc_entries[];
+};
+
+#define READ_TRACK_INFO 0x52
+struct scsi_read_track_info
+{
+ uint8_t op_code;
+ uint8_t byte2;
+#define READ_TRACK_INFO_AT_TRACK 0x01
+ uint8_t address[4];
+ uint8_t reserved;
+ uint8_t alloc_len[2];
+ uint8_t control;
+};
+
+struct scsi_read_track_info_data
+{
+ uint8_t track_info_len[2];
+ uint8_t track_num_lsb;
+ uint8_t session_num_lsb;
+ uint8_t reserved1;
+ uint8_t track_info1;
+ uint8_t track_info2;
+#define READ_TRACK_BLANK 0x40
+ uint8_t valid_data;
+#define READ_TRACK_INFO_LRA_V 0x2
+#define READ_TRACK_INFO_NWA_V 0x1
+ uint8_t track_start_addr[4];
+ uint8_t next_writable_addr[4];
+ uint8_t free_blocks[4];
+ uint8_t packet_size[4];
+ uint8_t track_size[4];
+ uint8_t last_recorded_addr[4];
+ uint8_t track_num_msb;
+ uint8_t session_num_msb;
+ uint8_t reserved2[2];
+};
+/* End of UDF */
+
struct scsi_pause
{
u_int8_t op_code;
@ish-org
Copy link

ish-org commented Aug 27, 2018

I want to mount UDF 2.50/2.60 BD-R[E] [DL].
I found this patch. Although I applied to head r338308/ 11-stable r338334, I can't make /sys/fs/udf2/udf_vnops.c because 'a_reqpage' in 'struct vop_getpages_args' is no longer not a member of that struct.
Can you supply more recent patches ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment