Actually add the UDF files!
This commit is contained in:
parent
b6bd548cdc
commit
51a7b740a1
12
sbin/mount_udf/Makefile
Normal file
12
sbin/mount_udf/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= mount_udf
|
||||
SRCS= mount_udf.c getmntopts.c
|
||||
MAN= mount_udf.8
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I${MOUNT} -I${.CURDIR}/../../sys -Wall
|
||||
.PATH: ${MOUNT}
|
||||
WARNS= 0
|
||||
|
||||
.include <bsd.prog.mk>
|
71
sbin/mount_udf/mount_udf.8
Normal file
71
sbin/mount_udf/mount_udf.8
Normal file
@ -0,0 +1,71 @@
|
||||
.\" Copyright (c) 2002
|
||||
.\" Scott Long <scottl@freebsd.org>
|
||||
.\" Jeroen Ruigrok van der Werven <asmodai@wxs.nl>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 23, 2002
|
||||
.Dt MOUNT_UDF 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mount_udf
|
||||
.Nd mount a UDF filesystem
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl v
|
||||
.Op Fl o Ar options
|
||||
.Ar special | node
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
command attaches the UDF filesystem residing on the device
|
||||
.Pa special
|
||||
to the global filesystem namespace at the location indicated by
|
||||
.Pa node .
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.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.
|
||||
The following UDF specific options are available:
|
||||
.It Fl v
|
||||
Be verbose about mounting the UDF filesystem.
|
||||
.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 4.6 .
|
142
sbin/mount_udf/mount_udf.c
Normal file
142
sbin/mount_udf/mount_udf.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Scott Long
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley
|
||||
* by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
|
||||
* Support code is derived from software contributed to Berkeley
|
||||
* by Atsushi Murai (amurai@spec.co.jp).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <fs/udf/udf_mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
MOPT_UPDATE,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct udf_args args;
|
||||
int ch, mntflags, opts;
|
||||
char *dev, *dir, mntpath[MAXPATHLEN];
|
||||
struct vfsconf vfc;
|
||||
int error, verbose;
|
||||
|
||||
mntflags = opts = verbose = 0;
|
||||
memset(&args, 0, sizeof args);
|
||||
args.ssector = -1;
|
||||
while ((ch = getopt(argc, argv, "o:v")) != -1)
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, &opts);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
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);
|
||||
|
||||
#define DEFAULT_ROOTUID -2
|
||||
/*
|
||||
* UDF filesystems are not writeable.
|
||||
*/
|
||||
mntflags |= MNT_RDONLY;
|
||||
args.export.ex_flags = MNT_EXRDONLY;
|
||||
args.fspec = dev;
|
||||
args.export.ex_root = DEFAULT_ROOTUID;
|
||||
args.flags = opts;
|
||||
|
||||
error = getvfsbyname("udf", &vfc);
|
||||
if (error && vfsisloadable("udf")) {
|
||||
if (vfsload("udf"))
|
||||
err(EX_OSERR, "vfsload(udf)");
|
||||
endvfsent(); /* flush cache */
|
||||
error = getvfsbyname("udf", &vfc);
|
||||
}
|
||||
if (error)
|
||||
errx(1, "udf filesystem is not available");
|
||||
|
||||
if (mount(vfc.vfc_name, mntpath, mntflags, &args) < 0)
|
||||
err(1, "%s", args.fspec);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_udf [-v] [-o options] special node\n");
|
||||
exit(EX_USAGE);
|
||||
}
|
368
sys/fs/udf/ecma167-udf.h
Normal file
368
sys/fs/udf/ecma167-udf.h
Normal file
@ -0,0 +1,368 @@
|
||||
/*-
|
||||
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* ecma167-udf.h */
|
||||
/* Structure/definitions/constants a la ECMA 167 rev. 3 */
|
||||
|
||||
/* Tag identifiers */
|
||||
enum {
|
||||
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_FENTRY = 261
|
||||
};
|
||||
|
||||
/* Descriptor tag [3/7.2] */
|
||||
struct desc_tag {
|
||||
u_int16_t id;
|
||||
u_int16_t descriptor_ver;
|
||||
u_int8_t cksum;
|
||||
u_int8_t reserved;
|
||||
u_int16_t serial_num;
|
||||
u_int16_t desc_crc;
|
||||
u_int16_t desc_crc_len;
|
||||
u_int32_t tag_loc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Recorded Address [4/7.1] */
|
||||
struct lb_addr {
|
||||
u_int32_t lb_num;
|
||||
u_int16_t part_num;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Extent Descriptor [3/7.1] */
|
||||
struct extent_ad {
|
||||
u_int32_t len;
|
||||
u_int32_t loc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Short Allocation Descriptor [4/14.14.1] */
|
||||
struct short_ad {
|
||||
u_int32_t len;
|
||||
u_int32_t pos;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Long Allocation Descriptor [4/14.14.2] */
|
||||
struct long_ad {
|
||||
u_int32_t len;
|
||||
struct lb_addr loc;
|
||||
u_int16_t ad_flags;
|
||||
u_int32_t ad_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Extended Allocation Descriptor [4/14.14.3] */
|
||||
struct ext_ad {
|
||||
u_int32_t ex_len;
|
||||
u_int32_t rec_len;
|
||||
u_int32_t inf_len;
|
||||
struct lb_addr ex_loc;
|
||||
u_int8_t reserved[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union icb {
|
||||
struct short_ad s_ad;
|
||||
struct long_ad l_ad;
|
||||
struct ext_ad e_ad;
|
||||
};
|
||||
|
||||
/* Character set spec [1/7.2.1] */
|
||||
struct charspec {
|
||||
u_int8_t type;
|
||||
u_int8_t inf[63];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Timestamp [1/7.3] */
|
||||
struct timestamp {
|
||||
u_int16_t type_tz;
|
||||
u_int16_t year;
|
||||
u_int8_t month;
|
||||
u_int8_t day;
|
||||
u_int8_t hour;
|
||||
u_int8_t minute;
|
||||
u_int8_t second;
|
||||
u_int8_t centisec;
|
||||
u_int8_t hund_usec;
|
||||
u_int8_t usec;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Entity Identifier [1/7.4] */
|
||||
#define UDF_REGID_ID_SIZE 23
|
||||
struct regid {
|
||||
u_int8_t flags;
|
||||
u_int8_t id[UDF_REGID_ID_SIZE];
|
||||
u_int8_t id_suffix[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* ICB Tag [4/14.6] */
|
||||
struct icb_tag {
|
||||
u_int32_t prev_num_dirs;
|
||||
u_int16_t strat_type;
|
||||
u_int8_t strat_param[2];
|
||||
u_int16_t max_num_entries;
|
||||
u_int8_t reserved;
|
||||
u_int8_t file_type;
|
||||
struct lb_addr parent_icb;
|
||||
u_int16_t flags;
|
||||
} __attribute__ ((packed));
|
||||
#define UDF_ICB_TAG_FLAGS_SETUID 0x40
|
||||
#define UDF_ICB_TAG_FLAGS_SETGID 0x80
|
||||
#define UDF_ICB_TAG_FLAGS_STICKY 0x100
|
||||
|
||||
/* Anchor Volume Descriptor Pointer [3/10.2] */
|
||||
struct anchor_vdp {
|
||||
struct desc_tag tag;
|
||||
struct extent_ad main_vds_ex;
|
||||
struct extent_ad reserve_vds_ex;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Volume Descriptor Pointer [3/10.3] */
|
||||
struct vol_desc_ptr {
|
||||
struct desc_tag tag;
|
||||
u_int32_t vds_number;
|
||||
struct extent_ad next_vds_ex;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Primary Volume Descriptor [3/10.1] */
|
||||
struct pri_vol_desc {
|
||||
struct desc_tag tag;
|
||||
u_int32_t seq_num;
|
||||
u_int32_t pdv_num;
|
||||
char vol_id[32];
|
||||
u_int16_t vds_num;
|
||||
u_int16_t max_vol_seq;
|
||||
u_int16_t ichg_lvl;
|
||||
u_int16_t max_ichg_lvl;
|
||||
u_int32_t charset_list;
|
||||
u_int32_t max_charset_list;
|
||||
char volset_id[128];
|
||||
struct charspec desc_charset;
|
||||
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;
|
||||
u_int8_t imp_use[64];
|
||||
u_int32_t prev_vds_lov;
|
||||
u_int16_t flags;
|
||||
u_int8_t reserved[22];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Logical Volume Descriptor [3/10.6] */
|
||||
struct logvol_desc {
|
||||
struct desc_tag tag;
|
||||
u_int32_t seq_num;
|
||||
struct charspec desc_charset;
|
||||
char logvol_id[128];
|
||||
u_int32_t lb_size;
|
||||
struct regid domain_id;
|
||||
union {
|
||||
struct long_ad fsd_loc;
|
||||
u_int8_t logvol_content_use[16];
|
||||
} _lvd_use;
|
||||
u_int32_t mt_l; /* Partition map length */
|
||||
u_int32_t n_pm; /* Number of partition maps */
|
||||
struct regid imp_id;
|
||||
u_int8_t imp_use[128];
|
||||
struct extent_ad integrity_seq_id;
|
||||
u_int8_t maps[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define UDF_PMAP_SIZE 64
|
||||
|
||||
/* Type 1 Partition Map [3/10.7.2] */
|
||||
struct part_map_1 {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int16_t vol_seq_num;
|
||||
u_int16_t part_num;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Type 2 Partition Map [3/10.7.3] */
|
||||
struct part_map_2 {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int8_t part_id[62];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Virtual Partition Map [UDF 2.01/2.2.8] */
|
||||
struct part_map_virt {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int8_t reserved[2];
|
||||
struct regid id;
|
||||
u_int16_t vol_seq_num;
|
||||
u_int16_t part_num;
|
||||
u_int8_t reserved1[24];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Sparable Partition Map [UDF 2.01/2.2.9] */
|
||||
struct part_map_spare {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int8_t reserved[2];
|
||||
struct regid id;
|
||||
u_int16_t vol_seq_num;
|
||||
u_int16_t part_num;
|
||||
u_int16_t packet_len;
|
||||
u_int8_t n_st; /* Number of Sparing Tables */
|
||||
u_int8_t reserved1;
|
||||
u_int32_t st_size;
|
||||
u_int32_t st_loc[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union udf_pmap {
|
||||
u_int8_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;
|
||||
};
|
||||
|
||||
/* Sparing Map Entry [UDF 2.01/2.2.11] */
|
||||
struct spare_map_entry {
|
||||
u_int32_t org;
|
||||
u_int32_t map;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Sparing Table [UDF 2.01/2.2.11] */
|
||||
struct udf_sparing_table {
|
||||
struct desc_tag tag;
|
||||
struct regid id;
|
||||
u_int16_t rt_l; /* Relocation Table len */
|
||||
u_int8_t reserved[2];
|
||||
u_int32_t seq_num;
|
||||
struct spare_map_entry entries[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition Descriptor [3/10.5] */
|
||||
struct part_desc {
|
||||
struct desc_tag tag;
|
||||
u_int32_t seq_num;
|
||||
u_int16_t flags;
|
||||
u_int16_t part_num;
|
||||
struct regid contents;
|
||||
u_int8_t contents_use[128];
|
||||
u_int32_t access_type;
|
||||
u_int32_t start_loc;
|
||||
u_int32_t part_len;
|
||||
struct regid imp_id;
|
||||
u_int8_t imp_use[128];
|
||||
u_int8_t reserved[156];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Set Descriptor [4/14.1] */
|
||||
struct fileset_desc {
|
||||
struct desc_tag tag;
|
||||
struct timestamp time;
|
||||
u_int16_t ichg_lvl;
|
||||
u_int16_t max_ichg_lvl;
|
||||
u_int32_t charset_list;
|
||||
u_int32_t max_charset_list;
|
||||
u_int32_t fileset_num;
|
||||
u_int32_t fileset_desc_num;
|
||||
struct charspec logvol_id_charset;
|
||||
char logvol_id[128];
|
||||
struct charspec fileset_charset;
|
||||
char fileset_id[32];
|
||||
char copyright_file_id[32];
|
||||
char abstract_file_id[32];
|
||||
struct long_ad rootdir_icb;
|
||||
struct regid domain_id;
|
||||
struct long_ad next_ex;
|
||||
struct long_ad streamdir_icb;
|
||||
u_int8_t reserved[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Identifier Descriptor [4/14.4] */
|
||||
struct fileid_desc {
|
||||
struct desc_tag tag;
|
||||
u_int16_t file_num;
|
||||
u_int8_t file_char;
|
||||
u_int8_t l_fi; /* Length of file identifier area */
|
||||
struct long_ad icb;
|
||||
u_int16_t l_iu; /* Length of implementaion use area */
|
||||
u_int8_t data[1];
|
||||
} __attribute__ ((packed));
|
||||
#define UDF_FID_SIZE 38
|
||||
|
||||
/* File Entry [4/14.9] */
|
||||
struct file_entry {
|
||||
struct desc_tag tag;
|
||||
struct icb_tag icbtag;
|
||||
u_int32_t uid;
|
||||
u_int32_t gid;
|
||||
u_int32_t perm;
|
||||
u_int16_t link_cnt;
|
||||
u_int8_t rec_format;
|
||||
u_int8_t rec_disp_attr;
|
||||
u_int32_t rec_len;
|
||||
u_int64_t inf_len;
|
||||
u_int64_t logblks_rec;
|
||||
struct timestamp atime;
|
||||
struct timestamp mtime;
|
||||
struct timestamp attrtime;
|
||||
u_int32_t ckpoint;
|
||||
struct long_ad ex_attr_icb;
|
||||
struct regid imp_id;
|
||||
u_int64_t unique_id;
|
||||
u_int32_t l_ea; /* Length of extended attribute area */
|
||||
u_int32_t l_ad; /* Length of allocation descriptors */
|
||||
u_int8_t data[1];
|
||||
} __attribute ((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
|
||||
|
||||
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 part_desc pd;
|
||||
struct fileset_desc fsd;
|
||||
struct fileid_desc fid;
|
||||
struct file_entry fe;
|
||||
};
|
||||
|
||||
/* Useful defines */
|
||||
|
||||
#define GETICB(ad_type, fentry, offset) \
|
||||
(struct ad_type *)&fentry->data[offset]
|
||||
|
||||
#define GETICBLEN(ad_type, icb) ((struct ad_type *)(icb))->len
|
466
sys/fs/udf/osta.c
Normal file
466
sys/fs/udf/osta.c
Normal file
@ -0,0 +1,466 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <fs/udf/osta.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
/***********************************************************************
|
||||
* OSTA compliant Unicode compression, uncompression routines.
|
||||
* Copyright 1995 Micro Design International, Inc.
|
||||
* Written by Jason M. Rinn.
|
||||
* Micro Design International gives permission for the free use of the
|
||||
* following source code.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
/***********************************************************************
|
||||
* Takes an OSTA CS0 compressed unicode name, and converts
|
||||
* it to Unicode.
|
||||
* The Unicode output will be in the byte order
|
||||
* that the local compiler uses for 16-bit values.
|
||||
* NOTE: This routine only performs error checking on the compID.
|
||||
* It is up to the user to ensure that the unicode buffer is large
|
||||
* enough, and that the compressed unicode name is correct.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* The number of unicode characters which were uncompressed.
|
||||
* A -1 is returned if the compression ID is invalid.
|
||||
*/
|
||||
int
|
||||
udf_UncompressUnicode(
|
||||
int numberOfBytes, /* (Input) number of bytes read from media. */
|
||||
byte *UDFCompressed, /* (Input) bytes read from media. */
|
||||
unicode_t *unicode) /* (Output) uncompressed unicode characters. */
|
||||
{
|
||||
unsigned int compID;
|
||||
int returnValue, unicodeIndex, byteIndex;
|
||||
|
||||
/* Use UDFCompressed to store current byte being read. */
|
||||
compID = UDFCompressed[0];
|
||||
|
||||
/* First check for valid compID. */
|
||||
if (compID != 8 && compID != 16) {
|
||||
returnValue = -1;
|
||||
} else {
|
||||
unicodeIndex = 0;
|
||||
byteIndex = 1;
|
||||
|
||||
/* Loop through all the bytes. */
|
||||
while (byteIndex < numberOfBytes) {
|
||||
if (compID == 16) {
|
||||
/* Move the first byte to the high bits of the
|
||||
* unicode char.
|
||||
*/
|
||||
unicode[unicodeIndex] =
|
||||
UDFCompressed[byteIndex++] << 8;
|
||||
} else {
|
||||
unicode[unicodeIndex] = 0;
|
||||
}
|
||||
if (byteIndex < numberOfBytes) {
|
||||
/*Then the next byte to the low bits. */
|
||||
unicode[unicodeIndex] |=
|
||||
UDFCompressed[byteIndex++];
|
||||
}
|
||||
unicodeIndex++;
|
||||
}
|
||||
returnValue = unicodeIndex;
|
||||
}
|
||||
return(returnValue);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DESCRIPTION:
|
||||
* Takes a string of unicode wide characters and returns an OSTA CS0
|
||||
* compressed unicode string. The unicode MUST be in the byte order of
|
||||
* the compiler in order to obtain correct results. Returns an error
|
||||
* if the compression ID is invalid.
|
||||
*
|
||||
* NOTE: This routine assumes the implementation already knows, by
|
||||
* the local environment, how many bits are appropriate and
|
||||
* therefore does no checking to test if the input characters fit
|
||||
* into that number of bits or not.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* The total number of bytes in the compressed OSTA CS0 string,
|
||||
* including the compression ID.
|
||||
* A -1 is returned if the compression ID is invalid.
|
||||
*/
|
||||
int
|
||||
udf_CompressUnicode(
|
||||
int numberOfChars, /* (Input) number of unicode characters. */
|
||||
int compID, /* (Input) compression ID to be used. */
|
||||
unicode_t *unicode, /* (Input) unicode characters to compress. */
|
||||
byte *UDFCompressed) /* (Output) compressed string, as bytes. */
|
||||
{
|
||||
int byteIndex, unicodeIndex;
|
||||
|
||||
if (compID != 8 && compID != 16) {
|
||||
byteIndex = -1; /* Unsupported compression ID ! */
|
||||
} else {
|
||||
/* Place compression code in first byte. */
|
||||
UDFCompressed[0] = compID;
|
||||
|
||||
byteIndex = 1;
|
||||
unicodeIndex = 0;
|
||||
while (unicodeIndex < numberOfChars) {
|
||||
if (compID == 16) {
|
||||
/* First, place the high bits of the char
|
||||
* into the byte stream.
|
||||
*/
|
||||
UDFCompressed[byteIndex++] =
|
||||
(unicode[unicodeIndex] & 0xFF00) >> 8;
|
||||
}
|
||||
/*Then place the low bits into the stream. */
|
||||
UDFCompressed[byteIndex++] =
|
||||
unicode[unicodeIndex] & 0x00FF;
|
||||
unicodeIndex++;
|
||||
}
|
||||
}
|
||||
return(byteIndex);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* CRC 010041
|
||||
*/
|
||||
static unsigned short 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
|
||||
};
|
||||
|
||||
unsigned short
|
||||
udf_cksum(s, n)
|
||||
unsigned char *s;
|
||||
int n;
|
||||
{
|
||||
unsigned short crc=0;
|
||||
|
||||
while (n-- > 0)
|
||||
crc = crc_table[(crc>>8 ^ *s++) & 0xff] ^ (crc<<8);
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* UNICODE Checksum */
|
||||
unsigned short
|
||||
udf_unicode_cksum(s, n)
|
||||
unsigned short *s;
|
||||
int n;
|
||||
{
|
||||
unsigned short crc=0;
|
||||
|
||||
while (n-- > 0) {
|
||||
/* Take high order byte first--corresponds to a big endian
|
||||
* byte stream.
|
||||
*/
|
||||
crc = crc_table[(crc>>8 ^ (*s>>8)) & 0xff] ^ (crc<<8);
|
||||
crc = crc_table[(crc>>8 ^ (*s++ & 0xff)) & 0xff] ^ (crc<<8);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
#ifdef MAIN
|
||||
unsigned char bytes[] = { 0x70, 0x6A, 0x77 };
|
||||
|
||||
main()
|
||||
{
|
||||
unsigned short x;
|
||||
x = cksum(bytes, sizeof bytes);
|
||||
printf("checksum: calculated=%4.4x, correct=%4.4x\en", x, 0x3299);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
#ifdef NEEDS_ISPRINT
|
||||
/***********************************************************************
|
||||
* OSTA UDF compliant file name translation routine for OS/2,
|
||||
* Windows 95, Windows NT, Macintosh and UNIX.
|
||||
* Copyright 1995 Micro Design International, Inc.
|
||||
* Written by Jason M. Rinn.
|
||||
* Micro Design International gives permission for the free use of the
|
||||
* following source code.
|
||||
*/
|
||||
|
||||
/***********************************************************************
|
||||
* To use these routines with different operating systems.
|
||||
*
|
||||
* OS/2
|
||||
* Define OS2
|
||||
* Define MAXLEN = 254
|
||||
*
|
||||
* Windows 95
|
||||
* Define WIN_95
|
||||
* Define MAXLEN = 255
|
||||
*
|
||||
* Windows NT
|
||||
* Define WIN_NT
|
||||
* Define MAXLEN = 255
|
||||
*
|
||||
* Macintosh:
|
||||
* Define MAC.
|
||||
* Define MAXLEN = 31.
|
||||
*
|
||||
* UNIX
|
||||
* Define UNIX.
|
||||
* Define MAXLEN as specified by unix version.
|
||||
*/
|
||||
|
||||
#define ILLEGAL_CHAR_MARK 0x005F
|
||||
#define CRC_MARK 0x0023
|
||||
#define EXT_SIZE 5
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define PERIOD 0x002E
|
||||
#define SPACE 0x0020
|
||||
|
||||
/*** PROTOTYPES ***/
|
||||
int IsIllegal(unicode_t ch);
|
||||
|
||||
/* Define a function or macro which determines if a Unicode character is
|
||||
* printable under your implementation.
|
||||
*/
|
||||
int UnicodeIsPrint(unicode_t);
|
||||
|
||||
/***********************************************************************
|
||||
* Translates a long file name to one using a MAXLEN and an illegal
|
||||
* char set in accord with the OSTA requirements. Assumes the name has
|
||||
* already been translated to Unicode.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* Number of unicode characters in translated name.
|
||||
*/
|
||||
int UDFTransName(
|
||||
unicode_t *newName, /* (Output)Translated name. Must be of length
|
||||
* MAXLEN */
|
||||
unicode_t *udfName, /* (Input) Name from UDF volume.*/
|
||||
int udfLen) /* (Input) Length of UDF Name. */
|
||||
{
|
||||
int index, newIndex = 0, needsCRC = FALSE;
|
||||
int extIndex = 0, newExtIndex = 0, hasExt = FALSE;
|
||||
#if defined OS2 || defined WIN_95 || defined WIN_NT
|
||||
int trailIndex = 0;
|
||||
#endif
|
||||
unsigned short valueCRC;
|
||||
unicode_t current;
|
||||
const char hexChar[] = "0123456789ABCDEF";
|
||||
|
||||
for (index = 0; index < udfLen; index++) {
|
||||
current = udfName[index];
|
||||
|
||||
if (IsIllegal(current) || !UnicodeIsPrint(current)) {
|
||||
needsCRC = TRUE;
|
||||
/* Replace Illegal and non-displayable chars with
|
||||
* underscore.
|
||||
*/
|
||||
current = ILLEGAL_CHAR_MARK;
|
||||
/* Skip any other illegal or non-displayable
|
||||
* characters.
|
||||
*/
|
||||
while(index+1 < udfLen && (IsIllegal(udfName[index+1])
|
||||
|| !UnicodeIsPrint(udfName[index+1]))) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record position of extension, if one is found. */
|
||||
if (current == PERIOD && (udfLen - index -1) <= EXT_SIZE) {
|
||||
if (udfLen == index + 1) {
|
||||
/* A trailing period is NOT an extension. */
|
||||
hasExt = FALSE;
|
||||
} else {
|
||||
hasExt = TRUE;
|
||||
extIndex = index;
|
||||
newExtIndex = newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined OS2 || defined WIN_95 || defined WIN_NT
|
||||
/* Record position of last char which is NOT period or space. */
|
||||
else if (current != PERIOD && current != SPACE) {
|
||||
trailIndex = newIndex;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (newIndex < MAXLEN) {
|
||||
newName[newIndex++] = current;
|
||||
} else {
|
||||
needsCRC = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined OS2 || defined WIN_95 || defined WIN_NT
|
||||
/* For OS2, 95 & NT, truncate any trailing periods and\or spaces. */
|
||||
if (trailIndex != newIndex - 1) {
|
||||
newIndex = trailIndex + 1;
|
||||
needsCRC = TRUE;
|
||||
hasExt = FALSE; /* Trailing period does not make an
|
||||
* extension. */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (needsCRC) {
|
||||
unicode_t ext[EXT_SIZE];
|
||||
int localExtIndex = 0;
|
||||
if (hasExt) {
|
||||
int maxFilenameLen;
|
||||
/* Translate extension, and store it in ext. */
|
||||
for(index = 0; index<EXT_SIZE &&
|
||||
extIndex + index +1 < udfLen; index++ ) {
|
||||
current = udfName[extIndex + index + 1];
|
||||
if (IsIllegal(current) ||
|
||||
!UnicodeIsPrint(current)) {
|
||||
needsCRC = 1;
|
||||
/* Replace Illegal and non-displayable
|
||||
* chars with underscore.
|
||||
*/
|
||||
current = ILLEGAL_CHAR_MARK;
|
||||
/* Skip any other illegal or
|
||||
* non-displayable characters.
|
||||
*/
|
||||
while(index + 1 < EXT_SIZE
|
||||
&& (IsIllegal(udfName[extIndex +
|
||||
index + 2]) ||
|
||||
!isprint(udfName[extIndex +
|
||||
index + 2]))) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
ext[localExtIndex++] = current;
|
||||
}
|
||||
|
||||
/* Truncate filename to leave room for extension and
|
||||
* CRC.
|
||||
*/
|
||||
maxFilenameLen = ((MAXLEN - 5) - localExtIndex - 1);
|
||||
if (newIndex > maxFilenameLen) {
|
||||
newIndex = maxFilenameLen;
|
||||
} else {
|
||||
newIndex = newExtIndex;
|
||||
}
|
||||
} else if (newIndex > MAXLEN - 5) {
|
||||
/*If no extension, make sure to leave room for CRC. */
|
||||
newIndex = MAXLEN - 5;
|
||||
}
|
||||
newName[newIndex++] = CRC_MARK; /* Add mark for CRC. */
|
||||
|
||||
/*Calculate CRC from original filename from FileIdentifier. */
|
||||
valueCRC = udf_unicode_cksum(udfName, udfLen);
|
||||
/* Convert 16-bits of CRC to hex characters. */
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
|
||||
|
||||
/* Place a translated extension at end, if found. */
|
||||
if (hasExt) {
|
||||
newName[newIndex++] = PERIOD;
|
||||
for (index = 0;index < localExtIndex ;index++ ) {
|
||||
newName[newIndex++] = ext[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
return(newIndex);
|
||||
}
|
||||
|
||||
#if defined OS2 || defined WIN_95 || defined WIN_NT
|
||||
/***********************************************************************
|
||||
* Decides if a Unicode character matches one of a list
|
||||
* of ASCII characters.
|
||||
* Used by OS2 version of IsIllegal for readability, since all of the
|
||||
* illegal characters above 0x0020 are in the ASCII subset of Unicode.
|
||||
* Works very similarly to the standard C function strchr().
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* Non-zero if the Unicode character is in the given ASCII string.
|
||||
*/
|
||||
int UnicodeInString(
|
||||
unsigned char *string, /* (Input) String to search through. */
|
||||
unicode_t ch) /* (Input) Unicode char to search for. */
|
||||
{
|
||||
int found = FALSE;
|
||||
while (*string != '\0' && found == FALSE) {
|
||||
/* These types should compare, since both are unsigned
|
||||
* numbers. */
|
||||
if (*string == ch) {
|
||||
found = TRUE;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
return(found);
|
||||
}
|
||||
#endif /* OS2 */
|
||||
|
||||
/***********************************************************************
|
||||
* Decides whether the given character is illegal for a given OS.
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* Non-zero if char is illegal.
|
||||
*/
|
||||
int IsIllegal(unicode_t ch)
|
||||
{
|
||||
#ifdef MAC
|
||||
/* Only illegal character on the MAC is the colon. */
|
||||
if (ch == 0x003A) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
|
||||
#elif defined UNIX
|
||||
/* Illegal UNIX characters are NULL and slash. */
|
||||
if (ch == 0x0000 || ch == 0x002F) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
|
||||
#elif defined OS2 || defined WIN_95 || defined WIN_NT
|
||||
/* Illegal char's for OS/2 according to WARP toolkit. */
|
||||
if (ch < 0x0020 || UnicodeInString("\\/:*?\"<>|", ch)) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
27
sys/fs/udf/osta.h
Normal file
27
sys/fs/udf/osta.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Prototypes for the OSTA functions
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef UNIX
|
||||
#define UNIX
|
||||
#endif
|
||||
|
||||
#ifndef MAXLEN
|
||||
#define MAXLEN 255
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* The following two typedef's are to remove compiler dependancies.
|
||||
* byte needs to be unsigned 8-bit, and unicode_t needs to be
|
||||
* unsigned 16-bit.
|
||||
*/
|
||||
typedef unsigned short unicode_t;
|
||||
typedef unsigned char byte;
|
||||
|
||||
int udf_UncompressUnicode(int, byte *, unicode_t *);
|
||||
int udf_CompressUnicode(int, int, unicode_t *, byte *);
|
||||
unsigned short udf_cksum(unsigned char *, int);
|
||||
unsigned short udf_unicode_cksum(unsigned short *, int);
|
||||
int UDFTransName(unicode_t *, unicode_t *, int);
|
115
sys/fs/udf/udf.h
Normal file
115
sys/fs/udf/udf.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*-
|
||||
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
struct udf_node {
|
||||
TAILQ_ENTRY(udf_node) tq;
|
||||
struct vnode *i_vnode;
|
||||
struct vnode *i_devvp;
|
||||
struct udf_mnt *udfmp;
|
||||
dev_t i_dev;
|
||||
ino_t hash_id;
|
||||
long diroff;
|
||||
struct file_entry *fentry;
|
||||
};
|
||||
|
||||
struct udf_mnt {
|
||||
int im_flags;
|
||||
struct mount *im_mountp;
|
||||
dev_t im_dev;
|
||||
struct vnode *im_devvp;
|
||||
int bsize;
|
||||
int bshift;
|
||||
int bmask;
|
||||
u_int32_t part_start;
|
||||
u_int32_t part_len;
|
||||
u_int64_t root_id;
|
||||
struct vnode *root_vp;
|
||||
struct long_ad root_icb;
|
||||
TAILQ_HEAD(, udf_node) udf_tqh;
|
||||
struct mtx hash_mtx;
|
||||
int p_sectors;
|
||||
int s_table_entries;
|
||||
struct udf_sparing_table *s_table;
|
||||
};
|
||||
|
||||
#define VFSTOUDFFS(mp) ((struct udf_mnt *)((mp)->mnt_data))
|
||||
#define VTON(vp) ((struct udf_node *)((vp)->v_data))
|
||||
|
||||
/*
|
||||
* The block layer refers to things in terms of 512 byte blocks by default.
|
||||
* btodb() is expensive, so speed things up.
|
||||
* XXX Can the block layer be forced to use a different block size?
|
||||
*/
|
||||
#define RDSECTOR(devvp, sector, size, bp) \
|
||||
bread(devvp, sector << (udfmp->bshift - DEV_BSHIFT), size, NOCRED, bp)
|
||||
|
||||
MALLOC_DECLARE(M_UDFFENTRY);
|
||||
|
||||
static __inline int
|
||||
udf_readlblks(struct udf_mnt *udfmp, int sector, int size, struct buf **bp)
|
||||
{
|
||||
return (bread(udfmp->im_devvp, sector << (udfmp->bshift - DEV_BSHIFT),
|
||||
(size + udfmp->bmask) & ~udfmp->bmask, NOCRED, bp));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
udf_readalblks(struct udf_mnt *udfmp, int lsector, int size, struct buf **bp)
|
||||
{
|
||||
daddr_t rablock, lblk;
|
||||
int rasize;
|
||||
|
||||
lblk = (lsector + udfmp->part_start) << (udfmp->bshift - DEV_BSHIFT);
|
||||
rablock = (lblk + 1) << udfmp->bshift;
|
||||
rasize = size;
|
||||
|
||||
return (breadn(udfmp->im_devvp, lblk,
|
||||
(size + udfmp->bmask) & ~udfmp->bmask,
|
||||
&rablock, &rasize, 1, NOCRED, bp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce a suitable file number from an ICB.
|
||||
* XXX If the fileno resolves to 0, we might be in big trouble.
|
||||
* XXX Assumes the ICB is a long_ad. This struct is compatible with short_ad,
|
||||
* but not ext_ad.
|
||||
*/
|
||||
static ino_t
|
||||
udf_getid(struct long_ad *icb)
|
||||
{
|
||||
return (icb->loc.lb_num);
|
||||
}
|
||||
|
||||
int udf_allocv(struct mount *, struct vnode **, struct thread *);
|
||||
int udf_hashlookup(struct udf_mnt *, ino_t, int, struct vnode **);
|
||||
int udf_hashins(struct udf_node *);
|
||||
int udf_hashrem(struct udf_node *);
|
||||
int udf_checktag(struct desc_tag *, u_int16_t);
|
||||
int udf_vget(struct mount *, ino_t, int, struct vnode **);
|
||||
|
||||
extern uma_zone_t udf_zone_trans;
|
||||
extern uma_zone_t udf_zone_node;
|
34
sys/fs/udf/udf_mount.h
Normal file
34
sys/fs/udf/udf_mount.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*-
|
||||
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
struct udf_args {
|
||||
char *fspec;
|
||||
struct export_args export;
|
||||
int flags;
|
||||
int ssector;
|
||||
};
|
744
sys/fs/udf/udf_vfsops.c
Normal file
744
sys/fs/udf/udf_vfsops.c
Normal file
@ -0,0 +1,744 @@
|
||||
/*-
|
||||
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* udf_vfsops.c */
|
||||
/* Implement the VFS side of things */
|
||||
|
||||
/*
|
||||
* Ok, here's how it goes. The UDF specs are pretty clear on how each data
|
||||
* structure is made up, but not very clear on how they relate to each other.
|
||||
* Here is the skinny... This demostrates a filesystem with one file in the
|
||||
* root directory. Subdirectories are treated just as normal files, but they
|
||||
* have File Id Descriptors of their children as their file data. As for the
|
||||
* Anchor Volume Descriptor Pointer, it can exist in two of the following three
|
||||
* places: sector 256, sector n (the max sector of the disk), or sector
|
||||
* n - 256. It's a pretty good bet that one will exist at sector 256 though.
|
||||
* One caveat is unclosed CD media. For that, sector 256 cannot be written,
|
||||
* so the Anchor Volume Descriptor Pointer can exist at sector 512 until the
|
||||
* media is closed.
|
||||
*
|
||||
* Sector:
|
||||
* 256:
|
||||
* n: Anchor Volume Descriptor Pointer
|
||||
* n - 256: |
|
||||
* |
|
||||
* |-->Main Volume Descriptor Sequence
|
||||
* | |
|
||||
* | |
|
||||
* | |-->Logical Volume Descriptor
|
||||
* | |
|
||||
* |-->Partition Descriptor |
|
||||
* | |
|
||||
* | |
|
||||
* |-->Fileset Descriptor
|
||||
* |
|
||||
* |
|
||||
* |-->Root Dir File Entry
|
||||
* |
|
||||
* |
|
||||
* |-->File data:
|
||||
* File Id Descriptor
|
||||
* |
|
||||
* |
|
||||
* |-->File Entry
|
||||
* |
|
||||
* |
|
||||
* |-->File data
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/dirent.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
#include <fs/udf/ecma167-udf.h>
|
||||
#include <fs/udf/udf.h>
|
||||
#include <fs/udf/udf_mount.h>
|
||||
#include <fs/udf/osta.h>
|
||||
|
||||
MALLOC_DEFINE(M_UDFMOUNT, "UDF mount", "UDF mount structure");
|
||||
MALLOC_DEFINE(M_UDFFENTRY, "UDF fentry", "UDF file entry structure");
|
||||
MALLOC_DEFINE(M_UDFSTABLE, "UDF s_table", "UDF sparing table");
|
||||
|
||||
/* Zones */
|
||||
uma_zone_t udf_zone_trans = NULL;
|
||||
uma_zone_t udf_zone_node = NULL;
|
||||
|
||||
static int udf_init(struct vfsconf *);
|
||||
static int udf_uninit(struct vfsconf *);
|
||||
static int udf_mount(struct mount *, char *, caddr_t, struct nameidata *,
|
||||
struct thread *);
|
||||
static int udf_unmount(struct mount *, int, struct thread *);
|
||||
static int udf_root(struct mount *, struct vnode **);
|
||||
static int udf_statfs(struct mount *, struct statfs *, struct thread *);
|
||||
static int udf_fhtovp(struct mount *, struct fid *, struct vnode **);
|
||||
static int udf_vptofh(struct vnode *, struct fid *);
|
||||
static int udf_find_partmaps(struct udf_mnt *, struct logvol_desc *);
|
||||
|
||||
static struct vfsops udf_vfsops = {
|
||||
udf_mount,
|
||||
vfs_stdstart,
|
||||
udf_unmount,
|
||||
udf_root,
|
||||
vfs_stdquotactl,
|
||||
udf_statfs,
|
||||
vfs_stdsync,
|
||||
udf_vget,
|
||||
udf_fhtovp,
|
||||
vfs_stdcheckexp,
|
||||
udf_vptofh,
|
||||
udf_init,
|
||||
udf_uninit,
|
||||
vfs_stdextattrctl,
|
||||
};
|
||||
VFS_SET(udf_vfsops, udf, VFCF_READONLY);
|
||||
|
||||
static int udf_mountfs(struct vnode *, struct mount *, struct thread *, struct udf_args *);
|
||||
|
||||
static int
|
||||
udf_init(struct vfsconf *foo)
|
||||
{
|
||||
|
||||
/*
|
||||
* This code used to pre-allocate a certain number of pages for each
|
||||
* pool, reducing the need to grow the zones later on. UMA doesn't
|
||||
* advertise any such functionality, unfortunately =-<
|
||||
*/
|
||||
udf_zone_trans = uma_zcreate("UDF translation buffer, zone", MAXNAMLEN *
|
||||
sizeof(unicode_t), NULL, NULL, NULL, NULL, 0, 0);
|
||||
|
||||
udf_zone_node = uma_zcreate("UDF Node zone", sizeof(struct udf_node),
|
||||
NULL, NULL, NULL, NULL, 0, 0);
|
||||
|
||||
if ((udf_zone_node == NULL) || (udf_zone_trans == NULL)) {
|
||||
printf("Cannot create allocation zones.\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
udf_uninit(struct vfsconf *foo)
|
||||
{
|
||||
|
||||
if (udf_zone_trans != NULL) {
|
||||
uma_zdestroy(udf_zone_trans);
|
||||
udf_zone_trans = NULL;
|
||||
}
|
||||
|
||||
if (udf_zone_node != NULL) {
|
||||
uma_zdestroy(udf_zone_node);
|
||||
udf_zone_node = NULL;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
udf_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct thread *td)
|
||||
{
|
||||
struct vnode *devvp; /* vnode of the mount device */
|
||||
struct udf_args args;
|
||||
struct udf_mnt *imp = 0;
|
||||
size_t size;
|
||||
int error;
|
||||
|
||||
if ((mp->mnt_flag & MNT_RDONLY) == 0)
|
||||
return (EROFS);
|
||||
|
||||
/*
|
||||
* No root filesystem support. Probably not a big deal, since the
|
||||
* bootloader doesn't understand UDF.
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_ROOTFS)
|
||||
return (ENOTSUP);
|
||||
|
||||
if ((error = copyin(data, (caddr_t)&args, sizeof(struct udf_args))))
|
||||
return (error);
|
||||
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
imp = VFSTOUDFFS(mp);
|
||||
if (args.fspec == 0)
|
||||
return (vfs_export(mp, &args.export));
|
||||
}
|
||||
|
||||
/* Check that the mount device exists */
|
||||
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
|
||||
if ((error = namei(ndp)))
|
||||
return (error);
|
||||
NDFREE(ndp, NDF_ONLY_PNBUF);
|
||||
devvp = ndp->ni_vp;
|
||||
|
||||
if (vn_isdisk(devvp, &error) == 0) {
|
||||
vrele(devvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Check the access rights on the mount device */
|
||||
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
error = VOP_ACCESS(devvp, VREAD, td->td_ucred, td);
|
||||
if (error)
|
||||
error = suser(td);
|
||||
if (error) {
|
||||
vput(devvp);
|
||||
return (error);
|
||||
}
|
||||
VOP_UNLOCK(devvp, 0, td);
|
||||
|
||||
if ((error = udf_mountfs(devvp, mp, td, &args))) {
|
||||
vrele(devvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
imp = VFSTOUDFFS(mp);
|
||||
copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
udf_statfs(mp, &mp->mnt_stat, td);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Check the descriptor tag for both the correct id and correct checksum.
|
||||
* Return zero if all is good, EINVAL if not.
|
||||
*/
|
||||
int
|
||||
udf_checktag(struct desc_tag *tag, u_int16_t id)
|
||||
{
|
||||
u_int8_t *itag;
|
||||
u_int8_t i, cksum = 0;
|
||||
|
||||
itag = (u_int8_t *)tag;
|
||||
|
||||
if (tag->id != id)
|
||||
return (EINVAL);
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
cksum = cksum + itag[i];
|
||||
cksum = cksum - itag[4];
|
||||
|
||||
if (cksum == tag->cksum)
|
||||
return (0);
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td, struct udf_args *argp) {
|
||||
struct buf *bp = NULL;
|
||||
struct anchor_vdp avdp;
|
||||
struct udf_mnt *udfmp = NULL;
|
||||
struct part_desc *pd;
|
||||
struct logvol_desc *lvd;
|
||||
struct fileset_desc *fsd;
|
||||
struct file_entry *root_fentry;
|
||||
u_int32_t sector, size, mvds_start, mvds_end;
|
||||
u_int32_t fsd_offset = 0;
|
||||
u_int16_t part_num = 0, fsd_part = 0;
|
||||
int error = EINVAL, needclose = 0;
|
||||
int logvol_found = 0, part_found = 0, fsd_found = 0;
|
||||
int bsize;
|
||||
|
||||
/*
|
||||
* Disallow multiple mounts of the same device. Flush the buffer
|
||||
* cache for the device.
|
||||
*/
|
||||
if ((error = vfs_mountedon(devvp)))
|
||||
return (error);
|
||||
if (vcount(devvp) > 1)
|
||||
return (EBUSY);
|
||||
if ((error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0)))
|
||||
return (error);
|
||||
|
||||
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
error = VOP_OPEN(devvp, FREAD, FSCRED, td);
|
||||
VOP_UNLOCK(devvp, 0, td);
|
||||
if (error)
|
||||
return error;
|
||||
needclose = 1;
|
||||
|
||||
MALLOC(udfmp, struct udf_mnt *, sizeof(struct udf_mnt), M_UDFMOUNT,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (udfmp == NULL) {
|
||||
printf("Cannot allocate UDF mount struct\n");
|
||||
error = ENOMEM;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
mp->mnt_data = (qaddr_t)udfmp;
|
||||
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_flag |= MNT_LOCAL;
|
||||
udfmp->im_mountp = mp;
|
||||
udfmp->im_dev = devvp->v_rdev;
|
||||
udfmp->im_devvp = devvp;
|
||||
|
||||
bsize = 2048; /* XXX Should probe the media for it's size */
|
||||
|
||||
/*
|
||||
* Get the Anchor Volume Descriptor Pointer from sector 256.
|
||||
* XXX Should also check sector n - 256, n, and 512.
|
||||
*/
|
||||
sector = 256;
|
||||
if ((error = bread(devvp, sector * btodb(bsize), bsize, NOCRED,
|
||||
&bp)) != 0)
|
||||
goto bail;
|
||||
if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
|
||||
goto bail;
|
||||
|
||||
bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
|
||||
/*
|
||||
* Extract the Partition Descriptor and Logical Volume Descriptor
|
||||
* from the Volume Descriptor Sequence.
|
||||
* XXX Should we care about the partition type right now?
|
||||
* XXX What about multiple partitions?
|
||||
*/
|
||||
mvds_start = avdp.main_vds_ex.loc;
|
||||
mvds_end = mvds_start + (avdp.main_vds_ex.len - 1) / bsize;
|
||||
for (sector = mvds_start; sector < mvds_end; sector++) {
|
||||
if ((error = bread(devvp, sector * btodb(bsize), bsize,
|
||||
NOCRED, &bp)) != 0) {
|
||||
printf("Can't read sector %d of VDS\n", sector);
|
||||
goto bail;
|
||||
}
|
||||
lvd = (struct logvol_desc *)bp->b_data;
|
||||
if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
|
||||
udfmp->bsize = lvd->lb_size;
|
||||
udfmp->bmask = udfmp->bsize - 1;
|
||||
udfmp->bshift = ffs(udfmp->bsize) - 1;
|
||||
fsd_part = lvd->_lvd_use.fsd_loc.loc.part_num;
|
||||
fsd_offset = lvd->_lvd_use.fsd_loc.loc.lb_num;
|
||||
if (udf_find_partmaps(udfmp, lvd))
|
||||
break;
|
||||
logvol_found = 1;
|
||||
}
|
||||
pd = (struct part_desc *)bp->b_data;
|
||||
if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
|
||||
part_found = 1;
|
||||
part_num = pd->part_num;
|
||||
udfmp->part_len = pd->part_len;
|
||||
udfmp->part_start = pd->start_loc;
|
||||
}
|
||||
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
if ((part_found) && (logvol_found))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!part_found || !logvol_found) {
|
||||
error = EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (fsd_part != part_num) {
|
||||
printf("FSD does not lie within the partition!\n");
|
||||
error = EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Grab the Fileset Descriptor
|
||||
* Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
|
||||
* me in the right direction here.
|
||||
*/
|
||||
sector = udfmp->part_start + fsd_offset;
|
||||
if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
|
||||
printf("Cannot read sector %d of FSD\n", sector);
|
||||
goto bail;
|
||||
}
|
||||
fsd = (struct fileset_desc *)bp->b_data;
|
||||
if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
|
||||
fsd_found = 1;
|
||||
bcopy(&fsd->rootdir_icb, &udfmp->root_icb,
|
||||
sizeof(struct long_ad));
|
||||
}
|
||||
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
|
||||
if (!fsd_found) {
|
||||
printf("Couldn't find the fsd\n");
|
||||
error = EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the file entry for the root directory.
|
||||
*/
|
||||
sector = udfmp->root_icb.loc.lb_num + udfmp->part_start;
|
||||
size = udfmp->root_icb.len;
|
||||
if ((error = udf_readlblks(udfmp, sector, size, &bp)) != 0) {
|
||||
printf("Cannot read sector %d\n", sector);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
root_fentry = (struct file_entry *)bp->b_data;
|
||||
if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) {
|
||||
printf("Invalid root file entry!\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
|
||||
TAILQ_INIT(&udfmp->udf_tqh);
|
||||
devvp->v_rdev->si_mountpoint = mp;
|
||||
|
||||
mtx_init(&udfmp->hash_mtx, "udf_hash", NULL, MTX_DEF);
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
if (udfmp != NULL)
|
||||
FREE(udfmp, M_UDFMOUNT);
|
||||
if (bp != NULL)
|
||||
brelse(bp);
|
||||
if (needclose)
|
||||
VOP_CLOSE(devvp, FREAD, NOCRED, td);
|
||||
return error;
|
||||
};
|
||||
|
||||
static int
|
||||
udf_unmount(struct mount *mp, int mntflags, struct thread *td)
|
||||
{
|
||||
struct udf_mnt *udfmp;
|
||||
int error, flags = 0;
|
||||
|
||||
udfmp = VFSTOUDFFS(mp);
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
if ((error = vflush(mp, 0, flags)))
|
||||
return (error);
|
||||
|
||||
udfmp->im_devvp->v_rdev->si_mountpoint = NULL;
|
||||
error = VOP_CLOSE(udfmp->im_devvp, FREAD, NOCRED, td);
|
||||
vrele(udfmp->im_devvp);
|
||||
|
||||
if (udfmp->s_table != NULL)
|
||||
FREE(udfmp->s_table, M_UDFSTABLE);
|
||||
FREE(udfmp, M_UDFMOUNT);
|
||||
|
||||
mp->mnt_data = (qaddr_t)0;
|
||||
mp->mnt_flag &= ~MNT_LOCAL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
udf_root(struct mount *mp, struct vnode **vpp)
|
||||
{
|
||||
struct udf_mnt *udfmp;
|
||||
struct vnode *vp;
|
||||
ino_t id;
|
||||
int error;
|
||||
|
||||
udfmp = VFSTOUDFFS(mp);
|
||||
|
||||
id = udf_getid(&udfmp->root_icb);
|
||||
|
||||
error = udf_vget(mp, id, LK_EXCLUSIVE, vpp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
vp = *vpp;
|
||||
vp->v_flag |= VROOT;
|
||||
udfmp->root_vp = vp;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
udf_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
|
||||
{
|
||||
struct udf_mnt *udfmp;
|
||||
|
||||
udfmp = VFSTOUDFFS(mp);
|
||||
|
||||
sbp->f_bsize = udfmp->bsize;
|
||||
sbp->f_iosize = udfmp->bsize;
|
||||
sbp->f_blocks = udfmp->part_len;
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = 0;
|
||||
sbp->f_ffree = 0;
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct vnode *devvp;
|
||||
struct udf_mnt *udfmp;
|
||||
struct thread *td;
|
||||
struct vnode *vp;
|
||||
struct udf_node *unode;
|
||||
struct file_entry *fe;
|
||||
int error, sector, size;
|
||||
|
||||
td = curthread;
|
||||
udfmp = VFSTOUDFFS(mp);
|
||||
|
||||
/* See if we already have this in the cache */
|
||||
if ((error = udf_hashlookup(udfmp, ino, flags, vpp)) != 0)
|
||||
return (error);
|
||||
if (*vpp != NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate memory and check the tag id's before grabbing a new
|
||||
* vnode, since it's hard to roll back if there is a problem.
|
||||
*/
|
||||
unode = uma_zalloc(udf_zone_node, M_WAITOK);
|
||||
if (unode == NULL) {
|
||||
printf("Cannot allocate udf node\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in the file entry. Per the spec, the size can only be 1 block.
|
||||
*/
|
||||
sector = ino + udfmp->part_start;
|
||||
devvp = udfmp->im_devvp;
|
||||
if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
|
||||
printf("Cannot read sector %d\n", sector);
|
||||
uma_zfree(udf_zone_node, unode);
|
||||
return (error);
|
||||
}
|
||||
|
||||
fe = (struct file_entry *)bp->b_data;
|
||||
if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
|
||||
printf("Invalid file entry!\n");
|
||||
uma_zfree(udf_zone_node, unode);
|
||||
brelse(bp);
|
||||
return (ENOMEM);
|
||||
}
|
||||
size = UDF_FENTRY_SIZE + fe->l_ea + fe->l_ad;
|
||||
MALLOC(unode->fentry, struct file_entry *, size, M_UDFFENTRY,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (unode->fentry == NULL) {
|
||||
printf("Cannot allocate file entry block\n");
|
||||
uma_zfree(udf_zone_node, unode);
|
||||
brelse(bp);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
bcopy(bp->b_data, unode->fentry, size);
|
||||
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
|
||||
if ((error = udf_allocv(mp, &vp, td))) {
|
||||
printf("Error from udf_allocv\n");
|
||||
uma_zfree(udf_zone_node, unode);
|
||||
return (error);
|
||||
}
|
||||
|
||||
unode->i_vnode = vp;
|
||||
unode->hash_id = ino;
|
||||
unode->i_devvp = udfmp->im_devvp;
|
||||
unode->i_dev = udfmp->im_dev;
|
||||
unode->udfmp = udfmp;
|
||||
vp->v_data = unode;
|
||||
lockinit(&vp->v_lock, PINOD, "udfnode", 0, 0);
|
||||
vp->v_vnlock = &vp->v_lock;
|
||||
VREF(udfmp->im_devvp);
|
||||
udf_hashins(unode);
|
||||
|
||||
switch (unode->fentry->icbtag.file_type) {
|
||||
default:
|
||||
vp->v_type = VBAD;
|
||||
break;
|
||||
case 4:
|
||||
vp->v_type = VDIR;
|
||||
break;
|
||||
case 5:
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
case 6:
|
||||
vp->v_type = VBLK;
|
||||
break;
|
||||
case 7:
|
||||
vp->v_type = VCHR;
|
||||
break;
|
||||
case 9:
|
||||
vp->v_type = VFIFO;
|
||||
break;
|
||||
case 10:
|
||||
vp->v_type = VSOCK;
|
||||
break;
|
||||
case 12:
|
||||
vp->v_type = VLNK;
|
||||
break;
|
||||
}
|
||||
*vpp = vp;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct ifid {
|
||||
ushort ifid_len;
|
||||
ushort ifid_pad;
|
||||
int ifid_ino;
|
||||
long ifid_start;
|
||||
};
|
||||
|
||||
static int
|
||||
udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
|
||||
{
|
||||
struct ifid *ifhp;
|
||||
struct vnode *nvp;
|
||||
int error;
|
||||
|
||||
ifhp = (struct ifid *)fhp;
|
||||
|
||||
if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
|
||||
*vpp = NULLVP;
|
||||
return (error);
|
||||
}
|
||||
|
||||
*vpp = nvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
udf_vptofh (struct vnode *vp, struct fid *fhp)
|
||||
{
|
||||
struct udf_node *node;
|
||||
struct ifid *ifhp;
|
||||
|
||||
node = VTON(vp);
|
||||
ifhp = (struct ifid *)fhp;
|
||||
ifhp->ifid_len = sizeof(struct ifid);
|
||||
ifhp->ifid_ino = node->hash_id;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
udf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd)
|
||||
{
|
||||
union udf_pmap *pmap;
|
||||
struct part_map_spare *pms;
|
||||
struct regid *pmap_id;
|
||||
struct buf *bp;
|
||||
unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
|
||||
int i, ptype, psize, error;
|
||||
|
||||
for (i = 0; i < lvd->n_pm; i++) {
|
||||
pmap = (union udf_pmap *)&lvd->maps[i * UDF_PMAP_SIZE];
|
||||
ptype = pmap->data[0];
|
||||
psize = pmap->data[1];
|
||||
if (((ptype != 1) && (ptype != 2)) ||
|
||||
((psize != UDF_PMAP_SIZE) && (psize != 6))) {
|
||||
printf("Invalid partition map found\n");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (ptype == 1) {
|
||||
/* Type 1 map. We don't care */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Type 2 map. Gotta find out the details */
|
||||
pmap_id = (struct regid *)&pmap->data[4];
|
||||
bzero(®id_id[0], UDF_REGID_ID_SIZE);
|
||||
bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE);
|
||||
|
||||
if (bcmp(®id_id[0], "*UDF Sparable Partition",
|
||||
UDF_REGID_ID_SIZE)) {
|
||||
printf("Unsupported partition map: %s\n", ®id_id[0]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
pms = &pmap->pms;
|
||||
MALLOC(udfmp->s_table, struct udf_sparing_table *, pms->st_size,
|
||||
M_UDFSTABLE, M_NOWAIT | M_ZERO);
|
||||
if (udfmp->s_table == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/* Calculate the number of sectors per packet. */
|
||||
/* XXX Logical or physical? */
|
||||
udfmp->p_sectors = pms->packet_len / udfmp->bsize;
|
||||
|
||||
/*
|
||||
* XXX If reading the first Sparing Table fails, should look
|
||||
* for another table.
|
||||
*/
|
||||
if ((error = udf_readlblks(udfmp, pms->st_loc[0], pms->st_size,
|
||||
&bp)) != 0) {
|
||||
printf("Failed to read Sparing Table at sector %d\n",
|
||||
pms->st_loc[0]);
|
||||
return (error);
|
||||
}
|
||||
bcopy(bp->b_data, udfmp->s_table, pms->st_size);
|
||||
brelse(bp);
|
||||
|
||||
if (udf_checktag(&udfmp->s_table->tag, 0)) {
|
||||
printf("Invalid sparing table found\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* See how many valid entries there are here. The list is
|
||||
* supposed to be sorted. 0xfffffff0 and higher are not valid
|
||||
*/
|
||||
for (i = 0; i < udfmp->s_table->rt_l; i++) {
|
||||
udfmp->s_table_entries = i;
|
||||
if (udfmp->s_table->entries[i].org >= 0xfffffff0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
1232
sys/fs/udf/udf_vnops.c
Normal file
1232
sys/fs/udf/udf_vnops.c
Normal file
File diff suppressed because it is too large
Load Diff
14
sys/modules/udf/Makefile
Normal file
14
sys/modules/udf/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../fs/udf
|
||||
|
||||
KMOD= udf
|
||||
|
||||
SRCS= udf_vfsops.c udf_vnops.c osta.c
|
||||
SRCS+= vnode_if.h
|
||||
NOMAN=
|
||||
|
||||
CFLAGS+= -g
|
||||
|
||||
CLEANFILES= .depend
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user