Actually add the UDF files!

This commit is contained in:
Scott Long 2002-04-14 16:52:14 +00:00
parent b6bd548cdc
commit 51a7b740a1
11 changed files with 3225 additions and 0 deletions

12
sbin/mount_udf/Makefile Normal file
View 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>

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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(&regid_id[0], UDF_REGID_ID_SIZE);
bcopy(&pmap_id->id[0], &regid_id[0], UDF_REGID_ID_SIZE);
if (bcmp(&regid_id[0], "*UDF Sparable Partition",
UDF_REGID_ID_SIZE)) {
printf("Unsupported partition map: %s\n", &regid_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

File diff suppressed because it is too large Load Diff

14
sys/modules/udf/Makefile Normal file
View 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>