Last active
May 31, 2022 20:24
-
-
Save waitman/07849a747d0d633a7009 to your computer and use it in GitHub Desktop.
UDF2 diff against FreeBSD-11.0-Current source r285141
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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 ([email protected]). The Rock Ridge Extension | |
+ * Support code is derived from software contributed to Berkeley | |
+ * by Atsushi Murai ([email protected]). | |
+ * | |
+ * 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 <[email protected]> | |
+.\" Jeroen Ruigrok van der Werven <[email protected]> | |
+.\" 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 * <[email protected]> | |
+ * Copyright (c) 2001, 2002 Scott Long <[email protected]> | |
+ * 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, §or, &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, §or, &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, §or, &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; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 ?